mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-23 08:48:07 -06:00
Compare commits
83 Commits
release-4.
...
v4_0_x
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2f3d1ec2c | ||
|
|
bc6e3ae40d | ||
|
|
b02e239f7c | ||
|
|
397cd4bf60 | ||
|
|
409f972ad3 | ||
|
|
267961ffca | ||
|
|
dff753c452 | ||
|
|
ce3bafd30d | ||
|
|
e5538d9f25 | ||
|
|
7a8a32b1c3 | ||
|
|
cac5e0391b | ||
|
|
726790fa93 | ||
|
|
c9c7a5be53 | ||
|
|
1495513cfc | ||
|
|
085afaac14 | ||
|
|
d58a54c758 | ||
|
|
78d9bcb6a1 | ||
|
|
1a43cd329d | ||
|
|
2fe687eeca | ||
|
|
107bd8a54f | ||
|
|
865df3fcf1 | ||
|
|
cbf9c52462 | ||
|
|
171e25e962 | ||
|
|
239d14fd10 | ||
|
|
0b7a175156 | ||
|
|
b37dbb60b5 | ||
|
|
d5acd1f210 | ||
|
|
65eda4a68e | ||
|
|
7209881025 | ||
|
|
a5d0a4b619 | ||
|
|
79276a8786 | ||
|
|
fa2b645a64 | ||
|
|
4d5d6df734 | ||
|
|
2c39b69c18 | ||
|
|
13c0077e95 | ||
|
|
9299e3f371 | ||
|
|
b9ddc6ee86 | ||
|
|
276856a614 | ||
|
|
fbd6a8a0da | ||
|
|
6fc18b4af6 | ||
|
|
44d633fb68 | ||
|
|
eb4bf6cc68 | ||
|
|
6db6c850eb | ||
|
|
02ae1e3734 | ||
|
|
eb887139fd | ||
|
|
84805f7fb8 | ||
|
|
2719131ed2 | ||
|
|
52401bd2b0 | ||
|
|
4834703bc4 | ||
|
|
3ed73244b1 | ||
|
|
97cd430125 | ||
|
|
d202b85d51 | ||
|
|
c51b79e9fc | ||
|
|
4449018207 | ||
|
|
ced8e41473 | ||
|
|
2c66ed6708 | ||
|
|
c7d3d6ac90 | ||
|
|
13210b3e9f | ||
|
|
6e622fc23b | ||
|
|
ae35111b59 | ||
|
|
e1c3d419a7 | ||
|
|
7396b8adba | ||
|
|
c09001545d | ||
|
|
f8d4315f7e | ||
|
|
1fa2957d27 | ||
|
|
ade50d2b53 | ||
|
|
0fa1d35b87 | ||
|
|
6486fc5f4d | ||
|
|
1e059ab1a2 | ||
|
|
15b137211b | ||
|
|
6f8f1d7bad | ||
|
|
a31f0c0a3d | ||
|
|
f977d1293a | ||
|
|
1399be50cb | ||
|
|
52dcf32cc8 | ||
|
|
52b2b807ab | ||
|
|
5cf4f00824 | ||
|
|
faa6fad025 | ||
|
|
9f94bbce3a | ||
|
|
5c49b2486c | ||
|
|
4f6e7f97c6 | ||
|
|
7751c5b75c | ||
|
|
a1a9f3317b |
19
.travis.yml
19
.travis.yml
@@ -76,10 +76,13 @@ before_install:
|
||||
|
||||
- shopt -s expand_aliases
|
||||
- alias make="colormake -j3" # Using nprocs/2 sometimes may fail (gcc is killed by system)
|
||||
#- libt_path="$HOME/libt_install"
|
||||
#- ltconf="$ltconf --prefix="$libt_path" --disable-geoip"
|
||||
- qbt_path="$HOME/qbt_install"
|
||||
- qbtconf="$qbtconf --prefix="$qbt_path" PKG_CONFIG_PATH="$libt_path/lib/pkgconfig":/opt/qt55/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
qbtconf="$qbtconf --prefix="$qbt_path" PKG_CONFIG_PATH=/opt/qt55/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
else
|
||||
qbtconf="$qbtconf --prefix="$qbt_path""
|
||||
fi
|
||||
|
||||
# options for specific branches
|
||||
- if [ "$gui" = false ]; then qbtconf="$qbtconf --disable-gui" ; fi
|
||||
@@ -131,13 +134,13 @@ install:
|
||||
cp "version" $HOME/hombebrew_cache
|
||||
cd "$HOME/hombebrew_cache"
|
||||
wget https://builds.shiki.hu/homebrew/libtorrent-rasterbar.rb
|
||||
wget https://builds.shiki.hu/homebrew/libtorrent-rasterbar-1.0.11+git20170910.6d5625e0ea.el_capitan.bottle.tar.gz
|
||||
wget https://builds.shiki.hu/homebrew/libtorrent-rasterbar-1.1.6+git20180101.b45acf28a5+patched-configure.el_capitan.bottle.tar.gz
|
||||
fi
|
||||
|
||||
# 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.11+git20170910.6d5625e0ea.el_capitan.bottle.tar.gz" "$(brew --cache)"
|
||||
cp "$HOME/hombebrew_cache/libtorrent-rasterbar-1.1.6+git20180101.b45acf28a5+patched-configure.el_capitan.bottle.tar.gz" "$(brew --cache)"
|
||||
brew install "$HOME/hombebrew_cache/libtorrent-rasterbar.rb"
|
||||
|
||||
if [ "$build_system" = "cmake" ]; then
|
||||
@@ -168,11 +171,15 @@ script:
|
||||
BUILD_TOOL="ninja"
|
||||
fi
|
||||
if [ "$build_system" = "qmake" ]; then
|
||||
./bootstrap.sh && ./configure $qbtconf
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
# For some reason for RC_1_1 we need to also specify the OpenSSL compiler/linker flags
|
||||
# Homebrew doesn't symlink OpenSSL for security reasons
|
||||
./bootstrap.sh && ./configure $qbtconf CXXFLAGS="$(PKG_CONFIG_PATH="/usr/local/opt/openssl/lib/pkgconfig:$PKG_CONFIG_PATH" pkg-config --cflags openssl)" LDFLAGS="$(PKG_CONFIG_PATH="/usr/local/opt/openssl/lib/pkgconfig:$PKG_CONFIG_PATH" pkg-config --libs openssl)"
|
||||
sed -i "" -e "s/^\(CC.*&&\).*$/\1 $CC/" src/Makefile # workaround for Qt & ccache: https://bugreports.qt.io/browse/QTBUG-31034
|
||||
sed -i "" -e "s/^\(CXX.*&&\).*$/\1 $CXX/" src/Makefile
|
||||
sed -i "" -e 's/^\(CXXFLAGS.*\)$/\1 -Wno-unused-local-typedefs -Wno-inconsistent-missing-override/' src/Makefile
|
||||
else
|
||||
./bootstrap.sh && ./configure $qbtconf
|
||||
fi
|
||||
BUILD_TOOL="make"
|
||||
fi
|
||||
|
||||
@@ -240,7 +240,23 @@ Example:
|
||||
|
||||
```
|
||||
|
||||
### 9. Misc. ###
|
||||
### 9. Include guard. ###
|
||||
`#pragma once` should be used instead of "include guard" in new code:
|
||||
```c++
|
||||
// examplewidget.h
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class ExampleWidget : public QWidget
|
||||
{
|
||||
// (some code omitted)
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### 10. Misc. ###
|
||||
|
||||
* Line breaks for long lines with operation:
|
||||
|
||||
|
||||
62
Changelog
62
Changelog
@@ -1,3 +1,65 @@
|
||||
* Fri Feb 16 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.0.4
|
||||
- FEATURE: Add source field in Torrent creator. Closes #7965. (Chocobo1)
|
||||
- FEATURE: Torrent creator: raise maximum piece size to 32 MiB (Chocobo1)
|
||||
- FEATURE: Add a force reannounce option in the transfer list context menu. Closes #6448. (Jesse Bryan)
|
||||
- BUGFIX: Fix sorting of country flags column in Peers tab. (sledgehammer999)
|
||||
- BUGFIX: Fix natural sorting when the common part of 2 strings ends partially in a number which continues in the uncommon part. Closes #8080 #6732. (sledgehammer999)
|
||||
- BUGFIX: Fix application of speed limits on LAN and μTP connections. Closes #7745. (sledgehammer999)
|
||||
- BUGFIX: Make peer information flags in peerlist more readable. (thalieht)
|
||||
- BUGFIX: Fix gui issues on high DPI monitor. (Chocobo1)
|
||||
- BUGFIX: Fix dialog and column size on high DPI monitors. (Chocobo1)
|
||||
- BUGFIX: Fix constant status of '[F] Downloading'. Closes #7628. (sledgehammer999)
|
||||
- BUGFIX: Fix translation context. Closes #8211. (sledgehammer999)
|
||||
- BUGFIX: Separate subnet whitelist options into two lines. (Thomas Piccirello)
|
||||
- BUGFIX: Don't set application name twice. (Luís Pereira)
|
||||
- BUGFIX: Set default file log size to 65 KiB and delete backup logs older than 1 month. (sledgehammer999)
|
||||
- WEBUI: Only prepend scheme when it is not present. Closes #8057. (Chocobo1)
|
||||
- WEBUI: Add "Remaining" and "Availability" columns to webui Content tab. (Thomas Piccirello)
|
||||
- WEBUI: Make value formatting consistent with GUI (Thomas Piccirello)
|
||||
- WEBUI: Reposition Total Size column to match gui (Thomas Piccirello)
|
||||
- WEBUI: Add Tags and Time Active columns (Thomas Piccirello)
|
||||
- WEBUI: Use https for www.qbittorrent.org (Thomas Piccirello)
|
||||
- WEBUI: Match webui statuses to gui, closes #7516 (Thomas Piccirello)
|
||||
- WEBUI: Right-align stat values (Thomas Piccirello)
|
||||
- WEBUI: Add missing units. (Thomas Piccirello)
|
||||
- RSS: Fix crash when deleting rule because it tries to update. Closes #8094 (glassez)
|
||||
- RSS: Don't process new/updated RSS rules when disabled (glassez)
|
||||
- RSS: Remove legacy and corrupted RSS settings (glassez)
|
||||
- SEARCH: Search only when category is supported by plugin. Closes #8053. (jan.karberg)
|
||||
- SEARCH: Only add search separators as needed. (Thomas Piccirello)
|
||||
- COSMETIC: Tweak spacing in torrent properties widget and speed widget. (Chocobo1)
|
||||
- WINDOWS: Use standard folder icon for open file behavior on Windows. Closes #7880. (Chocobo1)
|
||||
- WINDOWS: Revert "Run external program" function. Now you will not be able to directly run batch scripts. (Chocobo1)
|
||||
- MACOS: Fix torrent file selection in Finder on mac (vit9696)
|
||||
- MACOS: Fix Finder reveal in preview and torrent contents (vit9696)
|
||||
- MACOS: Fix cmd+w not closing the main window on macOS (vit9696)
|
||||
- OTHER: Fix splitting of compiler flags in configure. Autoconf removes a set of [] during script translation, resulting in a wrong sed command. (sledgehammer999)
|
||||
- OTHER: configure: Parse all compiler related flags together. (sledgehammer999)
|
||||
- OTHER: Update copyright year. (sledgehammer999)
|
||||
|
||||
* Sun Dec 17 2017 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.0.3
|
||||
- BUGFIX: Add height padding to the transfer list icons. Closes #7951. (sledgehammer999)
|
||||
- BUGFIX: Allow to drag-n-drop URLs into mainwindow to initiate download. (Chocobo1)
|
||||
- BUGFIX: Fix crash when fitlering search results. Stable sorting is removed. Closes #7952.(Chocobo1)
|
||||
- WEBUI: Fix missing qbt logo on login page in webUI. Closes #7953. (Chocobo1)
|
||||
- WEBUI: Add check to avoid type error after logout. (Chocobo1)
|
||||
- WEBUI: Use POST for logout command. This is to avoid browser being smart to prefetch the link then logging out the user. (Chocobo1)
|
||||
- WEBUI: Fix WebUI is not reachable via IPv6. (glassez)
|
||||
- WINDOWS: Disable the "?" help button in all dialogs on Windows. Closes #7365. Requires Qt 5.10. (Chocobo1)
|
||||
|
||||
* Fri Dec 01 2017 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.0.2
|
||||
- BUGFIX: Fix crash on some systems when creating address object for 255.255.255.255. Closes #7735. (sledgehammer999)
|
||||
- PERFORMANCE: Change MixedModeAlgorithm default to TCP. This was the v3_3_x default and should sustain higher speeds. Closes #7779. (Chocobo1)
|
||||
- PERFORMANCE: Stop logging IP filter parsing errors after a while, otherwise the GUI freezes or qBittorrent doesn't start. (sledgehammer999)
|
||||
- GUI: Implement stable sort. Rows in transfer list shouldn't flicker anymore. (Chocobo1)
|
||||
- WEBUI: Fix build when webui is disabled. (Heiko Becker)
|
||||
- RSS: Fix build because of missing header. Closes #7805. (thoradia)
|
||||
- RSS: Fix RSS parser. (glassez)
|
||||
- RSS: Implement Import/Export RSS rules in legacy(aka v3_3_x) format. (glassez)
|
||||
- RSS: Implement Import/Export RSS rules in JSON format. (glassez)
|
||||
- WINDOWS: Fixed blurry text under Windows by setting DPI awareness to default. (TheNicker)
|
||||
- LINUX: Fix i386 build. (Evgeny Lensky)
|
||||
|
||||
* Wed Nov 22 2017 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.0.1
|
||||
- BUGFIX: Fix crash on opening torrent/magnet (uninitialized pointer). Closes #7739 #7723. (sledgehammer999)
|
||||
- BUGFIX: Enable preferences Apply button when ip banlist is modified (Thomas Piccirello)
|
||||
|
||||
@@ -35,7 +35,7 @@ You can also download it from [here](https://github.com/qbittorrent/qBittorrent/
|
||||
|
||||
### Misc:
|
||||
For more information please visit:
|
||||
http://www.qbittorrent.org
|
||||
https://www.qbittorrent.org
|
||||
|
||||
or our wiki here:
|
||||
http://wiki.qbittorrent.org
|
||||
|
||||
40
configure
vendored
40
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for qbittorrent v3.2.0alpha.
|
||||
# Generated by GNU Autoconf 2.69 for qbittorrent v4.0.4.
|
||||
#
|
||||
# Report bugs to <bugs.qbittorrent.org>.
|
||||
#
|
||||
@@ -580,10 +580,10 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='qbittorrent'
|
||||
PACKAGE_TARNAME='qbittorrent'
|
||||
PACKAGE_VERSION='v3.2.0alpha'
|
||||
PACKAGE_STRING='qbittorrent v3.2.0alpha'
|
||||
PACKAGE_VERSION='v4.0.4'
|
||||
PACKAGE_STRING='qbittorrent v4.0.4'
|
||||
PACKAGE_BUGREPORT='bugs.qbittorrent.org'
|
||||
PACKAGE_URL='http://www.qbittorrent.org/'
|
||||
PACKAGE_URL='https://www.qbittorrent.org/'
|
||||
|
||||
ac_subst_vars='am__EXEEXT_FALSE
|
||||
am__EXEEXT_TRUE
|
||||
@@ -1296,7 +1296,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures qbittorrent v3.2.0alpha to adapt to many kinds of systems.
|
||||
\`configure' configures qbittorrent v4.0.4 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1367,7 +1367,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of qbittorrent v3.2.0alpha:";;
|
||||
short | recursive ) echo "Configuration of qbittorrent v4.0.4:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1438,7 +1438,7 @@ Use these variables to override the choices made by `configure' or to help
|
||||
it to find libraries and programs with nonstandard names/locations.
|
||||
|
||||
Report bugs to <bugs.qbittorrent.org>.
|
||||
qbittorrent home page: <http://www.qbittorrent.org/>.
|
||||
qbittorrent home page: <https://www.qbittorrent.org/>.
|
||||
_ACEOF
|
||||
ac_status=$?
|
||||
fi
|
||||
@@ -1501,7 +1501,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
qbittorrent configure v3.2.0alpha
|
||||
qbittorrent configure v4.0.4
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -1640,7 +1640,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by qbittorrent $as_me v3.2.0alpha, which was
|
||||
It was created by qbittorrent $as_me v4.0.4, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -3818,7 +3818,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='qbittorrent'
|
||||
VERSION='v3.2.0alpha'
|
||||
VERSION='v4.0.4'
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@@ -4705,9 +4705,8 @@ fi
|
||||
libsubdirs="lib64 libx32 lib lib64" ;; #(
|
||||
ppc64|s390x|sparc64|aarch64|ppc64le) :
|
||||
libsubdirs="lib64 lib lib64" ;; #(
|
||||
libsubdirs="lib") :
|
||||
;; #(
|
||||
*) :
|
||||
libsubdirs="lib"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -5502,7 +5501,7 @@ extract() {
|
||||
new_line='
|
||||
'
|
||||
# Convert " -" to "\n" if not between quotes and remove possible leading white spaces
|
||||
string=$(echo " $*" | $SED -e "s: -:\\${new_line}:g" -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g" -e 's/^[:space:]*//')
|
||||
string=$(echo " $*" | $SED -e "s: -:\\${new_line}:g" -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g" -e 's/^[[:space:]]*//')
|
||||
SAVEIFS=$IFS
|
||||
IFS=$(printf "\n\b")
|
||||
for i in $string; do
|
||||
@@ -5516,9 +5515,8 @@ extract() {
|
||||
IFS=$SAVEIFS
|
||||
}
|
||||
|
||||
extract $CPPFLAGS
|
||||
extract "$CFLAGS $CPPFLAGS $CXXFLAGS"
|
||||
QBT_ADD_DEFINES="$QBT_ADD_DEFINES $QBT_CONF_DEFINES"
|
||||
QBT_CONF_EXTRA_CFLAGS="$QBT_CONF_EXTRA_CFLAGS $CXXFLAGS"
|
||||
|
||||
# Substitute the values of these vars in conf.pri.in
|
||||
|
||||
@@ -6100,7 +6098,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by qbittorrent $as_me v3.2.0alpha, which was
|
||||
This file was extended by qbittorrent $as_me v4.0.4, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -6152,13 +6150,13 @@ Configuration commands:
|
||||
$config_commands
|
||||
|
||||
Report bugs to <bugs.qbittorrent.org>.
|
||||
qbittorrent home page: <http://www.qbittorrent.org/>."
|
||||
qbittorrent home page: <https://www.qbittorrent.org/>."
|
||||
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
qbittorrent config.status v3.2.0alpha
|
||||
qbittorrent config.status v4.0.4
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
@@ -7415,7 +7413,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by qbittorrent $as_me v3.2.0alpha, which was
|
||||
This file was extended by qbittorrent $as_me v4.0.4, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -7467,13 +7465,13 @@ Configuration commands:
|
||||
$config_commands
|
||||
|
||||
Report bugs to <bugs.qbittorrent.org>.
|
||||
qbittorrent home page: <http://www.qbittorrent.org/>."
|
||||
qbittorrent home page: <https://www.qbittorrent.org/>."
|
||||
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
qbittorrent config.status v3.2.0alpha
|
||||
qbittorrent config.status v4.0.4
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
AC_INIT([qbittorrent], [v3.2.0alpha], [bugs.qbittorrent.org], [], [http://www.qbittorrent.org/])
|
||||
AC_INIT([qbittorrent], [v4.0.4], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_PROG_CC
|
||||
@@ -190,7 +190,7 @@ extract() {
|
||||
new_line='
|
||||
'
|
||||
# Convert " -" to "\n" if not between quotes and remove possible leading white spaces
|
||||
string=$(echo " $*" | $SED -e "s: -:\\${new_line}:g" -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g" -e 's/^[[:space:]]*//')
|
||||
string=$(echo " $*" | $SED -e "s: -:\\${new_line}:g" -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g" -e 's/^[[[:space:]]]*//')
|
||||
SAVEIFS=$IFS
|
||||
IFS=$(printf "\n\b")
|
||||
for i in $string; do
|
||||
@@ -204,9 +204,8 @@ extract() {
|
||||
IFS=$SAVEIFS
|
||||
}
|
||||
|
||||
extract $CPPFLAGS
|
||||
extract "$CFLAGS $CPPFLAGS $CXXFLAGS"
|
||||
QBT_ADD_DEFINES="$QBT_ADD_DEFINES $QBT_CONF_DEFINES"
|
||||
QBT_CONF_EXTRA_CFLAGS="$QBT_CONF_EXTRA_CFLAGS $CXXFLAGS"
|
||||
|
||||
# Substitute the values of these vars in conf.pri.in
|
||||
AC_SUBST(QBT_CONF_INCLUDES)
|
||||
|
||||
4
dist/mac/Info.plist
vendored
4
dist/mac/Info.plist
vendored
@@ -45,7 +45,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.0.1</string>
|
||||
<string>4.0.4</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>qBit</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
@@ -59,7 +59,7 @@
|
||||
<key>NSAppleScriptEnabled</key>
|
||||
<string>YES</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2006-2017 The qBittorrent project</string>
|
||||
<string>Copyright © 2006-2018 The qBittorrent project</string>
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
||||
2
dist/unix/qbittorrent.appdata.xml
vendored
2
dist/unix/qbittorrent.appdata.xml
vendored
@@ -56,7 +56,7 @@
|
||||
</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<url type="homepage">http://www.qbittorrent.org/</url>
|
||||
<url type="homepage">https://www.qbittorrent.org/</url>
|
||||
<update_contact>sledgehammer999@qbittorrent.org</update_contact>
|
||||
<developer_name>The qBittorrent Project</developer_name>
|
||||
<url type="bugtracker">http://bugs.qbittorrent.org/</url>
|
||||
|
||||
2
dist/windows/installer.nsi
vendored
2
dist/windows/installer.nsi
vendored
@@ -86,7 +86,7 @@ Section $(inst_qbt_req) ;"qBittorrent (required)"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "UninstallString" '"$INSTDIR\uninst.exe"'
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "DisplayIcon" '"$INSTDIR\qbittorrent.exe",0'
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "Publisher" "The qBittorrent project"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "URLInfoAbout" "http://www.qbittorrent.org"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "URLInfoAbout" "https://www.qbittorrent.org"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "DisplayVersion" "${PROG_VERSION}"
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "NoModify" 1
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "NoRepair" 1
|
||||
|
||||
4
dist/windows/options.nsi
vendored
4
dist/windows/options.nsi
vendored
@@ -27,7 +27,7 @@ XPStyle on
|
||||
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
|
||||
|
||||
; Program specific
|
||||
!define PROG_VERSION "4.0.1"
|
||||
!define PROG_VERSION "4.0.4"
|
||||
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
|
||||
@@ -50,7 +50,7 @@ XPStyle on
|
||||
;Installer Version Information
|
||||
VIAddVersionKey "ProductName" "qBittorrent"
|
||||
VIAddVersionKey "CompanyName" "The qBittorrent project"
|
||||
VIAddVersionKey "LegalCopyright" "Copyright ©2006-2017 The qBittorrent project"
|
||||
VIAddVersionKey "LegalCopyright" "Copyright ©2006-2018 The qBittorrent project"
|
||||
VIAddVersionKey "FileDescription" "qBittorrent - A Bittorrent Client"
|
||||
VIAddVersionKey "FileVersion" "${PROG_VERSION}"
|
||||
|
||||
|
||||
2
dist/windows/qt.conf
vendored
2
dist/windows/qt.conf
vendored
@@ -2,4 +2,4 @@
|
||||
Translations = translations
|
||||
|
||||
[Platforms]
|
||||
WindowsArguments = dpiawareness=1
|
||||
;WindowsArguments = dpiawareness=1
|
||||
|
||||
@@ -114,7 +114,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
|
||||
AS_CASE([${host_cpu}],
|
||||
[x86_64],[libsubdirs="lib64 libx32 lib lib64"],
|
||||
[ppc64|s390x|sparc64|aarch64|ppc64le],[libsubdirs="lib64 lib lib64"],
|
||||
[libsubdirs="lib"],
|
||||
[libsubdirs="lib"]
|
||||
)
|
||||
|
||||
dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace
|
||||
const QString KEY_FILELOGGER_PATH = FILELOGGER_SETTINGS_KEY("Path");
|
||||
const QString KEY_FILELOGGER_BACKUP = FILELOGGER_SETTINGS_KEY("Backup");
|
||||
const QString KEY_FILELOGGER_DELETEOLD = FILELOGGER_SETTINGS_KEY("DeleteOld");
|
||||
const QString KEY_FILELOGGER_MAXSIZE = FILELOGGER_SETTINGS_KEY("MaxSize");
|
||||
const QString KEY_FILELOGGER_MAXSIZEBYTES = FILELOGGER_SETTINGS_KEY("MaxSizeBytes");
|
||||
const QString KEY_FILELOGGER_AGE = FILELOGGER_SETTINGS_KEY("Age");
|
||||
const QString KEY_FILELOGGER_AGETYPE = FILELOGGER_SETTINGS_KEY("AgeType");
|
||||
|
||||
@@ -98,6 +98,10 @@ namespace
|
||||
const char PARAMS_SEPARATOR[] = "|";
|
||||
|
||||
const QString DEFAULT_PORTABLE_MODE_PROFILE_DIR = QLatin1String("profile");
|
||||
|
||||
const int MIN_FILELOG_SIZE = 1024; // 1KiB
|
||||
const int MAX_FILELOG_SIZE = 1000 * 1024 * 1024; // 1000MiB
|
||||
const int DEFAULT_FILELOG_SIZE = 65 * 1024; // 65KiB
|
||||
}
|
||||
|
||||
Application::Application(const QString &id, int &argc, char **argv)
|
||||
@@ -105,7 +109,9 @@ Application::Application(const QString &id, int &argc, char **argv)
|
||||
, m_running(false)
|
||||
, m_shutdownAct(ShutdownDialogAction::Exit)
|
||||
, m_commandLineArgs(parseCommandLine(this->arguments()))
|
||||
#ifndef DISABLE_WEBUI
|
||||
, m_webui(nullptr)
|
||||
#endif
|
||||
{
|
||||
qRegisterMetaType<Log::Msg>("Log::Msg");
|
||||
|
||||
@@ -126,7 +132,6 @@ Application::Application(const QString &id, int &argc, char **argv)
|
||||
if (m_commandLineArgs.webUiPort > 0) // it will be -1 when user did not set any value
|
||||
Preferences::instance()->setWebUiPort(m_commandLineArgs.webUiPort);
|
||||
|
||||
setApplicationName("qBittorrent");
|
||||
initializeTranslation();
|
||||
|
||||
#if !defined(DISABLE_GUI)
|
||||
@@ -219,29 +224,22 @@ void Application::setFileLoggerDeleteOld(bool value)
|
||||
|
||||
int Application::fileLoggerMaxSize() const
|
||||
{
|
||||
int val = settings()->loadValue(KEY_FILELOGGER_MAXSIZE, 10).toInt();
|
||||
if (val < 1)
|
||||
return 1;
|
||||
if (val > 1000)
|
||||
return 1000;
|
||||
return val;
|
||||
int val = settings()->loadValue(KEY_FILELOGGER_MAXSIZEBYTES, DEFAULT_FILELOG_SIZE).toInt();
|
||||
return std::min(std::max(val, MIN_FILELOG_SIZE), MAX_FILELOG_SIZE);
|
||||
}
|
||||
|
||||
void Application::setFileLoggerMaxSize(const int value)
|
||||
void Application::setFileLoggerMaxSize(const int bytes)
|
||||
{
|
||||
int clampedValue = std::min(std::max(bytes, MIN_FILELOG_SIZE), MAX_FILELOG_SIZE);
|
||||
if (m_fileLogger)
|
||||
m_fileLogger->setMaxSize(value);
|
||||
settings()->storeValue(KEY_FILELOGGER_MAXSIZE, std::min(std::max(value, 1), 1000));
|
||||
m_fileLogger->setMaxSize(clampedValue);
|
||||
settings()->storeValue(KEY_FILELOGGER_MAXSIZEBYTES, clampedValue);
|
||||
}
|
||||
|
||||
int Application::fileLoggerAge() const
|
||||
{
|
||||
int val = settings()->loadValue(KEY_FILELOGGER_AGE, 6).toInt();
|
||||
if (val < 1)
|
||||
return 1;
|
||||
if (val > 365)
|
||||
return 365;
|
||||
return val;
|
||||
int val = settings()->loadValue(KEY_FILELOGGER_AGE, 1).toInt();
|
||||
return std::min(std::max(val, 1), 365);
|
||||
}
|
||||
|
||||
void Application::setFileLoggerAge(const int value)
|
||||
@@ -289,27 +287,6 @@ void Application::runExternalProgram(BitTorrent::TorrentHandle *const torrent) c
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
QProcess::startDetached(QLatin1String("/bin/sh"), {QLatin1String("-c"), program});
|
||||
#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 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;
|
||||
}
|
||||
|
||||
STARTUPINFOW si = {0};
|
||||
si.cb = sizeof(si);
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
|
||||
WCHAR *arg = new WCHAR[program.size() + 1];
|
||||
program.toWCharArray(arg);
|
||||
arg[program.size()] = L'\0';
|
||||
if (CreateProcessW(NULL, arg, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
delete[] arg;
|
||||
#else
|
||||
QProcess::startDetached(program);
|
||||
#endif
|
||||
|
||||
@@ -101,7 +101,7 @@ public:
|
||||
bool isFileLoggerDeleteOld() const;
|
||||
void setFileLoggerDeleteOld(bool value);
|
||||
int fileLoggerMaxSize() const;
|
||||
void setFileLoggerMaxSize(const int value);
|
||||
void setFileLoggerMaxSize(const int bytes);
|
||||
int fileLoggerAge() const;
|
||||
void setFileLoggerAge(const int value);
|
||||
int fileLoggerAgeType() const;
|
||||
|
||||
@@ -135,7 +135,7 @@ void FileLogger::addLogMessage(const Log::Msg &msg)
|
||||
|
||||
str << QDateTime::fromMSecsSinceEpoch(msg.timestamp).toString(Qt::ISODate) << " - " << msg.message << endl;
|
||||
|
||||
if (m_backup && (m_logFile->size() >= (m_maxSize * 1024 * 1024))) {
|
||||
if (m_backup && (m_logFile->size() >= m_maxSize)) {
|
||||
closeLogFile();
|
||||
int counter = 0;
|
||||
QString backupLogFilename = m_path + ".bak";
|
||||
|
||||
@@ -212,6 +212,10 @@ int main(int argc, char *argv[])
|
||||
// 3. https://bugreports.qt.io/browse/QTBUG-46015
|
||||
|
||||
qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1));
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
// this is the default in Qt6
|
||||
app->setAttribute(Qt::AA_DisableWindowContextHelpButton);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
|
||||
@@ -1,124 +1,124 @@
|
||||
HEADERS += \
|
||||
$$PWD/asyncfilestorage.h \
|
||||
$$PWD/types.h \
|
||||
$$PWD/tristatebool.h \
|
||||
$$PWD/bittorrent/addtorrentparams.h \
|
||||
$$PWD/bittorrent/cachestatus.h \
|
||||
$$PWD/bittorrent/infohash.h \
|
||||
$$PWD/bittorrent/magneturi.h \
|
||||
$$PWD/bittorrent/peerinfo.h \
|
||||
$$PWD/bittorrent/private/bandwidthscheduler.h \
|
||||
$$PWD/bittorrent/private/filterparserthread.h \
|
||||
$$PWD/bittorrent/private/resumedatasavingmanager.h \
|
||||
$$PWD/bittorrent/private/speedmonitor.h \
|
||||
$$PWD/bittorrent/private/statistics.h \
|
||||
$$PWD/bittorrent/session.h \
|
||||
$$PWD/bittorrent/sessionstatus.h \
|
||||
$$PWD/bittorrent/torrentcreatorthread.h \
|
||||
$$PWD/bittorrent/torrenthandle.h \
|
||||
$$PWD/bittorrent/torrentinfo.h \
|
||||
$$PWD/bittorrent/tracker.h \
|
||||
$$PWD/bittorrent/trackerentry.h \
|
||||
$$PWD/filesystemwatcher.h \
|
||||
$$PWD/logger.h \
|
||||
$$PWD/settingsstorage.h \
|
||||
$$PWD/settingvalue.h \
|
||||
$$PWD/preferences.h \
|
||||
$$PWD/indexrange.h \
|
||||
$$PWD/iconprovider.h \
|
||||
$$PWD/http/irequesthandler.h \
|
||||
$$PWD/global.h \
|
||||
$$PWD/http/connection.h \
|
||||
$$PWD/http/irequesthandler.h \
|
||||
$$PWD/http/requestparser.h \
|
||||
$$PWD/http/responsebuilder.h \
|
||||
$$PWD/http/responsegenerator.h \
|
||||
$$PWD/http/server.h \
|
||||
$$PWD/http/types.h \
|
||||
$$PWD/http/responsebuilder.h \
|
||||
$$PWD/iconprovider.h \
|
||||
$$PWD/indexrange.h \
|
||||
$$PWD/logger.h \
|
||||
$$PWD/net/dnsupdater.h \
|
||||
$$PWD/net/downloadmanager.h \
|
||||
$$PWD/net/downloadhandler.h \
|
||||
$$PWD/net/downloadmanager.h \
|
||||
$$PWD/net/geoipmanager.h \
|
||||
$$PWD/net/portforwarder.h \
|
||||
$$PWD/net/private/geoipdatabase.h \
|
||||
$$PWD/net/proxyconfigurationmanager.h \
|
||||
$$PWD/net/reverseresolution.h \
|
||||
$$PWD/net/smtp.h \
|
||||
$$PWD/net/private/geoipdatabase.h \
|
||||
$$PWD/bittorrent/addtorrentparams.h \
|
||||
$$PWD/bittorrent/infohash.h \
|
||||
$$PWD/bittorrent/session.h \
|
||||
$$PWD/bittorrent/sessionstatus.h \
|
||||
$$PWD/bittorrent/cachestatus.h \
|
||||
$$PWD/bittorrent/magneturi.h \
|
||||
$$PWD/bittorrent/torrentinfo.h \
|
||||
$$PWD/bittorrent/torrenthandle.h \
|
||||
$$PWD/bittorrent/peerinfo.h \
|
||||
$$PWD/bittorrent/trackerentry.h \
|
||||
$$PWD/bittorrent/tracker.h \
|
||||
$$PWD/bittorrent/torrentcreatorthread.h \
|
||||
$$PWD/bittorrent/private/speedmonitor.h \
|
||||
$$PWD/bittorrent/private/bandwidthscheduler.h \
|
||||
$$PWD/bittorrent/private/filterparserthread.h \
|
||||
$$PWD/bittorrent/private/statistics.h \
|
||||
$$PWD/bittorrent/private/resumedatasavingmanager.h \
|
||||
$$PWD/preferences.h \
|
||||
$$PWD/private/profile_p.h \
|
||||
$$PWD/profile.h \
|
||||
$$PWD/rss/private/rss_parser.h \
|
||||
$$PWD/rss/rss_article.h \
|
||||
$$PWD/rss/rss_item.h \
|
||||
$$PWD/rss/rss_feed.h \
|
||||
$$PWD/rss/rss_folder.h \
|
||||
$$PWD/rss/rss_session.h \
|
||||
$$PWD/rss/rss_autodownloader.h \
|
||||
$$PWD/rss/rss_autodownloadrule.h \
|
||||
$$PWD/rss/private/rss_parser.h \
|
||||
$$PWD/rss/rss_feed.h \
|
||||
$$PWD/rss/rss_folder.h \
|
||||
$$PWD/rss/rss_item.h \
|
||||
$$PWD/rss/rss_session.h \
|
||||
$$PWD/scanfoldersmodel.h \
|
||||
$$PWD/searchengine.h \
|
||||
$$PWD/settingsstorage.h \
|
||||
$$PWD/settingvalue.h \
|
||||
$$PWD/torrentfileguard.h \
|
||||
$$PWD/torrentfilter.h \
|
||||
$$PWD/tristatebool.h \
|
||||
$$PWD/types.h \
|
||||
$$PWD/unicodestrings.h \
|
||||
$$PWD/utils/fs.h \
|
||||
$$PWD/utils/gzip.h \
|
||||
$$PWD/utils/misc.h \
|
||||
$$PWD/utils/net.h \
|
||||
$$PWD/utils/random.h \
|
||||
$$PWD/utils/string.h \
|
||||
$$PWD/utils/version.h \
|
||||
$$PWD/profile.h \
|
||||
$$PWD/private/profile_p.h \
|
||||
$$PWD/unicodestrings.h \
|
||||
$$PWD/torrentfileguard.h \
|
||||
$$PWD/torrentfilter.h \
|
||||
$$PWD/scanfoldersmodel.h \
|
||||
$$PWD/searchengine.h \
|
||||
$$PWD/global.h
|
||||
$$PWD/utils/version.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/asyncfilestorage.cpp \
|
||||
$$PWD/tristatebool.cpp \
|
||||
$$PWD/bittorrent/infohash.cpp \
|
||||
$$PWD/bittorrent/magneturi.cpp \
|
||||
$$PWD/bittorrent/peerinfo.cpp \
|
||||
$$PWD/bittorrent/private/bandwidthscheduler.cpp \
|
||||
$$PWD/bittorrent/private/filterparserthread.cpp \
|
||||
$$PWD/bittorrent/private/resumedatasavingmanager.cpp \
|
||||
$$PWD/bittorrent/private/speedmonitor.cpp \
|
||||
$$PWD/bittorrent/private/statistics.cpp \
|
||||
$$PWD/bittorrent/session.cpp \
|
||||
$$PWD/bittorrent/torrentcreatorthread.cpp \
|
||||
$$PWD/bittorrent/torrenthandle.cpp \
|
||||
$$PWD/bittorrent/torrentinfo.cpp \
|
||||
$$PWD/bittorrent/tracker.cpp \
|
||||
$$PWD/bittorrent/trackerentry.cpp \
|
||||
$$PWD/filesystemwatcher.cpp \
|
||||
$$PWD/logger.cpp \
|
||||
$$PWD/settingsstorage.cpp \
|
||||
$$PWD/preferences.cpp \
|
||||
$$PWD/iconprovider.cpp \
|
||||
$$PWD/http/connection.cpp \
|
||||
$$PWD/http/requestparser.cpp \
|
||||
$$PWD/http/responsebuilder.cpp \
|
||||
$$PWD/http/responsegenerator.cpp \
|
||||
$$PWD/http/server.cpp \
|
||||
$$PWD/http/responsebuilder.cpp \
|
||||
$$PWD/iconprovider.cpp \
|
||||
$$PWD/logger.cpp \
|
||||
$$PWD/net/dnsupdater.cpp \
|
||||
$$PWD/net/downloadmanager.cpp \
|
||||
$$PWD/net/downloadhandler.cpp \
|
||||
$$PWD/net/downloadmanager.cpp \
|
||||
$$PWD/net/geoipmanager.cpp \
|
||||
$$PWD/net/portforwarder.cpp \
|
||||
$$PWD/net/private/geoipdatabase.cpp \
|
||||
$$PWD/net/proxyconfigurationmanager.cpp \
|
||||
$$PWD/net/reverseresolution.cpp \
|
||||
$$PWD/net/smtp.cpp \
|
||||
$$PWD/net/private/geoipdatabase.cpp \
|
||||
$$PWD/bittorrent/infohash.cpp \
|
||||
$$PWD/bittorrent/session.cpp \
|
||||
$$PWD/bittorrent/magneturi.cpp \
|
||||
$$PWD/bittorrent/torrentinfo.cpp \
|
||||
$$PWD/bittorrent/torrenthandle.cpp \
|
||||
$$PWD/bittorrent/peerinfo.cpp \
|
||||
$$PWD/bittorrent/trackerentry.cpp \
|
||||
$$PWD/bittorrent/tracker.cpp \
|
||||
$$PWD/bittorrent/torrentcreatorthread.cpp \
|
||||
$$PWD/bittorrent/private/speedmonitor.cpp \
|
||||
$$PWD/bittorrent/private/bandwidthscheduler.cpp \
|
||||
$$PWD/bittorrent/private/filterparserthread.cpp \
|
||||
$$PWD/bittorrent/private/statistics.cpp \
|
||||
$$PWD/bittorrent/private/resumedatasavingmanager.cpp \
|
||||
$$PWD/preferences.cpp \
|
||||
$$PWD/private/profile_p.cpp \
|
||||
$$PWD/profile.cpp \
|
||||
$$PWD/rss/private/rss_parser.cpp \
|
||||
$$PWD/rss/rss_article.cpp \
|
||||
$$PWD/rss/rss_item.cpp \
|
||||
$$PWD/rss/rss_feed.cpp \
|
||||
$$PWD/rss/rss_folder.cpp \
|
||||
$$PWD/rss/rss_session.cpp \
|
||||
$$PWD/rss/rss_autodownloader.cpp \
|
||||
$$PWD/rss/rss_autodownloadrule.cpp \
|
||||
$$PWD/rss/private/rss_parser.cpp \
|
||||
$$PWD/rss/rss_feed.cpp \
|
||||
$$PWD/rss/rss_folder.cpp \
|
||||
$$PWD/rss/rss_item.cpp \
|
||||
$$PWD/rss/rss_session.cpp \
|
||||
$$PWD/scanfoldersmodel.cpp \
|
||||
$$PWD/searchengine.cpp \
|
||||
$$PWD/settingsstorage.cpp \
|
||||
$$PWD/torrentfileguard.cpp \
|
||||
$$PWD/torrentfilter.cpp \
|
||||
$$PWD/tristatebool.cpp \
|
||||
$$PWD/utils/fs.cpp \
|
||||
$$PWD/utils/gzip.cpp \
|
||||
$$PWD/utils/misc.cpp \
|
||||
$$PWD/utils/net.cpp \
|
||||
$$PWD/utils/random.cpp \
|
||||
$$PWD/utils/string.cpp \
|
||||
$$PWD/profile.cpp \
|
||||
$$PWD/private/profile_p.cpp \
|
||||
$$PWD/torrentfileguard.cpp \
|
||||
$$PWD/torrentfilter.cpp \
|
||||
$$PWD/scanfoldersmodel.cpp \
|
||||
$$PWD/searchengine.cpp
|
||||
$$PWD/utils/string.cpp
|
||||
|
||||
@@ -273,18 +273,20 @@ qreal PeerInfo::relevance() const
|
||||
|
||||
void PeerInfo::determineFlags()
|
||||
{
|
||||
QStringList flagsDescriptionList;
|
||||
|
||||
if (isInteresting()) {
|
||||
// d = Your client wants to download, but peer doesn't want to send (interested and choked)
|
||||
if (isRemoteChocked()) {
|
||||
m_flags += "d ";
|
||||
m_flagsDescription += tr("interested(local) and choked(peer)");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "d = "
|
||||
+ tr("Interested(local) and Choked(peer)");
|
||||
}
|
||||
else {
|
||||
// D = Currently downloading (interested and not choked)
|
||||
m_flags += "D ";
|
||||
m_flagsDescription += tr("interested(local) and unchoked(peer)");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "D = "
|
||||
+ tr("interested(local) and unchoked(peer)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,97 +294,95 @@ void PeerInfo::determineFlags()
|
||||
// u = Peer wants your client to upload, but your client doesn't want to (interested and choked)
|
||||
if (isChocked()) {
|
||||
m_flags += "u ";
|
||||
m_flagsDescription += tr("interested(peer) and choked(local)");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "u = "
|
||||
+ tr("interested(peer) and choked(local)");
|
||||
}
|
||||
else {
|
||||
// U = Currently uploading (interested and not choked)
|
||||
m_flags += "U ";
|
||||
m_flagsDescription += tr("interested(peer) and unchoked(local)");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "U = "
|
||||
+ tr("interested(peer) and unchoked(local)");
|
||||
}
|
||||
}
|
||||
|
||||
// O = Optimistic unchoke
|
||||
if (optimisticUnchoke()) {
|
||||
m_flags += "O ";
|
||||
m_flagsDescription += tr("optimistic unchoke");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "O = "
|
||||
+ tr("optimistic unchoke");
|
||||
}
|
||||
|
||||
// S = Peer is snubbed
|
||||
if (isSnubbed()) {
|
||||
m_flags += "S ";
|
||||
m_flagsDescription += tr("peer snubbed");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "S = "
|
||||
+ tr("peer snubbed");
|
||||
}
|
||||
|
||||
// I = Peer is an incoming connection
|
||||
if (!isLocalConnection()) {
|
||||
m_flags += "I ";
|
||||
m_flagsDescription += tr("incoming connection");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "I = "
|
||||
+ tr("incoming connection");
|
||||
}
|
||||
|
||||
// K = Peer is unchoking your client, but your client is not interested
|
||||
if (!isRemoteChocked() && !isInteresting()) {
|
||||
m_flags += "K ";
|
||||
m_flagsDescription += tr("not interested(local) and unchoked(peer)");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "K = "
|
||||
+ tr("not interested(local) and unchoked(peer)");
|
||||
}
|
||||
|
||||
// ? = Your client unchoked the peer but the peer is not interested
|
||||
if (!isChocked() && !isRemoteInterested()) {
|
||||
m_flags += "? ";
|
||||
m_flagsDescription += tr("not interested(peer) and unchoked(local)");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "? = "
|
||||
+ tr("not interested(peer) and unchoked(local)");
|
||||
}
|
||||
|
||||
// X = Peer was included in peerlists obtained through Peer Exchange (PEX)
|
||||
if (fromPeX()) {
|
||||
m_flags += "X ";
|
||||
m_flagsDescription += tr("peer from PEX");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "X = "
|
||||
+ tr("peer from PEX");
|
||||
}
|
||||
|
||||
// H = Peer was obtained through DHT
|
||||
if (fromDHT()) {
|
||||
m_flags += "H ";
|
||||
m_flagsDescription += tr("peer from DHT");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "H = "
|
||||
+ tr("peer from DHT");
|
||||
}
|
||||
|
||||
// E = Peer is using Protocol Encryption (all traffic)
|
||||
if (isRC4Encrypted()) {
|
||||
m_flags += "E ";
|
||||
m_flagsDescription += tr("encrypted traffic");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "E = "
|
||||
+ tr("encrypted traffic");
|
||||
}
|
||||
|
||||
// e = Peer is using Protocol Encryption (handshake)
|
||||
if (isPlaintextEncrypted()) {
|
||||
m_flags += "e ";
|
||||
m_flagsDescription += tr("encrypted handshake");
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "e = "
|
||||
+ tr("encrypted handshake");
|
||||
}
|
||||
|
||||
// P = Peer is using uTorrent uTP
|
||||
if (useUTPSocket()) {
|
||||
m_flags += "P ";
|
||||
m_flagsDescription += QString::fromUtf8(C_UTP);
|
||||
m_flagsDescription += ", ";
|
||||
flagsDescriptionList += "P = "
|
||||
+ QString::fromUtf8(C_UTP);
|
||||
}
|
||||
|
||||
// L = Peer is local
|
||||
if (fromLSD()) {
|
||||
m_flags += "L";
|
||||
m_flagsDescription += tr("peer from LSD");
|
||||
flagsDescriptionList += "L = "
|
||||
+ tr("peer from LSD");
|
||||
}
|
||||
|
||||
m_flags = m_flags.trimmed();
|
||||
m_flagsDescription = m_flagsDescription.trimmed();
|
||||
if (m_flagsDescription.endsWith(',', Qt::CaseInsensitive))
|
||||
m_flagsDescription.chop(1);
|
||||
m_flagsDescription = flagsDescriptionList.join('\n');
|
||||
}
|
||||
|
||||
QString PeerInfo::flags() const
|
||||
|
||||
@@ -102,6 +102,7 @@ namespace
|
||||
}
|
||||
|
||||
const int BUFFER_SIZE = 2 * 1024 * 1024; // 2 MiB
|
||||
const int MAX_LOGGED_ERRORS = 5;
|
||||
}
|
||||
|
||||
FilterParserThread::FilterParserThread(QObject *parent)
|
||||
@@ -134,6 +135,12 @@ int FilterParserThread::parseDATFilterFile()
|
||||
int start = 0;
|
||||
int endOfLine = -1;
|
||||
int nbLine = 0;
|
||||
int parseErrorCount = 0;
|
||||
const auto addLog = [&parseErrorCount](const QString &msg)
|
||||
{
|
||||
if (parseErrorCount <= MAX_LOGGED_ERRORS)
|
||||
LogMsg(msg, Log::CRITICAL);
|
||||
};
|
||||
|
||||
while (true) {
|
||||
bytesRead = file.read(buffer.data() + offset, BUFFER_SIZE - offset - 1);
|
||||
@@ -202,7 +209,8 @@ int FilterParserThread::parseDATFilterFile()
|
||||
int endOfIPRange = ((firstComma == -1) ? (endOfLine - 1) : (firstComma - 1));
|
||||
int delimIP = findAndNullDelimiter(buffer.data(), '-', start, endOfIPRange);
|
||||
if (delimIP == -1) {
|
||||
LogMsg(tr("IP filter line %1 is malformed.").arg(nbLine), Log::CRITICAL);
|
||||
++parseErrorCount;
|
||||
addLog(tr("IP filter line %1 is malformed.").arg(nbLine));
|
||||
start = endOfLine;
|
||||
continue;
|
||||
}
|
||||
@@ -210,7 +218,8 @@ int FilterParserThread::parseDATFilterFile()
|
||||
libt::address startAddr;
|
||||
int newStart = trim(buffer.data(), start, delimIP - 1);
|
||||
if (!parseIPAddress(buffer.data() + newStart, startAddr)) {
|
||||
LogMsg(tr("IP filter line %1 is malformed. Start IP of the range is malformed.").arg(nbLine), Log::CRITICAL);
|
||||
++parseErrorCount;
|
||||
addLog(tr("IP filter line %1 is malformed. Start IP of the range is malformed.").arg(nbLine));
|
||||
start = endOfLine;
|
||||
continue;
|
||||
}
|
||||
@@ -218,14 +227,16 @@ int FilterParserThread::parseDATFilterFile()
|
||||
libt::address endAddr;
|
||||
newStart = trim(buffer.data(), delimIP + 1, endOfIPRange);
|
||||
if (!parseIPAddress(buffer.data() + newStart, endAddr)) {
|
||||
LogMsg(tr("IP filter line %1 is malformed. End IP of the range is malformed.").arg(nbLine), Log::CRITICAL);
|
||||
++parseErrorCount;
|
||||
addLog(tr("IP filter line %1 is malformed. End IP of the range is malformed.").arg(nbLine));
|
||||
start = endOfLine;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((startAddr.is_v4() != endAddr.is_v4())
|
||||
|| (startAddr.is_v6() != endAddr.is_v6())) {
|
||||
LogMsg(tr("IP filter line %1 is malformed. One IP is IPv4 and the other is IPv6!").arg(nbLine), Log::CRITICAL);
|
||||
++parseErrorCount;
|
||||
addLog(tr("IP filter line %1 is malformed. One IP is IPv4 and the other is IPv6!").arg(nbLine));
|
||||
start = endOfLine;
|
||||
continue;
|
||||
}
|
||||
@@ -238,8 +249,9 @@ int FilterParserThread::parseDATFilterFile()
|
||||
++ruleCount;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
LogMsg(tr("IP filter exception thrown for line %1. Exception is: %2").arg(nbLine)
|
||||
.arg(QString::fromLocal8Bit(e.what())), Log::CRITICAL);
|
||||
++parseErrorCount;
|
||||
addLog(tr("IP filter exception thrown for line %1. Exception is: %2")
|
||||
.arg(nbLine).arg(QString::fromLocal8Bit(e.what())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,6 +259,9 @@ int FilterParserThread::parseDATFilterFile()
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (parseErrorCount > MAX_LOGGED_ERRORS)
|
||||
LogMsg(tr("%1 extra IP filter parsing errors occurred.", "513 extra IP filter parsing errors occurred.")
|
||||
.arg(parseErrorCount - MAX_LOGGED_ERRORS), Log::CRITICAL);
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
@@ -268,6 +283,12 @@ int FilterParserThread::parseP2PFilterFile()
|
||||
int start = 0;
|
||||
int endOfLine = -1;
|
||||
int nbLine = 0;
|
||||
int parseErrorCount = 0;
|
||||
const auto addLog = [&parseErrorCount](const QString &msg)
|
||||
{
|
||||
if (parseErrorCount <= MAX_LOGGED_ERRORS)
|
||||
LogMsg(msg, Log::CRITICAL);
|
||||
};
|
||||
|
||||
while (true) {
|
||||
bytesRead = file.read(buffer.data() + offset, BUFFER_SIZE - offset - 1);
|
||||
@@ -319,7 +340,8 @@ int FilterParserThread::parseP2PFilterFile()
|
||||
// The "Some organization" part might contain a ':' char itself so we find the last occurrence
|
||||
int partsDelimiter = findAndNullDelimiter(buffer.data(), ':', start, endOfLine, true);
|
||||
if (partsDelimiter == -1) {
|
||||
LogMsg(tr("IP filter line %1 is malformed.").arg(nbLine), Log::CRITICAL);
|
||||
++parseErrorCount;
|
||||
addLog(tr("IP filter line %1 is malformed.").arg(nbLine));
|
||||
start = endOfLine;
|
||||
continue;
|
||||
}
|
||||
@@ -327,7 +349,8 @@ int FilterParserThread::parseP2PFilterFile()
|
||||
// IP Range should be split by a dash
|
||||
int delimIP = findAndNullDelimiter(buffer.data(), '-', partsDelimiter + 1, endOfLine);
|
||||
if (delimIP == -1) {
|
||||
LogMsg(tr("IP filter line %1 is malformed.").arg(nbLine), Log::CRITICAL);
|
||||
++parseErrorCount;
|
||||
addLog(tr("IP filter line %1 is malformed.").arg(nbLine));
|
||||
start = endOfLine;
|
||||
continue;
|
||||
}
|
||||
@@ -335,7 +358,8 @@ int FilterParserThread::parseP2PFilterFile()
|
||||
libt::address startAddr;
|
||||
int newStart = trim(buffer.data(), partsDelimiter + 1, delimIP - 1);
|
||||
if (!parseIPAddress(buffer.data() + newStart, startAddr)) {
|
||||
LogMsg(tr("IP filter line %1 is malformed. Start IP of the range is malformed.").arg(nbLine), Log::CRITICAL);
|
||||
++parseErrorCount;
|
||||
addLog(tr("IP filter line %1 is malformed. Start IP of the range is malformed.").arg(nbLine));
|
||||
start = endOfLine;
|
||||
continue;
|
||||
}
|
||||
@@ -343,14 +367,16 @@ int FilterParserThread::parseP2PFilterFile()
|
||||
libt::address endAddr;
|
||||
newStart = trim(buffer.data(), delimIP + 1, endOfLine);
|
||||
if (!parseIPAddress(buffer.data() + newStart, endAddr)) {
|
||||
LogMsg(tr("IP filter line %1 is malformed. End IP of the range is malformed.").arg(nbLine), Log::CRITICAL);
|
||||
++parseErrorCount;
|
||||
addLog(tr("IP filter line %1 is malformed. End IP of the range is malformed.").arg(nbLine));
|
||||
start = endOfLine;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((startAddr.is_v4() != endAddr.is_v4())
|
||||
|| (startAddr.is_v6() != endAddr.is_v6())) {
|
||||
LogMsg(tr("IP filter line %1 is malformed. One IP is IPv4 and the other is IPv6!").arg(nbLine), Log::CRITICAL);
|
||||
++parseErrorCount;
|
||||
addLog(tr("IP filter line %1 is malformed. One IP is IPv4 and the other is IPv6!").arg(nbLine));
|
||||
start = endOfLine;
|
||||
continue;
|
||||
}
|
||||
@@ -362,8 +388,9 @@ int FilterParserThread::parseP2PFilterFile()
|
||||
++ruleCount;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
LogMsg(tr("IP filter exception thrown for line %1. Exception is: %2").arg(nbLine)
|
||||
.arg(QString::fromLocal8Bit(e.what())), Log::CRITICAL);
|
||||
++parseErrorCount;
|
||||
addLog(tr("IP filter exception thrown for line %1. Exception is: %2")
|
||||
.arg(nbLine).arg(QString::fromLocal8Bit(e.what())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,6 +398,9 @@ int FilterParserThread::parseP2PFilterFile()
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (parseErrorCount > MAX_LOGGED_ERRORS)
|
||||
LogMsg(tr("%1 extra IP filter parsing errors occurred.", "513 extra IP filter parsing errors occurred.")
|
||||
.arg(parseErrorCount - MAX_LOGGED_ERRORS), Log::CRITICAL);
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ Session::Session(QObject *parent)
|
||||
, m_btProtocol(BITTORRENT_SESSION_KEY("BTProtocol"), BTProtocol::Both
|
||||
, clampValue(BTProtocol::Both, BTProtocol::UTP))
|
||||
, m_isUTPRateLimited(BITTORRENT_SESSION_KEY("uTPRateLimited"), true)
|
||||
, m_utpMixedMode(BITTORRENT_SESSION_KEY("uTPMixedMode"), MixedModeAlgorithm::Proportional
|
||||
, m_utpMixedMode(BITTORRENT_SESSION_KEY("uTPMixedMode"), MixedModeAlgorithm::TCP
|
||||
, clampValue(MixedModeAlgorithm::TCP, MixedModeAlgorithm::Proportional))
|
||||
, m_multiConnectionsPerIpEnabled(BITTORRENT_SESSION_KEY("MultiConnectionsPerIp"), false)
|
||||
, m_isAddTrackersEnabled(BITTORRENT_SESSION_KEY("AddTrackersEnabled"), false)
|
||||
@@ -1418,8 +1418,11 @@ void Session::configure(libtorrent::settings_pack &settingsPack)
|
||||
void Session::configurePeerClasses()
|
||||
{
|
||||
libt::ip_filter f;
|
||||
f.add_rule(libt::address_v4::from_string("0.0.0.0")
|
||||
, libt::address_v4::from_string("255.255.255.255")
|
||||
// address_v4::from_string("255.255.255.255") crashes on some people's systems
|
||||
// so instead we use address_v4::broadcast()
|
||||
// Proactively do the same for 0.0.0.0 and address_v4::any()
|
||||
f.add_rule(libt::address_v4::any()
|
||||
, libt::address_v4::broadcast()
|
||||
, 1 << libt::session::global_peer_class_id);
|
||||
#if TORRENT_USE_IPV6
|
||||
// IPv6 may not be available on OS and the parsing
|
||||
@@ -1478,14 +1481,10 @@ void Session::configurePeerClasses()
|
||||
peerClassTypeFilter.add(libt::peer_class_type_filter::tcp_socket, libt::session::tcp_peer_class_id);
|
||||
peerClassTypeFilter.add(libt::peer_class_type_filter::ssl_tcp_socket, libt::session::tcp_peer_class_id);
|
||||
peerClassTypeFilter.add(libt::peer_class_type_filter::i2p_socket, libt::session::tcp_peer_class_id);
|
||||
if (isUTPRateLimited()) {
|
||||
peerClassTypeFilter.add(libt::peer_class_type_filter::utp_socket
|
||||
, libt::session::local_peer_class_id);
|
||||
peerClassTypeFilter.add(libt::peer_class_type_filter::utp_socket
|
||||
if (!isUTPRateLimited()) {
|
||||
peerClassTypeFilter.disallow(libt::peer_class_type_filter::utp_socket
|
||||
, libt::session::global_peer_class_id);
|
||||
peerClassTypeFilter.add(libt::peer_class_type_filter::ssl_utp_socket
|
||||
, libt::session::local_peer_class_id);
|
||||
peerClassTypeFilter.add(libt::peer_class_type_filter::ssl_utp_socket
|
||||
peerClassTypeFilter.disallow(libt::peer_class_type_filter::ssl_utp_socket
|
||||
, libt::session::global_peer_class_id);
|
||||
}
|
||||
m_nativeSession->set_peer_class_type_filter(peerClassTypeFilter);
|
||||
|
||||
@@ -59,8 +59,6 @@ using namespace BitTorrent;
|
||||
|
||||
TorrentCreatorThread::TorrentCreatorThread(QObject *parent)
|
||||
: QThread(parent)
|
||||
, m_private(false)
|
||||
, m_pieceSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -70,97 +68,91 @@ TorrentCreatorThread::~TorrentCreatorThread()
|
||||
wait();
|
||||
}
|
||||
|
||||
void TorrentCreatorThread::create(const QString &inputPath, const QString &savePath, const QStringList &trackers,
|
||||
const QStringList &urlSeeds, const QString &comment, bool isPrivate, int pieceSize)
|
||||
void TorrentCreatorThread::create(const TorrentCreatorParams ¶ms)
|
||||
{
|
||||
m_inputPath = Utils::Fs::fromNativePath(inputPath);
|
||||
m_savePath = Utils::Fs::fromNativePath(savePath);
|
||||
if (QFile(m_savePath).exists())
|
||||
Utils::Fs::forceRemove(m_savePath);
|
||||
m_trackers = trackers;
|
||||
m_urlSeeds = urlSeeds;
|
||||
m_comment = comment;
|
||||
m_private = isPrivate;
|
||||
m_pieceSize = pieceSize;
|
||||
|
||||
m_params = params;
|
||||
start();
|
||||
}
|
||||
|
||||
void TorrentCreatorThread::sendProgressSignal(int numHashes, int numPieces)
|
||||
void TorrentCreatorThread::sendProgressSignal(int currentPieceIdx, int totalPieces)
|
||||
{
|
||||
emit updateProgress(static_cast<int>((numHashes * 100.) / numPieces));
|
||||
emit updateProgress(static_cast<int>((currentPieceIdx * 100.) / totalPieces));
|
||||
}
|
||||
|
||||
void TorrentCreatorThread::run()
|
||||
{
|
||||
const QString creatorStr("qBittorrent " QBT_VERSION);
|
||||
|
||||
emit updateProgress(0);
|
||||
|
||||
QString creator_str("qBittorrent " QBT_VERSION);
|
||||
try {
|
||||
libt::file_storage fs;
|
||||
// Adding files to the torrent
|
||||
libt::add_files(fs, Utils::Fs::toNativePath(m_inputPath).toStdString(), fileFilter);
|
||||
libt::add_files(fs, Utils::Fs::toNativePath(m_params.inputPath).toStdString(), fileFilter);
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
|
||||
libt::create_torrent t(fs, m_pieceSize);
|
||||
libt::create_torrent newTorrent(fs, m_params.pieceSize);
|
||||
|
||||
// Add url seeds
|
||||
foreach (const QString &seed, m_urlSeeds)
|
||||
t.add_url_seed(seed.trimmed().toStdString());
|
||||
foreach (QString seed, m_params.urlSeeds) {
|
||||
seed = seed.trimmed();
|
||||
if (!seed.isEmpty())
|
||||
newTorrent.add_url_seed(seed.toStdString());
|
||||
}
|
||||
|
||||
int tier = 0;
|
||||
bool newline = false;
|
||||
foreach (const QString &tracker, m_trackers) {
|
||||
if (tracker.isEmpty()) {
|
||||
if (newline)
|
||||
continue;
|
||||
foreach (const QString &tracker, m_params.trackers) {
|
||||
if (tracker.isEmpty())
|
||||
++tier;
|
||||
newline = true;
|
||||
continue;
|
||||
}
|
||||
t.add_tracker(tracker.trimmed().toStdString(), tier);
|
||||
newline = false;
|
||||
else
|
||||
newTorrent.add_tracker(tracker.trimmed().toStdString(), tier);
|
||||
}
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
|
||||
// calculate the hash for all pieces
|
||||
const QString parentPath = Utils::Fs::branchPath(m_inputPath) + "/";
|
||||
libt::set_piece_hashes(t, Utils::Fs::toNativePath(parentPath).toStdString(), boost::bind(&TorrentCreatorThread::sendProgressSignal, this, _1, t.num_pieces()));
|
||||
const QString parentPath = Utils::Fs::branchPath(m_params.inputPath) + "/";
|
||||
libt::set_piece_hashes(newTorrent, Utils::Fs::toNativePath(parentPath).toStdString()
|
||||
, [this, &newTorrent](const int n) { sendProgressSignal(n, newTorrent.num_pieces()); });
|
||||
// Set qBittorrent as creator and add user comment to
|
||||
// torrent_info structure
|
||||
t.set_creator(creator_str.toUtf8().constData());
|
||||
t.set_comment(m_comment.toUtf8().constData());
|
||||
newTorrent.set_creator(creatorStr.toUtf8().constData());
|
||||
newTorrent.set_comment(m_params.comment.toUtf8().constData());
|
||||
// Is private ?
|
||||
t.set_priv(m_private);
|
||||
newTorrent.set_priv(m_params.isPrivate);
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
|
||||
// create the torrent and print it to out
|
||||
qDebug("Saving to %s", qUtf8Printable(m_savePath));
|
||||
libt::entry entry = newTorrent.generate();
|
||||
|
||||
// add source field
|
||||
if (!m_params.source.isEmpty())
|
||||
entry["info"]["source"] = m_params.source.toStdString();
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
|
||||
// create the torrent
|
||||
std::ofstream outfile(
|
||||
#ifdef _MSC_VER
|
||||
wchar_t *savePathW = new wchar_t[m_savePath.length() + 1];
|
||||
int len = Utils::Fs::toNativePath(m_savePath).toWCharArray(savePathW);
|
||||
savePathW[len] = L'\0';
|
||||
std::ofstream outfile(savePathW, std::ios_base::out | std::ios_base::binary);
|
||||
delete[] savePathW;
|
||||
Utils::Fs::toNativePath(m_params.savePath).toStdWString().c_str()
|
||||
#else
|
||||
std::ofstream outfile(Utils::Fs::toNativePath(m_savePath).toLocal8Bit().constData(), std::ios_base::out | std::ios_base::binary);
|
||||
Utils::Fs::toNativePath(m_params.savePath).toUtf8().constData()
|
||||
#endif
|
||||
, (std::ios_base::out | std::ios_base::binary | std::ios_base::trunc));
|
||||
if (outfile.fail())
|
||||
throw std::exception();
|
||||
throw std::runtime_error(tr("create new torrent file failed").toStdString());
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
|
||||
libt::bencode(std::ostream_iterator<char>(outfile), t.generate());
|
||||
libt::bencode(std::ostream_iterator<char>(outfile), entry);
|
||||
outfile.close();
|
||||
|
||||
emit updateProgress(100);
|
||||
emit creationSuccess(m_savePath, parentPath);
|
||||
emit creationSuccess(m_params.savePath, parentPath);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
emit creationFailure(QString::fromStdString(e.what()));
|
||||
catch (const std::exception &e) {
|
||||
emit creationFailure(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,16 +36,27 @@
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
struct TorrentCreatorParams
|
||||
{
|
||||
bool isPrivate;
|
||||
int pieceSize;
|
||||
QString inputPath;
|
||||
QString savePath;
|
||||
QString comment;
|
||||
QString source;
|
||||
QStringList trackers;
|
||||
QStringList urlSeeds;
|
||||
};
|
||||
|
||||
class TorrentCreatorThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TorrentCreatorThread(QObject *parent = 0);
|
||||
TorrentCreatorThread(QObject *parent = nullptr);
|
||||
~TorrentCreatorThread();
|
||||
|
||||
void create(const QString &inputPath, const QString &savePath, const QStringList &trackers,
|
||||
const QStringList &urlSeeds, const QString &comment, bool isPrivate, int pieceSize);
|
||||
void create(const TorrentCreatorParams ¶ms);
|
||||
|
||||
static int calculateTotalPieces(const QString &inputPath, const int pieceSize);
|
||||
|
||||
@@ -58,15 +69,9 @@ namespace BitTorrent
|
||||
void updateProgress(int progress);
|
||||
|
||||
private:
|
||||
void sendProgressSignal(int numHashes, int numPieces);
|
||||
void sendProgressSignal(int currentPieceIdx, int totalPieces);
|
||||
|
||||
QString m_inputPath;
|
||||
QString m_savePath;
|
||||
QStringList m_trackers;
|
||||
QStringList m_urlSeeds;
|
||||
QString m_comment;
|
||||
bool m_private;
|
||||
int m_pieceSize;
|
||||
TorrentCreatorParams m_params;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -156,6 +156,8 @@ const int TorrentHandle::MAX_SEEDING_TIME = 525600;
|
||||
// The following can be removed after one or two libtorrent releases on each branch.
|
||||
namespace
|
||||
{
|
||||
const char i18nContext[] = "TorrentHandle";
|
||||
|
||||
// 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)
|
||||
@@ -1469,7 +1471,7 @@ void TorrentHandle::handleStorageMovedFailedAlert(libtorrent::storage_moved_fail
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::instance()->addMessage(tr("Could not move torrent: '%1'. Reason: %2")
|
||||
LogMsg(QCoreApplication::translate(i18nContext, "Could not move torrent: '%1'. Reason: %2")
|
||||
.arg(name()).arg(QString::fromStdString(p->message())), Log::CRITICAL);
|
||||
|
||||
m_moveStorageInfo.newPath.clear();
|
||||
@@ -1647,13 +1649,13 @@ void TorrentHandle::handleFastResumeRejectedAlert(libtorrent::fastresume_rejecte
|
||||
updateStatus();
|
||||
if (p->error.value() == libt::errors::mismatching_file_size) {
|
||||
// Mismatching file size (files were probably moved)
|
||||
logger->addMessage(tr("File sizes mismatch for torrent '%1', pausing it.").arg(name()), Log::CRITICAL);
|
||||
logger->addMessage(QCoreApplication::translate(i18nContext, "File sizes mismatch for torrent '%1', pausing it.").arg(name()), Log::CRITICAL);
|
||||
m_hasMissingFiles = true;
|
||||
if (!isPaused())
|
||||
pause();
|
||||
}
|
||||
else {
|
||||
logger->addMessage(tr("Fast resume data was rejected for torrent '%1'. Reason: %2. Checking again...")
|
||||
logger->addMessage(QCoreApplication::translate(i18nContext, "Fast resume data was rejected for torrent '%1'. Reason: %2. Checking again...")
|
||||
.arg(name()).arg(QString::fromStdString(p->message())), Log::CRITICAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace Http
|
||||
const char CONTENT_TYPE_JSON[] = "application/json";
|
||||
const char CONTENT_TYPE_PNG[] = "image/png";
|
||||
const char CONTENT_TYPE_TXT[] = "text/plain; charset=UTF-8";
|
||||
const char CONTENT_TYPE_SVG[] = "image/svg+xml";
|
||||
|
||||
// portability: "\r\n" doesn't guarantee mapping to the correct value
|
||||
const char CRLF[] = {0x0D, 0x0A, '\0'};
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <QCryptographicHash>
|
||||
#include <QDir>
|
||||
#include <QLocale>
|
||||
#include <QMutableListIterator>
|
||||
#include <QPair>
|
||||
#include <QSettings>
|
||||
|
||||
@@ -487,13 +488,17 @@ QList<Utils::Net::Subnet> Preferences::getWebUiAuthSubnetWhitelist() const
|
||||
return subnets;
|
||||
}
|
||||
|
||||
void Preferences::setWebUiAuthSubnetWhitelist(const QList<Utils::Net::Subnet> &subnets)
|
||||
void Preferences::setWebUiAuthSubnetWhitelist(QStringList subnets)
|
||||
{
|
||||
QStringList subnetsStringList;
|
||||
for (const Utils::Net::Subnet &subnet : subnets)
|
||||
subnetsStringList.append(Utils::Net::subnetToString(subnet));
|
||||
QMutableListIterator<QString> i(subnets);
|
||||
while (i.hasNext()) {
|
||||
bool ok = false;
|
||||
const Utils::Net::Subnet subnet = Utils::Net::parseSubnet(i.next().trimmed(), &ok);
|
||||
if (!ok)
|
||||
i.remove();
|
||||
}
|
||||
|
||||
setValue("Preferences/WebUI/AuthSubnetWhitelist", subnetsStringList);
|
||||
setValue("Preferences/WebUI/AuthSubnetWhitelist", subnets);
|
||||
}
|
||||
|
||||
QString Preferences::getServerDomains() const
|
||||
@@ -1216,9 +1221,9 @@ void Preferences::setMainLastDir(const QString &path)
|
||||
setValue("MainWindowLastDir", path);
|
||||
}
|
||||
|
||||
QSize Preferences::getPrefSize(const QSize &defaultSize) const
|
||||
QSize Preferences::getPrefSize() const
|
||||
{
|
||||
return value("Preferences/State/size", defaultSize).toSize();
|
||||
return value("Preferences/State/size").toSize();
|
||||
}
|
||||
|
||||
void Preferences::setPrefSize(const QSize &size)
|
||||
@@ -1296,9 +1301,9 @@ void Preferences::setPropTrackerListState(const QByteArray &state)
|
||||
setValue("TorrentProperties/Trackers/qt5/TrackerListState", state);
|
||||
}
|
||||
|
||||
QSize Preferences::getRssGeometrySize(const QSize &defaultSize) const
|
||||
QSize Preferences::getRssGeometrySize() const
|
||||
{
|
||||
return value("RssFeedDownloader/geometrySize", defaultSize).toSize();
|
||||
return value("RssFeedDownloader/geometrySize").toSize();
|
||||
}
|
||||
|
||||
void Preferences::setRssGeometrySize(const QSize &geometry)
|
||||
|
||||
@@ -191,7 +191,7 @@ public:
|
||||
bool isWebUiAuthSubnetWhitelistEnabled() const;
|
||||
void setWebUiAuthSubnetWhitelistEnabled(bool enabled);
|
||||
QList<Utils::Net::Subnet> getWebUiAuthSubnetWhitelist() const;
|
||||
void setWebUiAuthSubnetWhitelist(const QList<Utils::Net::Subnet> &subnets);
|
||||
void setWebUiAuthSubnetWhitelist(QStringList subnets);
|
||||
QString getWebUiUsername() const;
|
||||
void setWebUiUsername(const QString &username);
|
||||
QString getWebUiPassword() const;
|
||||
@@ -301,7 +301,7 @@ public:
|
||||
void setMainVSplitterState(const QByteArray &state);
|
||||
QString getMainLastDir() const;
|
||||
void setMainLastDir(const QString &path);
|
||||
QSize getPrefSize(const QSize &defaultSize) const;
|
||||
QSize getPrefSize() const;
|
||||
void setPrefSize(const QSize &size);
|
||||
QStringList getPrefHSplitterSizes() const;
|
||||
void setPrefHSplitterSizes(const QStringList &sizes);
|
||||
@@ -317,7 +317,7 @@ public:
|
||||
void setPropVisible(const bool visible);
|
||||
QByteArray getPropTrackerListState() const;
|
||||
void setPropTrackerListState(const QByteArray &state);
|
||||
QSize getRssGeometrySize(const QSize &defaultSize) const;
|
||||
QSize getRssGeometrySize() const;
|
||||
void setRssGeometrySize(const QSize &geometry);
|
||||
QByteArray getRssHSplitterSizes() const;
|
||||
void setRssHSplitterSizes(const QByteArray &sizes);
|
||||
|
||||
@@ -227,10 +227,9 @@ void Parser::parse(const QByteArray &feedData)
|
||||
// read and create items from a rss document
|
||||
void Parser::parse_impl(const QByteArray &feedData)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
QXmlStreamReader xml(feedData);
|
||||
bool foundChannel = false;
|
||||
|
||||
while (xml.readNextStartElement()) {
|
||||
if (xml.name() == "rss") {
|
||||
// Find channels
|
||||
@@ -258,11 +257,15 @@ void Parser::parse_impl(const QByteArray &feedData)
|
||||
}
|
||||
}
|
||||
|
||||
if (xml.hasError())
|
||||
m_result.error = xml.errorString();
|
||||
else if (!foundChannel)
|
||||
if (!foundChannel) {
|
||||
m_result.error = tr("Invalid RSS feed.");
|
||||
else
|
||||
}
|
||||
else if (xml.hasError()) {
|
||||
m_result.error = tr("%1 (line: %2, column: %3, offset: %4).")
|
||||
.arg(xml.errorString()).arg(xml.lineNumber())
|
||||
.arg(xml.columnNumber()).arg(xml.characterOffset());
|
||||
}
|
||||
else {
|
||||
// Sort article list chronologically
|
||||
// NOTE: We don't need to sort it here if articles are always
|
||||
// sorted in fetched XML in reverse chronological order
|
||||
@@ -271,6 +274,7 @@ void Parser::parse_impl(const QByteArray &feedData)
|
||||
{
|
||||
return a1["date"].toDateTime() < a2["date"].toDateTime();
|
||||
});
|
||||
}
|
||||
|
||||
emit finished(m_result);
|
||||
m_result.articles.clear(); // clear articles only
|
||||
@@ -288,35 +292,34 @@ void Parser::parseRssArticle(QXmlStreamReader &xml)
|
||||
break;
|
||||
|
||||
if (xml.isStartElement()) {
|
||||
const QString text(xml.readElementText().trimmed());
|
||||
|
||||
if (name == QLatin1String("title")) {
|
||||
article[Article::KeyTitle] = text;
|
||||
article[Article::KeyTitle] = xml.readElementText().trimmed();
|
||||
}
|
||||
else if (name == QLatin1String("enclosure")) {
|
||||
if (xml.attributes().value("type") == QLatin1String("application/x-bittorrent"))
|
||||
article[Article::KeyTorrentURL] = xml.attributes().value(QLatin1String("url")).toString();
|
||||
}
|
||||
else if (name == QLatin1String("link")) {
|
||||
const QString text {xml.readElementText().trimmed()};
|
||||
if (text.startsWith(QLatin1String("magnet:"), Qt::CaseInsensitive))
|
||||
article[Article::KeyTorrentURL] = text; // magnet link instead of a news URL
|
||||
else
|
||||
article[Article::KeyLink] = text;
|
||||
}
|
||||
else if (name == QLatin1String("description")) {
|
||||
article[Article::KeyDescription] = text;
|
||||
article[Article::KeyDescription] = xml.readElementText(QXmlStreamReader::IncludeChildElements);
|
||||
}
|
||||
else if (name == QLatin1String("pubDate")) {
|
||||
article[Article::KeyDate] = parseDate(text);
|
||||
article[Article::KeyDate] = parseDate(xml.readElementText().trimmed());
|
||||
}
|
||||
else if (name == QLatin1String("author")) {
|
||||
article[Article::KeyAuthor] = text;
|
||||
article[Article::KeyAuthor] = xml.readElementText().trimmed();
|
||||
}
|
||||
else if (name == QLatin1String("guid")) {
|
||||
article[Article::KeyId] = text;
|
||||
article[Article::KeyId] = xml.readElementText().trimmed();
|
||||
}
|
||||
else {
|
||||
article[name] = text;
|
||||
article[name] = xml.readElementText(QXmlStreamReader::IncludeChildElements);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,17 +329,14 @@ void Parser::parseRssArticle(QXmlStreamReader &xml)
|
||||
|
||||
void Parser::parseRSSChannel(QXmlStreamReader &xml)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
Q_ASSERT(xml.isStartElement() && xml.name() == "channel");
|
||||
|
||||
while (!xml.atEnd()) {
|
||||
xml.readNext();
|
||||
|
||||
if (xml.isStartElement()) {
|
||||
if (xml.name() == "title") {
|
||||
if (xml.name() == QLatin1String("title")) {
|
||||
m_result.title = xml.readElementText();
|
||||
}
|
||||
else if (xml.name() == "lastBuildDate") {
|
||||
else if (xml.name() == QLatin1String("lastBuildDate")) {
|
||||
QString lastBuildDate = xml.readElementText();
|
||||
if (!lastBuildDate.isEmpty()) {
|
||||
if (m_result.lastBuildDate == lastBuildDate) {
|
||||
@@ -346,7 +346,7 @@ void Parser::parseRSSChannel(QXmlStreamReader &xml)
|
||||
m_result.lastBuildDate = lastBuildDate;
|
||||
}
|
||||
}
|
||||
else if (xml.name() == "item") {
|
||||
else if (xml.name() == QLatin1String("item")) {
|
||||
parseRssArticle(xml);
|
||||
}
|
||||
}
|
||||
@@ -366,14 +366,12 @@ void Parser::parseAtomArticle(QXmlStreamReader &xml)
|
||||
break;
|
||||
|
||||
if (xml.isStartElement()) {
|
||||
const QString text(xml.readElementText().trimmed());
|
||||
|
||||
if (name == QLatin1String("title")) {
|
||||
article[Article::KeyTitle] = text;
|
||||
article[Article::KeyTitle] = xml.readElementText().trimmed();
|
||||
}
|
||||
else if (name == QLatin1String("link")) {
|
||||
QString link = (xml.attributes().isEmpty()
|
||||
? text
|
||||
? xml.readElementText().trimmed()
|
||||
: xml.attributes().value(QLatin1String("href")).toString());
|
||||
|
||||
if (link.startsWith(QLatin1String("magnet:"), Qt::CaseInsensitive))
|
||||
@@ -385,42 +383,38 @@ void Parser::parseAtomArticle(QXmlStreamReader &xml)
|
||||
article[Article::KeyLink] = (m_baseUrl.isEmpty() ? link : m_baseUrl + link);
|
||||
|
||||
}
|
||||
else if ((name == QLatin1String("summary")) || (name == QLatin1String("content"))){
|
||||
else if ((name == QLatin1String("summary")) || (name == QLatin1String("content"))) {
|
||||
if (doubleContent) { // Duplicate content -> ignore
|
||||
xml.readNext();
|
||||
|
||||
while ((xml.name() != QLatin1String("summary")) && (xml.name() != QLatin1String("content")))
|
||||
xml.readNext();
|
||||
|
||||
xml.skipCurrentElement();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to also parse broken articles, which don't use html '&' escapes
|
||||
// Actually works great for non-broken content too
|
||||
QString feedText = xml.readElementText(QXmlStreamReader::IncludeChildElements);
|
||||
if (!feedText.isEmpty())
|
||||
article[Article::KeyDescription] = feedText.trimmed();
|
||||
|
||||
doubleContent = true;
|
||||
QString feedText = xml.readElementText(QXmlStreamReader::IncludeChildElements).trimmed();
|
||||
if (!feedText.isEmpty()) {
|
||||
article[Article::KeyDescription] = feedText;
|
||||
doubleContent = true;
|
||||
}
|
||||
}
|
||||
else if (name == QLatin1String("updated")) {
|
||||
// ATOM uses standard compliant date, don't do fancy stuff
|
||||
QDateTime articleDate = QDateTime::fromString(text, Qt::ISODate);
|
||||
QDateTime articleDate = QDateTime::fromString(xml.readElementText().trimmed(), Qt::ISODate);
|
||||
article[Article::KeyDate] = (articleDate.isValid() ? articleDate : QDateTime::currentDateTime());
|
||||
}
|
||||
else if (name == QLatin1String("author")) {
|
||||
xml.readNext();
|
||||
while (xml.name() != QLatin1String("author")) {
|
||||
while (xml.readNextStartElement()) {
|
||||
if (xml.name() == QLatin1String("name"))
|
||||
article[Article::KeyAuthor] = xml.readElementText().trimmed();
|
||||
xml.readNext();
|
||||
else
|
||||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
else if (name == QLatin1String("id")) {
|
||||
article[Article::KeyId] = text;
|
||||
article[Article::KeyId] = xml.readElementText().trimmed();
|
||||
}
|
||||
else {
|
||||
article[name] = text;
|
||||
article[name] = xml.readElementText(QXmlStreamReader::IncludeChildElements);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -430,19 +424,16 @@ void Parser::parseAtomArticle(QXmlStreamReader &xml)
|
||||
|
||||
void Parser::parseAtomChannel(QXmlStreamReader &xml)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
Q_ASSERT(xml.isStartElement() && xml.name() == "feed");
|
||||
|
||||
m_baseUrl = xml.attributes().value("xml:base").toString();
|
||||
|
||||
while (!xml.atEnd()) {
|
||||
xml.readNext();
|
||||
|
||||
if (xml.isStartElement()) {
|
||||
if (xml.name() == "title") {
|
||||
if (xml.name() == QLatin1String("title")) {
|
||||
m_result.title = xml.readElementText();
|
||||
}
|
||||
else if (xml.name() == "updated") {
|
||||
else if (xml.name() == QLatin1String("updated")) {
|
||||
QString lastBuildDate = xml.readElementText();
|
||||
if (!lastBuildDate.isEmpty()) {
|
||||
if (m_result.lastBuildDate == lastBuildDate) {
|
||||
@@ -452,7 +443,7 @@ void Parser::parseAtomChannel(QXmlStreamReader &xml)
|
||||
m_result.lastBuildDate = lastBuildDate;
|
||||
}
|
||||
}
|
||||
else if (xml.name() == "entry") {
|
||||
else if (xml.name() == QLatin1String("entry")) {
|
||||
parseAtomArticle(xml);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "rss_autodownloader.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
@@ -37,6 +38,7 @@
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
|
||||
#include "../bittorrent/magneturi.h"
|
||||
#include "../bittorrent/session.h"
|
||||
@@ -63,6 +65,32 @@ const QString RulesFileName(QStringLiteral("download_rules.json"));
|
||||
|
||||
const QString SettingsKey_ProcessingEnabled(QStringLiteral("RSS/AutoDownloader/EnableProcessing"));
|
||||
|
||||
namespace
|
||||
{
|
||||
QVector<RSS::AutoDownloadRule> rulesFromJSON(const QByteArray &jsonData)
|
||||
{
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &jsonError);
|
||||
if (jsonError.error != QJsonParseError::NoError)
|
||||
throw RSS::ParsingError(jsonError.errorString());
|
||||
|
||||
if (!jsonDoc.isObject())
|
||||
throw RSS::ParsingError(RSS::AutoDownloader::tr("Invalid data format."));
|
||||
|
||||
const QJsonObject jsonObj {jsonDoc.object()};
|
||||
QVector<RSS::AutoDownloadRule> rules;
|
||||
for (auto it = jsonObj.begin(); it != jsonObj.end(); ++it) {
|
||||
const QJsonValue jsonVal {it.value()};
|
||||
if (!jsonVal.isObject())
|
||||
throw RSS::ParsingError(RSS::AutoDownloader::tr("Invalid data format."));
|
||||
|
||||
rules.append(RSS::AutoDownloadRule::fromJsonObject(jsonVal.toObject(), it.key()));
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace RSS;
|
||||
|
||||
QPointer<AutoDownloader> AutoDownloader::m_instance = nullptr;
|
||||
@@ -84,8 +112,8 @@ AutoDownloader::AutoDownloader()
|
||||
connect(m_ioThread, &QThread::finished, m_fileStorage, &AsyncFileStorage::deleteLater);
|
||||
connect(m_fileStorage, &AsyncFileStorage::failed, [](const QString &fileName, const QString &errorString)
|
||||
{
|
||||
Logger::instance()->addMessage(QString("Couldn't save RSS AutoDownloader data in %1. Error: %2")
|
||||
.arg(fileName).arg(errorString), Log::WARNING);
|
||||
LogMsg(tr("Couldn't save RSS AutoDownloader data in %1. Error: %2")
|
||||
.arg(fileName).arg(errorString), Log::CRITICAL);
|
||||
});
|
||||
|
||||
m_ioThread->start();
|
||||
@@ -174,6 +202,70 @@ void AutoDownloader::removeRule(const QString &ruleName)
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray AutoDownloader::exportRules(AutoDownloader::RulesFileFormat format) const
|
||||
{
|
||||
switch (format) {
|
||||
case RulesFileFormat::Legacy:
|
||||
return exportRulesToLegacyFormat();
|
||||
default:
|
||||
return exportRulesToJSONFormat();
|
||||
}
|
||||
}
|
||||
|
||||
void AutoDownloader::importRules(const QByteArray &data, AutoDownloader::RulesFileFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case RulesFileFormat::Legacy:
|
||||
importRulesFromLegacyFormat(data);
|
||||
break;
|
||||
default:
|
||||
importRulesFromJSONFormat(data);
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray AutoDownloader::exportRulesToJSONFormat() const
|
||||
{
|
||||
QJsonObject jsonObj;
|
||||
for (const auto &rule : rules())
|
||||
jsonObj.insert(rule.name(), rule.toJsonObject());
|
||||
|
||||
return QJsonDocument(jsonObj).toJson();
|
||||
}
|
||||
|
||||
void AutoDownloader::importRulesFromJSONFormat(const QByteArray &data)
|
||||
{
|
||||
const auto rules = rulesFromJSON(data);
|
||||
for (const auto &rule : rules)
|
||||
insertRule(rule);
|
||||
}
|
||||
|
||||
QByteArray AutoDownloader::exportRulesToLegacyFormat() const
|
||||
{
|
||||
QVariantHash dict;
|
||||
for (const auto &rule : rules())
|
||||
dict[rule.name()] = rule.toLegacyDict();
|
||||
|
||||
QByteArray data;
|
||||
QDataStream out(&data, QIODevice::WriteOnly);
|
||||
out.setVersion(QDataStream::Qt_4_5);
|
||||
out << dict;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void AutoDownloader::importRulesFromLegacyFormat(const QByteArray &data)
|
||||
{
|
||||
QDataStream in(data);
|
||||
in.setVersion(QDataStream::Qt_4_5);
|
||||
QVariantHash dict;
|
||||
in >> dict;
|
||||
if (in.status() != QDataStream::Ok)
|
||||
throw ParsingError(tr("Invalid data format"));
|
||||
|
||||
for (const QVariant &val : dict)
|
||||
insertRule(AutoDownloadRule::fromLegacyDict(val.toHash()));
|
||||
}
|
||||
|
||||
void AutoDownloader::process()
|
||||
{
|
||||
if (m_processingQueue.isEmpty()) return; // processing was disabled
|
||||
@@ -276,39 +368,20 @@ void AutoDownloader::load()
|
||||
else if (rulesFile.open(QFile::ReadOnly))
|
||||
loadRules(rulesFile.readAll());
|
||||
else
|
||||
Logger::instance()->addMessage(
|
||||
QString("Couldn't read RSS AutoDownloader rules from %1. Error: %2")
|
||||
.arg(rulesFile.fileName()).arg(rulesFile.errorString()), Log::WARNING);
|
||||
LogMsg(tr("Couldn't read RSS AutoDownloader rules from %1. Error: %2")
|
||||
.arg(rulesFile.fileName()).arg(rulesFile.errorString()), Log::CRITICAL);
|
||||
}
|
||||
|
||||
void AutoDownloader::loadRules(const QByteArray &data)
|
||||
{
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
||||
if (jsonError.error != QJsonParseError::NoError) {
|
||||
Logger::instance()->addMessage(
|
||||
QString("Couldn't parse RSS AutoDownloader rules. Error: %1")
|
||||
.arg(jsonError.errorString()), Log::WARNING);
|
||||
return;
|
||||
try {
|
||||
const auto rules = rulesFromJSON(data);
|
||||
for (const auto &rule : rules)
|
||||
setRule_impl(rule);
|
||||
}
|
||||
|
||||
if (!jsonDoc.isObject()) {
|
||||
Logger::instance()->addMessage(
|
||||
QString("Couldn't load RSS AutoDownloader rules. Invalid data format."), Log::WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject jsonObj = jsonDoc.object();
|
||||
foreach (const QString &key, jsonObj.keys()) {
|
||||
const QJsonValue jsonVal = jsonObj.value(key);
|
||||
if (!jsonVal.isObject()) {
|
||||
Logger::instance()->addMessage(
|
||||
QString("Couldn't load RSS AutoDownloader rule '%1'. Invalid data format.")
|
||||
.arg(key), Log::WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
setRule_impl(AutoDownloadRule::fromJsonObject(jsonVal.toObject(), key));
|
||||
catch (const ParsingError &error) {
|
||||
LogMsg(tr("Couldn't load RSS AutoDownloader rules. Reason: %1")
|
||||
.arg(error.message()), Log::CRITICAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +390,7 @@ void AutoDownloader::loadRulesLegacy()
|
||||
SettingsPtr settings = Profile::instance().applicationSettings(QStringLiteral("qBittorrent-rss"));
|
||||
QVariantHash rules = settings->value(QStringLiteral("download_rules")).toHash();
|
||||
foreach (const QVariant &ruleVar, rules) {
|
||||
auto rule = AutoDownloadRule::fromVariantHash(ruleVar.toHash());
|
||||
auto rule = AutoDownloadRule::fromLegacyDict(ruleVar.toHash());
|
||||
if (!rule.name().isEmpty())
|
||||
insertRule(rule);
|
||||
}
|
||||
@@ -351,6 +424,8 @@ bool AutoDownloader::isProcessingEnabled() const
|
||||
void AutoDownloader::resetProcessingQueue()
|
||||
{
|
||||
m_processingQueue.clear();
|
||||
if (!m_processingEnabled) return;
|
||||
|
||||
foreach (Article *article, Session::instance()->rootFolder()->articles()) {
|
||||
if (!article->isRead() && !article->torrentUrl().isEmpty())
|
||||
addJobForArticle(article);
|
||||
@@ -385,3 +460,13 @@ void AutoDownloader::timerEvent(QTimerEvent *event)
|
||||
Q_UNUSED(event);
|
||||
store();
|
||||
}
|
||||
|
||||
ParsingError::ParsingError(const QString &message)
|
||||
: std::runtime_error(message.toUtf8().data())
|
||||
{
|
||||
}
|
||||
|
||||
QString ParsingError::message() const
|
||||
{
|
||||
return what();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <QBasicTimer>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
@@ -49,6 +51,13 @@ namespace RSS
|
||||
|
||||
class AutoDownloadRule;
|
||||
|
||||
class ParsingError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit ParsingError(const QString &message);
|
||||
QString message() const;
|
||||
};
|
||||
|
||||
class AutoDownloader final: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -60,6 +69,12 @@ namespace RSS
|
||||
~AutoDownloader() override;
|
||||
|
||||
public:
|
||||
enum class RulesFileFormat
|
||||
{
|
||||
Legacy,
|
||||
JSON
|
||||
};
|
||||
|
||||
static AutoDownloader *instance();
|
||||
|
||||
bool isProcessingEnabled() const;
|
||||
@@ -73,6 +88,9 @@ namespace RSS
|
||||
bool renameRule(const QString &ruleName, const QString &newRuleName);
|
||||
void removeRule(const QString &ruleName);
|
||||
|
||||
QByteArray exportRules(RulesFileFormat format = RulesFileFormat::JSON) const;
|
||||
void importRules(const QByteArray &data, RulesFileFormat format = RulesFileFormat::JSON);
|
||||
|
||||
signals:
|
||||
void processingStateChanged(bool enabled);
|
||||
void ruleAdded(const QString &ruleName);
|
||||
@@ -98,6 +116,10 @@ namespace RSS
|
||||
void loadRulesLegacy();
|
||||
void store();
|
||||
void storeDeferred();
|
||||
QByteArray exportRulesToJSONFormat() const;
|
||||
void importRulesFromJSONFormat(const QByteArray &data);
|
||||
QByteArray exportRulesToLegacyFormat() const;
|
||||
void importRulesFromLegacyFormat(const QByteArray &data);
|
||||
|
||||
static QPointer<AutoDownloader> m_instance;
|
||||
|
||||
|
||||
@@ -63,11 +63,29 @@ namespace
|
||||
QJsonValue triStateBoolToJsonValue(const TriStateBool &triStateBool)
|
||||
{
|
||||
switch (static_cast<int>(triStateBool)) {
|
||||
case 0: return false; break;
|
||||
case 1: return true; break;
|
||||
case 0: return false;
|
||||
case 1: return true;
|
||||
default: return QJsonValue();
|
||||
}
|
||||
}
|
||||
|
||||
TriStateBool addPausedLegacyToTriStateBool(int val)
|
||||
{
|
||||
switch (val) {
|
||||
case 1: return TriStateBool::True; // always
|
||||
case 2: return TriStateBool::False; // never
|
||||
default: return TriStateBool::Undefined; // default
|
||||
}
|
||||
}
|
||||
|
||||
int triStateBoolToAddPausedLegacy(const TriStateBool &triStateBool)
|
||||
{
|
||||
switch (static_cast<int>(triStateBool)) {
|
||||
case 0: return 2; // never
|
||||
case 1: return 1; // always
|
||||
default: return 0; // default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const QString Str_Name(QStringLiteral("name"));
|
||||
@@ -378,21 +396,37 @@ AutoDownloadRule AutoDownloadRule::fromJsonObject(const QJsonObject &jsonObj, co
|
||||
return rule;
|
||||
}
|
||||
|
||||
AutoDownloadRule AutoDownloadRule::fromVariantHash(const QVariantHash &varHash)
|
||||
QVariantHash AutoDownloadRule::toLegacyDict() const
|
||||
{
|
||||
AutoDownloadRule rule(varHash.value("name").toString());
|
||||
return {{"name", name()},
|
||||
{"must_contain", mustContain()},
|
||||
{"must_not_contain", mustNotContain()},
|
||||
{"save_path", savePath()},
|
||||
{"affected_feeds", feedURLs()},
|
||||
{"enabled", isEnabled()},
|
||||
{"category_assigned", assignedCategory()},
|
||||
{"use_regex", useRegex()},
|
||||
{"add_paused", triStateBoolToAddPausedLegacy(addPaused())},
|
||||
{"episode_filter", episodeFilter()},
|
||||
{"last_match", lastMatch()},
|
||||
{"ignore_days", ignoreDays()}};
|
||||
}
|
||||
|
||||
rule.setUseRegex(varHash.value("use_regex", false).toBool());
|
||||
rule.setMustContain(varHash.value("must_contain").toString());
|
||||
rule.setMustNotContain(varHash.value("must_not_contain").toString());
|
||||
rule.setEpisodeFilter(varHash.value("episode_filter").toString());
|
||||
rule.setFeedURLs(varHash.value("affected_feeds").toStringList());
|
||||
rule.setEnabled(varHash.value("enabled", false).toBool());
|
||||
rule.setSavePath(varHash.value("save_path").toString());
|
||||
rule.setCategory(varHash.value("category_assigned").toString());
|
||||
rule.setAddPaused(TriStateBool(varHash.value("add_paused").toInt() - 1));
|
||||
rule.setLastMatch(varHash.value("last_match").toDateTime());
|
||||
rule.setIgnoreDays(varHash.value("ignore_days").toInt());
|
||||
AutoDownloadRule AutoDownloadRule::fromLegacyDict(const QVariantHash &dict)
|
||||
{
|
||||
AutoDownloadRule rule(dict.value("name").toString());
|
||||
|
||||
rule.setUseRegex(dict.value("use_regex", false).toBool());
|
||||
rule.setMustContain(dict.value("must_contain").toString());
|
||||
rule.setMustNotContain(dict.value("must_not_contain").toString());
|
||||
rule.setEpisodeFilter(dict.value("episode_filter").toString());
|
||||
rule.setFeedURLs(dict.value("affected_feeds").toStringList());
|
||||
rule.setEnabled(dict.value("enabled", false).toBool());
|
||||
rule.setSavePath(dict.value("save_path").toString());
|
||||
rule.setCategory(dict.value("category_assigned").toString());
|
||||
rule.setAddPaused(addPausedLegacyToTriStateBool(dict.value("add_paused").toInt()));
|
||||
rule.setLastMatch(dict.value("last_match").toDateTime());
|
||||
rule.setIgnoreDays(dict.value("ignore_days").toInt());
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,9 @@ namespace RSS
|
||||
|
||||
QJsonObject toJsonObject() const;
|
||||
static AutoDownloadRule fromJsonObject(const QJsonObject &jsonObj, const QString &name = "");
|
||||
static AutoDownloadRule fromVariantHash(const QVariantHash &varHash);
|
||||
|
||||
QVariantHash toLegacyDict() const;
|
||||
static AutoDownloadRule fromLegacyDict(const QVariantHash &dict);
|
||||
|
||||
private:
|
||||
bool matches(const QString &articleTitle, const QString &expression) const;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "rss_feed.h"
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
@@ -102,6 +102,27 @@ Session::Session()
|
||||
m_refreshTimer.start(m_refreshInterval * MsecsPerMin);
|
||||
refresh();
|
||||
}
|
||||
|
||||
// Remove legacy/corrupted settings
|
||||
// (at least on Windows, QSettings is case-insensitive and it can get
|
||||
// confused when asked about settings that differ only in their case)
|
||||
auto settingsStorage = SettingsStorage::instance();
|
||||
settingsStorage->removeValue("Rss/streamList");
|
||||
settingsStorage->removeValue("Rss/streamAlias");
|
||||
settingsStorage->removeValue("Rss/open_folders");
|
||||
settingsStorage->removeValue("Rss/qt5/splitter_h");
|
||||
settingsStorage->removeValue("Rss/qt5/splitterMain");
|
||||
settingsStorage->removeValue("Rss/hosts_cookies");
|
||||
settingsStorage->removeValue("RSS/streamList");
|
||||
settingsStorage->removeValue("RSS/streamAlias");
|
||||
settingsStorage->removeValue("RSS/open_folders");
|
||||
settingsStorage->removeValue("RSS/qt5/splitter_h");
|
||||
settingsStorage->removeValue("RSS/qt5/splitterMain");
|
||||
settingsStorage->removeValue("RSS/hosts_cookies");
|
||||
settingsStorage->removeValue("Rss/Session/EnableProcessing");
|
||||
settingsStorage->removeValue("Rss/Session/RefreshInterval");
|
||||
settingsStorage->removeValue("Rss/Session/MaxArticlesPerFeed");
|
||||
settingsStorage->removeValue("Rss/AutoDownloader/EnableProcessing");
|
||||
}
|
||||
|
||||
Session::~Session()
|
||||
@@ -295,20 +316,6 @@ void Session::loadFolder(const QJsonObject &jsonObj, Folder *folder)
|
||||
|
||||
void Session::loadLegacy()
|
||||
{
|
||||
struct LegacySettingsDeleter
|
||||
{
|
||||
~LegacySettingsDeleter()
|
||||
{
|
||||
auto settingsStorage = SettingsStorage::instance();
|
||||
settingsStorage->removeValue("Rss/streamList");
|
||||
settingsStorage->removeValue("Rss/streamAlias");
|
||||
settingsStorage->removeValue("Rss/open_folders");
|
||||
settingsStorage->removeValue("Rss/qt5/splitter_h");
|
||||
settingsStorage->removeValue("Rss/qt5/splitterMain");
|
||||
settingsStorage->removeValue("Rss/hosts_cookies");
|
||||
}
|
||||
} legacySettingsDeleter;
|
||||
|
||||
const QStringList legacyFeedPaths = SettingsStorage::instance()->loadValue("Rss/streamList").toStringList();
|
||||
const QStringList feedAliases = SettingsStorage::instance()->loadValue("Rss/streamAlias").toStringList();
|
||||
if (legacyFeedPaths.size() != feedAliases.size()) {
|
||||
|
||||
@@ -632,19 +632,6 @@ void Utils::Misc::openFolderSelect(const QString &absolutePath)
|
||||
#endif
|
||||
}
|
||||
|
||||
QSize Utils::Misc::smallIconSize()
|
||||
{
|
||||
// Get DPI scaled icon size (device-dependent), see QT source
|
||||
int s = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
|
||||
return QSize(s, s);
|
||||
}
|
||||
|
||||
QSize Utils::Misc::largeIconSize()
|
||||
{
|
||||
// Get DPI scaled icon size (device-dependent), see QT source
|
||||
int s = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize);
|
||||
return QSize(s, s);
|
||||
}
|
||||
#endif // DISABLE_GUI
|
||||
|
||||
QString Utils::Misc::osName()
|
||||
|
||||
@@ -103,8 +103,6 @@ namespace Utils
|
||||
void openFolderSelect(const QString& absolutePath);
|
||||
|
||||
QPoint screenCenter(const QWidget *w);
|
||||
QSize smallIconSize();
|
||||
QSize largeIconSize();
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
@@ -33,9 +33,9 @@
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QCollator>
|
||||
#include <QtGlobal>
|
||||
#include <QLocale>
|
||||
#include <QRegExp>
|
||||
#include <QtGlobal>
|
||||
#ifdef Q_OS_MAC
|
||||
#include <QThreadStorage>
|
||||
#endif
|
||||
@@ -45,110 +45,106 @@ namespace
|
||||
class NaturalCompare
|
||||
{
|
||||
public:
|
||||
explicit NaturalCompare(const bool caseSensitive = true)
|
||||
: m_caseSensitive(caseSensitive)
|
||||
explicit NaturalCompare(const Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive)
|
||||
: m_caseSensitivity(caseSensitivity)
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
#ifdef Q_OS_WIN
|
||||
// Without ICU library, QCollator uses the native API on Windows 7+. But that API
|
||||
// sorts older versions of μTorrent differently than the newer ones because the
|
||||
// 'μ' character is encoded differently and the native API can't cope with that.
|
||||
// So default to using our custom natural sorting algorithm instead.
|
||||
// See #5238 and #5240
|
||||
// Without ICU library, QCollator doesn't support `setNumericMode(true)` on OS older than Win7
|
||||
// if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7)
|
||||
return;
|
||||
#endif
|
||||
// Without ICU library, QCollator doesn't support `setNumericMode(true)` on an OS older than Win7
|
||||
#else
|
||||
m_collator.setNumericMode(true);
|
||||
m_collator.setCaseSensitivity(caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
bool operator()(const QString &left, const QString &right) const
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
// Without ICU library, QCollator uses the native API on Windows 7+. But that API
|
||||
// sorts older versions of μTorrent differently than the newer ones because the
|
||||
// 'μ' character is encoded differently and the native API can't cope with that.
|
||||
// So default to using our custom natural sorting algorithm instead.
|
||||
// See #5238 and #5240
|
||||
// Without ICU library, QCollator doesn't support `setNumericMode(true)` on OS older than Win7
|
||||
// if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7)
|
||||
return lessThan(left, right);
|
||||
m_collator.setCaseSensitivity(caseSensitivity);
|
||||
#endif
|
||||
return (m_collator.compare(left, right) < 0);
|
||||
}
|
||||
|
||||
bool lessThan(const QString &left, const QString &right) const
|
||||
int operator()(const QString &left, const QString &right) const
|
||||
{
|
||||
// Return value `false` indicates `right` should go before `left`, otherwise, after
|
||||
int posL = 0;
|
||||
int posR = 0;
|
||||
while (true) {
|
||||
while (true) {
|
||||
if ((posL == left.size()) || (posR == right.size()))
|
||||
return (left.size() < right.size()); // when a shorter string is another string's prefix, shorter string place before longer string
|
||||
|
||||
QChar leftChar = m_caseSensitive ? left[posL] : left[posL].toLower();
|
||||
QChar rightChar = m_caseSensitive ? right[posR] : right[posR].toLower();
|
||||
if (leftChar == rightChar)
|
||||
; // compare next character
|
||||
else if (leftChar.isDigit() && rightChar.isDigit())
|
||||
break; // Both are digits, break this loop and compare numbers
|
||||
else
|
||||
return leftChar < rightChar;
|
||||
|
||||
++posL;
|
||||
++posR;
|
||||
}
|
||||
|
||||
int startL = posL;
|
||||
while ((posL < left.size()) && left[posL].isDigit())
|
||||
++posL;
|
||||
int numL = left.midRef(startL, posL - startL).toInt();
|
||||
|
||||
int startR = posR;
|
||||
while ((posR < right.size()) && right[posR].isDigit())
|
||||
++posR;
|
||||
int numR = right.midRef(startR, posR - startR).toInt();
|
||||
|
||||
if (numL != numR)
|
||||
return (numL < numR);
|
||||
|
||||
// Strings + digits do match and we haven't hit string end
|
||||
// Do another round
|
||||
}
|
||||
return false;
|
||||
#ifdef Q_OS_WIN
|
||||
return compare(left, right);
|
||||
#else
|
||||
return m_collator.compare(left, right);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
int compare(const QString &left, const QString &right) const
|
||||
{
|
||||
// Return value <0: `left` is smaller than `right`
|
||||
// Return value >0: `left` is greater than `right`
|
||||
// Return value =0: both strings are equal
|
||||
|
||||
int posL = 0;
|
||||
int posR = 0;
|
||||
while (true) {
|
||||
if ((posL == left.size()) || (posR == right.size()))
|
||||
return (left.size() - right.size()); // when a shorter string is another string's prefix, shorter string place before longer string
|
||||
|
||||
const QChar leftChar = (m_caseSensitivity == Qt::CaseSensitive) ? left[posL] : left[posL].toLower();
|
||||
const QChar rightChar = (m_caseSensitivity == Qt::CaseSensitive) ? right[posR] : right[posR].toLower();
|
||||
// Compare only non-digits.
|
||||
// Numbers should be compared as a whole
|
||||
// otherwise the string->int conversion can yield a wrong value
|
||||
if ((leftChar == rightChar) && !leftChar.isDigit()) {
|
||||
// compare next character
|
||||
++posL;
|
||||
++posR;
|
||||
}
|
||||
else if (leftChar.isDigit() && rightChar.isDigit()) {
|
||||
// Both are digits, compare the numbers
|
||||
const auto consumeNumber = [](const QString &str, int &pos) -> int
|
||||
{
|
||||
const int start = pos;
|
||||
while ((pos < str.size()) && str[pos].isDigit())
|
||||
++pos;
|
||||
return str.midRef(start, (pos - start)).toInt();
|
||||
};
|
||||
|
||||
const int numL = consumeNumber(left, posL);
|
||||
const int numR = consumeNumber(right, posR);
|
||||
if (numL != numR)
|
||||
return (numL - numR);
|
||||
|
||||
// String + digits do match and we haven't hit the end of both strings
|
||||
// then continue to consume the remainings
|
||||
}
|
||||
else {
|
||||
return (leftChar.unicode() - rightChar.unicode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QCollator m_collator;
|
||||
const bool m_caseSensitive;
|
||||
const Qt::CaseSensitivity m_caseSensitivity;
|
||||
};
|
||||
}
|
||||
|
||||
bool Utils::String::naturalCompareCaseSensitive(const QString &left, const QString &right)
|
||||
int Utils::String::naturalCompare(const QString &left, const QString &right, const Qt::CaseSensitivity caseSensitivity)
|
||||
{
|
||||
// provide a single `NaturalCompare` instance for easy use
|
||||
// https://doc.qt.io/qt-5/threads-reentrancy.html
|
||||
if (caseSensitivity == Qt::CaseSensitive) {
|
||||
#ifdef Q_OS_MAC // workaround for Apple xcode: https://stackoverflow.com/a/29929949
|
||||
static QThreadStorage<NaturalCompare> nCmp;
|
||||
if (!nCmp.hasLocalData()) nCmp.setLocalData(NaturalCompare(true));
|
||||
return (nCmp.localData())(left, right);
|
||||
static QThreadStorage<NaturalCompare> nCmp;
|
||||
if (!nCmp.hasLocalData())
|
||||
nCmp.setLocalData(NaturalCompare(Qt::CaseSensitive));
|
||||
return (nCmp.localData())(left, right);
|
||||
#else
|
||||
thread_local NaturalCompare nCmp(true);
|
||||
return nCmp(left, right);
|
||||
thread_local NaturalCompare nCmp(Qt::CaseSensitive);
|
||||
return nCmp(left, right);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool Utils::String::naturalCompareCaseInsensitive(const QString &left, const QString &right)
|
||||
{
|
||||
// provide a single `NaturalCompare` instance for easy use
|
||||
// https://doc.qt.io/qt-5/threads-reentrancy.html
|
||||
#ifdef Q_OS_MAC // workaround for Apple xcode: https://stackoverflow.com/a/29929949
|
||||
#ifdef Q_OS_MAC
|
||||
static QThreadStorage<NaturalCompare> nCmp;
|
||||
if (!nCmp.hasLocalData()) nCmp.setLocalData(NaturalCompare(false));
|
||||
if (!nCmp.hasLocalData())
|
||||
nCmp.setLocalData(NaturalCompare(Qt::CaseInsensitive));
|
||||
return (nCmp.localData())(left, right);
|
||||
#else
|
||||
thread_local NaturalCompare nCmp(false);
|
||||
thread_local NaturalCompare nCmp(Qt::CaseInsensitive);
|
||||
return nCmp(left, right);
|
||||
#endif
|
||||
}
|
||||
@@ -188,4 +184,3 @@ QString Utils::String::wildcardToRegex(const QString &pattern)
|
||||
{
|
||||
return qt_regexp_toCanonical(pattern, QRegExp::Wildcard);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,12 @@ namespace Utils
|
||||
// Taken from https://crackstation.net/hashing-security.htm
|
||||
bool slowEquals(const QByteArray &a, const QByteArray &b);
|
||||
|
||||
bool naturalCompareCaseSensitive(const QString &left, const QString &right);
|
||||
bool naturalCompareCaseInsensitive(const QString &left, const QString &right);
|
||||
int naturalCompare(const QString &left, const QString &right, const Qt::CaseSensitivity caseSensitivity);
|
||||
template <Qt::CaseSensitivity caseSensitivity>
|
||||
bool naturalLessThan(const QString &left, const QString &right)
|
||||
{
|
||||
return (naturalCompare(left, right, caseSensitivity) < 0);
|
||||
}
|
||||
|
||||
QString wildcardToRegex(const QString &pattern);
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ transferlistfilterswidget.h
|
||||
transferlistsortmodel.h
|
||||
transferlistwidget.h
|
||||
updownratiodlg.h
|
||||
utils.h
|
||||
)
|
||||
|
||||
set(QBT_GUI_SOURCES
|
||||
@@ -119,6 +120,7 @@ transferlistfilterswidget.cpp
|
||||
transferlistsortmodel.cpp
|
||||
transferlistwidget.cpp
|
||||
updownratiodlg.cpp
|
||||
utils.cpp
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
|
||||
@@ -18,11 +18,7 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="titleHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="logo">
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../icons.qrc">:/icons/skin/qbittorrent32.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="logo"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_name">
|
||||
@@ -57,11 +53,7 @@
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="aboutTabLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="mascot_lbl">
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../icons.qrc">:/icons/skin/mascot.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="labelMascot"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="lb_about">
|
||||
|
||||
@@ -31,10 +31,12 @@
|
||||
#ifndef ABOUT_H
|
||||
#define ABOUT_H
|
||||
|
||||
#include "ui_about.h"
|
||||
#include <QFile>
|
||||
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/unicodestrings.h"
|
||||
#include "ui_about.h"
|
||||
#include "utils.h"
|
||||
|
||||
class about: public QDialog, private Ui::AboutDlg
|
||||
{
|
||||
@@ -53,24 +55,28 @@ public:
|
||||
lb_name->setText("<b><h2>qBittorrent " QBT_VERSION " (32-bit)</h2></b>");
|
||||
#endif
|
||||
|
||||
logo->setPixmap(Utils::Gui::scaledPixmap(":/icons/skin/qbittorrent32.png", this));
|
||||
|
||||
// About
|
||||
QString aboutText = QString(
|
||||
"<p style=\"white-space: pre-wrap;\">"
|
||||
"%1\n\n"
|
||||
"%2\n\n"
|
||||
"<table>"
|
||||
"<tr><td>%3</td><td><a href=\"http://www.qbittorrent.org\">http://www.qbittorrent.org</a></td></tr>"
|
||||
"<tr><td>%3</td><td><a href=\"https://www.qbittorrent.org\">https://www.qbittorrent.org</a></td></tr>"
|
||||
"<tr><td>%4</td><td><a href=\"http://forum.qbittorrent.org\">http://forum.qbittorrent.org</a></td></tr>"
|
||||
"<tr><td>%5</td><td><a href=\"http://bugs.qbittorrent.org\">http://bugs.qbittorrent.org</a></td></tr>"
|
||||
"</table>"
|
||||
"</p>")
|
||||
.arg(tr("An advanced BitTorrent client programmed in C++, based on Qt toolkit and libtorrent-rasterbar."))
|
||||
.arg(tr("Copyright %1 2006-2017 The qBittorrent project").arg(QString::fromUtf8(C_COPYRIGHT)))
|
||||
.arg(tr("Copyright %1 2006-2018 The qBittorrent project").arg(QString::fromUtf8(C_COPYRIGHT)))
|
||||
.arg(tr("Home Page:"))
|
||||
.arg(tr("Forum:"))
|
||||
.arg(tr("Bug Tracker:"));
|
||||
lb_about->setText(aboutText);
|
||||
|
||||
labelMascot->setPixmap(Utils::Gui::scaledPixmap(":/icons/skin/mascot.png", this));
|
||||
|
||||
// Thanks
|
||||
QFile thanksfile(":/thanks.html");
|
||||
if (thanksfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
@@ -97,6 +103,7 @@ public:
|
||||
label_12->setText(Utils::Misc::libtorrentVersionString());
|
||||
label_13->setText(Utils::Misc::boostVersionString());
|
||||
|
||||
Utils::Gui::resize(this);
|
||||
show();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -28,36 +28,38 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QFile>
|
||||
#include <QUrl>
|
||||
#include <QMenu>
|
||||
#include <QFileDialog>
|
||||
#include <QPushButton>
|
||||
#include "addnewtorrentdialog.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QMenu>
|
||||
#include <QPushButton>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "base/bittorrent/magneturi.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "base/bittorrent/torrentinfo.h"
|
||||
#include "base/net/downloadhandler.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/settingsstorage.h"
|
||||
#include "base/settingvalue.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/net/downloadhandler.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/bittorrent/magneturi.h"
|
||||
#include "base/bittorrent/torrentinfo.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "base/torrentfileguard.h"
|
||||
#include "base/unicodestrings.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/utils/string.h"
|
||||
#include "base/torrentfileguard.h"
|
||||
#include "base/unicodestrings.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "messageboxraised.h"
|
||||
#include "proplistdelegate.h"
|
||||
#include "torrentcontentmodel.h"
|
||||
#include "torrentcontentfiltermodel.h"
|
||||
#include "torrentcontentmodel.h"
|
||||
#include "ui_addnewtorrentdialog.h"
|
||||
#include "addnewtorrentdialog.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -128,7 +130,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP
|
||||
|
||||
// Load categories
|
||||
QStringList categories = session->categories().keys();
|
||||
std::sort(categories.begin(), categories.end(), Utils::String::naturalCompareCaseInsensitive);
|
||||
std::sort(categories.begin(), categories.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
|
||||
QString defaultCategory = settings()->loadValue(KEY_DEFAULTCATEGORY).toString();
|
||||
|
||||
if (!m_torrentParams.category.isEmpty())
|
||||
@@ -212,10 +214,11 @@ CachedSettingValue<int> &AddNewTorrentDialog::savePathHistoryLengthSetting()
|
||||
void AddNewTorrentDialog::loadState()
|
||||
{
|
||||
m_headerState = settings()->loadValue(KEY_TREEHEADERSTATE).toByteArray();
|
||||
int width = settings()->loadValue(KEY_WIDTH, -1).toInt();
|
||||
QSize geo = size();
|
||||
geo.setWidth(width);
|
||||
resize(geo);
|
||||
|
||||
const QSize newSize = Utils::Gui::scaledSize(this, size());
|
||||
const int width = settings()->loadValue(KEY_WIDTH, newSize.width()).toInt();
|
||||
const int height = newSize.height();
|
||||
resize(width, height);
|
||||
|
||||
ui->adv_button->setChecked(settings()->loadValue(KEY_EXPANDED).toBool());
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "ui_autoexpandabledialog.h"
|
||||
#include "utils.h"
|
||||
|
||||
AutoExpandableDialog::AutoExpandableDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
@@ -68,30 +69,29 @@ QString AutoExpandableDialog::getText(QWidget *parent, const QString &title, con
|
||||
void AutoExpandableDialog::showEvent(QShowEvent *e)
|
||||
{
|
||||
// Overriding showEvent is required for consistent UI with fixed size under custom DPI
|
||||
// Show dialog
|
||||
QDialog::showEvent(e);
|
||||
// and resize textbox to fit the text
|
||||
|
||||
// NOTE: For some strange reason QFontMetrics gets more accurate
|
||||
// when called from showEvent. Only 6 symbols off instead of 11 symbols off.
|
||||
int textW = m_ui->textEdit->fontMetrics().width(m_ui->textEdit->text()) + 4;
|
||||
int wd = textW;
|
||||
// Show dialog and resize textbox to fit the text
|
||||
// NOTE: For unknown reason QFontMetrics gets more accurate when called from showEvent.
|
||||
int wd = m_ui->textEdit->fontMetrics().width(m_ui->textEdit->text()) + 4;
|
||||
|
||||
if (!windowTitle().isEmpty()) {
|
||||
int w = fontMetrics().width(windowTitle());
|
||||
if (w > wd)
|
||||
wd = w;
|
||||
// not really the font metrics in window title, so we enlarge it a bit,
|
||||
// including the small icon and close button width
|
||||
int w = fontMetrics().width(windowTitle()) * 1.8;
|
||||
wd = std::max(wd, w);
|
||||
}
|
||||
|
||||
if (!m_ui->textLabel->text().isEmpty()) {
|
||||
int w = m_ui->textLabel->fontMetrics().width(m_ui->textLabel->text());
|
||||
if (w > wd)
|
||||
wd = w;
|
||||
wd = std::max(wd, w);
|
||||
}
|
||||
|
||||
// Now resize the dialog to fit the contents
|
||||
// max width of text from either of: label, title, textedit
|
||||
// If the value is less than dialog default size, default size is used
|
||||
if (wd > width())
|
||||
resize(width() - m_ui->verticalLayout->sizeHint().width() + wd, height());
|
||||
if (wd > width()) {
|
||||
QSize size = {width() - m_ui->verticalLayout->sizeHint().width() + wd, height()};
|
||||
Utils::Gui::resize(this, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/utils/net.h"
|
||||
#include "ui_banlistoptions.h"
|
||||
#include "utils.h"
|
||||
|
||||
BanListOptions::BanListOptions(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
@@ -52,6 +53,8 @@ BanListOptions::BanListOptions(QWidget *parent)
|
||||
m_ui->bannedIPList->setModel(m_sortFilter);
|
||||
m_ui->bannedIPList->sortByColumn(0, Qt::AscendingOrder);
|
||||
m_ui->buttonBanIP->setEnabled(false);
|
||||
|
||||
Utils::Gui::resize(this);
|
||||
}
|
||||
|
||||
BanListOptions::~BanListOptions()
|
||||
|
||||
@@ -50,8 +50,10 @@ bool CategoryFilterProxyModel::lessThan(const QModelIndex &left, const QModelInd
|
||||
{
|
||||
// "All" and "Uncategorized" must be left in place
|
||||
if (CategoryFilterModel::isSpecialItem(left) || CategoryFilterModel::isSpecialItem(right))
|
||||
return left.row() < right.row();
|
||||
else
|
||||
return Utils::String::naturalCompareCaseInsensitive(
|
||||
left.data().toString(), right.data().toString());
|
||||
return (left < right);
|
||||
|
||||
int result = Utils::String::naturalCompare(left.data().toString(), right.data().toString()
|
||||
, Qt::CaseInsensitive);
|
||||
|
||||
return (result < 0);
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "categoryfiltermodel.h"
|
||||
#include "categoryfilterproxymodel.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "torrentcategorydialog.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -70,7 +70,7 @@ CategoryFilterWidget::CategoryFilterWidget(QWidget *parent)
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
setUniformRowHeights(true);
|
||||
setHeaderHidden(true);
|
||||
setIconSize(Utils::Misc::smallIconSize());
|
||||
setIconSize(Utils::Gui::smallIconSize());
|
||||
#ifdef Q_OS_MAC
|
||||
setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "cookiesmodel.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "ui_cookiesdialog.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define SETTINGS_KEY(name) "CookiesDialog/" name
|
||||
const QString KEY_SIZE = SETTINGS_KEY("Size");
|
||||
@@ -50,6 +51,8 @@ CookiesDialog::CookiesDialog(QWidget *parent)
|
||||
setWindowIcon(GuiIconProvider::instance()->getIcon("preferences-web-browser-cookies"));
|
||||
m_ui->buttonAdd->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
|
||||
m_ui->buttonDelete->setIcon(GuiIconProvider::instance()->getIcon("list-remove"));
|
||||
m_ui->buttonAdd->setIconSize(Utils::Gui::mediumIconSize());
|
||||
m_ui->buttonDelete->setIconSize(Utils::Gui::mediumIconSize());
|
||||
|
||||
m_ui->treeView->setModel(m_cookiesModel);
|
||||
if (m_cookiesModel->rowCount() > 0)
|
||||
@@ -57,7 +60,7 @@ CookiesDialog::CookiesDialog(QWidget *parent)
|
||||
m_cookiesModel->index(0, 0),
|
||||
QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||
|
||||
resize(SettingsStorage::instance()->loadValue(KEY_SIZE, size()).toSize());
|
||||
Utils::Gui::resize(this, SettingsStorage::instance()->loadValue(KEY_SIZE).toSize());
|
||||
m_ui->treeView->header()->restoreState(
|
||||
SettingsStorage::instance()->loadValue(KEY_COOKIESVIEWSTATE).toByteArray());
|
||||
}
|
||||
|
||||
@@ -49,12 +49,6 @@
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -78,12 +72,6 @@
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
||||
@@ -33,11 +33,13 @@
|
||||
|
||||
#include <QDialog>
|
||||
#include <QPushButton>
|
||||
#include "ui_confirmdeletiondlg.h"
|
||||
|
||||
#include "base/preferences.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/utils/string.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "ui_confirmdeletiondlg.h"
|
||||
#include "utils.h"
|
||||
|
||||
class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
|
||||
Q_OBJECT
|
||||
@@ -50,13 +52,17 @@ class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
|
||||
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
|
||||
lbl_warn->setPixmap(GuiIconProvider::instance()->getIcon("dialog-warning").pixmap(lbl_warn->height()));
|
||||
lbl_warn->setFixedWidth(lbl_warn->height());
|
||||
const QSize iconSize = Utils::Gui::largeIconSize();
|
||||
lbl_warn->setPixmap(GuiIconProvider::instance()->getIcon("dialog-warning").pixmap(iconSize));
|
||||
lbl_warn->setFixedWidth(iconSize.width());
|
||||
rememberBtn->setIcon(GuiIconProvider::instance()->getIcon("object-locked"));
|
||||
rememberBtn->setIconSize(Utils::Gui::mediumIconSize());
|
||||
|
||||
checkPermDelete->setChecked(defaultDeleteFiles || Preferences::instance()->deleteTorrentFilesAsDefault());
|
||||
connect(checkPermDelete, SIGNAL(clicked()), this, SLOT(updateRememberButtonState()));
|
||||
buttonBox->button(QDialogButtonBox::Cancel)->setFocus();
|
||||
|
||||
Utils::Gui::resize(this);
|
||||
}
|
||||
|
||||
bool shouldDeleteLocalFiles() const {
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <QStringList>
|
||||
|
||||
#include "ui_downloadfromurldlg.h"
|
||||
#include "utils.h"
|
||||
|
||||
class downloadFromURL : public QDialog, private Ui::downloadFromURL
|
||||
{
|
||||
@@ -82,6 +83,7 @@ class downloadFromURL : public QDialog, private Ui::downloadFromURL
|
||||
if (clip_txt_list_cleaned.size() > 0)
|
||||
textUrls->setText(clip_txt_list_cleaned.join("\n"));
|
||||
|
||||
Utils::Gui::resize(this);
|
||||
show();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QFileDialog>
|
||||
#include <QHBoxLayout>
|
||||
#include <QStyle>
|
||||
@@ -40,6 +41,7 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
const char i18nContext[] = "FileSystemPathEdit";
|
||||
struct TrStringWithComment
|
||||
{
|
||||
const char *source;
|
||||
@@ -47,18 +49,18 @@ namespace
|
||||
|
||||
QString tr() const
|
||||
{
|
||||
return QObject::tr(source, comment);
|
||||
return QCoreApplication::translate(i18nContext, source, comment);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr TrStringWithComment browseButtonBriefText =
|
||||
QT_TRANSLATE_NOOP3("FileSystemPathEdit", "...", "Launch file dialog button text (brief)");
|
||||
QT_TRANSLATE_NOOP3(i18nContext, "...", "Launch file dialog button text (brief)");
|
||||
constexpr TrStringWithComment browseButtonFullText =
|
||||
QT_TRANSLATE_NOOP3("FileSystemPathEdit", "&Browse...", "Launch file dialog button text (full)");
|
||||
QT_TRANSLATE_NOOP3(i18nContext, "&Browse...", "Launch file dialog button text (full)");
|
||||
constexpr TrStringWithComment defaultDialogCaptionForFile =
|
||||
QT_TRANSLATE_NOOP3("FileSystemPathEdit", "Choose a file", "Caption for file open/save dialog");
|
||||
QT_TRANSLATE_NOOP3(i18nContext, "Choose a file", "Caption for file open/save dialog");
|
||||
constexpr TrStringWithComment defaultDialogCaptionForDirectory =
|
||||
QT_TRANSLATE_NOOP3("FileSystemPathEdit", "Choose a folder", "Caption for directory open dialog");
|
||||
QT_TRANSLATE_NOOP3(i18nContext, "Choose a folder", "Caption for directory open dialog");
|
||||
}
|
||||
|
||||
class FileSystemPathEdit::FileSystemPathEditPrivate
|
||||
@@ -154,7 +156,9 @@ void FileSystemPathEdit::FileSystemPathEditPrivate::modeChanged()
|
||||
switch (m_mode) {
|
||||
case FileSystemPathEdit::Mode::FileOpen:
|
||||
case FileSystemPathEdit::Mode::FileSave:
|
||||
pixmap = QStyle::SP_DialogOpenButton;
|
||||
#ifdef Q_OS_WIN
|
||||
pixmap = QStyle::SP_DirOpenIcon;
|
||||
#endif
|
||||
showDirsOnly = false;
|
||||
break;
|
||||
case FileSystemPathEdit::Mode::DirectoryOpen:
|
||||
|
||||
214
src/gui/gui.pri
214
src/gui/gui.pri
@@ -1,124 +1,126 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
include(lineedit/lineedit.pri)
|
||||
include(properties/properties.pri)
|
||||
include(powermanagement/powermanagement.pri)
|
||||
include(properties/properties.pri)
|
||||
unix:!macx:dbus: include(qtnotify/qtnotify.pri)
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/mainwindow.h \
|
||||
$$PWD/transferlistwidget.h \
|
||||
$$PWD/transferlistdelegate.h \
|
||||
$$PWD/transferlistfilterswidget.h \
|
||||
$$PWD/transferlistsortmodel.h \
|
||||
$$PWD/torrentcategorydialog.h \
|
||||
$$PWD/torrentcontentmodel.h \
|
||||
$$PWD/torrentcontentmodelitem.h \
|
||||
$$PWD/torrentcontentmodelfolder.h \
|
||||
$$PWD/torrentcontentmodelfile.h \
|
||||
$$PWD/torrentcontentfiltermodel.h \
|
||||
$$PWD/torrentcontenttreeview.h \
|
||||
$$PWD/deletionconfirmationdlg.h \
|
||||
$$PWD/statusbar.h \
|
||||
$$PWD/speedlimitdlg.h \
|
||||
$$PWD/about_imp.h \
|
||||
$$PWD/previewlistdelegate.h \
|
||||
$$PWD/downloadfromurldlg.h \
|
||||
$$PWD/trackerlogin.h \
|
||||
$$PWD/hidabletabwidget.h \
|
||||
$$PWD/executionlog.h \
|
||||
$$PWD/guiiconprovider.h \
|
||||
$$PWD/updownratiodlg.h \
|
||||
$$PWD/loglistwidget.h \
|
||||
$$PWD/addnewtorrentdialog.h \
|
||||
$$PWD/advancedsettings.h \
|
||||
$$PWD/autoexpandabledialog.h \
|
||||
$$PWD/statsdialog.h \
|
||||
$$PWD/banlistoptions.h \
|
||||
$$PWD/categoryfiltermodel.h \
|
||||
$$PWD/categoryfilterproxymodel.h \
|
||||
$$PWD/categoryfilterwidget.h \
|
||||
$$PWD/cookiesdialog.h \
|
||||
$$PWD/cookiesmodel.h \
|
||||
$$PWD/deletionconfirmationdlg.h \
|
||||
$$PWD/downloadfromurldlg.h \
|
||||
$$PWD/executionlog.h \
|
||||
$$PWD/fspathedit.h \
|
||||
$$PWD/fspathedit_p.h \
|
||||
$$PWD/guiiconprovider.h \
|
||||
$$PWD/hidabletabwidget.h \
|
||||
$$PWD/ipsubnetwhitelistoptionsdialog.h \
|
||||
$$PWD/loglistwidget.h \
|
||||
$$PWD/mainwindow.h \
|
||||
$$PWD/messageboxraised.h \
|
||||
$$PWD/optionsdlg.h \
|
||||
$$PWD/advancedsettings.h \
|
||||
$$PWD/shutdownconfirmdlg.h \
|
||||
$$PWD/torrentmodel.h \
|
||||
$$PWD/torrentcreatordlg.h \
|
||||
$$PWD/previewlistdelegate.h \
|
||||
$$PWD/previewselectdialog.h \
|
||||
$$PWD/rss/articlelistwidget.h \
|
||||
$$PWD/rss/automatedrssdownloader.h \
|
||||
$$PWD/rss/feedlistwidget.h \
|
||||
$$PWD/rss/htmlbrowser.h \
|
||||
$$PWD/rss/rsswidget.h \
|
||||
$$PWD/scanfoldersdelegate.h \
|
||||
$$PWD/search/searchwidget.h \
|
||||
$$PWD/search/searchtab.h \
|
||||
$$PWD/search/pluginselectdlg.h \
|
||||
$$PWD/search/pluginsourcedlg.h \
|
||||
$$PWD/search/searchlistdelegate.h \
|
||||
$$PWD/search/searchsortmodel.h \
|
||||
$$PWD/cookiesmodel.h \
|
||||
$$PWD/cookiesdialog.h \
|
||||
$$PWD/categoryfiltermodel.h \
|
||||
$$PWD/categoryfilterproxymodel.h \
|
||||
$$PWD/categoryfilterwidget.h \
|
||||
$$PWD/search/searchtab.h \
|
||||
$$PWD/search/searchwidget.h \
|
||||
$$PWD/shutdownconfirmdlg.h \
|
||||
$$PWD/speedlimitdlg.h \
|
||||
$$PWD/statsdialog.h \
|
||||
$$PWD/statusbar.h \
|
||||
$$PWD/tagfiltermodel.h \
|
||||
$$PWD/tagfilterproxymodel.h \
|
||||
$$PWD/tagfilterwidget.h \
|
||||
$$PWD/banlistoptions.h \
|
||||
$$PWD/ipsubnetwhitelistoptionsdialog.h \
|
||||
$$PWD/rss/rsswidget.h \
|
||||
$$PWD/rss/articlelistwidget.h \
|
||||
$$PWD/rss/feedlistwidget.h \
|
||||
$$PWD/rss/automatedrssdownloader.h \
|
||||
$$PWD/rss/htmlbrowser.h \
|
||||
$$PWD/fspathedit.h \
|
||||
$$PWD/fspathedit_p.h \
|
||||
$$PWD/previewselectdialog.h \
|
||||
$$PWD/torrentcategorydialog.h \
|
||||
$$PWD/torrentcontentfiltermodel.h \
|
||||
$$PWD/torrentcontentmodel.h \
|
||||
$$PWD/torrentcontentmodelfile.h \
|
||||
$$PWD/torrentcontentmodelfolder.h \
|
||||
$$PWD/torrentcontentmodelitem.h \
|
||||
$$PWD/torrentcontenttreeview.h \
|
||||
$$PWD/torrentcreatordlg.h \
|
||||
$$PWD/torrentmodel.h \
|
||||
$$PWD/trackerlogin.h \
|
||||
$$PWD/transferlistdelegate.h \
|
||||
$$PWD/transferlistfilterswidget.h \
|
||||
$$PWD/transferlistsortmodel.h \
|
||||
$$PWD/transferlistwidget.h \
|
||||
$$PWD/updownratiodlg.h \
|
||||
$$PWD/utils.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/mainwindow.cpp \
|
||||
$$PWD/transferlistwidget.cpp \
|
||||
$$PWD/transferlistsortmodel.cpp \
|
||||
$$PWD/transferlistdelegate.cpp \
|
||||
$$PWD/transferlistfilterswidget.cpp \
|
||||
$$PWD/torrentcategorydialog.cpp \
|
||||
$$PWD/torrentcontentmodel.cpp \
|
||||
$$PWD/torrentcontentmodelitem.cpp \
|
||||
$$PWD/torrentcontentmodelfolder.cpp \
|
||||
$$PWD/torrentcontentmodelfile.cpp \
|
||||
$$PWD/torrentcontentfiltermodel.cpp \
|
||||
$$PWD/torrentcontenttreeview.cpp \
|
||||
$$PWD/executionlog.cpp \
|
||||
$$PWD/speedlimitdlg.cpp \
|
||||
$$PWD/guiiconprovider.cpp \
|
||||
$$PWD/updownratiodlg.cpp \
|
||||
$$PWD/loglistwidget.cpp \
|
||||
$$PWD/addnewtorrentdialog.cpp \
|
||||
$$PWD/autoexpandabledialog.cpp \
|
||||
$$PWD/statsdialog.cpp \
|
||||
$$PWD/messageboxraised.cpp \
|
||||
$$PWD/statusbar.cpp \
|
||||
$$PWD/advancedsettings.cpp \
|
||||
$$PWD/trackerlogin.cpp \
|
||||
$$PWD/autoexpandabledialog.cpp \
|
||||
$$PWD/banlistoptions.cpp \
|
||||
$$PWD/categoryfiltermodel.cpp \
|
||||
$$PWD/categoryfilterproxymodel.cpp \
|
||||
$$PWD/categoryfilterwidget.cpp \
|
||||
$$PWD/cookiesdialog.cpp \
|
||||
$$PWD/cookiesmodel.cpp \
|
||||
$$PWD/executionlog.cpp \
|
||||
$$PWD/fspathedit.cpp \
|
||||
$$PWD/fspathedit_p.cpp \
|
||||
$$PWD/guiiconprovider.cpp \
|
||||
$$PWD/ipsubnetwhitelistoptionsdialog.cpp \
|
||||
$$PWD/loglistwidget.cpp \
|
||||
$$PWD/mainwindow.cpp \
|
||||
$$PWD/messageboxraised.cpp \
|
||||
$$PWD/optionsdlg.cpp \
|
||||
$$PWD/shutdownconfirmdlg.cpp \
|
||||
$$PWD/torrentmodel.cpp \
|
||||
$$PWD/torrentcreatordlg.cpp \
|
||||
$$PWD/previewselectdialog.cpp \
|
||||
$$PWD/rss/articlelistwidget.cpp \
|
||||
$$PWD/rss/automatedrssdownloader.cpp \
|
||||
$$PWD/rss/feedlistwidget.cpp \
|
||||
$$PWD/rss/htmlbrowser.cpp \
|
||||
$$PWD/rss/rsswidget.cpp \
|
||||
$$PWD/scanfoldersdelegate.cpp \
|
||||
$$PWD/search/searchwidget.cpp \
|
||||
$$PWD/search/searchtab.cpp \
|
||||
$$PWD/search/pluginselectdlg.cpp \
|
||||
$$PWD/search/pluginsourcedlg.cpp \
|
||||
$$PWD/search/searchlistdelegate.cpp \
|
||||
$$PWD/search/searchsortmodel.cpp \
|
||||
$$PWD/cookiesmodel.cpp \
|
||||
$$PWD/cookiesdialog.cpp \
|
||||
$$PWD/categoryfiltermodel.cpp \
|
||||
$$PWD/categoryfilterproxymodel.cpp \
|
||||
$$PWD/categoryfilterwidget.cpp \
|
||||
$$PWD/search/searchtab.cpp \
|
||||
$$PWD/search/searchwidget.cpp \
|
||||
$$PWD/shutdownconfirmdlg.cpp \
|
||||
$$PWD/speedlimitdlg.cpp \
|
||||
$$PWD/statsdialog.cpp \
|
||||
$$PWD/statusbar.cpp \
|
||||
$$PWD/tagfiltermodel.cpp \
|
||||
$$PWD/tagfilterproxymodel.cpp \
|
||||
$$PWD/tagfilterwidget.cpp \
|
||||
$$PWD/banlistoptions.cpp \
|
||||
$$PWD/ipsubnetwhitelistoptionsdialog.cpp \
|
||||
$$PWD/rss/rsswidget.cpp \
|
||||
$$PWD/rss/articlelistwidget.cpp \
|
||||
$$PWD/rss/feedlistwidget.cpp \
|
||||
$$PWD/rss/automatedrssdownloader.cpp \
|
||||
$$PWD/rss/htmlbrowser.cpp \
|
||||
$$PWD/fspathedit.cpp \
|
||||
$$PWD/fspathedit_p.cpp \
|
||||
$$PWD/previewselectdialog.cpp \
|
||||
$$PWD/torrentcategorydialog.cpp \
|
||||
$$PWD/torrentcontentfiltermodel.cpp \
|
||||
$$PWD/torrentcontentmodel.cpp \
|
||||
$$PWD/torrentcontentmodelfile.cpp \
|
||||
$$PWD/torrentcontentmodelfolder.cpp \
|
||||
$$PWD/torrentcontentmodelitem.cpp \
|
||||
$$PWD/torrentcontenttreeview.cpp \
|
||||
$$PWD/torrentcreatordlg.cpp \
|
||||
$$PWD/torrentmodel.cpp \
|
||||
$$PWD/trackerlogin.cpp \
|
||||
$$PWD/transferlistdelegate.cpp \
|
||||
$$PWD/transferlistfilterswidget.cpp \
|
||||
$$PWD/transferlistsortmodel.cpp \
|
||||
$$PWD/transferlistwidget.cpp \
|
||||
$$PWD/updownratiodlg.cpp \
|
||||
$$PWD/utils.cpp
|
||||
|
||||
win32|macx {
|
||||
HEADERS += $$PWD/programupdater.h
|
||||
@@ -131,30 +133,30 @@ macx {
|
||||
}
|
||||
|
||||
FORMS += \
|
||||
$$PWD/mainwindow.ui \
|
||||
$$PWD/about.ui \
|
||||
$$PWD/previewselectdialog.ui \
|
||||
$$PWD/login.ui \
|
||||
$$PWD/downloadfromurldlg.ui \
|
||||
$$PWD/bandwidth_limit.ui \
|
||||
$$PWD/updownratiodlg.ui \
|
||||
$$PWD/confirmdeletiondlg.ui \
|
||||
$$PWD/shutdownconfirmdlg.ui \
|
||||
$$PWD/executionlog.ui \
|
||||
$$PWD/addnewtorrentdialog.ui \
|
||||
$$PWD/autoexpandabledialog.ui \
|
||||
$$PWD/statsdialog.ui \
|
||||
$$PWD/bandwidth_limit.ui \
|
||||
$$PWD/banlistoptions.ui \
|
||||
$$PWD/confirmdeletiondlg.ui \
|
||||
$$PWD/cookiesdialog.ui \
|
||||
$$PWD/downloadfromurldlg.ui \
|
||||
$$PWD/executionlog.ui \
|
||||
$$PWD/ipsubnetwhitelistoptionsdialog.ui \
|
||||
$$PWD/login.ui \
|
||||
$$PWD/mainwindow.ui \
|
||||
$$PWD/optionsdlg.ui \
|
||||
$$PWD/torrentcreatordlg.ui \
|
||||
$$PWD/search/searchwidget.ui \
|
||||
$$PWD/previewselectdialog.ui \
|
||||
$$PWD/rss/automatedrssdownloader.ui \
|
||||
$$PWD/rss/rsswidget.ui \
|
||||
$$PWD/search/pluginselectdlg.ui \
|
||||
$$PWD/search/pluginsourcedlg.ui \
|
||||
$$PWD/search/searchtab.ui \
|
||||
$$PWD/cookiesdialog.ui \
|
||||
$$PWD/banlistoptions.ui \
|
||||
$$PWD/ipsubnetwhitelistoptionsdialog.ui \
|
||||
$$PWD/rss/rsswidget.ui \
|
||||
$$PWD/rss/automatedrssdownloader.ui \
|
||||
$$PWD/torrentcategorydialog.ui
|
||||
$$PWD/search/searchwidget.ui \
|
||||
$$PWD/shutdownconfirmdlg.ui \
|
||||
$$PWD/statsdialog.ui \
|
||||
$$PWD/torrentcategorydialog.ui \
|
||||
$$PWD/torrentcreatordlg.ui \
|
||||
$$PWD/updownratiodlg.ui
|
||||
|
||||
RESOURCES += $$PWD/about.qrc
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "base/preferences.h"
|
||||
#include "base/utils/net.h"
|
||||
#include "ui_ipsubnetwhitelistoptionsdialog.h"
|
||||
#include "utils.h"
|
||||
|
||||
IPSubnetWhitelistOptionsDialog::IPSubnetWhitelistOptionsDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
@@ -57,6 +58,8 @@ IPSubnetWhitelistOptionsDialog::IPSubnetWhitelistOptionsDialog(QWidget *parent)
|
||||
m_ui->whitelistedIPSubnetList->setModel(m_sortFilter);
|
||||
m_ui->whitelistedIPSubnetList->sortByColumn(0, Qt::AscendingOrder);
|
||||
m_ui->buttonWhitelistIPSubnet->setEnabled(false);
|
||||
|
||||
Utils::Gui::resize(this);
|
||||
}
|
||||
|
||||
IPSubnetWhitelistOptionsDialog::~IPSubnetWhitelistOptionsDialog()
|
||||
@@ -68,12 +71,10 @@ void IPSubnetWhitelistOptionsDialog::on_buttonBox_accepted()
|
||||
{
|
||||
if (m_modified) {
|
||||
// save to session
|
||||
QList<Utils::Net::Subnet> subnets;
|
||||
QStringList subnets;
|
||||
// Operate on the m_sortFilter to grab the strings in sorted order
|
||||
for (int i = 0; i < m_sortFilter->rowCount(); ++i) {
|
||||
const QString subnet = m_sortFilter->index(i, 0).data().toString();
|
||||
subnets.append(QHostAddress::parseSubnet(subnet));
|
||||
}
|
||||
for (int i = 0; i < m_sortFilter->rowCount(); ++i)
|
||||
subnets.append(m_sortFilter->index(i, 0).data().toString());
|
||||
Preferences::instance()->setWebUiAuthSubnetWhitelist(subnets);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_21">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_31">
|
||||
<item>
|
||||
<widget class="QTreeView" name="whitelistedIPSubnetList">
|
||||
<property name="rootIsDecorated">
|
||||
@@ -46,7 +46,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_18">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="txtIPSubnet">
|
||||
<property name="placeholderText">
|
||||
@@ -54,6 +54,10 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonWhitelistIPSubnet">
|
||||
<property name="text">
|
||||
|
||||
@@ -6,11 +6,5 @@ set(QBT_LINEEDIT_HEADERS
|
||||
src/lineedit.h
|
||||
)
|
||||
|
||||
set(QBT_LINEEDIT_RESOURCES
|
||||
resources/lineeditimages.qrc
|
||||
)
|
||||
|
||||
add_library(qbt_lineedit STATIC ${QBT_LINEEDIT_SOURCES} ${QBT_LINEEDIT_HEADERS})
|
||||
target_link_libraries(qbt_lineedit Qt5::Widgets)
|
||||
|
||||
qbt_target_sources(${QBT_LINEEDIT_RESOURCES})
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
INCLUDEPATH += $$PWD/src
|
||||
HEADERS += $$PWD/src/lineedit.h
|
||||
SOURCES += $$PWD/src/lineedit.cpp
|
||||
RESOURCES += $$PWD/resources/lineeditimages.qrc
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>lineeditimages/search.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 292 B |
@@ -8,37 +8,35 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "lineedit.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QResizeEvent>
|
||||
#include <QStyle>
|
||||
#include <QToolButton>
|
||||
#include <QResizeEvent>
|
||||
|
||||
#include "guiiconprovider.h"
|
||||
|
||||
LineEdit::LineEdit(QWidget *parent)
|
||||
: QLineEdit(parent)
|
||||
{
|
||||
QPixmap pixmap1(":/lineeditimages/search.png");
|
||||
searchButton = new QToolButton(this);
|
||||
searchButton->setIcon(QIcon(pixmap1));
|
||||
searchButton->setIconSize(pixmap1.size());
|
||||
searchButton->setCursor(Qt::ArrowCursor);
|
||||
searchButton->setStyleSheet("QToolButton { border: none; padding: 2px; }");
|
||||
QSize searchButtonHint = searchButton->sizeHint();
|
||||
m_searchButton = new QToolButton(this);
|
||||
m_searchButton->setIcon(GuiIconProvider::instance()->getIcon("edit-find"));
|
||||
m_searchButton->setCursor(Qt::ArrowCursor);
|
||||
m_searchButton->setStyleSheet("QToolButton {border: none; padding: 2px;}");
|
||||
|
||||
// padding between text and widget borders
|
||||
setStyleSheet(QString("QLineEdit {padding-left: %1px;}").arg(m_searchButton->sizeHint().width()));
|
||||
|
||||
QSize clearButtonHint(0, 0);
|
||||
setClearButtonEnabled(true);
|
||||
setStyleSheet(QString("QLineEdit { padding-left: %1px; }").arg(searchButtonHint.width())); // padding between text and widget borders
|
||||
|
||||
QSize widgetHint = sizeHint();
|
||||
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||
setMaximumHeight(std::max({ widgetHint.height(), searchButtonHint.height(), clearButtonHint.height() }) + frameWidth * 2);
|
||||
const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||
setMaximumHeight(std::max(sizeHint().height(), m_searchButton->sizeHint().height()) + frameWidth * 2);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
}
|
||||
|
||||
void LineEdit::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||
|
||||
QSize sz = searchButton->sizeHint();
|
||||
searchButton->move(frameWidth, (e->size().height() - sz.height()) / 2);
|
||||
const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||
m_searchButton->move(frameWidth, (e->size().height() - m_searchButton->sizeHint().height()) / 2);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@ public:
|
||||
LineEdit(QWidget *parent);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
QToolButton *searchButton;
|
||||
QToolButton *m_searchButton;
|
||||
};
|
||||
|
||||
#endif // LIENEDIT_H
|
||||
|
||||
@@ -33,8 +33,12 @@
|
||||
#include <QSize>
|
||||
#include <objc/objc.h>
|
||||
|
||||
QPixmap pixmapForExtension(const QString &ext, const QSize &size);
|
||||
void overrideDockClickHandler(bool (*dockClickHandler)(id, SEL, ...));
|
||||
void displayNotification(const QString &title, const QString &message);
|
||||
namespace MacUtils
|
||||
{
|
||||
QPixmap pixmapForExtension(const QString &ext, const QSize &size);
|
||||
void overrideDockClickHandler(bool (*dockClickHandler)(id, SEL, ...));
|
||||
void displayNotification(const QString &title, const QString &message);
|
||||
void openFiles(const QSet<QString> &pathsList);
|
||||
}
|
||||
|
||||
#endif // MACUTILITIES_H
|
||||
|
||||
@@ -28,56 +28,72 @@
|
||||
|
||||
#include "macutilities.h"
|
||||
|
||||
#include <QSet>
|
||||
#include <QtMac>
|
||||
#include <objc/message.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
QPixmap pixmapForExtension(const QString &ext, const QSize &size)
|
||||
namespace MacUtils
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSImage *image = [[NSWorkspace sharedWorkspace] iconForFileType:ext.toNSString()];
|
||||
if (image) {
|
||||
NSRect rect = NSMakeRect(0, 0, size.width(), size.height());
|
||||
CGImageRef cgImage = [image CGImageForProposedRect:&rect context:nil hints:nil];
|
||||
return QtMac::fromCGImageRef(cgImage);
|
||||
QPixmap pixmapForExtension(const QString &ext, const QSize &size)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSImage *image = [[NSWorkspace sharedWorkspace] iconForFileType:ext.toNSString()];
|
||||
if (image) {
|
||||
NSRect rect = NSMakeRect(0, 0, size.width(), size.height());
|
||||
CGImageRef cgImage = [image CGImageForProposedRect:&rect context:nil hints:nil];
|
||||
return QtMac::fromCGImageRef(cgImage);
|
||||
}
|
||||
|
||||
return QPixmap();
|
||||
}
|
||||
}
|
||||
|
||||
void overrideDockClickHandler(bool (*dockClickHandler)(id, SEL, ...))
|
||||
{
|
||||
NSApplication *appInst = [NSApplication sharedApplication];
|
||||
|
||||
if (!appInst)
|
||||
return;
|
||||
|
||||
Class delClass = [[appInst delegate] class];
|
||||
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
|
||||
|
||||
if (class_getInstanceMethod(delClass, shouldHandle)) {
|
||||
if (class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
|
||||
qDebug("Registered dock click handler (replaced original method)");
|
||||
else
|
||||
qWarning("Failed to replace method for dock click handler");
|
||||
}
|
||||
else {
|
||||
if (class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
|
||||
qDebug("Registered dock click handler");
|
||||
else
|
||||
qWarning("Failed to register dock click handler");
|
||||
}
|
||||
}
|
||||
|
||||
void displayNotification(const QString &title, const QString &message)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSUserNotification *notification = [[NSUserNotification alloc] init];
|
||||
notification.title = title.toNSString();
|
||||
notification.informativeText = message.toNSString();
|
||||
notification.soundName = NSUserNotificationDefaultSoundName;
|
||||
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
|
||||
}
|
||||
}
|
||||
|
||||
void openFiles(const QSet<QString> &pathsList)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSMutableArray *pathURLs = [NSMutableArray arrayWithCapacity:pathsList.size()];
|
||||
|
||||
for (const auto &path : pathsList)
|
||||
[pathURLs addObject:[NSURL fileURLWithPath:path.toNSString()]];
|
||||
|
||||
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:pathURLs];
|
||||
}
|
||||
|
||||
return QPixmap();
|
||||
}
|
||||
}
|
||||
|
||||
void overrideDockClickHandler(bool (*dockClickHandler)(id, SEL, ...))
|
||||
{
|
||||
NSApplication *appInst = [NSApplication sharedApplication];
|
||||
|
||||
if (!appInst)
|
||||
return;
|
||||
|
||||
Class delClass = [[appInst delegate] class];
|
||||
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
|
||||
|
||||
if (class_getInstanceMethod(delClass, shouldHandle)) {
|
||||
if (class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
|
||||
qDebug("Registered dock click handler (replaced original method)");
|
||||
else
|
||||
qWarning("Failed to replace method for dock click handler");
|
||||
}
|
||||
else {
|
||||
if (class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
|
||||
qDebug("Registered dock click handler");
|
||||
else
|
||||
qWarning("Failed to register dock click handler");
|
||||
}
|
||||
}
|
||||
|
||||
void displayNotification(const QString &title, const QString &message)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSUserNotification *notification = [[NSUserNotification alloc] init];
|
||||
notification.title = title.toNSString();
|
||||
notification.informativeText = message.toNSString();
|
||||
notification.soundName = NSUserNotificationDefaultSoundName;
|
||||
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,84 +30,84 @@
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include <QtMacExtras>
|
||||
#include <QtMac>
|
||||
#endif
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QCloseEvent>
|
||||
#include <QCryptographicHash>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QFileDialog>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QMessageBox>
|
||||
#include <QMimeData>
|
||||
#include <QProcess>
|
||||
#include <QScrollBar>
|
||||
#include <QShortcut>
|
||||
#include <QSplitter>
|
||||
#include <QStatusBar>
|
||||
#include <QSysInfo>
|
||||
#include <QtGlobal>
|
||||
#include <QTimer>
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include <QtMac>
|
||||
#include <QtMacExtras>
|
||||
#endif
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB)
|
||||
#include <QDBusConnection>
|
||||
#include "notifications.h"
|
||||
#endif
|
||||
#include <QDebug>
|
||||
#include <QFileDialog>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QMessageBox>
|
||||
#include <QTimer>
|
||||
#include <QDesktopServices>
|
||||
#include <QStatusBar>
|
||||
#include <QClipboard>
|
||||
#include <QCloseEvent>
|
||||
#include <QShortcut>
|
||||
#include <QScrollBar>
|
||||
#include <QSplitter>
|
||||
#include <QSysInfo>
|
||||
#include <QMimeData>
|
||||
#include <QCryptographicHash>
|
||||
#include <QProcess>
|
||||
|
||||
#include "base/preferences.h"
|
||||
#include "base/settingsstorage.h"
|
||||
#include "base/logger.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/utils/fs.h"
|
||||
#ifdef Q_OS_WIN
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/net/downloadhandler.h"
|
||||
#endif
|
||||
#include "about_imp.h"
|
||||
#include "addnewtorrentdialog.h"
|
||||
#include "application.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/bittorrent/sessionstatus.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "base/global.h"
|
||||
#include "base/logger.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/rss/rss_folder.h"
|
||||
#include "base/rss/rss_session.h"
|
||||
#include "base/settingsstorage.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "cookiesdialog.h"
|
||||
#include "downloadfromurldlg.h"
|
||||
#include "executionlog.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "hidabletabwidget.h"
|
||||
#include "lineedit.h"
|
||||
#include "optionsdlg.h"
|
||||
#include "peerlistwidget.h"
|
||||
#include "powermanagement.h"
|
||||
#include "propertieswidget.h"
|
||||
#include "rss/rsswidget.h"
|
||||
#include "search/searchwidget.h"
|
||||
#include "speedlimitdlg.h"
|
||||
#include "statsdialog.h"
|
||||
#include "statusbar.h"
|
||||
#include "torrentcreatordlg.h"
|
||||
#include "torrentmodel.h"
|
||||
#include "trackerlist.h"
|
||||
#include "transferlistfilterswidget.h"
|
||||
#include "transferlistwidget.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "application.h"
|
||||
#ifdef Q_OS_WIN
|
||||
#include "base/net/downloadhandler.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#endif
|
||||
#ifdef Q_OS_MAC
|
||||
#include "macutilities.h"
|
||||
#endif
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
#include "programupdater.h"
|
||||
#endif
|
||||
#include "powermanagement.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "torrentmodel.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "torrentcreatordlg.h"
|
||||
#include "downloadfromurldlg.h"
|
||||
#include "addnewtorrentdialog.h"
|
||||
#include "statsdialog.h"
|
||||
#include "cookiesdialog.h"
|
||||
#include "speedlimitdlg.h"
|
||||
#include "transferlistwidget.h"
|
||||
#include "search/searchwidget.h"
|
||||
#include "trackerlist.h"
|
||||
#include "peerlistwidget.h"
|
||||
#include "transferlistfilterswidget.h"
|
||||
#include "propertieswidget.h"
|
||||
#include "statusbar.h"
|
||||
#include "rss/rsswidget.h"
|
||||
#include "about_imp.h"
|
||||
#include "optionsdlg.h"
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
#include "trackerlogin.h"
|
||||
#endif
|
||||
#include "lineedit.h"
|
||||
#include "executionlog.h"
|
||||
#include "hidabletabwidget.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include "macutilities.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
void qt_mac_set_dock_menu(QMenu *menu);
|
||||
@@ -231,7 +231,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
m_searchFilter = new LineEdit(this);
|
||||
m_searchFilterAction = m_ui->toolBar->insertWidget(m_ui->actionLock, m_searchFilter);
|
||||
m_searchFilter->setPlaceholderText(tr("Filter torrent list..."));
|
||||
m_searchFilter->setFixedWidth(200);
|
||||
m_searchFilter->setFixedWidth(Utils::Gui::scaledSize(this, 200));
|
||||
|
||||
QWidget *spacer = new QWidget(this);
|
||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
@@ -843,6 +843,11 @@ void MainWindow::createKeyboardShortcuts()
|
||||
m_ui->actionDelete->setShortcutContext(Qt::WidgetShortcut); // nullify its effect: delete key event is handled by respective widgets, not here
|
||||
m_ui->actionDownloadFromURL->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_O);
|
||||
m_ui->actionExit->setShortcut(Qt::CTRL + Qt::Key_Q);
|
||||
#ifdef Q_OS_MAC
|
||||
m_ui->actionCloseWindow->setShortcut(QKeySequence::Close);
|
||||
#else
|
||||
m_ui->actionCloseWindow->setVisible(false);
|
||||
#endif
|
||||
|
||||
QShortcut *switchTransferShortcut = new QShortcut(Qt::ALT + Qt::Key_1, this);
|
||||
connect(switchTransferShortcut, &QShortcut::activated, this, &MainWindow::displayTransferTab);
|
||||
@@ -978,6 +983,16 @@ void MainWindow::on_actionExit_triggered()
|
||||
close();
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
void MainWindow::on_actionCloseWindow_triggered()
|
||||
{
|
||||
// On macOS window close is basically equivalent to window hide.
|
||||
// If you decide to implement this functionality for other OS,
|
||||
// then you will also need ui lock checks like in actionExit.
|
||||
close();
|
||||
}
|
||||
#endif
|
||||
|
||||
QWidget *MainWindow::currentTabWidget() const
|
||||
{
|
||||
if (isMinimized() || !isVisible())
|
||||
@@ -1225,25 +1240,26 @@ void MainWindow::dropEvent(QDropEvent *event)
|
||||
// remove scheme
|
||||
QStringList files;
|
||||
if (event->mimeData()->hasUrls()) {
|
||||
const QList<QUrl> urls = event->mimeData()->urls();
|
||||
foreach (const QUrl &url, urls) {
|
||||
if (!url.isEmpty()) {
|
||||
if (url.scheme().compare("file", Qt::CaseInsensitive) == 0)
|
||||
files << url.toLocalFile();
|
||||
else
|
||||
files << url.toString();
|
||||
}
|
||||
foreach (const QUrl &url, event->mimeData()->urls()) {
|
||||
if (url.isEmpty())
|
||||
continue;
|
||||
|
||||
files << ((url.scheme().compare("file", Qt::CaseInsensitive) == 0)
|
||||
? url.toLocalFile()
|
||||
: url.toString());
|
||||
}
|
||||
}
|
||||
else {
|
||||
files = event->mimeData()->text().split('\n');
|
||||
}
|
||||
|
||||
// differentiate ".torrent" files and others
|
||||
// differentiate ".torrent" files/links & magnet links from others
|
||||
QStringList torrentFiles, otherFiles;
|
||||
foreach (const QString &file, files) {
|
||||
if (file.startsWith("magnet:", Qt::CaseInsensitive)
|
||||
|| file.endsWith(C_TORRENT_FILE_EXTENSION, Qt::CaseInsensitive))
|
||||
const bool isTorrentLink = (file.startsWith("magnet:", Qt::CaseInsensitive)
|
||||
|| file.endsWith(C_TORRENT_FILE_EXTENSION, Qt::CaseInsensitive)
|
||||
|| Utils::Misc::isUrl(file));
|
||||
if (isTorrentLink)
|
||||
torrentFiles << file;
|
||||
else
|
||||
otherFiles << file;
|
||||
@@ -1297,7 +1313,7 @@ static bool dockClickHandler(id self, SEL cmd, ...)
|
||||
void MainWindow::setupDockClickHandler()
|
||||
{
|
||||
dockMainWindowHandle = this;
|
||||
overrideDockClickHandler(dockClickHandler);
|
||||
MacUtils::overrideDockClickHandler(dockClickHandler);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1556,7 +1572,7 @@ void MainWindow::showNotificationBaloon(QString title, QString msg) const
|
||||
if (!reply.isError())
|
||||
return;
|
||||
#elif defined(Q_OS_MAC)
|
||||
displayNotification(title, msg);
|
||||
MacUtils::displayNotification(title, msg);
|
||||
#else
|
||||
if (m_systrayIcon && QSystemTrayIcon::supportsMessages())
|
||||
m_systrayIcon->showMessage(title, msg, QSystemTrayIcon::Information, TIME_TRAY_BALLOON);
|
||||
@@ -1838,7 +1854,7 @@ void MainWindow::toggleAlternativeSpeeds()
|
||||
|
||||
void MainWindow::on_actionDonateMoney_triggered()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl("http://www.qbittorrent.org/donate"));
|
||||
QDesktopServices::openUrl(QUrl("https://www.qbittorrent.org/donate"));
|
||||
}
|
||||
|
||||
void MainWindow::showConnectionSettings()
|
||||
|
||||
@@ -187,7 +187,9 @@ private slots:
|
||||
void toolbarTextBeside();
|
||||
void toolbarTextUnder();
|
||||
void toolbarFollowSystem();
|
||||
#ifndef Q_OS_MAC
|
||||
#ifdef Q_OS_MAC
|
||||
void on_actionCloseWindow_triggered();
|
||||
#else
|
||||
void toggleVisibility(const QSystemTrayIcon::ActivationReason reason = QSystemTrayIcon::Trigger);
|
||||
void createSystrayDelayed();
|
||||
void updateTrayIconMenu();
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
</property>
|
||||
<addaction name="actionOpen"/>
|
||||
<addaction name="actionDownloadFromURL"/>
|
||||
<addaction name="actionCloseWindow"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionExit"/>
|
||||
</widget>
|
||||
@@ -466,6 +467,11 @@
|
||||
<string>Critical Messages</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCloseWindow">
|
||||
<property name="text">
|
||||
<string>Close Window</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
#include "ipsubnetwhitelistoptionsdialog.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "scanfoldersdelegate.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "ui_optionsdlg.h"
|
||||
|
||||
@@ -99,13 +100,21 @@ OptionsDialog::OptionsDialog(QWidget *parent)
|
||||
m_ui->tabSelection->item(TAB_WEBUI)->setHidden(true);
|
||||
#endif
|
||||
m_ui->tabSelection->item(TAB_ADVANCED)->setIcon(GuiIconProvider::instance()->getIcon("preferences-other"));
|
||||
|
||||
// set uniform size for all icons
|
||||
int maxHeight = -1;
|
||||
for (int i = 0; i < m_ui->tabSelection->count(); ++i)
|
||||
maxHeight = std::max(maxHeight, m_ui->tabSelection->visualItemRect(m_ui->tabSelection->item(i)).size().height());
|
||||
for (int i = 0; i < m_ui->tabSelection->count(); ++i) {
|
||||
// uniform size for all icons
|
||||
m_ui->tabSelection->item(i)->setSizeHint(QSize(std::numeric_limits<int>::max(), 62));
|
||||
const QSize size(std::numeric_limits<int>::max(), static_cast<int>(maxHeight * 1.2));
|
||||
m_ui->tabSelection->item(i)->setSizeHint(size);
|
||||
}
|
||||
|
||||
m_ui->IpFilterRefreshBtn->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
|
||||
m_ui->labelGlobalRate->setPixmap(Utils::Gui::scaledPixmap(":/icons/slow_off.png", this, 16));
|
||||
m_ui->labelAltRate->setPixmap(Utils::Gui::scaledPixmap(":/icons/slow.png", this, 16));
|
||||
|
||||
m_ui->deleteTorrentWarningIcon->setPixmap(QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(16, 16));
|
||||
m_ui->deleteTorrentWarningIcon->hide();
|
||||
m_ui->deleteTorrentWarningLabel->hide();
|
||||
@@ -139,7 +148,7 @@ OptionsDialog::OptionsDialog(QWidget *parent)
|
||||
connect(ScanFoldersModel::instance(), &QAbstractListModel::dataChanged, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->scanFoldersView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ThisType::handleScanFolderViewSelectionChanged);
|
||||
|
||||
connect(m_ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(applySettings(QAbstractButton*)));
|
||||
connect(m_ui->buttonBox, &QDialogButtonBox::clicked, this, &OptionsDialog::applySettings);
|
||||
// Languages supported
|
||||
initializeLanguageCombo();
|
||||
|
||||
@@ -445,25 +454,19 @@ void OptionsDialog::changePage(QListWidgetItem *current, QListWidgetItem *previo
|
||||
|
||||
void OptionsDialog::loadWindowState()
|
||||
{
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
|
||||
resize(pref->getPrefSize(this->size()));
|
||||
Utils::Gui::resize(this, Preferences::instance()->getPrefSize());
|
||||
}
|
||||
|
||||
void OptionsDialog::loadSplitterState()
|
||||
{
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
const QStringList sizesStr = Preferences::instance()->getPrefHSplitterSizes();
|
||||
|
||||
const QStringList sizes_str = pref->getPrefHSplitterSizes();
|
||||
QList<int> sizes;
|
||||
if (sizes_str.size() == 2) {
|
||||
sizes << sizes_str.first().toInt();
|
||||
sizes << sizes_str.last().toInt();
|
||||
}
|
||||
else {
|
||||
sizes << 116;
|
||||
sizes << m_ui->hsplitter->width() - 116;
|
||||
}
|
||||
// width has been modified, use height as width reference instead
|
||||
const int width = Utils::Gui::scaledSize(this
|
||||
, (m_ui->tabSelection->item(TAB_UI)->sizeHint().height() * 2));
|
||||
QList<int> sizes {width, (m_ui->hsplitter->width() - width)};
|
||||
if (sizesStr.size() == 2)
|
||||
sizes = {sizesStr.first().toInt(), sizesStr.last().toInt()};
|
||||
m_ui->hsplitter->setSizes(sizes);
|
||||
}
|
||||
|
||||
@@ -534,7 +537,7 @@ void OptionsDialog::saveOptions()
|
||||
Application * const app = static_cast<Application*>(QCoreApplication::instance());
|
||||
app->setFileLoggerPath(m_ui->textFileLogPath->selectedPath());
|
||||
app->setFileLoggerBackup(m_ui->checkFileLogBackup->isChecked());
|
||||
app->setFileLoggerMaxSize(m_ui->spinFileLogSize->value());
|
||||
app->setFileLoggerMaxSize(m_ui->spinFileLogSize->value() * 1024);
|
||||
app->setFileLoggerAge(m_ui->spinFileLogAge->value());
|
||||
app->setFileLoggerAgeType(m_ui->comboFileLogAgeType->currentIndex());
|
||||
app->setFileLoggerDeleteOld(m_ui->checkFileLogDelete->isChecked());
|
||||
@@ -762,7 +765,7 @@ void OptionsDialog::loadOptions()
|
||||
m_ui->checkFileLogDelete->setChecked(fileLogDelete);
|
||||
m_ui->spinFileLogAge->setEnabled(fileLogDelete);
|
||||
m_ui->comboFileLogAgeType->setEnabled(fileLogDelete);
|
||||
m_ui->spinFileLogSize->setValue(app->fileLoggerMaxSize());
|
||||
m_ui->spinFileLogSize->setValue(app->fileLoggerMaxSize() / 1024);
|
||||
m_ui->spinFileLogAge->setValue(app->fileLoggerAge());
|
||||
m_ui->comboFileLogAgeType->setCurrentIndex(app->fileLoggerAgeType());
|
||||
// End General preferences
|
||||
@@ -1578,7 +1581,7 @@ void OptionsDialog::on_IpFilterRefreshBtn_clicked()
|
||||
session->setIPFilteringEnabled(true);
|
||||
session->setIPFilterFile(""); // forcing Session reload filter file
|
||||
session->setIPFilterFile(getFilter());
|
||||
connect(session, SIGNAL(IPFilterParsed(bool, int)), SLOT(handleIPFilterParsed(bool, int)));
|
||||
connect(session, &BitTorrent::Session::IPFilterParsed, this, &OptionsDialog::handleIPFilterParsed);
|
||||
setCursor(QCursor(Qt::WaitCursor));
|
||||
}
|
||||
|
||||
@@ -1590,7 +1593,7 @@ void OptionsDialog::handleIPFilterParsed(bool error, int ruleCount)
|
||||
else
|
||||
QMessageBox::information(this, tr("Successfully refreshed"), tr("Successfully parsed the provided IP filter: %1 rules were applied.", "%1 is a number").arg(ruleCount));
|
||||
m_refreshingIpFilter = false;
|
||||
disconnect(BitTorrent::Session::instance(), SIGNAL(IPFilterParsed(bool, int)), this, SLOT(handleIPFilterParsed(bool, int)));
|
||||
disconnect(BitTorrent::Session::instance(), &BitTorrent::Session::IPFilterParsed, this, &OptionsDialog::handleIPFilterParsed);
|
||||
}
|
||||
|
||||
QString OptionsDialog::languageToLocalizedString(const QLocale &locale)
|
||||
@@ -1675,11 +1678,11 @@ bool OptionsDialog::setSslKey(const QByteArray &key)
|
||||
// try different formats
|
||||
const bool isKeyValid = (!QSslKey(key, QSsl::Rsa).isNull() || !QSslKey(key, QSsl::Ec).isNull());
|
||||
if (isKeyValid) {
|
||||
m_ui->lblSslKeyStatus->setPixmap(QPixmap(":/icons/qbt-theme/security-high.png").scaledToHeight(20, Qt::SmoothTransformation));
|
||||
m_ui->lblSslKeyStatus->setPixmap(Utils::Gui::scaledPixmap(":/icons/qbt-theme/security-high.png", this, 24));
|
||||
m_sslKey = key;
|
||||
}
|
||||
else {
|
||||
m_ui->lblSslKeyStatus->setPixmap(QPixmap(":/icons/qbt-theme/security-low.png").scaledToHeight(20, Qt::SmoothTransformation));
|
||||
m_ui->lblSslKeyStatus->setPixmap(Utils::Gui::scaledPixmap(":/icons/qbt-theme/security-low.png", this, 24));
|
||||
m_sslKey.clear();
|
||||
}
|
||||
return isKeyValid;
|
||||
@@ -1694,11 +1697,11 @@ bool OptionsDialog::setSslCertificate(const QByteArray &cert)
|
||||
#ifndef QT_NO_OPENSSL
|
||||
const bool isCertValid = !QSslCertificate(cert).isNull();
|
||||
if (isCertValid) {
|
||||
m_ui->lblSslCertStatus->setPixmap(QPixmap(":/icons/qbt-theme/security-high.png").scaledToHeight(20, Qt::SmoothTransformation));
|
||||
m_ui->lblSslCertStatus->setPixmap(Utils::Gui::scaledPixmap(":/icons/qbt-theme/security-high.png", this, 24));
|
||||
m_sslCert = cert;
|
||||
}
|
||||
else {
|
||||
m_ui->lblSslCertStatus->setPixmap(QPixmap(":/icons/qbt-theme/security-low.png").scaledToHeight(20, Qt::SmoothTransformation));
|
||||
m_ui->lblSslCertStatus->setPixmap(Utils::Gui::scaledPixmap(":/icons/qbt-theme/security-low.png", this, 24));
|
||||
m_sslCert.clear();
|
||||
}
|
||||
return isCertValid;
|
||||
|
||||
@@ -535,16 +535,16 @@
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinFileLogSize">
|
||||
<property name="suffix">
|
||||
<string> MB</string>
|
||||
<string> KiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
<number>1024000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
<number>65</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -1823,11 +1823,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" rowspan="2">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../icons.qrc">:/icons/slow_off.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="labelGlobalRate"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="checkDownloadLimit">
|
||||
@@ -1970,11 +1966,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" rowspan="2">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../icons.qrc">:/icons/slow.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="labelAltRate"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="checkUploadLimitAlt">
|
||||
@@ -2853,20 +2845,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.</string>
|
||||
<layout class="QGridLayout" name="gridLayout_11">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblSslCertStatus">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -2906,20 +2886,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.</string>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblSslKeyStatus">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "previewlistdelegate.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define SETTINGS_KEY(name) "PreviewSelectDialog/" name
|
||||
|
||||
@@ -146,7 +147,7 @@ void PreviewSelectDialog::previewButtonClicked()
|
||||
void PreviewSelectDialog::saveWindowState()
|
||||
{
|
||||
// Persist dialog size
|
||||
m_storeDialogSize = this->size();
|
||||
m_storeDialogSize = size();
|
||||
// Persist TreeView Header state
|
||||
m_storeTreeHeaderState = previewList->header()->saveState();
|
||||
}
|
||||
@@ -154,9 +155,8 @@ void PreviewSelectDialog::saveWindowState()
|
||||
void PreviewSelectDialog::loadWindowState()
|
||||
{
|
||||
// Restore dialog size
|
||||
if (m_storeDialogSize.value().isValid()) {
|
||||
resize(m_storeDialogSize);
|
||||
}
|
||||
Utils::Gui::resize(this, m_storeDialogSize);
|
||||
|
||||
// Restore TreeView Header state
|
||||
if (!m_storeTreeHeaderState.value().isEmpty()) {
|
||||
m_headerStateInitialized = previewList->header()->restoreState(m_storeTreeHeaderState);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,8 +24,6 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "downloadedpiecesbar.h"
|
||||
@@ -127,24 +125,24 @@ bool DownloadedPiecesBar::updateImage(QImage &image)
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<float> scaled_pieces = bitfieldToFloatVector(m_pieces, image2.width());
|
||||
QVector<float> scaled_pieces_dl = bitfieldToFloatVector(m_downloadedPieces, image2.width());
|
||||
QVector<float> scaledPieces = bitfieldToFloatVector(m_pieces, image2.width());
|
||||
QVector<float> scaledPiecesDl = bitfieldToFloatVector(m_downloadedPieces, image2.width());
|
||||
|
||||
// filling image
|
||||
for (int x = 0; x < scaled_pieces.size(); ++x) {
|
||||
float pieces2_val = scaled_pieces.at(x);
|
||||
float pieces2_val_dl = scaled_pieces_dl.at(x);
|
||||
if (pieces2_val_dl != 0) {
|
||||
float fill_ratio = pieces2_val + pieces2_val_dl;
|
||||
float ratio = pieces2_val_dl / fill_ratio;
|
||||
for (int x = 0; x < scaledPieces.size(); ++x) {
|
||||
float piecesToValue = scaledPieces.at(x);
|
||||
float piecesToValueDl = scaledPiecesDl.at(x);
|
||||
if (piecesToValueDl != 0) {
|
||||
float fillRatio = piecesToValue + piecesToValueDl;
|
||||
float ratio = piecesToValueDl / fillRatio;
|
||||
|
||||
QRgb mixedColor = mixTwoColors(pieceColor().rgb(), m_dlPieceColor.rgb(), ratio);
|
||||
mixedColor = mixTwoColors(backgroundColor().rgb(), mixedColor, fill_ratio);
|
||||
mixedColor = mixTwoColors(backgroundColor().rgb(), mixedColor, fillRatio);
|
||||
|
||||
image2.setPixel(x, 0, mixedColor);
|
||||
}
|
||||
else {
|
||||
image2.setPixel(x, 0, pieceColors()[pieces2_val * 255]);
|
||||
image2.setPixel(x, 0, pieceColors()[piecesToValue * 255]);
|
||||
}
|
||||
}
|
||||
image = image2;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,20 +24,18 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef DOWNLOADEDPIECESBAR_H
|
||||
#define DOWNLOADEDPIECESBAR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QBitArray>
|
||||
#include <QVector>
|
||||
#include <QWidget>
|
||||
|
||||
#include "piecesbar.h"
|
||||
|
||||
class DownloadedPiecesBar: public PiecesBar
|
||||
class DownloadedPiecesBar : public PiecesBar
|
||||
{
|
||||
using base = PiecesBar;
|
||||
Q_OBJECT
|
||||
|
||||
@@ -61,7 +61,6 @@ public:
|
||||
COL_COUNT
|
||||
};
|
||||
|
||||
public:
|
||||
PeerListDelegate(QObject *parent) : QItemDelegate(parent) {}
|
||||
|
||||
~PeerListDelegate() {}
|
||||
|
||||
@@ -50,13 +50,15 @@ protected:
|
||||
switch (sortColumn()) {
|
||||
case PeerListDelegate::IP:
|
||||
case PeerListDelegate::CLIENT: {
|
||||
QString vL = left.data().toString();
|
||||
QString vR = right.data().toString();
|
||||
return Utils::String::naturalCompareCaseInsensitive(vL, vR);
|
||||
}
|
||||
const QString strL = left.data().toString();
|
||||
const QString strR = right.data().toString();
|
||||
const int result = Utils::String::naturalCompare(strL, strR, Qt::CaseInsensitive);
|
||||
return (result < 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return QSortFilterProxyModel::lessThan(left, right);
|
||||
};
|
||||
|
||||
return QSortFilterProxyModel::lessThan(left, right);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -180,10 +180,9 @@ void PeerListWidget::displayToggleColumnsMenu(const QPoint &)
|
||||
Q_ASSERT(visibleCols > 0);
|
||||
if (!isColumnHidden(col) && (visibleCols == 1))
|
||||
return;
|
||||
qDebug("Toggling column %d visibility", col);
|
||||
setColumnHidden(col, !isColumnHidden(col));
|
||||
if (!isColumnHidden(col) && (columnWidth(col) <= 5))
|
||||
setColumnWidth(col, 100);
|
||||
resizeColumnToContents(col);
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
@@ -231,8 +230,8 @@ void PeerListWidget::showPeerListMenu(const QPoint &)
|
||||
addPeerAct = menu.addAction(GuiIconProvider::instance()->getIcon("user-group-new"), tr("Add a new peer..."));
|
||||
emptyMenu = false;
|
||||
}
|
||||
QAction *banAct = 0;
|
||||
QAction *copyPeerAct = 0;
|
||||
QAction *banAct = nullptr;
|
||||
QAction *copyPeerAct = nullptr;
|
||||
if (!selectionModel()->selectedRows().isEmpty()) {
|
||||
copyPeerAct = menu.addAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy IP:port"));
|
||||
menu.addSeparator();
|
||||
@@ -241,7 +240,8 @@ void PeerListWidget::showPeerListMenu(const QPoint &)
|
||||
}
|
||||
if (emptyMenu) return;
|
||||
QAction *act = menu.exec(QCursor::pos());
|
||||
if (act == 0) return;
|
||||
if (!act) return;
|
||||
|
||||
if (act == addPeerAct) {
|
||||
QList<BitTorrent::PeerAddress> peersList = PeersAdditionDlg::askForPeers(this);
|
||||
int peerCount = 0;
|
||||
@@ -249,7 +249,7 @@ void PeerListWidget::showPeerListMenu(const QPoint &)
|
||||
if (torrent->connectPeer(addr)) {
|
||||
qDebug("Adding peer %s...", qUtf8Printable(addr.ip.toString()));
|
||||
Logger::instance()->addMessage(tr("Manually adding peer '%1'...").arg(addr.ip.toString()));
|
||||
peerCount++;
|
||||
++peerCount;
|
||||
}
|
||||
else {
|
||||
Logger::instance()->addMessage(tr("The peer '%1' could not be added to this torrent.").arg(addr.ip.toString()), Log::WARNING);
|
||||
@@ -277,8 +277,7 @@ void PeerListWidget::banSelectedPeers()
|
||||
int ret = QMessageBox::question(this, tr("Ban peer permanently"), tr("Are you sure you want to ban permanently the selected peers?"),
|
||||
tr("&Yes"), tr("&No"),
|
||||
QString(), 0, 1);
|
||||
if (ret)
|
||||
return;
|
||||
if (ret) return;
|
||||
|
||||
QModelIndexList selectedIndexes = selectionModel()->selectedRows();
|
||||
foreach (const QModelIndex &index, selectedIndexes) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,14 +24,12 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "peersadditiondlg.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QHostAddress>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "ui_peersadditiondlg.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,8 +24,6 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef PEERADDITION_H
|
||||
@@ -42,7 +40,7 @@ namespace Ui
|
||||
class addPeersDialog;
|
||||
}
|
||||
|
||||
class PeersAdditionDlg: public QDialog
|
||||
class PeersAdditionDlg : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -60,7 +58,6 @@ private:
|
||||
|
||||
Ui::addPeersDialog *m_ui;
|
||||
QList<BitTorrent::PeerAddress> m_peersList;
|
||||
|
||||
};
|
||||
|
||||
#endif // PEERADDITION_H
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,8 +24,6 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "pieceavailabilitybar.h"
|
||||
@@ -134,12 +132,12 @@ bool PieceAvailabilityBar::updateImage(QImage &image)
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<float> scaled_pieces = intToFloatVector(m_pieces, image2.width());
|
||||
QVector<float> scaledPieces = intToFloatVector(m_pieces, image2.width());
|
||||
|
||||
// filling image
|
||||
for (int x = 0; x < scaled_pieces.size(); ++x) {
|
||||
float pieces2_val = scaled_pieces.at(x);
|
||||
image2.setPixel(x, 0, pieceColors()[pieces2_val * 255]);
|
||||
for (int x = 0; x < scaledPieces.size(); ++x) {
|
||||
float piecesToValue = scaledPieces.at(x);
|
||||
image2.setPixel(x, 0, pieceColors()[piecesToValue * 255]);
|
||||
}
|
||||
image = image2;
|
||||
return true;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,8 +24,6 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef PIECEAVAILABILITYBAR_H
|
||||
@@ -33,7 +31,7 @@
|
||||
|
||||
#include "piecesbar.h"
|
||||
|
||||
class PieceAvailabilityBar: public PiecesBar
|
||||
class PieceAvailabilityBar : public PiecesBar
|
||||
{
|
||||
using base = PiecesBar;
|
||||
Q_OBJECT
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace BitTorrent
|
||||
class TorrentHandle;
|
||||
}
|
||||
|
||||
class PiecesBar: public QWidget
|
||||
class PiecesBar : public QWidget
|
||||
{
|
||||
using base = QWidget;
|
||||
Q_OBJECT
|
||||
|
||||
@@ -1,33 +1,36 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
FORMS += $$PWD/propertieswidget.ui \
|
||||
$$PWD/trackersadditiondlg.ui \
|
||||
$$PWD/peersadditiondlg.ui
|
||||
FORMS += \
|
||||
$$PWD/peersadditiondlg.ui \
|
||||
$$PWD/propertieswidget.ui \
|
||||
$$PWD/trackersadditiondlg.ui
|
||||
|
||||
HEADERS += $$PWD/propertieswidget.h \
|
||||
$$PWD/peerlistwidget.h \
|
||||
$$PWD/proplistdelegate.h \
|
||||
$$PWD/trackerlist.h \
|
||||
$$PWD/downloadedpiecesbar.h \
|
||||
$$PWD/peerlistdelegate.h \
|
||||
$$PWD/peerlistsortmodel.h \
|
||||
$$PWD/peersadditiondlg.h \
|
||||
$$PWD/trackersadditiondlg.h \
|
||||
$$PWD/pieceavailabilitybar.h \
|
||||
$$PWD/proptabbar.h \
|
||||
$$PWD/speedwidget.h \
|
||||
$$PWD/speedplotview.h \
|
||||
$$PWD/piecesbar.h
|
||||
HEADERS += \
|
||||
$$PWD/downloadedpiecesbar.h \
|
||||
$$PWD/peerlistdelegate.h \
|
||||
$$PWD/peerlistsortmodel.h \
|
||||
$$PWD/peerlistwidget.h \
|
||||
$$PWD/peersadditiondlg.h \
|
||||
$$PWD/pieceavailabilitybar.h \
|
||||
$$PWD/piecesbar.h \
|
||||
$$PWD/propertieswidget.h \
|
||||
$$PWD/proplistdelegate.h \
|
||||
$$PWD/proptabbar.h \
|
||||
$$PWD/speedplotview.h \
|
||||
$$PWD/speedwidget.h \
|
||||
$$PWD/trackerlist.h \
|
||||
$$PWD/trackersadditiondlg.h
|
||||
|
||||
SOURCES += $$PWD/propertieswidget.cpp \
|
||||
$$PWD/proplistdelegate.cpp \
|
||||
$$PWD/peerlistwidget.cpp \
|
||||
$$PWD/trackerlist.cpp \
|
||||
$$PWD/peersadditiondlg.cpp \
|
||||
$$PWD/downloadedpiecesbar.cpp \
|
||||
$$PWD/trackersadditiondlg.cpp \
|
||||
$$PWD/pieceavailabilitybar.cpp \
|
||||
$$PWD/proptabbar.cpp \
|
||||
$$PWD/speedwidget.cpp \
|
||||
$$PWD/speedplotview.cpp \
|
||||
$$PWD/piecesbar.cpp
|
||||
SOURCES += \
|
||||
$$PWD/downloadedpiecesbar.cpp \
|
||||
$$PWD/peerlistwidget.cpp \
|
||||
$$PWD/peersadditiondlg.cpp \
|
||||
$$PWD/pieceavailabilitybar.cpp \
|
||||
$$PWD/piecesbar.cpp \
|
||||
$$PWD/propertieswidget.cpp \
|
||||
$$PWD/proplistdelegate.cpp \
|
||||
$$PWD/proptabbar.cpp \
|
||||
$$PWD/speedplotview.cpp \
|
||||
$$PWD/speedwidget.cpp \
|
||||
$$PWD/trackerlist.cpp \
|
||||
$$PWD/trackersadditiondlg.cpp
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,8 +24,6 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "propertieswidget.h"
|
||||
@@ -64,89 +62,95 @@
|
||||
#include "torrentcontentmodel.h"
|
||||
#include "trackerlist.h"
|
||||
#include "transferlistwidget.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "ui_propertieswidget.h"
|
||||
|
||||
PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow *main_window, TransferListWidget *transferList)
|
||||
#ifdef Q_OS_MAC
|
||||
#include "macutilities.h"
|
||||
#endif
|
||||
|
||||
PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow *mainWindow, TransferListWidget *transferList)
|
||||
: QWidget(parent)
|
||||
, m_ui(new Ui::PropertiesWidget())
|
||||
, transferList(transferList)
|
||||
, main_window(main_window)
|
||||
, m_transferList(transferList)
|
||||
, m_mainWindow(mainWindow)
|
||||
, m_torrent(nullptr)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setAutoFillBackground(true);
|
||||
|
||||
state = VISIBLE;
|
||||
m_state = VISIBLE;
|
||||
|
||||
// Set Properties list model
|
||||
PropListModel = new TorrentContentFilterModel();
|
||||
m_ui->filesList->setModel(PropListModel);
|
||||
PropDelegate = new PropListDelegate(this);
|
||||
m_ui->filesList->setItemDelegate(PropDelegate);
|
||||
m_propListModel = new TorrentContentFilterModel();
|
||||
m_ui->filesList->setModel(m_propListModel);
|
||||
m_propListDelegate = new PropListDelegate(this);
|
||||
m_ui->filesList->setItemDelegate(m_propListDelegate);
|
||||
m_ui->filesList->setSortingEnabled(true);
|
||||
|
||||
// Torrent content filtering
|
||||
m_contentFilterLine = new LineEdit(this);
|
||||
m_contentFilterLine->setPlaceholderText(tr("Filter files..."));
|
||||
m_contentFilterLine->setMaximumSize(300, m_contentFilterLine->size().height());
|
||||
m_contentFilterLine->setFixedWidth(Utils::Gui::scaledSize(this, 300));
|
||||
connect(m_contentFilterLine, SIGNAL(textChanged(QString)), this, SLOT(filterText(QString)));
|
||||
m_ui->contentFilterLayout->insertWidget(3, m_contentFilterLine);
|
||||
|
||||
// SIGNAL/SLOTS
|
||||
connect(m_ui->filesList, SIGNAL(clicked(const QModelIndex&)), m_ui->filesList, SLOT(edit(const QModelIndex&)));
|
||||
connect(m_ui->selectAllButton, SIGNAL(clicked()), PropListModel, SLOT(selectAll()));
|
||||
connect(m_ui->selectNoneButton, SIGNAL(clicked()), PropListModel, SLOT(selectNone()));
|
||||
connect(m_ui->selectAllButton, SIGNAL(clicked()), m_propListModel, SLOT(selectAll()));
|
||||
connect(m_ui->selectNoneButton, SIGNAL(clicked()), m_propListModel, SLOT(selectNone()));
|
||||
connect(m_ui->filesList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayFilesListMenu(const QPoint&)));
|
||||
connect(m_ui->filesList, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(openDoubleClickedFile(const QModelIndex&)));
|
||||
connect(PropListModel, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged()));
|
||||
connect(m_propListModel, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged()));
|
||||
connect(m_ui->listWebSeeds, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayWebSeedListMenu(const QPoint&)));
|
||||
connect(transferList, SIGNAL(currentTorrentChanged(BitTorrent::TorrentHandle * const)), this, SLOT(loadTorrentInfos(BitTorrent::TorrentHandle * const)));
|
||||
connect(PropDelegate, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged()));
|
||||
connect(transferList, SIGNAL(currentTorrentChanged(BitTorrent::TorrentHandle *const)), this, SLOT(loadTorrentInfos(BitTorrent::TorrentHandle *const)));
|
||||
connect(m_propListDelegate, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged()));
|
||||
connect(m_ui->stackedProperties, SIGNAL(currentChanged(int)), this, SLOT(loadDynamicData()));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentSavePathChanged(BitTorrent::TorrentHandle * const)), this, SLOT(updateSavePath(BitTorrent::TorrentHandle * const)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentMetadataLoaded(BitTorrent::TorrentHandle * const)), this, SLOT(updateTorrentInfos(BitTorrent::TorrentHandle * const)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentSavePathChanged(BitTorrent::TorrentHandle *const)), this, SLOT(updateSavePath(BitTorrent::TorrentHandle *const)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentMetadataLoaded(BitTorrent::TorrentHandle *const)), this, SLOT(updateTorrentInfos(BitTorrent::TorrentHandle *const)));
|
||||
connect(m_ui->filesList->header(), SIGNAL(sectionMoved(int,int,int)), this, SLOT(saveSettings()));
|
||||
connect(m_ui->filesList->header(), SIGNAL(sectionResized(int,int,int)), this, SLOT(saveSettings()));
|
||||
connect(m_ui->filesList->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSettings()));
|
||||
|
||||
// set bar height relative to screen dpi
|
||||
int barHeight = devicePixelRatio() * 18;
|
||||
const int barHeight = Utils::Gui::scaledSize(this, 18);
|
||||
|
||||
// Downloaded pieces progress bar
|
||||
m_ui->tempProgressBarArea->setVisible(false);
|
||||
downloaded_pieces = new DownloadedPiecesBar(this);
|
||||
m_ui->groupBarLayout->addWidget(downloaded_pieces, 0, 1);
|
||||
downloaded_pieces->setFixedHeight(barHeight);
|
||||
downloaded_pieces->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
m_downloadedPieces = new DownloadedPiecesBar(this);
|
||||
m_ui->groupBarLayout->addWidget(m_downloadedPieces, 0, 1);
|
||||
m_downloadedPieces->setFixedHeight(barHeight);
|
||||
m_downloadedPieces->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
// Pieces availability bar
|
||||
m_ui->tempAvailabilityBarArea->setVisible(false);
|
||||
pieces_availability = new PieceAvailabilityBar(this);
|
||||
m_ui->groupBarLayout->addWidget(pieces_availability, 1, 1);
|
||||
pieces_availability->setFixedHeight(barHeight);
|
||||
pieces_availability->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
m_piecesAvailability = new PieceAvailabilityBar(this);
|
||||
m_ui->groupBarLayout->addWidget(m_piecesAvailability, 1, 1);
|
||||
m_piecesAvailability->setFixedHeight(barHeight);
|
||||
m_piecesAvailability->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
// Tracker list
|
||||
trackerList = new TrackerList(this);
|
||||
m_trackerList = new TrackerList(this);
|
||||
m_ui->trackerUpButton->setIcon(GuiIconProvider::instance()->getIcon("go-up"));
|
||||
m_ui->trackerUpButton->setIconSize(Utils::Misc::smallIconSize());
|
||||
m_ui->trackerUpButton->setIconSize(Utils::Gui::smallIconSize());
|
||||
m_ui->trackerDownButton->setIcon(GuiIconProvider::instance()->getIcon("go-down"));
|
||||
m_ui->trackerDownButton->setIconSize(Utils::Misc::smallIconSize());
|
||||
connect(m_ui->trackerUpButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionUp()));
|
||||
connect(m_ui->trackerDownButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionDown()));
|
||||
m_ui->horizontalLayout_trackers->insertWidget(0, trackerList);
|
||||
connect(trackerList->header(), SIGNAL(sectionMoved(int,int,int)), trackerList, SLOT(saveSettings()));
|
||||
connect(trackerList->header(), SIGNAL(sectionResized(int,int,int)), trackerList, SLOT(saveSettings()));
|
||||
connect(trackerList->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), trackerList, SLOT(saveSettings()));
|
||||
m_ui->trackerDownButton->setIconSize(Utils::Gui::smallIconSize());
|
||||
connect(m_ui->trackerUpButton, SIGNAL(clicked()), m_trackerList, SLOT(moveSelectionUp()));
|
||||
connect(m_ui->trackerDownButton, SIGNAL(clicked()), m_trackerList, SLOT(moveSelectionDown()));
|
||||
m_ui->horizontalLayout_trackers->insertWidget(0, m_trackerList);
|
||||
connect(m_trackerList->header(), SIGNAL(sectionMoved(int,int,int)), m_trackerList, SLOT(saveSettings()));
|
||||
connect(m_trackerList->header(), SIGNAL(sectionResized(int,int,int)), m_trackerList, SLOT(saveSettings()));
|
||||
connect(m_trackerList->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), m_trackerList, SLOT(saveSettings()));
|
||||
// Peers list
|
||||
peersList = new PeerListWidget(this);
|
||||
m_ui->peerpage_layout->addWidget(peersList);
|
||||
connect(peersList->header(), SIGNAL(sectionMoved(int,int,int)), peersList, SLOT(saveSettings()));
|
||||
connect(peersList->header(), SIGNAL(sectionResized(int,int,int)), peersList, SLOT(saveSettings()));
|
||||
connect(peersList->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), peersList, SLOT(saveSettings()));
|
||||
m_peerList = new PeerListWidget(this);
|
||||
m_ui->peerpage_layout->addWidget(m_peerList);
|
||||
connect(m_peerList->header(), SIGNAL(sectionMoved(int,int,int)), m_peerList, SLOT(saveSettings()));
|
||||
connect(m_peerList->header(), SIGNAL(sectionResized(int,int,int)), m_peerList, SLOT(saveSettings()));
|
||||
connect(m_peerList->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), m_peerList, SLOT(saveSettings()));
|
||||
// Speed widget
|
||||
speedWidget = new SpeedWidget(this);
|
||||
m_ui->speed_layout->addWidget(speedWidget);
|
||||
m_speedWidget = new SpeedWidget(this);
|
||||
m_ui->speedLayout->addWidget(m_speedWidget);
|
||||
// Tab bar
|
||||
m_tabBar = new PropTabBar();
|
||||
m_tabBar->setContentsMargins(0, 5, 0, 0);
|
||||
@@ -156,79 +160,79 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow *main_window, Tra
|
||||
connect(m_tabBar, SIGNAL(visibilityToggled(bool)), SLOT(setVisibility(bool)));
|
||||
connect(m_tabBar, SIGNAL(visibilityToggled(bool)), this, SLOT(saveSettings()));
|
||||
// Dynamic data refresher
|
||||
refreshTimer = new QTimer(this);
|
||||
connect(refreshTimer, SIGNAL(timeout()), this, SLOT(loadDynamicData()));
|
||||
refreshTimer->start(3000); // 3sec
|
||||
editHotkeyFile = new QShortcut(Qt::Key_F2, m_ui->filesList, 0, 0, Qt::WidgetShortcut);
|
||||
connect(editHotkeyFile, SIGNAL(activated()), SLOT(renameSelectedFile()));
|
||||
editHotkeyWeb = new QShortcut(Qt::Key_F2, m_ui->listWebSeeds, 0, 0, Qt::WidgetShortcut);
|
||||
connect(editHotkeyWeb, SIGNAL(activated()), SLOT(editWebSeed()));
|
||||
m_refreshTimer = new QTimer(this);
|
||||
connect(m_refreshTimer, SIGNAL(timeout()), this, SLOT(loadDynamicData()));
|
||||
m_refreshTimer->start(3000); // 3sec
|
||||
m_editHotkeyFile = new QShortcut(Qt::Key_F2, m_ui->filesList, 0, 0, Qt::WidgetShortcut);
|
||||
connect(m_editHotkeyFile, SIGNAL(activated()), SLOT(renameSelectedFile()));
|
||||
m_editHotkeyWeb = new QShortcut(Qt::Key_F2, m_ui->listWebSeeds, 0, 0, Qt::WidgetShortcut);
|
||||
connect(m_editHotkeyWeb, SIGNAL(activated()), SLOT(editWebSeed()));
|
||||
connect(m_ui->listWebSeeds, SIGNAL(doubleClicked(QModelIndex)), SLOT(editWebSeed()));
|
||||
deleteHotkeyWeb = new QShortcut(QKeySequence::Delete, m_ui->listWebSeeds, 0, 0, Qt::WidgetShortcut);
|
||||
connect(deleteHotkeyWeb, SIGNAL(activated()), SLOT(deleteSelectedUrlSeeds()));
|
||||
openHotkeyFile = new QShortcut(Qt::Key_Return, m_ui->filesList, 0, 0, Qt::WidgetShortcut);
|
||||
connect(openHotkeyFile, SIGNAL(activated()), SLOT(openSelectedFile()));
|
||||
m_deleteHotkeyWeb = new QShortcut(QKeySequence::Delete, m_ui->listWebSeeds, 0, 0, Qt::WidgetShortcut);
|
||||
connect(m_deleteHotkeyWeb, SIGNAL(activated()), SLOT(deleteSelectedUrlSeeds()));
|
||||
m_openHotkeyFile = new QShortcut(Qt::Key_Return, m_ui->filesList, 0, 0, Qt::WidgetShortcut);
|
||||
connect(m_openHotkeyFile, SIGNAL(activated()), SLOT(openSelectedFile()));
|
||||
}
|
||||
|
||||
PropertiesWidget::~PropertiesWidget()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "ENTER";
|
||||
delete refreshTimer;
|
||||
delete trackerList;
|
||||
delete peersList;
|
||||
delete speedWidget;
|
||||
delete downloaded_pieces;
|
||||
delete pieces_availability;
|
||||
delete PropListModel;
|
||||
delete PropDelegate;
|
||||
delete m_refreshTimer;
|
||||
delete m_trackerList;
|
||||
delete m_peerList;
|
||||
delete m_speedWidget;
|
||||
delete m_downloadedPieces;
|
||||
delete m_piecesAvailability;
|
||||
delete m_propListModel;
|
||||
delete m_propListDelegate;
|
||||
delete m_tabBar;
|
||||
delete editHotkeyFile;
|
||||
delete editHotkeyWeb;
|
||||
delete deleteHotkeyWeb;
|
||||
delete openHotkeyFile;
|
||||
delete m_editHotkeyFile;
|
||||
delete m_editHotkeyWeb;
|
||||
delete m_deleteHotkeyWeb;
|
||||
delete m_openHotkeyFile;
|
||||
delete m_ui;
|
||||
qDebug() << Q_FUNC_INFO << "EXIT";
|
||||
}
|
||||
|
||||
void PropertiesWidget::showPiecesAvailability(bool show)
|
||||
{
|
||||
m_ui->avail_pieces_lbl->setVisible(show);
|
||||
pieces_availability->setVisible(show);
|
||||
m_ui->avail_average_lbl->setVisible(show);
|
||||
if (show || !downloaded_pieces->isVisible())
|
||||
m_ui->line_2->setVisible(show);
|
||||
m_ui->labelPiecesAvailability->setVisible(show);
|
||||
m_piecesAvailability->setVisible(show);
|
||||
m_ui->labelAverageAvailabilityVal->setVisible(show);
|
||||
if (show || !m_downloadedPieces->isVisible())
|
||||
m_ui->lineBelowBars->setVisible(show);
|
||||
}
|
||||
|
||||
void PropertiesWidget::showPiecesDownloaded(bool show)
|
||||
{
|
||||
m_ui->downloaded_pieces_lbl->setVisible(show);
|
||||
downloaded_pieces->setVisible(show);
|
||||
m_ui->progress_lbl->setVisible(show);
|
||||
if (show || !pieces_availability->isVisible())
|
||||
m_ui->line_2->setVisible(show);
|
||||
m_ui->labelDownloadedPieces->setVisible(show);
|
||||
m_downloadedPieces->setVisible(show);
|
||||
m_ui->labelProgressVal->setVisible(show);
|
||||
if (show || !m_piecesAvailability->isVisible())
|
||||
m_ui->lineBelowBars->setVisible(show);
|
||||
}
|
||||
|
||||
void PropertiesWidget::setVisibility(bool visible)
|
||||
{
|
||||
if (!visible && (state == VISIBLE)) {
|
||||
if (!visible && (m_state == VISIBLE)) {
|
||||
QSplitter *hSplitter = static_cast<QSplitter *>(parentWidget());
|
||||
m_ui->stackedProperties->setVisible(false);
|
||||
slideSizes = hSplitter->sizes();
|
||||
m_slideSizes = hSplitter->sizes();
|
||||
hSplitter->handle(1)->setVisible(false);
|
||||
hSplitter->handle(1)->setDisabled(true);
|
||||
QList<int> sizes = QList<int>() << hSplitter->geometry().height() - 30 << 30;
|
||||
hSplitter->setSizes(sizes);
|
||||
state = REDUCED;
|
||||
m_state = REDUCED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (visible && (state == REDUCED)) {
|
||||
if (visible && (m_state == REDUCED)) {
|
||||
m_ui->stackedProperties->setVisible(true);
|
||||
QSplitter *hSplitter = static_cast<QSplitter *>(parentWidget());
|
||||
hSplitter->handle(1)->setDisabled(false);
|
||||
hSplitter->handle(1)->setVisible(true);
|
||||
hSplitter->setSizes(slideSizes);
|
||||
state = VISIBLE;
|
||||
hSplitter->setSizes(m_slideSizes);
|
||||
m_state = VISIBLE;
|
||||
// Force refresh
|
||||
loadDynamicData();
|
||||
}
|
||||
@@ -237,39 +241,39 @@ void PropertiesWidget::setVisibility(bool visible)
|
||||
void PropertiesWidget::clear()
|
||||
{
|
||||
qDebug("Clearing torrent properties");
|
||||
m_ui->save_path->clear();
|
||||
m_ui->lbl_creationDate->clear();
|
||||
m_ui->label_total_pieces_val->clear();
|
||||
m_ui->hash_lbl->clear();
|
||||
m_ui->comment_text->clear();
|
||||
m_ui->progress_lbl->clear();
|
||||
trackerList->clear();
|
||||
downloaded_pieces->clear();
|
||||
pieces_availability->clear();
|
||||
m_ui->avail_average_lbl->clear();
|
||||
m_ui->wasted->clear();
|
||||
m_ui->upTotal->clear();
|
||||
m_ui->dlTotal->clear();
|
||||
peersList->clear();
|
||||
m_ui->lbl_uplimit->clear();
|
||||
m_ui->lbl_dllimit->clear();
|
||||
m_ui->lbl_elapsed->clear();
|
||||
m_ui->lbl_connections->clear();
|
||||
m_ui->reannounce_lbl->clear();
|
||||
m_ui->shareRatio->clear();
|
||||
m_ui->labelSavePathVal->clear();
|
||||
m_ui->labelCreatedOnVal->clear();
|
||||
m_ui->labelTotalPiecesVal->clear();
|
||||
m_ui->labelHashVal->clear();
|
||||
m_ui->labelCommentVal->clear();
|
||||
m_ui->labelProgressVal->clear();
|
||||
m_ui->labelAverageAvailabilityVal->clear();
|
||||
m_ui->labelWastedVal->clear();
|
||||
m_ui->labelUpTotalVal->clear();
|
||||
m_ui->labelDlTotalVal->clear();
|
||||
m_ui->labelUpLimitVal->clear();
|
||||
m_ui->labelDlLimitVal->clear();
|
||||
m_ui->labelElapsedVal->clear();
|
||||
m_ui->labelConnectionsVal->clear();
|
||||
m_ui->labelReannounceInVal->clear();
|
||||
m_ui->labelShareRatioVal->clear();
|
||||
m_ui->listWebSeeds->clear();
|
||||
m_ui->labelETAVal->clear();
|
||||
m_ui->labelSeedsVal->clear();
|
||||
m_ui->labelPeersVal->clear();
|
||||
m_ui->labelDlSpeedVal->clear();
|
||||
m_ui->labelUpSpeedVal->clear();
|
||||
m_ui->labelTotalSizeVal->clear();
|
||||
m_ui->labelCompletedOnVal->clear();
|
||||
m_ui->labelLastSeenCompleteVal->clear();
|
||||
m_ui->labelCreatedByVal->clear();
|
||||
m_ui->labelAddedOnVal->clear();
|
||||
m_trackerList->clear();
|
||||
m_downloadedPieces->clear();
|
||||
m_piecesAvailability->clear();
|
||||
m_peerList->clear();
|
||||
m_contentFilterLine->clear();
|
||||
PropListModel->model()->clear();
|
||||
m_ui->label_eta_val->clear();
|
||||
m_ui->label_seeds_val->clear();
|
||||
m_ui->label_peers_val->clear();
|
||||
m_ui->label_dl_speed_val->clear();
|
||||
m_ui->label_upload_speed_val->clear();
|
||||
m_ui->label_total_size_val->clear();
|
||||
m_ui->label_completed_on_val->clear();
|
||||
m_ui->label_last_complete_val->clear();
|
||||
m_ui->label_created_by_val->clear();
|
||||
m_ui->label_added_on_val->clear();
|
||||
m_propListModel->model()->clear();
|
||||
}
|
||||
|
||||
BitTorrent::TorrentHandle *PropertiesWidget::getCurrentTorrent() const
|
||||
@@ -277,26 +281,41 @@ BitTorrent::TorrentHandle *PropertiesWidget::getCurrentTorrent() const
|
||||
return m_torrent;
|
||||
}
|
||||
|
||||
TrackerList *PropertiesWidget::getTrackerList() const
|
||||
{
|
||||
return m_trackerList;
|
||||
}
|
||||
|
||||
PeerListWidget *PropertiesWidget::getPeerList() const
|
||||
{
|
||||
return m_peerList;
|
||||
}
|
||||
|
||||
QTreeView *PropertiesWidget::getFilesList() const
|
||||
{
|
||||
return m_ui->filesList;
|
||||
}
|
||||
|
||||
SpeedWidget *PropertiesWidget::getSpeedWidget() const
|
||||
{
|
||||
return m_speedWidget;
|
||||
}
|
||||
|
||||
void PropertiesWidget::updateSavePath(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
if (m_torrent == torrent)
|
||||
m_ui->save_path->setText(Utils::Fs::toNativePath(m_torrent->savePath()));
|
||||
if (torrent == m_torrent)
|
||||
m_ui->labelSavePathVal->setText(Utils::Fs::toNativePath(m_torrent->savePath()));
|
||||
}
|
||||
|
||||
void PropertiesWidget::loadTrackers(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
if (torrent == m_torrent)
|
||||
trackerList->loadTrackers();
|
||||
m_trackerList->loadTrackers();
|
||||
}
|
||||
|
||||
void PropertiesWidget::updateTorrentInfos(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
if (m_torrent == torrent)
|
||||
if (torrent == m_torrent)
|
||||
loadTorrentInfos(m_torrent);
|
||||
}
|
||||
|
||||
@@ -304,36 +323,36 @@ void PropertiesWidget::loadTorrentInfos(BitTorrent::TorrentHandle *const torrent
|
||||
{
|
||||
clear();
|
||||
m_torrent = torrent;
|
||||
downloaded_pieces->setTorrent(m_torrent);
|
||||
pieces_availability->setTorrent(m_torrent);
|
||||
m_downloadedPieces->setTorrent(m_torrent);
|
||||
m_piecesAvailability->setTorrent(m_torrent);
|
||||
if (!m_torrent) return;
|
||||
|
||||
// Save path
|
||||
updateSavePath(m_torrent);
|
||||
// Hash
|
||||
m_ui->hash_lbl->setText(m_torrent->hash());
|
||||
PropListModel->model()->clear();
|
||||
m_ui->labelHashVal->setText(m_torrent->hash());
|
||||
m_propListModel->model()->clear();
|
||||
if (m_torrent->hasMetadata()) {
|
||||
// Creation date
|
||||
m_ui->lbl_creationDate->setText(m_torrent->creationDate().toString(Qt::DefaultLocaleShortDate));
|
||||
m_ui->labelCreatedOnVal->setText(m_torrent->creationDate().toString(Qt::DefaultLocaleShortDate));
|
||||
|
||||
m_ui->label_total_size_val->setText(Utils::Misc::friendlyUnit(m_torrent->totalSize()));
|
||||
m_ui->labelTotalSizeVal->setText(Utils::Misc::friendlyUnit(m_torrent->totalSize()));
|
||||
|
||||
// Comment
|
||||
m_ui->comment_text->setText(Utils::Misc::parseHtmlLinks(m_torrent->comment().toHtmlEscaped()));
|
||||
m_ui->labelCommentVal->setText(Utils::Misc::parseHtmlLinks(m_torrent->comment().toHtmlEscaped()));
|
||||
|
||||
// URL seeds
|
||||
loadUrlSeeds();
|
||||
|
||||
m_ui->label_created_by_val->setText(m_torrent->creator().toHtmlEscaped());
|
||||
m_ui->labelCreatedByVal->setText(m_torrent->creator().toHtmlEscaped());
|
||||
|
||||
// List files in torrent
|
||||
PropListModel->model()->setupModelData(m_torrent->info());
|
||||
if (PropListModel->model()->rowCount() == 1)
|
||||
m_ui->filesList->setExpanded(PropListModel->index(0, 0), true);
|
||||
m_propListModel->model()->setupModelData(m_torrent->info());
|
||||
if (m_propListModel->model()->rowCount() == 1)
|
||||
m_ui->filesList->setExpanded(m_propListModel->index(0, 0), true);
|
||||
|
||||
// Load file priorities
|
||||
PropListModel->model()->updateFilesPriorities(m_torrent->filePriorities());
|
||||
m_propListModel->model()->updateFilesPriorities(m_torrent->filePriorities());
|
||||
}
|
||||
// Load dynamic data
|
||||
loadDynamicData();
|
||||
@@ -343,18 +362,16 @@ void PropertiesWidget::readSettings()
|
||||
{
|
||||
const Preferences *const pref = Preferences::instance();
|
||||
// Restore splitter sizes
|
||||
QStringList sizes_str = pref->getPropSplitterSizes().split(",");
|
||||
if (sizes_str.size() == 2) {
|
||||
slideSizes << sizes_str.first().toInt();
|
||||
slideSizes << sizes_str.last().toInt();
|
||||
QStringList sizesStr = pref->getPropSplitterSizes().split(",");
|
||||
if (sizesStr.size() == 2) {
|
||||
m_slideSizes << sizesStr.first().toInt();
|
||||
m_slideSizes << sizesStr.last().toInt();
|
||||
QSplitter *hSplitter = static_cast<QSplitter *>(parentWidget());
|
||||
hSplitter->setSizes(slideSizes);
|
||||
hSplitter->setSizes(m_slideSizes);
|
||||
}
|
||||
const int current_tab = pref->getPropCurTab();
|
||||
const bool visible = pref->getPropVisible();
|
||||
// the following will call saveSettings but shouldn't change any state
|
||||
if (!m_ui->filesList->header()->restoreState(pref->getPropFileListState()))
|
||||
m_ui->filesList->header()->resizeSection(0, 400); // Default
|
||||
m_ui->filesList->header()->restoreState(pref->getPropFileListState());
|
||||
m_tabBar->setCurrentIndex(current_tab);
|
||||
if (!visible)
|
||||
setVisibility(false);
|
||||
@@ -363,14 +380,14 @@ void PropertiesWidget::readSettings()
|
||||
void PropertiesWidget::saveSettings()
|
||||
{
|
||||
Preferences *const pref = Preferences::instance();
|
||||
pref->setPropVisible(state == VISIBLE);
|
||||
pref->setPropVisible(m_state == VISIBLE);
|
||||
// Splitter sizes
|
||||
QSplitter *hSplitter = static_cast<QSplitter *>(parentWidget());
|
||||
QList<int> sizes;
|
||||
if (state == VISIBLE)
|
||||
if (m_state == VISIBLE)
|
||||
sizes = hSplitter->sizes();
|
||||
else
|
||||
sizes = slideSizes;
|
||||
sizes = m_slideSizes;
|
||||
qDebug("Sizes: %d", sizes.size());
|
||||
if (sizes.size() == 2)
|
||||
pref->setPropSplitterSizes(QString::number(sizes.first()) + ',' + QString::number(sizes.last()));
|
||||
@@ -382,118 +399,112 @@ void PropertiesWidget::saveSettings()
|
||||
void PropertiesWidget::reloadPreferences()
|
||||
{
|
||||
// Take program preferences into consideration
|
||||
peersList->updatePeerHostNameResolutionState();
|
||||
peersList->updatePeerCountryResolutionState();
|
||||
m_peerList->updatePeerHostNameResolutionState();
|
||||
m_peerList->updatePeerCountryResolutionState();
|
||||
}
|
||||
|
||||
void PropertiesWidget::loadDynamicData()
|
||||
{
|
||||
// Refresh only if the torrent handle is valid and if visible
|
||||
if (!m_torrent || (main_window->currentTabWidget() != transferList) || (state != VISIBLE)) return;
|
||||
// Refresh only if the torrent handle is valid and visible
|
||||
if (!m_torrent || (m_mainWindow->currentTabWidget() != m_transferList) || (m_state != VISIBLE)) return;
|
||||
|
||||
// Transfer infos
|
||||
switch (m_ui->stackedProperties->currentIndex()) {
|
||||
case PropTabBar::MAIN_TAB: {
|
||||
m_ui->wasted->setText(Utils::Misc::friendlyUnit(m_torrent->wastedSize()));
|
||||
case PropTabBar::MainTab: {
|
||||
m_ui->labelWastedVal->setText(Utils::Misc::friendlyUnit(m_torrent->wastedSize()));
|
||||
|
||||
m_ui->upTotal->setText(tr("%1 (%2 this session)").arg(Utils::Misc::friendlyUnit(m_torrent->totalUpload()))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalPayloadUpload())));
|
||||
m_ui->labelUpTotalVal->setText(tr("%1 (%2 this session)").arg(Utils::Misc::friendlyUnit(m_torrent->totalUpload()))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalPayloadUpload())));
|
||||
|
||||
m_ui->dlTotal->setText(tr("%1 (%2 this session)").arg(Utils::Misc::friendlyUnit(m_torrent->totalDownload()))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalPayloadDownload())));
|
||||
m_ui->labelDlTotalVal->setText(tr("%1 (%2 this session)").arg(Utils::Misc::friendlyUnit(m_torrent->totalDownload()))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalPayloadDownload())));
|
||||
|
||||
m_ui->lbl_uplimit->setText(m_torrent->uploadLimit() <= 0 ? QString::fromUtf8(C_INFINITY) : Utils::Misc::friendlyUnit(m_torrent->uploadLimit(), true));
|
||||
m_ui->labelUpLimitVal->setText(m_torrent->uploadLimit() <= 0 ? QString::fromUtf8(C_INFINITY) : Utils::Misc::friendlyUnit(m_torrent->uploadLimit(), true));
|
||||
|
||||
m_ui->lbl_dllimit->setText(m_torrent->downloadLimit() <= 0 ? QString::fromUtf8(C_INFINITY) : Utils::Misc::friendlyUnit(m_torrent->downloadLimit(), true));
|
||||
m_ui->labelDlLimitVal->setText(m_torrent->downloadLimit() <= 0 ? QString::fromUtf8(C_INFINITY) : Utils::Misc::friendlyUnit(m_torrent->downloadLimit(), true));
|
||||
|
||||
QString elapsed_txt;
|
||||
if (m_torrent->isSeed())
|
||||
elapsed_txt = tr("%1 (seeded for %2)", "e.g. 4m39s (seeded for 3m10s)")
|
||||
.arg(Utils::Misc::userFriendlyDuration(m_torrent->activeTime()))
|
||||
.arg(Utils::Misc::userFriendlyDuration(m_torrent->seedingTime()));
|
||||
else
|
||||
elapsed_txt = Utils::Misc::userFriendlyDuration(m_torrent->activeTime());
|
||||
m_ui->lbl_elapsed->setText(elapsed_txt);
|
||||
QString elapsedString;
|
||||
if (m_torrent->isSeed())
|
||||
elapsedString = tr("%1 (seeded for %2)", "e.g. 4m39s (seeded for 3m10s)")
|
||||
.arg(Utils::Misc::userFriendlyDuration(m_torrent->activeTime()))
|
||||
.arg(Utils::Misc::userFriendlyDuration(m_torrent->seedingTime()));
|
||||
else
|
||||
elapsedString = Utils::Misc::userFriendlyDuration(m_torrent->activeTime());
|
||||
m_ui->labelElapsedVal->setText(elapsedString);
|
||||
|
||||
m_ui->lbl_connections->setText(tr("%1 (%2 max)", "%1 and %2 are numbers, e.g. 3 (10 max)")
|
||||
.arg(m_torrent->connectionsCount())
|
||||
.arg(m_torrent->connectionsLimit() < 0 ? QString::fromUtf8(C_INFINITY) : QString::number(m_torrent->connectionsLimit())));
|
||||
m_ui->labelConnectionsVal->setText(tr("%1 (%2 max)", "%1 and %2 are numbers, e.g. 3 (10 max)")
|
||||
.arg(m_torrent->connectionsCount())
|
||||
.arg(m_torrent->connectionsLimit() < 0 ? QString::fromUtf8(C_INFINITY) : QString::number(m_torrent->connectionsLimit())));
|
||||
|
||||
m_ui->label_eta_val->setText(Utils::Misc::userFriendlyDuration(m_torrent->eta()));
|
||||
m_ui->labelETAVal->setText(Utils::Misc::userFriendlyDuration(m_torrent->eta()));
|
||||
|
||||
// Update next announce time
|
||||
m_ui->reannounce_lbl->setText(Utils::Misc::userFriendlyDuration(m_torrent->nextAnnounce()));
|
||||
// Update next announce time
|
||||
m_ui->labelReannounceInVal->setText(Utils::Misc::userFriendlyDuration(m_torrent->nextAnnounce()));
|
||||
|
||||
// Update ratio info
|
||||
const qreal ratio = m_torrent->realRatio();
|
||||
m_ui->shareRatio->setText(ratio > BitTorrent::TorrentHandle::MAX_RATIO ? QString::fromUtf8(C_INFINITY) : Utils::String::fromDouble(ratio, 2));
|
||||
// Update ratio info
|
||||
const qreal ratio = m_torrent->realRatio();
|
||||
m_ui->labelShareRatioVal->setText(ratio > BitTorrent::TorrentHandle::MAX_RATIO ? QString::fromUtf8(C_INFINITY) : Utils::String::fromDouble(ratio, 2));
|
||||
|
||||
m_ui->label_seeds_val->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)")
|
||||
.arg(QString::number(m_torrent->seedsCount()))
|
||||
.arg(QString::number(m_torrent->totalSeedsCount())));
|
||||
m_ui->labelSeedsVal->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)")
|
||||
.arg(QString::number(m_torrent->seedsCount()))
|
||||
.arg(QString::number(m_torrent->totalSeedsCount())));
|
||||
|
||||
m_ui->label_peers_val->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)")
|
||||
.arg(QString::number(m_torrent->leechsCount()))
|
||||
.arg(QString::number(m_torrent->totalLeechersCount())));
|
||||
m_ui->labelPeersVal->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)")
|
||||
.arg(QString::number(m_torrent->leechsCount()))
|
||||
.arg(QString::number(m_torrent->totalLeechersCount())));
|
||||
|
||||
m_ui->label_dl_speed_val->setText(tr("%1 (%2 avg.)", "%1 and %2 are speed rates, e.g. 200KiB/s (100KiB/s avg.)")
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->downloadPayloadRate(), true))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalDownload() / (1 + m_torrent->activeTime() - m_torrent->finishedTime()), true)));
|
||||
m_ui->labelDlSpeedVal->setText(tr("%1 (%2 avg.)", "%1 and %2 are speed rates, e.g. 200KiB/s (100KiB/s avg.)")
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->downloadPayloadRate(), true))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalDownload() / (1 + m_torrent->activeTime() - m_torrent->finishedTime()), true)));
|
||||
|
||||
m_ui->label_upload_speed_val->setText(tr("%1 (%2 avg.)", "%1 and %2 are speed rates, e.g. 200KiB/s (100KiB/s avg.)")
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->uploadPayloadRate(), true))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalUpload() / (1 + m_torrent->activeTime()), true)));
|
||||
m_ui->labelUpSpeedVal->setText(tr("%1 (%2 avg.)", "%1 and %2 are speed rates, e.g. 200KiB/s (100KiB/s avg.)")
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->uploadPayloadRate(), true))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalUpload() / (1 + m_torrent->activeTime()), true)));
|
||||
|
||||
m_ui->label_last_complete_val->setText(m_torrent->lastSeenComplete().isValid() ? m_torrent->lastSeenComplete().toString(Qt::DefaultLocaleShortDate) : tr("Never"));
|
||||
m_ui->labelLastSeenCompleteVal->setText(m_torrent->lastSeenComplete().isValid() ? m_torrent->lastSeenComplete().toString(Qt::DefaultLocaleShortDate) : tr("Never"));
|
||||
|
||||
m_ui->label_completed_on_val->setText(m_torrent->completedTime().isValid() ? m_torrent->completedTime().toString(Qt::DefaultLocaleShortDate) : "");
|
||||
m_ui->labelCompletedOnVal->setText(m_torrent->completedTime().isValid() ? m_torrent->completedTime().toString(Qt::DefaultLocaleShortDate) : "");
|
||||
|
||||
m_ui->label_added_on_val->setText(m_torrent->addedTime().toString(Qt::DefaultLocaleShortDate));
|
||||
m_ui->labelAddedOnVal->setText(m_torrent->addedTime().toString(Qt::DefaultLocaleShortDate));
|
||||
|
||||
if (m_torrent->hasMetadata()) {
|
||||
m_ui->label_total_pieces_val->setText(tr("%1 x %2 (have %3)", "(torrent pieces) eg 152 x 4MB (have 25)").arg(m_torrent->piecesCount()).arg(Utils::Misc::friendlyUnit(m_torrent->pieceLength())).arg(m_torrent->piecesHave()));
|
||||
if (m_torrent->hasMetadata()) {
|
||||
m_ui->labelTotalPiecesVal->setText(tr("%1 x %2 (have %3)", "(torrent pieces) eg 152 x 4MB (have 25)").arg(m_torrent->piecesCount()).arg(Utils::Misc::friendlyUnit(m_torrent->pieceLength())).arg(m_torrent->piecesHave()));
|
||||
|
||||
if (!m_torrent->isSeed() && !m_torrent->isPaused() && !m_torrent->isQueued() && !m_torrent->isChecking()) {
|
||||
// Pieces availability
|
||||
showPiecesAvailability(true);
|
||||
pieces_availability->setAvailability(m_torrent->pieceAvailability());
|
||||
m_ui->avail_average_lbl->setText(Utils::String::fromDouble(m_torrent->distributedCopies(), 3));
|
||||
if (!m_torrent->isSeed() && !m_torrent->isPaused() && !m_torrent->isQueued() && !m_torrent->isChecking()) {
|
||||
// Pieces availability
|
||||
showPiecesAvailability(true);
|
||||
m_piecesAvailability->setAvailability(m_torrent->pieceAvailability());
|
||||
m_ui->labelAverageAvailabilityVal->setText(Utils::String::fromDouble(m_torrent->distributedCopies(), 3));
|
||||
}
|
||||
else {
|
||||
showPiecesAvailability(false);
|
||||
}
|
||||
|
||||
// Progress
|
||||
qreal progress = m_torrent->progress() * 100.;
|
||||
m_ui->labelProgressVal->setText(Utils::String::fromDouble(progress, 1) + "%");
|
||||
m_downloadedPieces->setProgress(m_torrent->pieces(), m_torrent->downloadingPieces());
|
||||
}
|
||||
else {
|
||||
showPiecesAvailability(false);
|
||||
}
|
||||
|
||||
// Progress
|
||||
qreal progress = m_torrent->progress() * 100.;
|
||||
m_ui->progress_lbl->setText(Utils::String::fromDouble(progress, 1) + "%");
|
||||
downloaded_pieces->setProgress(m_torrent->pieces(), m_torrent->downloadingPieces());
|
||||
}
|
||||
else {
|
||||
showPiecesAvailability(false);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PropTabBar::TRACKERS_TAB: {
|
||||
case PropTabBar::TrackersTab:
|
||||
// Trackers
|
||||
trackerList->loadTrackers();
|
||||
m_trackerList->loadTrackers();
|
||||
break;
|
||||
}
|
||||
|
||||
case PropTabBar::PEERS_TAB: {
|
||||
case PropTabBar::PeersTab:
|
||||
// Load peers
|
||||
peersList->loadPeers(m_torrent);
|
||||
m_peerList->loadPeers(m_torrent);
|
||||
break;
|
||||
}
|
||||
|
||||
case PropTabBar::FILES_TAB: {
|
||||
case PropTabBar::FilesTab:
|
||||
// Files progress
|
||||
if (m_torrent->hasMetadata()) {
|
||||
qDebug("Updating priorities in files tab");
|
||||
m_ui->filesList->setUpdatesEnabled(false);
|
||||
PropListModel->model()->updateFilesProgress(m_torrent->filesProgress());
|
||||
PropListModel->model()->updateFilesAvailability(m_torrent->availableFileFractions());
|
||||
m_propListModel->model()->updateFilesProgress(m_torrent->filesProgress());
|
||||
m_propListModel->model()->updateFilesAvailability(m_torrent->availableFileFractions());
|
||||
// XXX: We don't update file priorities regularly for performance
|
||||
// reasons. This means that priorities will not be updated if
|
||||
// set from the Web UI.
|
||||
@@ -501,8 +512,6 @@ void PropertiesWidget::loadDynamicData()
|
||||
m_ui->filesList->setUpdatesEnabled(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:;
|
||||
}
|
||||
}
|
||||
@@ -511,19 +520,19 @@ void PropertiesWidget::loadUrlSeeds()
|
||||
{
|
||||
m_ui->listWebSeeds->clear();
|
||||
qDebug("Loading URL seeds");
|
||||
const QList<QUrl> hc_seeds = m_torrent->urlSeeds();
|
||||
const QList<QUrl> hcSeeds = m_torrent->urlSeeds();
|
||||
// Add url seeds
|
||||
foreach (const QUrl &hc_seed, hc_seeds) {
|
||||
qDebug("Loading URL seed: %s", qUtf8Printable(hc_seed.toString()));
|
||||
new QListWidgetItem(hc_seed.toString(), m_ui->listWebSeeds);
|
||||
foreach (const QUrl &hcSeed, hcSeeds) {
|
||||
qDebug("Loading URL seed: %s", qUtf8Printable(hcSeed.toString()));
|
||||
new QListWidgetItem(hcSeed.toString(), m_ui->listWebSeeds);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::openDoubleClickedFile(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid()) return;
|
||||
if (!m_torrent || !m_torrent->hasMetadata()) return;
|
||||
if (PropListModel->itemType(index) == TorrentContentModelItem::FileType)
|
||||
if (!index.isValid() || !m_torrent || !m_torrent->hasMetadata()) return;
|
||||
|
||||
if (m_propListModel->itemType(index) == TorrentContentModelItem::FileType)
|
||||
openFile(index);
|
||||
else
|
||||
openFolder(index, false);
|
||||
@@ -531,48 +540,52 @@ void PropertiesWidget::openDoubleClickedFile(const QModelIndex &index)
|
||||
|
||||
void PropertiesWidget::openFile(const QModelIndex &index)
|
||||
{
|
||||
int i = PropListModel->getFileIndex(index);
|
||||
int i = m_propListModel->getFileIndex(index);
|
||||
const QDir saveDir(m_torrent->savePath(true));
|
||||
const QString filename = m_torrent->filePath(i);
|
||||
const QString file_path = Utils::Fs::expandPath(saveDir.absoluteFilePath(filename));
|
||||
qDebug("Trying to open file at %s", qUtf8Printable(file_path));
|
||||
const QString filePath = Utils::Fs::expandPath(saveDir.absoluteFilePath(filename));
|
||||
qDebug("Trying to open file at %s", qUtf8Printable(filePath));
|
||||
// Flush data
|
||||
m_torrent->flushCache();
|
||||
Utils::Misc::openPath(file_path);
|
||||
Utils::Misc::openPath(filePath);
|
||||
}
|
||||
|
||||
void PropertiesWidget::openFolder(const QModelIndex &index, bool containing_folder)
|
||||
void PropertiesWidget::openFolder(const QModelIndex &index, bool containingFolder)
|
||||
{
|
||||
QString absolute_path;
|
||||
QString absolutePath;
|
||||
// FOLDER
|
||||
if (PropListModel->itemType(index) == TorrentContentModelItem::FolderType) {
|
||||
if (m_propListModel->itemType(index) == TorrentContentModelItem::FolderType) {
|
||||
// Generate relative path to selected folder
|
||||
QStringList path_items;
|
||||
path_items << index.data().toString();
|
||||
QModelIndex parent = PropListModel->parent(index);
|
||||
QStringList pathItems;
|
||||
pathItems << index.data().toString();
|
||||
QModelIndex parent = m_propListModel->parent(index);
|
||||
while (parent.isValid()) {
|
||||
path_items.prepend(parent.data().toString());
|
||||
parent = PropListModel->parent(parent);
|
||||
pathItems.prepend(parent.data().toString());
|
||||
parent = m_propListModel->parent(parent);
|
||||
}
|
||||
if (path_items.isEmpty())
|
||||
if (pathItems.isEmpty())
|
||||
return;
|
||||
const QDir saveDir(m_torrent->savePath(true));
|
||||
const QString relative_path = path_items.join("/");
|
||||
absolute_path = Utils::Fs::expandPath(saveDir.absoluteFilePath(relative_path));
|
||||
const QString relativePath = pathItems.join("/");
|
||||
absolutePath = Utils::Fs::expandPath(saveDir.absoluteFilePath(relativePath));
|
||||
}
|
||||
else {
|
||||
int i = PropListModel->getFileIndex(index);
|
||||
int i = m_propListModel->getFileIndex(index);
|
||||
const QDir saveDir(m_torrent->savePath(true));
|
||||
const QString relative_path = m_torrent->filePath(i);
|
||||
absolute_path = Utils::Fs::expandPath(saveDir.absoluteFilePath(relative_path));
|
||||
const QString relativePath = m_torrent->filePath(i);
|
||||
absolutePath = Utils::Fs::expandPath(saveDir.absoluteFilePath(relativePath));
|
||||
}
|
||||
|
||||
// Flush data
|
||||
m_torrent->flushCache();
|
||||
if (containing_folder)
|
||||
Utils::Misc::openFolderSelect(absolute_path);
|
||||
#ifdef Q_OS_MAC
|
||||
MacUtils::openFiles(QSet<QString>{absolutePath});
|
||||
#else
|
||||
if (containingFolder)
|
||||
Utils::Misc::openFolderSelect(absolutePath);
|
||||
else
|
||||
Utils::Misc::openPath(absolute_path);
|
||||
Utils::Misc::openPath(absolutePath);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PropertiesWidget::displayFilesListMenu(const QPoint &)
|
||||
@@ -580,8 +593,8 @@ void PropertiesWidget::displayFilesListMenu(const QPoint &)
|
||||
if (!m_torrent) return;
|
||||
|
||||
QModelIndexList selectedRows = m_ui->filesList->selectionModel()->selectedRows(0);
|
||||
if (selectedRows.empty())
|
||||
return;
|
||||
if (selectedRows.empty()) return;
|
||||
|
||||
QMenu myFilesLlistMenu;
|
||||
QAction *actOpen = nullptr;
|
||||
QAction *actOpenContainingFolder = nullptr;
|
||||
@@ -606,35 +619,33 @@ void PropertiesWidget::displayFilesListMenu(const QPoint &)
|
||||
// The selected torrent might have disappeared during exec()
|
||||
// from the current view thus leaving invalid indices.
|
||||
const QModelIndex index = *(selectedRows.begin());
|
||||
if (!index.isValid())
|
||||
return;
|
||||
if (act) {
|
||||
if (act == actOpen) {
|
||||
openDoubleClickedFile(index);
|
||||
}
|
||||
else if (act == actOpenContainingFolder) {
|
||||
openFolder(index, true);
|
||||
}
|
||||
else if (act == actRename) {
|
||||
renameSelectedFile();
|
||||
}
|
||||
else {
|
||||
int prio = prio::NORMAL;
|
||||
if (act == m_ui->actionHigh)
|
||||
prio = prio::HIGH;
|
||||
else if (act == m_ui->actionMaximum)
|
||||
prio = prio::MAXIMUM;
|
||||
else if (act == m_ui->actionNot_downloaded)
|
||||
prio = prio::IGNORED;
|
||||
if (!index.isValid() || !act) return;
|
||||
|
||||
qDebug("Setting files priority");
|
||||
foreach (QModelIndex index, selectedRows) {
|
||||
qDebug("Setting priority(%d) for file at row %d", prio, index.row());
|
||||
PropListModel->setData(PropListModel->index(index.row(), PRIORITY, index.parent()), prio);
|
||||
}
|
||||
// Save changes
|
||||
filteredFilesChanged();
|
||||
if (act == actOpen) {
|
||||
openDoubleClickedFile(index);
|
||||
}
|
||||
else if (act == actOpenContainingFolder) {
|
||||
openFolder(index, true);
|
||||
}
|
||||
else if (act == actRename) {
|
||||
renameSelectedFile();
|
||||
}
|
||||
else {
|
||||
int prio = prio::NORMAL;
|
||||
if (act == m_ui->actionHigh)
|
||||
prio = prio::HIGH;
|
||||
else if (act == m_ui->actionMaximum)
|
||||
prio = prio::MAXIMUM;
|
||||
else if (act == m_ui->actionNot_downloaded)
|
||||
prio = prio::IGNORED;
|
||||
|
||||
qDebug("Setting files priority");
|
||||
foreach (QModelIndex index, selectedRows) {
|
||||
qDebug("Setting priority(%d) for file at row %d", prio, index.row());
|
||||
m_propListModel->setData(m_propListModel->index(index.row(), PRIORITY, index.parent()), prio);
|
||||
}
|
||||
// Save changes
|
||||
filteredFilesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -657,16 +668,16 @@ void PropertiesWidget::displayWebSeedListMenu(const QPoint &)
|
||||
}
|
||||
|
||||
const QAction *act = seedMenu.exec(QCursor::pos());
|
||||
if (act) {
|
||||
if (act == actAdd)
|
||||
askWebSeed();
|
||||
else if (act == actDel)
|
||||
deleteSelectedUrlSeeds();
|
||||
else if (act == actCpy)
|
||||
copySelectedWebSeedsToClipboard();
|
||||
else if (act == actEdit)
|
||||
editWebSeed();
|
||||
}
|
||||
if (!act) return;
|
||||
|
||||
if (act == actAdd)
|
||||
askWebSeed();
|
||||
else if (act == actDel)
|
||||
deleteSelectedUrlSeeds();
|
||||
else if (act == actCpy)
|
||||
copySelectedWebSeedsToClipboard();
|
||||
else if (act == actEdit)
|
||||
editWebSeed();
|
||||
}
|
||||
|
||||
void PropertiesWidget::renameSelectedFile()
|
||||
@@ -692,9 +703,9 @@ void PropertiesWidget::renameSelectedFile()
|
||||
return;
|
||||
}
|
||||
|
||||
if (PropListModel->itemType(modelIndex) == TorrentContentModelItem::FileType) {
|
||||
if (m_propListModel->itemType(modelIndex) == TorrentContentModelItem::FileType) {
|
||||
// renaming a file
|
||||
const int fileIndex = PropListModel->getFileIndex(modelIndex);
|
||||
const int fileIndex = m_propListModel->getFileIndex(modelIndex);
|
||||
|
||||
if (newName.endsWith(QB_EXT))
|
||||
newName.chop(QB_EXT.size());
|
||||
@@ -722,16 +733,16 @@ void PropertiesWidget::renameSelectedFile()
|
||||
qDebug("Renaming %s to %s", qUtf8Printable(oldFilePath), qUtf8Printable(newFilePath));
|
||||
m_torrent->renameFile(fileIndex, newFilePath);
|
||||
|
||||
PropListModel->setData(modelIndex, newName);
|
||||
m_propListModel->setData(modelIndex, newName);
|
||||
}
|
||||
else {
|
||||
// renaming a folder
|
||||
QStringList pathItems;
|
||||
pathItems << modelIndex.data().toString();
|
||||
QModelIndex parent = PropListModel->parent(modelIndex);
|
||||
QModelIndex parent = m_propListModel->parent(modelIndex);
|
||||
while (parent.isValid()) {
|
||||
pathItems.prepend(parent.data().toString());
|
||||
parent = PropListModel->parent(parent);
|
||||
parent = m_propListModel->parent(parent);
|
||||
}
|
||||
const QString oldPath = pathItems.join("/");
|
||||
pathItems.removeLast();
|
||||
@@ -773,7 +784,7 @@ void PropertiesWidget::renameSelectedFile()
|
||||
// Force recheck
|
||||
if (forceRecheck) m_torrent->forceRecheck();
|
||||
// Rename folder in torrent files model too
|
||||
PropListModel->setData(modelIndex, newName);
|
||||
m_propListModel->setData(modelIndex, newName);
|
||||
// Remove old folder
|
||||
const QDir oldFolder(m_torrent->savePath(true) + "/" + oldPath);
|
||||
int timeout = 10;
|
||||
@@ -830,52 +841,48 @@ void PropertiesWidget::deleteSelectedUrlSeeds()
|
||||
|
||||
void PropertiesWidget::copySelectedWebSeedsToClipboard() const
|
||||
{
|
||||
const QList<QListWidgetItem *> selected_items = m_ui->listWebSeeds->selectedItems();
|
||||
if (selected_items.isEmpty())
|
||||
return;
|
||||
const QList<QListWidgetItem *> selectedItems = m_ui->listWebSeeds->selectedItems();
|
||||
if (selectedItems.isEmpty()) return;
|
||||
|
||||
QStringList urls_to_copy;
|
||||
foreach (QListWidgetItem *item, selected_items)
|
||||
urls_to_copy << item->text();
|
||||
QStringList urlsToCopy;
|
||||
foreach (QListWidgetItem *item, selectedItems)
|
||||
urlsToCopy << item->text();
|
||||
|
||||
QApplication::clipboard()->setText(urls_to_copy.join("\n"));
|
||||
QApplication::clipboard()->setText(urlsToCopy.join("\n"));
|
||||
}
|
||||
|
||||
void PropertiesWidget::editWebSeed()
|
||||
{
|
||||
const QList<QListWidgetItem *> selected_items = m_ui->listWebSeeds->selectedItems();
|
||||
if (selected_items.size() != 1)
|
||||
return;
|
||||
const QList<QListWidgetItem *> selectedItems = m_ui->listWebSeeds->selectedItems();
|
||||
if (selectedItems.size() != 1) return;
|
||||
|
||||
const QListWidgetItem *selected_item = selected_items.last();
|
||||
const QString old_seed = selected_item->text();
|
||||
const QListWidgetItem *selectedItem = selectedItems.last();
|
||||
const QString oldSeed = selectedItem->text();
|
||||
bool result;
|
||||
const QString new_seed = AutoExpandableDialog::getText(this, tr("Web seed editing"),
|
||||
const QString newSeed = AutoExpandableDialog::getText(this, tr("Web seed editing"),
|
||||
tr("Web seed URL:"), QLineEdit::Normal,
|
||||
old_seed, &result);
|
||||
if (!result)
|
||||
return;
|
||||
oldSeed, &result);
|
||||
if (!result) return;
|
||||
|
||||
if (!m_ui->listWebSeeds->findItems(new_seed, Qt::MatchFixedString).empty()) {
|
||||
if (!m_ui->listWebSeeds->findItems(newSeed, Qt::MatchFixedString).empty()) {
|
||||
QMessageBox::warning(this, tr("qBittorrent"),
|
||||
tr("This URL seed is already in the list."),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
m_torrent->removeUrlSeeds(QList<QUrl>() << old_seed);
|
||||
m_torrent->addUrlSeeds(QList<QUrl>() << new_seed);
|
||||
m_torrent->removeUrlSeeds(QList<QUrl>() << oldSeed);
|
||||
m_torrent->addUrlSeeds(QList<QUrl>() << newSeed);
|
||||
loadUrlSeeds();
|
||||
}
|
||||
|
||||
bool PropertiesWidget::applyPriorities()
|
||||
void PropertiesWidget::applyPriorities()
|
||||
{
|
||||
qDebug("Saving files priorities");
|
||||
const QVector<int> priorities = PropListModel->model()->getFilePriorities();
|
||||
const QVector<int> priorities = m_propListModel->model()->getFilePriorities();
|
||||
// Prioritize the files
|
||||
qDebug("prioritize files: %d", priorities[0]);
|
||||
m_torrent->prioritizeFiles(priorities);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PropertiesWidget::filteredFilesChanged()
|
||||
@@ -886,10 +893,10 @@ void PropertiesWidget::filteredFilesChanged()
|
||||
|
||||
void PropertiesWidget::filterText(const QString &filter)
|
||||
{
|
||||
PropListModel->setFilterRegExp(QRegExp(filter, Qt::CaseInsensitive, QRegExp::WildcardUnix));
|
||||
m_propListModel->setFilterRegExp(QRegExp(filter, Qt::CaseInsensitive, QRegExp::WildcardUnix));
|
||||
if (filter.isEmpty()) {
|
||||
m_ui->filesList->collapseAll();
|
||||
m_ui->filesList->expand(PropListModel->index(0, 0));
|
||||
m_ui->filesList->expand(m_propListModel->index(0, 0));
|
||||
}
|
||||
else {
|
||||
m_ui->filesList->expandAll();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,8 +24,6 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef PROPERTIESWIDGET_H
|
||||
@@ -36,32 +34,30 @@
|
||||
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
|
||||
class TransferListWidget;
|
||||
class TorrentContentFilterModel;
|
||||
class PropListDelegate;
|
||||
class torrent_file;
|
||||
class PeerListWidget;
|
||||
class TrackerList;
|
||||
class SpeedWidget;
|
||||
class MainWindow;
|
||||
class DownloadedPiecesBar;
|
||||
class PieceAvailabilityBar;
|
||||
class PropTabBar;
|
||||
class LineEdit;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAction;
|
||||
class QPushButton;
|
||||
class QTimer;
|
||||
class QTreeView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class DownloadedPiecesBar;
|
||||
class LineEdit;
|
||||
class MainWindow;
|
||||
class PeerListWidget;
|
||||
class PieceAvailabilityBar;
|
||||
class PropListDelegate;
|
||||
class PropTabBar;
|
||||
class SpeedWidget;
|
||||
class torrent_file;
|
||||
class TorrentContentFilterModel;
|
||||
class TrackerList;
|
||||
class TransferListWidget;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class PropertiesWidget;
|
||||
}
|
||||
|
||||
class PropertiesWidget: public QWidget
|
||||
class PropertiesWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PropertiesWidget)
|
||||
@@ -73,13 +69,13 @@ public:
|
||||
VISIBLE
|
||||
};
|
||||
|
||||
PropertiesWidget(QWidget *parent, MainWindow *main_window, TransferListWidget *transferList);
|
||||
PropertiesWidget(QWidget *parent, MainWindow *mainWindow, TransferListWidget *transferList);
|
||||
~PropertiesWidget();
|
||||
BitTorrent::TorrentHandle *getCurrentTorrent() const;
|
||||
TrackerList *getTrackerList() const { return trackerList; }
|
||||
PeerListWidget *getPeerList() const { return peersList; }
|
||||
TrackerList *getTrackerList() const;
|
||||
PeerListWidget *getPeerList() const;
|
||||
QTreeView *getFilesList() const;
|
||||
SpeedWidget *getSpeedWidget() const { return speedWidget; }
|
||||
SpeedWidget *getSpeedWidget() const;
|
||||
|
||||
public slots:
|
||||
void setVisibility(bool visible);
|
||||
@@ -93,7 +89,7 @@ public slots:
|
||||
|
||||
protected:
|
||||
QPushButton *getButtonFromIndex(int index);
|
||||
bool applyPriorities();
|
||||
void applyPriorities();
|
||||
|
||||
protected slots:
|
||||
void loadTorrentInfos(BitTorrent::TorrentHandle *const torrent);
|
||||
@@ -113,28 +109,28 @@ protected slots:
|
||||
|
||||
private:
|
||||
void openFile(const QModelIndex &index);
|
||||
void openFolder(const QModelIndex &index, bool containing_folder);
|
||||
void openFolder(const QModelIndex &index, bool containingFolder);
|
||||
|
||||
Ui::PropertiesWidget *m_ui;
|
||||
TransferListWidget *transferList;
|
||||
MainWindow *main_window;
|
||||
TransferListWidget *m_transferList;
|
||||
MainWindow *m_mainWindow;
|
||||
BitTorrent::TorrentHandle *m_torrent;
|
||||
QTimer *refreshTimer;
|
||||
SlideState state;
|
||||
TorrentContentFilterModel *PropListModel;
|
||||
PropListDelegate *PropDelegate;
|
||||
PeerListWidget *peersList;
|
||||
TrackerList *trackerList;
|
||||
SpeedWidget *speedWidget;
|
||||
QList<int> slideSizes;
|
||||
DownloadedPiecesBar *downloaded_pieces;
|
||||
PieceAvailabilityBar *pieces_availability;
|
||||
QTimer *m_refreshTimer;
|
||||
SlideState m_state;
|
||||
TorrentContentFilterModel *m_propListModel;
|
||||
PropListDelegate *m_propListDelegate;
|
||||
PeerListWidget *m_peerList;
|
||||
TrackerList *m_trackerList;
|
||||
SpeedWidget *m_speedWidget;
|
||||
QList<int> m_slideSizes;
|
||||
DownloadedPiecesBar *m_downloadedPieces;
|
||||
PieceAvailabilityBar *m_piecesAvailability;
|
||||
PropTabBar *m_tabBar;
|
||||
LineEdit *m_contentFilterLine;
|
||||
QShortcut *editHotkeyFile;
|
||||
QShortcut *editHotkeyWeb;
|
||||
QShortcut *deleteHotkeyWeb;
|
||||
QShortcut *openHotkeyFile;
|
||||
QShortcut *m_editHotkeyFile;
|
||||
QShortcut *m_editHotkeyWeb;
|
||||
QShortcut *m_deleteHotkeyWeb;
|
||||
QShortcut *m_openHotkeyFile;
|
||||
|
||||
private slots:
|
||||
void filterText(const QString &filter);
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="downloaded_pieces_lbl">
|
||||
<widget class="QLabel" name="labelDownloadedPieces">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -83,7 +83,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="progress_lbl">
|
||||
<widget class="QLabel" name="labelProgressVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -96,7 +96,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="avail_pieces_lbl">
|
||||
<widget class="QLabel" name="labelPiecesAvailability">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -112,7 +112,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="avail_average_lbl">
|
||||
<widget class="QLabel" name="labelAverageAvailabilityVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -142,7 +142,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<widget class="Line" name="lineBelowBars">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@@ -161,7 +161,7 @@
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_dl_speed_val">
|
||||
<widget class="QLabel" name="labelDlSpeedVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -174,7 +174,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="label_upload_speed">
|
||||
<widget class="QLabel" name="labelUpSpeed">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -190,7 +190,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3" colspan="4">
|
||||
<widget class="QLabel" name="label_upload_speed_val">
|
||||
<widget class="QLabel" name="labelUpSpeedVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -203,7 +203,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QLabel" name="label_peers">
|
||||
<widget class="QLabel" name="labelPeers">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -219,7 +219,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<widget class="QLabel" name="labelConnections">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -235,7 +235,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="reannounce_lbl">
|
||||
<widget class="QLabel" name="labelReannounceInVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -248,7 +248,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_eta_val">
|
||||
<widget class="QLabel" name="labelETAVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -261,7 +261,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<widget class="QLabel" name="labelDlLimit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -277,7 +277,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="lbl_ratio">
|
||||
<widget class="QLabel" name="labelRatio">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -293,7 +293,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QLabel" name="lbl_connections">
|
||||
<widget class="QLabel" name="labelConnectionsVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -306,7 +306,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="5">
|
||||
<widget class="QLabel" name="label_peers_val">
|
||||
<widget class="QLabel" name="labelPeersVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -319,7 +319,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<widget class="QLabel" name="labelDownloaded">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -335,7 +335,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<widget class="QLabel" name="labelUpLimit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -351,7 +351,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="4">
|
||||
<widget class="QLabel" name="label_last_complete">
|
||||
<widget class="QLabel" name="labelLastSeenComplete">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -367,7 +367,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="lbl_dllimit">
|
||||
<widget class="QLabel" name="labelDlLimitVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -380,7 +380,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" colspan="4">
|
||||
<widget class="QLabel" name="upTotal">
|
||||
<widget class="QLabel" name="labelUpTotalVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -393,7 +393,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<widget class="QLabel" name="labelReannounceIn">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -409,7 +409,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="5">
|
||||
<widget class="QLabel" name="label_last_complete_val">
|
||||
<widget class="QLabel" name="labelLastSeenCompleteVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -422,7 +422,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLabel" name="label_seeds">
|
||||
<widget class="QLabel" name="labelSeeds">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -438,7 +438,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_dl_speed">
|
||||
<widget class="QLabel" name="labelDlSpeed">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -454,7 +454,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="dlTotal">
|
||||
<widget class="QLabel" name="labelDlTotalVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -467,7 +467,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="5">
|
||||
<widget class="QLabel" name="wasted">
|
||||
<widget class="QLabel" name="labelWastedVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -480,7 +480,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="shareRatio">
|
||||
<widget class="QLabel" name="labelShareRatioVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -493,7 +493,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<widget class="QLabel" name="labelUploaded">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -509,7 +509,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<widget class="QLabel" name="label_seeds_val">
|
||||
<widget class="QLabel" name="labelSeedsVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -522,7 +522,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="lbl_elapsed">
|
||||
<widget class="QLabel" name="labelElapsedVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -535,7 +535,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<widget class="QLabel" name="labelTimeActive">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -551,7 +551,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="lbl_uplimit">
|
||||
<widget class="QLabel" name="labelUpLimitVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -564,7 +564,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_eta">
|
||||
<widget class="QLabel" name="labelETA">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -580,7 +580,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<widget class="QLabel" name="labelWasted">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -611,7 +611,7 @@
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_total_size">
|
||||
<widget class="QLabel" name="labelTotalSize">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -627,7 +627,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_total_size_val">
|
||||
<widget class="QLabel" name="labelTotalSizeVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -640,7 +640,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_total_pieces">
|
||||
<widget class="QLabel" name="labelTotalPieces">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -656,7 +656,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_total_pieces_val">
|
||||
<widget class="QLabel" name="labelTotalPiecesVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -669,7 +669,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="label_created_by">
|
||||
<widget class="QLabel" name="labelCreatedBy">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -685,7 +685,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QLabel" name="label_created_by_val">
|
||||
<widget class="QLabel" name="labelCreatedByVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -698,7 +698,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_added_on">
|
||||
<widget class="QLabel" name="labelAddedOn">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -714,7 +714,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_added_on_val">
|
||||
<widget class="QLabel" name="labelAddedOnVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -727,7 +727,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_completed_on">
|
||||
<widget class="QLabel" name="labelCompletedOn">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -743,7 +743,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label_completed_on_val">
|
||||
<widget class="QLabel" name="labelCompletedOnVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -756,7 +756,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<widget class="QLabel" name="labelCreatedOn">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -772,7 +772,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<widget class="QLabel" name="lbl_creationDate">
|
||||
<widget class="QLabel" name="labelCreatedOnVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -785,7 +785,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="hash_lbl2">
|
||||
<widget class="QLabel" name="labelHash">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -801,7 +801,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="5">
|
||||
<widget class="QLabel" name="hash_lbl">
|
||||
<widget class="QLabel" name="labelHashVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -817,7 +817,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="savePath_lbl">
|
||||
<widget class="QLabel" name="labelSavePath">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -833,7 +833,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="5">
|
||||
<widget class="QLabel" name="save_path">
|
||||
<widget class="QLabel" name="labelSavePathVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -852,7 +852,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="comment_lbl2">
|
||||
<widget class="QLabel" name="labelComment">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -868,7 +868,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="5">
|
||||
<widget class="QLabel" name="comment_text">
|
||||
<widget class="QLabel" name="labelCommentVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -1000,6 +1000,9 @@
|
||||
</widget>
|
||||
<widget class="QWidget" name="pageContents">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@@ -1062,7 +1065,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="pageSpeed">
|
||||
<layout class="QVBoxLayout" name="speed_layout">
|
||||
<layout class="QVBoxLayout" name="speedLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,8 +24,6 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "proplistdelegate.h"
|
||||
@@ -83,53 +81,53 @@ void PropListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, Utils::Misc::friendlyUnit(index.data().toLongLong()));
|
||||
break;
|
||||
case PROGRESS: {
|
||||
if (index.data().toDouble() < 0)
|
||||
break;
|
||||
if (index.data().toDouble() < 0)
|
||||
break;
|
||||
|
||||
QStyleOptionProgressBar newopt;
|
||||
qreal progress = index.data().toDouble() * 100.;
|
||||
newopt.rect = opt.rect;
|
||||
newopt.text = ((progress == 100.0) ? QString("100%") : Utils::String::fromDouble(progress, 1) + "%");
|
||||
newopt.progress = int(progress);
|
||||
newopt.maximum = 100;
|
||||
newopt.minimum = 0;
|
||||
newopt.textVisible = true;
|
||||
if (index.sibling(index.row(), PRIORITY).data().toInt() == prio::IGNORED) {
|
||||
newopt.state &= ~QStyle::State_Enabled;
|
||||
newopt.palette = progressBarDisabledPalette();
|
||||
}
|
||||
else {
|
||||
newopt.state |= QStyle::State_Enabled;
|
||||
}
|
||||
QStyleOptionProgressBar newopt;
|
||||
qreal progress = index.data().toDouble() * 100.;
|
||||
newopt.rect = opt.rect;
|
||||
newopt.text = ((progress == 100.0) ? QString("100%") : Utils::String::fromDouble(progress, 1) + "%");
|
||||
newopt.progress = int(progress);
|
||||
newopt.maximum = 100;
|
||||
newopt.minimum = 0;
|
||||
newopt.textVisible = true;
|
||||
if (index.sibling(index.row(), PRIORITY).data().toInt() == prio::IGNORED) {
|
||||
newopt.state &= ~QStyle::State_Enabled;
|
||||
newopt.palette = progressBarDisabledPalette();
|
||||
}
|
||||
else {
|
||||
newopt.state |= QStyle::State_Enabled;
|
||||
}
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, painter);
|
||||
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, painter);
|
||||
#else
|
||||
// XXX: To avoid having the progress text on the right of the bar
|
||||
QProxyStyle("fusion").drawControl(QStyle::CE_ProgressBar, &newopt, painter, 0);
|
||||
// XXX: To avoid having the progress text on the right of the bar
|
||||
QProxyStyle("fusion").drawControl(QStyle::CE_ProgressBar, &newopt, painter, 0);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PRIORITY: {
|
||||
QString text = "";
|
||||
switch (index.data().toInt()) {
|
||||
case prio::MIXED:
|
||||
text = tr("Mixed", "Mixed (priorities");
|
||||
break;
|
||||
case prio::IGNORED:
|
||||
text = tr("Not downloaded");
|
||||
break;
|
||||
case prio::HIGH:
|
||||
text = tr("High", "High (priority)");
|
||||
break;
|
||||
case prio::MAXIMUM:
|
||||
text = tr("Maximum", "Maximum (priority)");
|
||||
break;
|
||||
default:
|
||||
text = tr("Normal", "Normal (priority)");
|
||||
break;
|
||||
}
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, text);
|
||||
break;
|
||||
case PRIORITY: {
|
||||
QString text = "";
|
||||
switch (index.data().toInt()) {
|
||||
case prio::MIXED:
|
||||
text = tr("Mixed", "Mixed (priorities");
|
||||
break;
|
||||
case prio::IGNORED:
|
||||
text = tr("Not downloaded");
|
||||
break;
|
||||
case prio::HIGH:
|
||||
text = tr("High", "High (priority)");
|
||||
break;
|
||||
case prio::MAXIMUM:
|
||||
text = tr("Maximum", "Maximum (priority)");
|
||||
break;
|
||||
default:
|
||||
text = tr("Normal", "Normal (priority)");
|
||||
break;
|
||||
}
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, text);
|
||||
}
|
||||
break;
|
||||
case AVAILABILITY: {
|
||||
@@ -174,16 +172,16 @@ void PropListDelegate::setEditorData(QWidget *editor, const QModelIndex &index)
|
||||
|
||||
QWidget *PropListDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const
|
||||
{
|
||||
if (index.column() != PRIORITY) return 0;
|
||||
if (index.column() != PRIORITY) return nullptr;
|
||||
|
||||
if (m_properties) {
|
||||
BitTorrent::TorrentHandle *const torrent = m_properties->getCurrentTorrent();
|
||||
if (!torrent || !torrent->hasMetadata() || torrent->isSeed())
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (index.data().toInt() == prio::MIXED)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
editor->setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,8 +24,6 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef PROPLISTDELEGATE_H
|
||||
@@ -33,10 +31,10 @@
|
||||
|
||||
#include <QItemDelegate>
|
||||
|
||||
class QPainter;
|
||||
class QModelIndex;
|
||||
class QStyleOptionViewItem;
|
||||
class QAbstractItemModel;
|
||||
class QModelIndex;
|
||||
class QPainter;
|
||||
class QStyleOptionViewItem;
|
||||
class PropertiesWidget;
|
||||
|
||||
// Defines for properties list columns
|
||||
@@ -50,7 +48,7 @@ enum PropColumn
|
||||
AVAILABILITY
|
||||
};
|
||||
|
||||
class PropListDelegate: public QItemDelegate
|
||||
class PropListDelegate : public QItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -72,5 +70,4 @@ private:
|
||||
PropertiesWidget *m_properties;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // PROPLISTDELEGATE_H
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,120 +24,121 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "proptabbar.h"
|
||||
|
||||
#include <QButtonGroup>
|
||||
#include <QKeySequence>
|
||||
#include <QPushButton>
|
||||
#include <QSpacerItem>
|
||||
#include <QKeySequence>
|
||||
|
||||
#include "proptabbar.h"
|
||||
#include "guiiconprovider.h"
|
||||
|
||||
PropTabBar::PropTabBar(QWidget *parent) :
|
||||
QHBoxLayout(parent), m_currentIndex(-1)
|
||||
PropTabBar::PropTabBar(QWidget *parent)
|
||||
: QHBoxLayout(parent)
|
||||
, m_currentIndex(-1)
|
||||
{
|
||||
setAlignment(Qt::AlignLeft | Qt::AlignCenter);
|
||||
setSpacing(3);
|
||||
m_btnGroup = new QButtonGroup(this);
|
||||
// General tab
|
||||
QPushButton *main_infos_button = new QPushButton(
|
||||
setAlignment(Qt::AlignLeft | Qt::AlignCenter);
|
||||
setSpacing(3);
|
||||
m_btnGroup = new QButtonGroup(this);
|
||||
// General tab
|
||||
QPushButton *mainInfosButton = new QPushButton(
|
||||
#ifndef Q_OS_MAC
|
||||
GuiIconProvider::instance()->getIcon("document-properties"),
|
||||
GuiIconProvider::instance()->getIcon("document-properties"),
|
||||
#endif
|
||||
tr("General"), parent);
|
||||
main_infos_button->setShortcut(Qt::ALT + Qt::Key_G);
|
||||
addWidget(main_infos_button);
|
||||
m_btnGroup->addButton(main_infos_button, MAIN_TAB);
|
||||
// Trackers tab
|
||||
QPushButton *trackers_button = new QPushButton(
|
||||
tr("General"), parent);
|
||||
mainInfosButton->setShortcut(Qt::ALT + Qt::Key_G);
|
||||
addWidget(mainInfosButton);
|
||||
m_btnGroup->addButton(mainInfosButton, MainTab);
|
||||
// Trackers tab
|
||||
QPushButton *trackersButton = new QPushButton(
|
||||
#ifndef Q_OS_MAC
|
||||
GuiIconProvider::instance()->getIcon("network-server"),
|
||||
GuiIconProvider::instance()->getIcon("network-server"),
|
||||
#endif
|
||||
tr("Trackers"), parent);
|
||||
trackers_button->setShortcut(Qt::ALT + Qt::Key_C);
|
||||
addWidget(trackers_button);
|
||||
m_btnGroup->addButton(trackers_button, TRACKERS_TAB);
|
||||
// Peers tab
|
||||
QPushButton *peers_button = new QPushButton(
|
||||
tr("Trackers"), parent);
|
||||
trackersButton->setShortcut(Qt::ALT + Qt::Key_C);
|
||||
addWidget(trackersButton);
|
||||
m_btnGroup->addButton(trackersButton, TrackersTab);
|
||||
// Peers tab
|
||||
QPushButton *peersButton = new QPushButton(
|
||||
#ifndef Q_OS_MAC
|
||||
GuiIconProvider::instance()->getIcon("edit-find-user"),
|
||||
GuiIconProvider::instance()->getIcon("edit-find-user"),
|
||||
#endif
|
||||
tr("Peers"), parent);
|
||||
peers_button->setShortcut(Qt::ALT + Qt::Key_R);
|
||||
addWidget(peers_button);
|
||||
m_btnGroup->addButton(peers_button, PEERS_TAB);
|
||||
// URL seeds tab
|
||||
QPushButton *urlseeds_button = new QPushButton(
|
||||
tr("Peers"), parent);
|
||||
peersButton->setShortcut(Qt::ALT + Qt::Key_R);
|
||||
addWidget(peersButton);
|
||||
m_btnGroup->addButton(peersButton, PeersTab);
|
||||
// URL seeds tab
|
||||
QPushButton *URLSeedsButton = new QPushButton(
|
||||
#ifndef Q_OS_MAC
|
||||
GuiIconProvider::instance()->getIcon("network-server"),
|
||||
GuiIconProvider::instance()->getIcon("network-server"),
|
||||
#endif
|
||||
tr("HTTP Sources"), parent);
|
||||
urlseeds_button->setShortcut(Qt::ALT + Qt::Key_B);
|
||||
addWidget(urlseeds_button);
|
||||
m_btnGroup->addButton(urlseeds_button, URLSEEDS_TAB);
|
||||
// Files tab
|
||||
QPushButton *files_button = new QPushButton(
|
||||
tr("HTTP Sources"), parent);
|
||||
URLSeedsButton->setShortcut(Qt::ALT + Qt::Key_B);
|
||||
addWidget(URLSeedsButton);
|
||||
m_btnGroup->addButton(URLSeedsButton, URLSeedsTab);
|
||||
// Files tab
|
||||
QPushButton *filesButton = new QPushButton(
|
||||
#ifndef Q_OS_MAC
|
||||
GuiIconProvider::instance()->getIcon("inode-directory"),
|
||||
GuiIconProvider::instance()->getIcon("inode-directory"),
|
||||
#endif
|
||||
tr("Content"), parent);
|
||||
files_button->setShortcut(Qt::ALT + Qt::Key_Z);
|
||||
addWidget(files_button);
|
||||
m_btnGroup->addButton(files_button, FILES_TAB);
|
||||
// Spacer
|
||||
addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed));
|
||||
// Speed tab
|
||||
QPushButton *speed_button = new QPushButton(
|
||||
tr("Content"), parent);
|
||||
filesButton->setShortcut(Qt::ALT + Qt::Key_Z);
|
||||
addWidget(filesButton);
|
||||
m_btnGroup->addButton(filesButton, FilesTab);
|
||||
// Spacer
|
||||
addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed));
|
||||
// Speed tab
|
||||
QPushButton *speedButton = new QPushButton(
|
||||
#ifndef Q_OS_MAC
|
||||
GuiIconProvider::instance()->getIcon("office-chart-line"),
|
||||
GuiIconProvider::instance()->getIcon("office-chart-line"),
|
||||
#endif
|
||||
tr("Speed"), parent);
|
||||
speed_button->setShortcut(Qt::ALT + Qt::Key_D);
|
||||
addWidget(speed_button);
|
||||
m_btnGroup->addButton(speed_button, SPEED_TAB);
|
||||
// SIGNAL/SLOT
|
||||
connect(m_btnGroup, SIGNAL(buttonClicked(int)), SLOT(setCurrentIndex(int)));
|
||||
// Disable buttons focus
|
||||
foreach (QAbstractButton *btn, m_btnGroup->buttons()) {
|
||||
btn->setFocusPolicy(Qt::NoFocus);
|
||||
}
|
||||
tr("Speed"), parent);
|
||||
speedButton->setShortcut(Qt::ALT + Qt::Key_D);
|
||||
addWidget(speedButton);
|
||||
m_btnGroup->addButton(speedButton, SpeedTab);
|
||||
// SIGNAL/SLOT
|
||||
connect(m_btnGroup, SIGNAL(buttonClicked(int)), SLOT(setCurrentIndex(int)));
|
||||
// Disable buttons focus
|
||||
foreach (QAbstractButton *btn, m_btnGroup->buttons())
|
||||
btn->setFocusPolicy(Qt::NoFocus);
|
||||
}
|
||||
|
||||
PropTabBar::~PropTabBar() {
|
||||
delete m_btnGroup;
|
||||
PropTabBar::~PropTabBar()
|
||||
{
|
||||
delete m_btnGroup;
|
||||
}
|
||||
|
||||
int PropTabBar::currentIndex() const
|
||||
{
|
||||
return m_currentIndex;
|
||||
return m_currentIndex;
|
||||
}
|
||||
|
||||
void PropTabBar::setCurrentIndex(int index)
|
||||
{
|
||||
if (index >= m_btnGroup->buttons().size())
|
||||
if (index >= m_btnGroup->buttons().size())
|
||||
index = 0;
|
||||
// If asked to hide or if the currently selected tab is clicked
|
||||
if (index < 0 || m_currentIndex == index) {
|
||||
if (m_currentIndex >= 0) {
|
||||
m_btnGroup->button(m_currentIndex)->setDown(false);
|
||||
m_currentIndex = -1;
|
||||
emit visibilityToggled(false);
|
||||
// If asked to hide or if the currently selected tab is clicked
|
||||
if (index < 0 || m_currentIndex == index) {
|
||||
if (m_currentIndex >= 0) {
|
||||
m_btnGroup->button(m_currentIndex)->setDown(false);
|
||||
m_currentIndex = -1;
|
||||
emit visibilityToggled(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Unselect previous tab
|
||||
if (m_currentIndex >= 0) {
|
||||
m_btnGroup->button(m_currentIndex)->setDown(false);
|
||||
} else {
|
||||
// Nothing was selected, show!
|
||||
emit visibilityToggled(true);
|
||||
}
|
||||
// Select the new button
|
||||
m_btnGroup->button(index)->setDown(true);
|
||||
m_currentIndex = index;
|
||||
// Emit the signal
|
||||
emit tabChanged(index);
|
||||
// Unselect previous tab
|
||||
if (m_currentIndex >= 0) {
|
||||
m_btnGroup->button(m_currentIndex)->setDown(false);
|
||||
}
|
||||
else {
|
||||
// Nothing was selected, show!
|
||||
emit visibilityToggled(true);
|
||||
}
|
||||
// Select the new button
|
||||
m_btnGroup->button(index)->setDown(true);
|
||||
m_currentIndex = index;
|
||||
// Emit the signal
|
||||
emit tabChanged(index);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,8 +24,6 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef PROPTABBAR_H
|
||||
@@ -33,9 +31,7 @@
|
||||
|
||||
#include <QHBoxLayout>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QButtonGroup;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class PropTabBar : public QHBoxLayout
|
||||
{
|
||||
@@ -43,24 +39,30 @@ class PropTabBar : public QHBoxLayout
|
||||
Q_DISABLE_COPY(PropTabBar)
|
||||
|
||||
public:
|
||||
enum PropertyTab {MAIN_TAB, TRACKERS_TAB, PEERS_TAB, URLSEEDS_TAB, FILES_TAB, SPEED_TAB};
|
||||
enum PropertyTab
|
||||
{
|
||||
MainTab,
|
||||
TrackersTab,
|
||||
PeersTab,
|
||||
URLSeedsTab,
|
||||
FilesTab,
|
||||
SpeedTab
|
||||
};
|
||||
|
||||
public:
|
||||
explicit PropTabBar(QWidget *parent = 0);
|
||||
~PropTabBar();
|
||||
int currentIndex() const;
|
||||
explicit PropTabBar(QWidget *parent = nullptr);
|
||||
~PropTabBar();
|
||||
int currentIndex() const;
|
||||
|
||||
signals:
|
||||
void tabChanged(int index);
|
||||
void visibilityToggled(bool visible);
|
||||
void tabChanged(int index);
|
||||
void visibilityToggled(bool visible);
|
||||
|
||||
public slots:
|
||||
void setCurrentIndex(int index);
|
||||
void setCurrentIndex(int index);
|
||||
|
||||
private:
|
||||
QButtonGroup *m_btnGroup;
|
||||
int m_currentIndex;
|
||||
|
||||
QButtonGroup *m_btnGroup;
|
||||
int m_currentIndex;
|
||||
};
|
||||
|
||||
#endif // PROPTABBAR_H
|
||||
|
||||
@@ -191,20 +191,20 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
|
||||
Utils::Misc::friendlyUnit(0, true)
|
||||
};
|
||||
|
||||
int yAxeWidth = 0;
|
||||
int yAxisWidth = 0;
|
||||
for (const QString &label : speedLabels)
|
||||
if (fontMetrics.width(label) > yAxeWidth)
|
||||
yAxeWidth = fontMetrics.width(label);
|
||||
if (fontMetrics.width(label) > yAxisWidth)
|
||||
yAxisWidth = fontMetrics.width(label);
|
||||
|
||||
int i = 0;
|
||||
for (const QString &label : speedLabels) {
|
||||
QRectF labelRect(rect.topLeft() + QPointF(-yAxeWidth, (i++) * 0.25 * rect.height() - fontMetrics.height()),
|
||||
QSizeF(2 * yAxeWidth, fontMetrics.height()));
|
||||
QRectF labelRect(rect.topLeft() + QPointF(-yAxisWidth, (i++) * 0.25 * rect.height() - fontMetrics.height()),
|
||||
QSizeF(2 * yAxisWidth, fontMetrics.height()));
|
||||
painter.drawText(labelRect, label, Qt::AlignRight | Qt::AlignTop);
|
||||
}
|
||||
|
||||
// draw grid lines
|
||||
rect.adjust(yAxeWidth + 4, 0, 0, 0);
|
||||
rect.adjust(yAxisWidth + 4, 0, 0, 0);
|
||||
|
||||
QPen gridPen;
|
||||
gridPen.setStyle(Qt::DashLine);
|
||||
@@ -236,18 +236,16 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
|
||||
boost::circular_buffer<PointData> &queue = getCurrentData();
|
||||
|
||||
for (int id = UP; id < NB_GRAPHS; ++id) {
|
||||
|
||||
if (!m_properties[static_cast<GraphID>(id)].enable)
|
||||
continue;
|
||||
|
||||
QVector<QPoint> points;
|
||||
|
||||
for (int i = int(queue.size()) - 1, j = 0; i >= 0 && j <= m_viewablePointsCount; --i, ++j) {
|
||||
|
||||
int new_x = rect.right() - j * xTickSize;
|
||||
int new_y = rect.bottom() - queue[i].y[id] * yMultiplier;
|
||||
int newX = rect.right() - j * xTickSize;
|
||||
int newY = rect.bottom() - queue[i].y[id] * yMultiplier;
|
||||
|
||||
points.push_back(QPoint(new_x, new_y));
|
||||
points.push_back(QPoint(newX, newY));
|
||||
}
|
||||
|
||||
painter.setPen(m_properties[static_cast<GraphID>(id)].pen);
|
||||
@@ -260,7 +258,6 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
|
||||
double legendHeight = 0;
|
||||
int legendWidth = 0;
|
||||
for (const auto &property : m_properties) {
|
||||
|
||||
if (!property.enable)
|
||||
continue;
|
||||
|
||||
@@ -276,7 +273,6 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
|
||||
|
||||
i = 0;
|
||||
for (const auto &property : m_properties) {
|
||||
|
||||
if (!property.enable)
|
||||
continue;
|
||||
|
||||
@@ -293,10 +289,12 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
|
||||
|
||||
SpeedPlotView::GraphProperties::GraphProperties()
|
||||
: enable(false)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
SpeedPlotView::GraphProperties::GraphProperties(const QString &name, const QPen &pen, bool enable)
|
||||
: name(name)
|
||||
, pen(pen)
|
||||
, enable(enable)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
DHT_DOWN,
|
||||
TRACKER_UP,
|
||||
TRACKER_DOWN,
|
||||
|
||||
NB_GRAPHS
|
||||
};
|
||||
|
||||
@@ -82,7 +83,7 @@ public:
|
||||
void replot();
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *event);
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
enum PeriodInSeconds
|
||||
@@ -110,6 +111,9 @@ private:
|
||||
bool enable;
|
||||
};
|
||||
|
||||
int maxYValue();
|
||||
boost::circular_buffer<PointData> &getCurrentData();
|
||||
|
||||
boost::circular_buffer<PointData> m_data5Min;
|
||||
boost::circular_buffer<PointData> m_data30Min;
|
||||
boost::circular_buffer<PointData> m_data6Hour;
|
||||
@@ -120,10 +124,6 @@ private:
|
||||
|
||||
int m_counter30Min;
|
||||
int m_counter6Hour;
|
||||
|
||||
int maxYValue();
|
||||
|
||||
boost::circular_buffer<PointData> &getCurrentData();
|
||||
};
|
||||
|
||||
#endif // SPEEDPLOTVIEW_H
|
||||
|
||||
@@ -38,10 +38,10 @@
|
||||
|
||||
#include <libtorrent/session_status.hpp>
|
||||
|
||||
#include "propertieswidget.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/bittorrent/sessionstatus.h"
|
||||
#include "base/preferences.h"
|
||||
#include "propertieswidget.h"
|
||||
|
||||
ComboBoxMenuButton::ComboBoxMenuButton(QWidget *parent, QMenu *menu)
|
||||
: QComboBox(parent)
|
||||
@@ -61,6 +61,7 @@ SpeedWidget::SpeedWidget(PropertiesWidget *parent)
|
||||
{
|
||||
m_layout = new QVBoxLayout(this);
|
||||
m_layout->setContentsMargins(0, 0, 0, 0);
|
||||
m_layout->setSpacing(3);
|
||||
|
||||
m_hlayout = new QHBoxLayout();
|
||||
m_hlayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#ifndef SPEEDWIDGET_H
|
||||
#define SPEEDWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
#include <QWidget>
|
||||
|
||||
#include "speedplotview.h"
|
||||
|
||||
@@ -44,6 +44,7 @@ class PropertiesWidget;
|
||||
class ComboBoxMenuButton : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ComboBoxMenuButton(QWidget *parent, QMenu *menu);
|
||||
virtual void showPopup();
|
||||
@@ -56,6 +57,7 @@ private:
|
||||
class SpeedWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpeedWidget(PropertiesWidget *parent);
|
||||
~SpeedWidget();
|
||||
|
||||
@@ -399,13 +399,13 @@ void TrackerList::copyTrackerUrl()
|
||||
QList<QTreeWidgetItem *> selectedTrackerItems = getSelectedTrackerItems();
|
||||
if (selectedTrackerItems.isEmpty()) return;
|
||||
|
||||
QStringList URLsToCopy;
|
||||
QStringList urlsToCopy;
|
||||
foreach (QTreeWidgetItem *item, selectedTrackerItems) {
|
||||
QString trackerURL = item->data(COL_URL, Qt::DisplayRole).toString();
|
||||
qDebug() << QString("Copy: ") + trackerURL;
|
||||
URLsToCopy << trackerURL;
|
||||
urlsToCopy << trackerURL;
|
||||
}
|
||||
QApplication::clipboard()->setText(URLsToCopy.join("\n"));
|
||||
QApplication::clipboard()->setText(urlsToCopy.join("\n"));
|
||||
}
|
||||
|
||||
|
||||
@@ -420,10 +420,10 @@ void TrackerList::deleteSelectedTrackers()
|
||||
QList<QTreeWidgetItem *> selectedTrackerItems = getSelectedTrackerItems();
|
||||
if (selectedTrackerItems.isEmpty()) return;
|
||||
|
||||
QStringList URLsToRemove;
|
||||
QStringList urlsToRemove;
|
||||
foreach (QTreeWidgetItem *item, selectedTrackerItems) {
|
||||
QString trackerURL = item->data(COL_URL, Qt::DisplayRole).toString();
|
||||
URLsToRemove << trackerURL;
|
||||
urlsToRemove << trackerURL;
|
||||
m_trackerItems.remove(trackerURL);
|
||||
delete item;
|
||||
}
|
||||
@@ -432,7 +432,7 @@ void TrackerList::deleteSelectedTrackers()
|
||||
QList<BitTorrent::TrackerEntry> remainingTrackers;
|
||||
QList<BitTorrent::TrackerEntry> trackers = torrent->trackers();
|
||||
foreach (const BitTorrent::TrackerEntry &entry, trackers) {
|
||||
if (!URLsToRemove.contains(entry.url()))
|
||||
if (!urlsToRemove.contains(entry.url()))
|
||||
remainingTrackers.push_back(entry);
|
||||
}
|
||||
|
||||
@@ -627,9 +627,8 @@ void TrackerList::displayToggleColumnsMenu(const QPoint &)
|
||||
Q_ASSERT(visibleColumnsCount() > 0);
|
||||
if (!isColumnHidden(col) && (visibleColumnsCount() == 1))
|
||||
return;
|
||||
qDebug("Toggling column %d visibility", col);
|
||||
setColumnHidden(col, !isColumnHidden(col));
|
||||
if (!isColumnHidden(col) && (columnWidth(col) <= 5))
|
||||
setColumnWidth(col, 100);
|
||||
resizeColumnToContents(col);
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,22 +24,20 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
#include "trackersadditiondlg.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QMessageBox>
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/net/downloadhandler.h"
|
||||
#include "base/bittorrent/trackerentry.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "base/bittorrent/trackerentry.h"
|
||||
#include "base/net/downloadhandler.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "ui_trackersadditiondlg.h"
|
||||
|
||||
@@ -75,14 +73,14 @@ void TrackersAdditionDlg::on_uTorrentListButton_clicked()
|
||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_ui->list_url->text(), true);
|
||||
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(parseUTorrentList(QString, QString)));
|
||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(getTrackerError(QString, QString)));
|
||||
//Just to show that it takes times
|
||||
// Just to show that it takes times
|
||||
setCursor(Qt::WaitCursor);
|
||||
}
|
||||
|
||||
void TrackersAdditionDlg::parseUTorrentList(const QString &, const QString &path)
|
||||
{
|
||||
QFile list_file(path);
|
||||
if (!list_file.open(QFile::ReadOnly)) {
|
||||
QFile listFile(path);
|
||||
if (!listFile.open(QFile::ReadOnly)) {
|
||||
QMessageBox::warning(this, tr("I/O Error"), tr("Error while trying to open the downloaded file."), QMessageBox::Ok);
|
||||
setCursor(Qt::ArrowCursor);
|
||||
m_ui->uTorrentListButton->setEnabled(true);
|
||||
@@ -94,8 +92,8 @@ void TrackersAdditionDlg::parseUTorrentList(const QString &, const QString &path
|
||||
QList<BitTorrent::TrackerEntry> existingTrackers = m_torrent->trackers();
|
||||
// Load from current user list
|
||||
QStringList tmp = m_ui->trackers_list->toPlainText().split("\n");
|
||||
foreach (const QString &user_url, tmp) {
|
||||
BitTorrent::TrackerEntry userTracker(user_url);
|
||||
foreach (const QString &userURL, tmp) {
|
||||
BitTorrent::TrackerEntry userTracker(userURL);
|
||||
if (!existingTrackers.contains(userTracker))
|
||||
existingTrackers << userTracker;
|
||||
}
|
||||
@@ -104,8 +102,8 @@ void TrackersAdditionDlg::parseUTorrentList(const QString &, const QString &path
|
||||
if (!m_ui->trackers_list->toPlainText().isEmpty() && !m_ui->trackers_list->toPlainText().endsWith("\n"))
|
||||
m_ui->trackers_list->insertPlainText("\n");
|
||||
int nb = 0;
|
||||
while (!list_file.atEnd()) {
|
||||
const QString line = list_file.readLine().trimmed();
|
||||
while (!listFile.atEnd()) {
|
||||
const QString line = listFile.readLine().trimmed();
|
||||
if (line.isEmpty()) continue;
|
||||
BitTorrent::TrackerEntry newTracker(line);
|
||||
if (!existingTrackers.contains(newTracker)) {
|
||||
@@ -114,7 +112,7 @@ void TrackersAdditionDlg::parseUTorrentList(const QString &, const QString &path
|
||||
}
|
||||
}
|
||||
// Clean up
|
||||
list_file.close();
|
||||
listFile.close();
|
||||
Utils::Fs::forceRemove(path);
|
||||
//To restore the cursor ...
|
||||
setCursor(Qt::ArrowCursor);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,8 +24,6 @@
|
||||
* 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.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef TRACKERSADDITION_H
|
||||
@@ -67,4 +65,4 @@ private:
|
||||
BitTorrent::TorrentHandle *const m_torrent;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // TRACKERSADDITION_H
|
||||
|
||||
@@ -53,9 +53,15 @@
|
||||
#include "guiiconprovider.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "ui_automatedrssdownloader.h"
|
||||
#include "utils.h"
|
||||
|
||||
const QString EXT_JSON {QStringLiteral(".json")};
|
||||
const QString EXT_LEGACY {QStringLiteral(".rssrules")};
|
||||
|
||||
AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_formatFilterJSON(QString("%1 (*%2)").arg(tr("Rules")).arg(EXT_JSON))
|
||||
, m_formatFilterLegacy(QString("%1 (*%2)").arg(tr("Rules (legacy)")).arg(EXT_LEGACY))
|
||||
, m_ui(new Ui::AutomatedRssDownloader)
|
||||
, m_currentRuleItem(nullptr)
|
||||
{
|
||||
@@ -150,14 +156,14 @@ AutomatedRssDownloader::~AutomatedRssDownloader()
|
||||
void AutomatedRssDownloader::loadSettings()
|
||||
{
|
||||
const Preferences *const pref = Preferences::instance();
|
||||
resize(pref->getRssGeometrySize(this->size()));
|
||||
Utils::Gui::resize(this, pref->getRssGeometrySize());
|
||||
m_ui->hsplitter->restoreState(pref->getRssHSplitterSizes());
|
||||
}
|
||||
|
||||
void AutomatedRssDownloader::saveSettings()
|
||||
{
|
||||
Preferences *const pref = Preferences::instance();
|
||||
pref->setRssGeometrySize(this->size());
|
||||
pref->setRssGeometrySize(size());
|
||||
pref->setRssHSplitterSizes(m_ui->hsplitter->saveState());
|
||||
}
|
||||
|
||||
@@ -306,7 +312,7 @@ void AutomatedRssDownloader::initCategoryCombobox()
|
||||
{
|
||||
// Load torrent categories
|
||||
QStringList categories = BitTorrent::Session::instance()->categories().keys();
|
||||
std::sort(categories.begin(), categories.end(), Utils::String::naturalCompareCaseInsensitive);
|
||||
std::sort(categories.begin(), categories.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
|
||||
m_ui->comboCategory->addItem("");
|
||||
m_ui->comboCategory->addItems(categories);
|
||||
}
|
||||
@@ -384,31 +390,73 @@ void AutomatedRssDownloader::on_browseSP_clicked()
|
||||
|
||||
void AutomatedRssDownloader::on_exportBtn_clicked()
|
||||
{
|
||||
// if (m_editableRuleList->isEmpty()) {
|
||||
// QMessageBox::warning(this, tr("Invalid action"), tr("The list is empty, there is nothing to export."));
|
||||
// return;
|
||||
// }
|
||||
// // Ask for a save path
|
||||
// QString save_path = QFileDialog::getSaveFileName(this, tr("Where would you like to save the list?"), QDir::homePath(), tr("Rules list (*.rssrules)"));
|
||||
// if (save_path.isEmpty()) return;
|
||||
// if (!save_path.endsWith(".rssrules", Qt::CaseInsensitive))
|
||||
// save_path += ".rssrules";
|
||||
// if (!m_editableRuleList->serialize(save_path)) {
|
||||
// QMessageBox::warning(this, tr("I/O Error"), tr("Failed to create the destination file"));
|
||||
// return;
|
||||
// }
|
||||
if (RSS::AutoDownloader::instance()->rules().isEmpty()) {
|
||||
QMessageBox::warning(this, tr("Invalid action")
|
||||
, tr("The list is empty, there is nothing to export."));
|
||||
return;
|
||||
}
|
||||
|
||||
QString selectedFilter {m_formatFilterJSON};
|
||||
QString path = QFileDialog::getSaveFileName(
|
||||
this, tr("Export RSS rules"), QDir::homePath()
|
||||
, QString("%1;;%2").arg(m_formatFilterJSON).arg(m_formatFilterLegacy), &selectedFilter);
|
||||
if (path.isEmpty()) return;
|
||||
|
||||
const RSS::AutoDownloader::RulesFileFormat format {
|
||||
(selectedFilter == m_formatFilterJSON)
|
||||
? RSS::AutoDownloader::RulesFileFormat::JSON
|
||||
: RSS::AutoDownloader::RulesFileFormat::Legacy
|
||||
};
|
||||
|
||||
if (format == RSS::AutoDownloader::RulesFileFormat::JSON) {
|
||||
if (!path.endsWith(EXT_JSON, Qt::CaseInsensitive))
|
||||
path += EXT_JSON;
|
||||
}
|
||||
else {
|
||||
if (!path.endsWith(EXT_LEGACY, Qt::CaseInsensitive))
|
||||
path += EXT_LEGACY;
|
||||
}
|
||||
|
||||
QFile file {path};
|
||||
if (!file.open(QFile::WriteOnly)
|
||||
|| (file.write(RSS::AutoDownloader::instance()->exportRules(format)) == -1)) {
|
||||
QMessageBox::critical(
|
||||
this, tr("I/O Error")
|
||||
, tr("Failed to create the destination file. Reason: %1").arg(file.errorString()));
|
||||
}
|
||||
}
|
||||
|
||||
void AutomatedRssDownloader::on_importBtn_clicked()
|
||||
{
|
||||
// // Ask for filter path
|
||||
// QString load_path = QFileDialog::getOpenFileName(this, tr("Please point to the RSS download rules file"), QDir::homePath(), tr("Rules list") + QString(" (*.rssrules *.filters)"));
|
||||
// if (load_path.isEmpty() || !QFile::exists(load_path)) return;
|
||||
// // Load it
|
||||
// if (!m_editableRuleList->unserialize(load_path)) {
|
||||
// QMessageBox::warning(this, tr("Import Error"), tr("Failed to import the selected rules file"));
|
||||
// return;
|
||||
// }
|
||||
QString selectedFilter {m_formatFilterJSON};
|
||||
QString path = QFileDialog::getOpenFileName(
|
||||
this, tr("Import RSS rules"), QDir::homePath()
|
||||
, QString("%1;;%2").arg(m_formatFilterJSON).arg(m_formatFilterLegacy), &selectedFilter);
|
||||
if (path.isEmpty() || !QFile::exists(path))
|
||||
return;
|
||||
|
||||
QFile file {path};
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
QMessageBox::critical(
|
||||
this, tr("I/O Error")
|
||||
, tr("Failed to open the file. Reason: %1").arg(file.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
const RSS::AutoDownloader::RulesFileFormat format {
|
||||
(selectedFilter == m_formatFilterJSON)
|
||||
? RSS::AutoDownloader::RulesFileFormat::JSON
|
||||
: RSS::AutoDownloader::RulesFileFormat::Legacy
|
||||
};
|
||||
|
||||
try {
|
||||
RSS::AutoDownloader::instance()->importRules(file.readAll(),format);
|
||||
}
|
||||
catch (const RSS::ParsingError &error) {
|
||||
QMessageBox::critical(
|
||||
this, tr("Import Error")
|
||||
, tr("Failed to import the selected rules file. Reason: %1").arg(error.message()));
|
||||
}
|
||||
}
|
||||
|
||||
void AutomatedRssDownloader::displayRulesListMenu()
|
||||
@@ -708,6 +756,7 @@ void AutomatedRssDownloader::handleRuleChanged(const QString &ruleName)
|
||||
|
||||
void AutomatedRssDownloader::handleRuleAboutToBeRemoved(const QString &ruleName)
|
||||
{
|
||||
m_currentRuleItem = nullptr;
|
||||
delete m_itemsByRuleName.take(ruleName);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,9 @@ private:
|
||||
void updateFeedList();
|
||||
void addFeedArticlesToTree(RSS::Feed *feed, const QStringList &articles);
|
||||
|
||||
const QString m_formatFilterJSON;
|
||||
const QString m_formatFilterLegacy;
|
||||
|
||||
Ui::AutomatedRssDownloader *m_ui;
|
||||
QListWidgetItem *m_currentRuleItem;
|
||||
QShortcut *m_editHotkey;
|
||||
|
||||
@@ -386,7 +386,7 @@
|
||||
<item>
|
||||
<widget class="QPushButton" name="importBtn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Import...</string>
|
||||
@@ -396,7 +396,7 @@
|
||||
<item>
|
||||
<widget class="QPushButton" name="exportBtn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Export...</string>
|
||||
|
||||
@@ -31,25 +31,26 @@
|
||||
|
||||
#include "pluginselectdlg.h"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QDropEvent>
|
||||
#include <QFileDialog>
|
||||
#include <QHeaderView>
|
||||
#include <QImageReader>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QDropEvent>
|
||||
#include <QMimeData>
|
||||
#include <QClipboard>
|
||||
#include <QTableView>
|
||||
#include <QImageReader>
|
||||
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "base/net/downloadhandler.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/net/downloadhandler.h"
|
||||
#include "searchwidget.h"
|
||||
#include "pluginsourcedlg.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "pluginsourcedlg.h"
|
||||
#include "searchwidget.h"
|
||||
#include "ui_pluginselectdlg.h"
|
||||
#include "utils.h"
|
||||
|
||||
enum PluginColumns
|
||||
{
|
||||
@@ -78,9 +79,6 @@ PluginSelectDlg::PluginSelectDlg(SearchEngine *pluginManager, QWidget *parent)
|
||||
unused.setVerticalHeader(new QHeaderView(Qt::Horizontal));
|
||||
|
||||
m_ui->pluginsTree->setRootIsDecorated(false);
|
||||
m_ui->pluginsTree->header()->resizeSection(0, 160);
|
||||
m_ui->pluginsTree->header()->resizeSection(1, 80);
|
||||
m_ui->pluginsTree->header()->resizeSection(2, 200);
|
||||
m_ui->pluginsTree->hideColumn(PLUGIN_ID);
|
||||
m_ui->pluginsTree->header()->setSortIndicator(0, Qt::AscendingOrder);
|
||||
|
||||
@@ -99,6 +97,7 @@ PluginSelectDlg::PluginSelectDlg(SearchEngine *pluginManager, QWidget *parent)
|
||||
connect(m_pluginManager, &SearchEngine::checkForUpdatesFinished, this, &PluginSelectDlg::checkForUpdatesFinished);
|
||||
connect(m_pluginManager, &SearchEngine::checkForUpdatesFailed, this, &PluginSelectDlg::checkForUpdatesFailed);
|
||||
|
||||
Utils::Gui::resize(this);
|
||||
show();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "pluginsourcedlg.h"
|
||||
|
||||
#include "ui_pluginsourcedlg.h"
|
||||
#include "utils.h"
|
||||
|
||||
PluginSourceDlg::PluginSourceDlg(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
@@ -38,6 +39,8 @@ PluginSourceDlg::PluginSourceDlg(QWidget *parent)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
Utils::Gui::resize(this);
|
||||
show();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,14 +28,20 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <QStyleOptionViewItem>
|
||||
#include <QCoreApplication>
|
||||
#include <QModelIndex>
|
||||
#include <QPainter>
|
||||
#include <QProgressBar>
|
||||
#include <QStyleOptionViewItem>
|
||||
|
||||
#include "base/utils/misc.h"
|
||||
#include "searchsortmodel.h"
|
||||
#include "searchlistdelegate.h"
|
||||
#include "searchsortmodel.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
const char i18nContext[] = "SearchListDelegate";
|
||||
}
|
||||
|
||||
SearchListDelegate::SearchListDelegate(QObject *parent)
|
||||
: QItemDelegate(parent)
|
||||
@@ -57,7 +63,8 @@ void SearchListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
|
||||
case SearchSortModel::SEEDS:
|
||||
case SearchSortModel::LEECHES:
|
||||
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, (index.data().toLongLong() >= 0) ? index.data().toString() : tr("Unknown"));
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect
|
||||
, (index.data().toLongLong() >= 0) ? index.data().toString() : QCoreApplication::translate(i18nContext, "Unknown"));
|
||||
break;
|
||||
default:
|
||||
QItemDelegate::paint(painter, option, index);
|
||||
|
||||
@@ -110,11 +110,12 @@ bool SearchSortModel::lessThan(const QModelIndex &left, const QModelIndex &right
|
||||
switch (sortColumn()) {
|
||||
case NAME:
|
||||
case ENGINE_URL: {
|
||||
QString vL = left.data().toString();
|
||||
QString vR = right.data().toString();
|
||||
return Utils::String::naturalCompareCaseInsensitive(vL, vR);
|
||||
const QString strL = left.data().toString();
|
||||
const QString strR = right.data().toString();
|
||||
const int result = Utils::String::naturalCompare(strL, strR, Qt::CaseInsensitive);
|
||||
return (result < 0);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return base::lessThan(left, right);
|
||||
};
|
||||
|
||||
@@ -334,10 +334,9 @@ void SearchTab::displayToggleColumnsMenu(const QPoint&)
|
||||
Q_ASSERT(visibleCols > 0);
|
||||
if ((!m_ui->resultsBrowser->isColumnHidden(col)) && (visibleCols == 1))
|
||||
return;
|
||||
qDebug("Toggling column %d visibility", col);
|
||||
m_ui->resultsBrowser->setColumnHidden(col, !m_ui->resultsBrowser->isColumnHidden(col));
|
||||
if ((!m_ui->resultsBrowser->isColumnHidden(col)) && (m_ui->resultsBrowser->columnWidth(col) <= 5))
|
||||
m_ui->resultsBrowser->setColumnWidth(col, 100);
|
||||
m_ui->resultsBrowser->resizeColumnToContents(col);
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user