You've already forked qBittorrent
mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-10-07 09:52:18 +02:00
Compare commits
74 Commits
release-3.
...
release-3.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c0ccf28d2c | ||
![]() |
9ff617a644 | ||
![]() |
0fbdc6471c | ||
![]() |
1ecdcfc29c | ||
![]() |
522ff3b611 | ||
![]() |
edac24ecca | ||
![]() |
6bbc26e613 | ||
![]() |
ca5f184c3d | ||
![]() |
47078d31c1 | ||
![]() |
a42bca6098 | ||
![]() |
ade4c44aad | ||
![]() |
fdbf8e8b6e | ||
![]() |
a9f14a8408 | ||
![]() |
73e5bdc5b5 | ||
![]() |
c18a56769d | ||
![]() |
291d006740 | ||
![]() |
3693b34c2c | ||
![]() |
ad5dd8391a | ||
![]() |
e77e90e8d2 | ||
![]() |
e828b3a398 | ||
![]() |
f31bdc1fc4 | ||
![]() |
81912736ed | ||
![]() |
176dd0bee8 | ||
![]() |
bbcfa5aae7 | ||
![]() |
2990492506 | ||
![]() |
9d7c7c51ca | ||
![]() |
2dd65b9eb9 | ||
![]() |
c8b74215c0 | ||
![]() |
87092e2716 | ||
![]() |
bf3cbfc608 | ||
![]() |
ddde91dbb9 | ||
![]() |
93173fadeb | ||
![]() |
4eb6e74dd6 | ||
![]() |
3f9e528633 | ||
![]() |
0501971e82 | ||
![]() |
6b4aad8a83 | ||
![]() |
80de35c5ee | ||
![]() |
a7528ec27a | ||
![]() |
ab49c80247 | ||
![]() |
0ec35a24e0 | ||
![]() |
600aa61095 | ||
![]() |
5db783cb7f | ||
![]() |
1a653829b8 | ||
![]() |
7d1e2944ab | ||
![]() |
7cecad4e82 | ||
![]() |
6dc82df368 | ||
![]() |
fcb22eb568 | ||
![]() |
82866605b4 | ||
![]() |
a78cd3d2ac | ||
![]() |
2e08b365a2 | ||
![]() |
9eca9585a0 | ||
![]() |
e29a714da4 | ||
![]() |
e3f6cea95c | ||
![]() |
ddbdeb1f89 | ||
![]() |
9471d17a65 | ||
![]() |
5e457353e5 | ||
![]() |
81089945ae | ||
![]() |
b305b8d8c5 | ||
![]() |
a8603d66dc | ||
![]() |
fda3704a03 | ||
![]() |
6258dee96b | ||
![]() |
6334144f81 | ||
![]() |
4696fbff4a | ||
![]() |
8679b70b4c | ||
![]() |
56beb0ddce | ||
![]() |
8bf23e8087 | ||
![]() |
6bdfe77c80 | ||
![]() |
15c785d298 | ||
![]() |
577582ee0b | ||
![]() |
60ab8f87e9 | ||
![]() |
4420ae1996 | ||
![]() |
778046439c | ||
![]() |
be47c35cba | ||
![]() |
a51a855870 |
52
Changelog
52
Changelog
@@ -1,3 +1,55 @@
|
||||
* Sat Oct 31 2015 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.2.5
|
||||
- BUGFIX: Fix difficult to reproduce crash. (glassez)
|
||||
- OTHER: Fix Windows' Qt5 build. (Gelmir)
|
||||
|
||||
* Sat Oct 10 2015 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.2.4
|
||||
- FEATURE: Select the file of single file torrents when opening destination folder (pmzqla)
|
||||
- BUGFIX: Fix crash with invalid favicon. Closes #3632. (glassez)
|
||||
- BUGFIX: Try to download favicon.png when the download of favicon.ico fails (pmzqla)
|
||||
- BUGFIX: Try to avoid loading a corrupted configuration file. Also log errors encountered while saving/loading the configuration. Closes #3503. (sledgehammer999)
|
||||
- BUGFIX: Allow adding torrent link from Torcache (jsayol)
|
||||
- BUGFIX: Don't limit the number of torrents that can be announced to the tracker/dht/lsd. Closes #3473. (sledgehammer999)
|
||||
- BUGFIX: Fix potential crash when memory allocation failed. Closes #3877. (Chocobo1)
|
||||
- COSMETIC: Change Queue buttons order in the Toolbar (GUI & Web UI) (ngosang)
|
||||
- COSMETIC: Move option "Ignore transfer limits on local network" to Speed page (Chocobo1)
|
||||
- COSMETIC: Move option "Confirm torrent deletion" to Behavior page (Chocobo1)
|
||||
- COSMETIC: Fix typos. Make `μTP` untranslatable. Use American variation of words. Closes #3654. (sledgehammer999)
|
||||
- COSMETIC: Optimize text color for dark themes. Closes #3633 and #3815. (sledgehammer999)
|
||||
- COSMETIC: Show current label in the torrent context menu. Closes #3776. (sledgehammer999)
|
||||
- WEBUI: Add save_path to /query/torrents (Casey Bodley)
|
||||
- WEBUI: Bump API_VERSION to 5
|
||||
- SEARCH: Fix python detection when the 'Anaconda' software is installed. Closes #3731. (sledgehammer999)
|
||||
- RSS: Handle magnet links as torrents instead of news URLs. Closes #3560 (ngosang)
|
||||
- RSS: Trim elements text in RSS articles (ngosang)
|
||||
- RSS: Fix contextual menu in RSS torrents list (ngosang)
|
||||
- RSS: Improve error handling when a RSS feed doesn't contain torrents (ngosang)
|
||||
- RSS: More precise message and code simplification in RSS feeds deletion (ngosang)
|
||||
- RSS: Don't hide the elements in Unread list when clicked (ngosang)
|
||||
- RSS: Allow multiple selection in RSS torrents list (ngosang)
|
||||
- RSS: Simplify string translation (ngosang)
|
||||
- RSS: Handle more types of RSS feeds (ngosang)
|
||||
- RSS: Fix RSS panel position not saved (ngosang)
|
||||
- RSS: Fix forgetting label changes to first item in RSS rule list. (Gelmir)
|
||||
- RSS: Add label to UI when a new one is creating during rule addition. (Gelmir)
|
||||
- RSS: Removes refresh message when adding a new feed (ngosang)
|
||||
- RSS: Fix RSS crash when deleting RSS feeds. Closes #997, #2152, #2461, #3718, #3747, #3766, #3806, #3814, #3829 and #3846. (ngosang)
|
||||
- RSS: Sort labels in RSS Downloader dialog, closes #3140. (Chocobo1)
|
||||
- WINDOWS: Correctly show german letters in the installer. Closes #3574, #3566. (sledgehammer999)
|
||||
- WINDOWS: Fix file selection on Explorer when the filename contains weird characters. Closes #3185. (sledgehammer999)
|
||||
- WINDOWS: Fix wrong default download directory in Windows. Closes #2625. (Chocobo1)
|
||||
- WINDOWS: Fix German translation of the installer. (netswap)
|
||||
- LINUX: Fix broken .desktop file icon for some locales. See #3905. (sledgehammer999)
|
||||
- OTHER: Fix ppc64le detection during configure (sledgehammer999)
|
||||
- OTHER: Don't use sed in configure. Closes #3169. (pmzqla)
|
||||
- OTHER: Fix broken donation link. Closes #3771. (sledgehammer999)
|
||||
- OTHER: Add forum link in README. Closes #3853. (sledgehammer999)
|
||||
- OTHER: New translation: Esperanto
|
||||
- OTHER: Fix Qt5 nox build on non-Windows. (sledgehammer999)
|
||||
|
||||
* Sun Aug 02 2015 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.2.3
|
||||
- BUGFIX: Fix crash when closing a search tab while search is running (pmzqla)
|
||||
- SEARCH: Other minor search fixes and improvements (pmzqla)
|
||||
|
||||
* Sat Aug 01 2015 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.2.2
|
||||
- FEATURE: Allow to force reannounce DHT too (Chocobo1)
|
||||
- FEATURE: Implement an option to disable confirmation of torrent recheck (blaxspirit)
|
||||
|
4
INSTALL
4
INSTALL
@@ -14,7 +14,7 @@ qBittorrent - A BitTorrent client in C++ / Qt4
|
||||
|
||||
- pkg-config executable
|
||||
|
||||
- libtorrent-rasterbar by Arvid Norberg (>= 0.15.0)
|
||||
- libtorrent-rasterbar by Arvid Norberg (>= 0.16.19 OR >= 1.0.6)
|
||||
-> http://www.libtorrent.net
|
||||
Be careful: another library (the one used by rTorrent) uses a similar name.
|
||||
|
||||
@@ -44,7 +44,7 @@ qBittorrent - A BitTorrent client in C++ / Qt4
|
||||
|
||||
- pkg-config executable
|
||||
|
||||
- libtorrent-rasterbar by Arvid Norberg (>= v0.15.0)
|
||||
- libtorrent-rasterbar by Arvid Norberg (>= 0.16.19 OR >= v1.0.6)
|
||||
-> http://www.libtorrent.net
|
||||
Be careful: another library (the one used by rTorrent) uses a similar name.
|
||||
|
||||
|
@@ -32,6 +32,9 @@ http://www.qbittorrent.org
|
||||
or our wiki here:
|
||||
http://wiki.qbittorrent.org
|
||||
|
||||
Use the forum for troubleshooting before reporting bugs:
|
||||
http://forum.qbittorrent.org
|
||||
|
||||
Please report any bug (or feature request) to:
|
||||
http://bugs.qbittorrent.org
|
||||
|
||||
|
5
configure
vendored
5
configure
vendored
@@ -5808,8 +5808,11 @@ extract() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# BSD sed needs an actual newline character in the substitute command
|
||||
new_line='
|
||||
'
|
||||
# Convert " -" to "\n" if not between quotes and remove possible leading white spaces
|
||||
string=$(echo " $*" | $SED -e 's: -:\n: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
|
||||
|
@@ -258,8 +258,11 @@ extract() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# BSD sed needs an actual newline character in the substitute command
|
||||
new_line='
|
||||
'
|
||||
# Convert " -" to "\n" if not between quotes and remove possible leading white spaces
|
||||
string=$(echo " $*" | $SED -e 's: -:\n: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
|
||||
|
2
dist/mac/Info.plist
vendored
2
dist/mac/Info.plist
vendored
@@ -45,7 +45,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.2.2</string>
|
||||
<string>3.2.5</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>qBit</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
;Installer strings
|
||||
;Installer strings
|
||||
|
||||
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_GERMAN} "qBittorrent (erforderlich)"
|
||||
@@ -44,6 +44,6 @@ LangString remove_cache ${LANG_GERMAN} "Torrents und zwischengespeicherte Daten
|
||||
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_GERMAN} "qBittorrent läuft gerade. Bitte das Programm vor der Deinstallation beenden."
|
||||
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_GERMAN} "Dateiverknüfung mit .torrent-Dateien konnte nicht entfernt werden, da dieser Typ mit diesem Programm verknüpft ist:"
|
||||
LangString uninst_tor_warn ${LANG_GERMAN} "Dateiverknüpfung mit .torrent-Dateien konnte nicht entfernt werden, da dieser Typ mit diesem Programm verknüpft ist:"
|
||||
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_GERMAN} "Dateiverknüfung mit Magnet-Links konnte nicht entfernt werden, da dieser Typ mit diesem Programm verknüpft ist:"
|
||||
LangString uninst_mag_warn ${LANG_GERMAN} "Dateiverknüpfung mit Magnet-Links konnte nicht entfernt werden, da dieser Typ mit diesem Programm verknüpft ist:"
|
||||
|
2
dist/windows/options.nsi
vendored
2
dist/windows/options.nsi
vendored
@@ -19,7 +19,7 @@ XPStyle on
|
||||
!define CSIDL_APPDATA '0x1A' ;Application Data path
|
||||
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
|
||||
|
||||
!define PROG_VERSION "3.2.2"
|
||||
!define PROG_VERSION "3.2.5"
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
|
||||
!define MUI_FINISHPAGE_RUN_TEXT $(launch_qbt)
|
||||
|
@@ -33,7 +33,7 @@
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 23
|
||||
#serial 26
|
||||
|
||||
AC_DEFUN([AX_BOOST_BASE],
|
||||
[
|
||||
@@ -92,8 +92,11 @@ if test "x$want_boost" = "xyes"; then
|
||||
libsubdirs="lib"
|
||||
ax_arch=`uname -m`
|
||||
case $ax_arch in
|
||||
x86_64|ppc64|s390x|sparc64|aarch64)
|
||||
libsubdirs="lib64 lib lib64"
|
||||
x86_64)
|
||||
libsubdirs="lib64 libx32 lib lib64"
|
||||
;;
|
||||
ppc64|s390x|sparc64|aarch64|ppc64le)
|
||||
libsubdirs="lib64 lib lib64 ppc64le"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -170,6 +173,10 @@ if test "x$want_boost" = "xyes"; then
|
||||
dnl if we found no boost with system layout we search for boost libraries
|
||||
dnl built and installed without the --layout=system option or for a staged(not installed) version
|
||||
if test "x$succeeded" != "xyes"; then
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
BOOST_CPPFLAGS=
|
||||
BOOST_LDFLAGS=
|
||||
_version=0
|
||||
if test "$ac_boost_path" != ""; then
|
||||
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
|
||||
@@ -182,6 +189,12 @@ if test "x$want_boost" = "xyes"; then
|
||||
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
|
||||
done
|
||||
dnl if nothing found search for layout used in Windows distributions
|
||||
if test -z "$BOOST_CPPFLAGS"; then
|
||||
if test -d "$ac_boost_path/boost" && test -r "$ac_boost_path/boost"; then
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if test "$cross_compiling" != yes; then
|
||||
|
@@ -193,6 +193,8 @@ QNetworkReply* DownloadThread::downloadUrl(const QString &url, const QList<QNetw
|
||||
QNetworkRequest request(qurl);
|
||||
// Spoof Firefox 38 user agent to avoid web server banning
|
||||
request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 Firefox/38.0");
|
||||
// Spoof HTTP Referer to allow adding torrent link from Torcache/KickAssTorrents
|
||||
request.setRawHeader("Referer", request.url().toEncoded().data());
|
||||
qDebug("Downloading %s...", request.url().toEncoded().data());
|
||||
qDebug("%d cookies for this URL", m_networkManager.cookieJar()->cookiesForUrl(url).size());
|
||||
for (int i=0; i<m_networkManager.cookieJar()->cookiesForUrl(url).size(); ++i) {
|
||||
@@ -276,7 +278,7 @@ QString DownloadThread::errorCodeToString(QNetworkReply::NetworkError status) {
|
||||
case QNetworkReply::ProxyTimeoutError:
|
||||
return tr("The connection to the proxy timed out or the proxy did not reply in time to the request sent");
|
||||
case QNetworkReply::ProxyAuthenticationRequiredError:
|
||||
return tr("The proxy requires authentication in order to honour the request but did not accept any credentials offered");
|
||||
return tr("The proxy requires authentication in order to honor the request but did not accept any credentials offered");
|
||||
case QNetworkReply::ContentAccessDenied:
|
||||
return tr("The access to the remote content was denied (401)");
|
||||
case QNetworkReply::ContentOperationNotPermittedError:
|
||||
|
@@ -62,13 +62,15 @@
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
#include <QDesktopServices>
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include <QStandardPaths>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
@@ -464,62 +466,76 @@ QString fsutils::QDesktopServicesCacheLocation() {
|
||||
return result;
|
||||
}
|
||||
|
||||
QString fsutils::QDesktopServicesDownloadLocation() {
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
|
||||
// as long as it stays WinXP like we do the same on OS/2
|
||||
// TODO: Use IKnownFolderManager to get path of FOLDERID_Downloads
|
||||
// instead of hardcoding "Downloads"
|
||||
// Unfortunately, this would break compatibility with WinXP
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
|
||||
return QDir(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)).absoluteFilePath(
|
||||
QCoreApplication::translate("fsutils", "Downloads"));
|
||||
#else
|
||||
return QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).absoluteFilePath(
|
||||
QCoreApplication::translate("fsutils", "Downloads"));
|
||||
QString fsutils::QDesktopServicesDownloadLocation()
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
||||
#if defined(Q_OS_WIN)
|
||||
if (QSysInfo::windowsVersion() <= QSysInfo::WV_XP) // Windows XP
|
||||
return QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).absoluteFilePath(
|
||||
QCoreApplication::translate("fsutils", "Downloads"));
|
||||
#endif
|
||||
return QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
|
||||
#else
|
||||
|
||||
#if defined(Q_OS_OS2)
|
||||
return QDir(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)).absoluteFilePath(
|
||||
QCoreApplication::translate("fsutils", "Downloads"));
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
// as long as it stays WinXP like we do the same on OS/2
|
||||
// TODO: Use IKnownFolderManager to get path of FOLDERID_Downloads
|
||||
// instead of hardcoding "Downloads"
|
||||
// Unfortunately, this would break compatibility with WinXP
|
||||
if (QSysInfo::windowsVersion() <= QSysInfo::WV_XP) // Windows XP
|
||||
return QDir(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)).absoluteFilePath(
|
||||
QCoreApplication::translate("fsutils", "Downloads"));
|
||||
else
|
||||
return QDir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation)).absoluteFilePath("Downloads");
|
||||
#endif
|
||||
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
QString save_path;
|
||||
// Default save path on Linux
|
||||
QString config_path = QString::fromLocal8Bit(qgetenv("XDG_CONFIG_HOME").constData());
|
||||
if (config_path.isEmpty())
|
||||
config_path = QDir::home().absoluteFilePath(".config");
|
||||
QString save_path;
|
||||
// Default save path on Linux
|
||||
QString config_path = QString::fromLocal8Bit(qgetenv("XDG_CONFIG_HOME").constData());
|
||||
if (config_path.isEmpty())
|
||||
config_path = QDir::home().absoluteFilePath(".config");
|
||||
|
||||
QString user_dirs_file = config_path + "/user-dirs.dirs";
|
||||
if (QFile::exists(user_dirs_file)) {
|
||||
QSettings settings(user_dirs_file, QSettings::IniFormat);
|
||||
// We need to force UTF-8 encoding here since this is not
|
||||
// the default for Ini files.
|
||||
settings.setIniCodec("UTF-8");
|
||||
QString xdg_download_dir = settings.value("XDG_DOWNLOAD_DIR").toString();
|
||||
if (!xdg_download_dir.isEmpty()) {
|
||||
// Resolve $HOME environment variables
|
||||
xdg_download_dir.replace("$HOME", QDir::homePath());
|
||||
save_path = xdg_download_dir;
|
||||
qDebug() << Q_FUNC_INFO << "SUCCESS: Using XDG path for downloads: " << save_path;
|
||||
QString user_dirs_file = config_path + "/user-dirs.dirs";
|
||||
if (QFile::exists(user_dirs_file)) {
|
||||
QSettings settings(user_dirs_file, QSettings::IniFormat);
|
||||
// We need to force UTF-8 encoding here since this is not
|
||||
// the default for Ini files.
|
||||
settings.setIniCodec("UTF-8");
|
||||
QString xdg_download_dir = settings.value("XDG_DOWNLOAD_DIR").toString();
|
||||
if (!xdg_download_dir.isEmpty()) {
|
||||
// Resolve $HOME environment variables
|
||||
xdg_download_dir.replace("$HOME", QDir::homePath());
|
||||
save_path = xdg_download_dir;
|
||||
qDebug() << Q_FUNC_INFO << "SUCCESS: Using XDG path for downloads: " << save_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
if (!save_path.isEmpty() && !QFile::exists(save_path)) {
|
||||
QDir().mkpath(save_path);
|
||||
}
|
||||
// Fallback
|
||||
if (!save_path.isEmpty() && !QFile::exists(save_path)) {
|
||||
QDir().mkpath(save_path);
|
||||
}
|
||||
|
||||
if (save_path.isEmpty() || !QFile::exists(save_path)) {
|
||||
save_path = QDir::home().absoluteFilePath(QCoreApplication::translate("fsutils", "Downloads"));
|
||||
qDebug() << Q_FUNC_INFO << "using" << save_path << "as fallback since the XDG detection did not work";
|
||||
}
|
||||
if (save_path.isEmpty() || !QFile::exists(save_path)) {
|
||||
save_path = QDir::home().absoluteFilePath(QCoreApplication::translate("fsutils", "Downloads"));
|
||||
qDebug() << Q_FUNC_INFO << "using" << save_path << "as fallback since the XDG detection did not work";
|
||||
}
|
||||
|
||||
return save_path;
|
||||
return save_path;
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
// TODO: How to support this on Mac OS X?
|
||||
#if defined(Q_OS_MAC)
|
||||
// TODO: How to support this on Mac OS?
|
||||
#endif
|
||||
|
||||
// Fallback
|
||||
return QDir::home().absoluteFilePath(QCoreApplication::translate("fsutils", "Downloads"));
|
||||
// Fallback
|
||||
return QDir::home().absoluteFilePath(QCoreApplication::translate("fsutils", "Downloads"));
|
||||
#endif
|
||||
}
|
||||
|
||||
QString fsutils::searchEngineLocation() {
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include "core/unicodestrings.h"
|
||||
#include "core/logger.h"
|
||||
#include "misc.h"
|
||||
#include "fs_utils.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
@@ -52,6 +53,11 @@
|
||||
#include <QDesktopWidget>
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
#include <QDesktopServices>
|
||||
#include <QProcess>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
#include <PowrProf.h>
|
||||
@@ -332,9 +338,15 @@ QString misc::pythonVersionComplete() {
|
||||
QByteArray output = pythonProc.readAllStandardOutput();
|
||||
if (output.isEmpty())
|
||||
output = pythonProc.readAllStandardError();
|
||||
const QByteArray versionStr = output.split(' ').last();
|
||||
version = versionStr.trimmed();
|
||||
Logger::instance()->addMessage(QCoreApplication::translate("misc", "Python version: %1").arg(version), Log::INFO);
|
||||
|
||||
// Software 'Anaconda' installs its own python interpreter
|
||||
// and `python --version` returns a string like this:
|
||||
// `Python 3.4.3 :: Anaconda 2.3.0 (64-bit)`
|
||||
const QList<QByteArray> verSplit = output.split(' ');
|
||||
if (verSplit.size() > 1) {
|
||||
version = verSplit.at(1).trimmed();
|
||||
Logger::instance()->addMessage(QCoreApplication::translate("misc", "Python version: %1").arg(version), Log::INFO);
|
||||
}
|
||||
}
|
||||
}
|
||||
return version;
|
||||
@@ -592,7 +604,7 @@ QString misc::toQString(time_t t, Qt::DateFormat f)
|
||||
}
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
bool misc::naturalSort(QString left, QString right, bool &result) // uses lessThan comparison
|
||||
bool misc::naturalSort(const QString &left, const QString &right, bool &result) // uses lessThan comparison
|
||||
{ // Return value indicates if functions was successful
|
||||
// result argument will contain actual comparison result if function was successful
|
||||
int posL = 0;
|
||||
@@ -651,6 +663,83 @@ bool misc::naturalSort(QString left, QString right, bool &result) // uses less
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
misc::NaturalCompare::NaturalCompare()
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
|
||||
#if defined(Q_OS_WIN)
|
||||
// Without ICU library, QCollator doesn't support `setNumericMode(true)` on OS older than Win7
|
||||
if(QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7)
|
||||
return;
|
||||
#endif
|
||||
m_collator.setNumericMode(true);
|
||||
m_collator.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool misc::NaturalCompare::operator()(const QString &l, const QString &r)
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
|
||||
#if defined(Q_OS_WIN)
|
||||
// Without ICU library, QCollator doesn't support `setNumericMode(true)` on OS older than Win7
|
||||
if(QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7)
|
||||
return lessThan(l, r);
|
||||
#endif
|
||||
return (m_collator.compare(l, r) < 0);
|
||||
#else
|
||||
return lessThan(l, r);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool misc::NaturalCompare::lessThan(const QString &left, const QString &right)
|
||||
{
|
||||
// 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 = left[posL].toLower();
|
||||
QChar rightChar = 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;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
|
||||
int numL = left.midRef(startL, posL - startL).toInt();
|
||||
#else
|
||||
int numL = left.mid(startL, posL - startL).toInt();
|
||||
#endif
|
||||
|
||||
int startR = posR;
|
||||
while ((posR < right.size()) && right[posR].isDigit())
|
||||
++posR;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
|
||||
int numR = right.midRef(startR, posR - startR).toInt();
|
||||
#else
|
||||
int numR = right.mid(startR, posR - startR).toInt();
|
||||
#endif
|
||||
|
||||
if (numL != numR)
|
||||
return (numL < numR);
|
||||
|
||||
// Strings + digits do match and we haven't hit string end
|
||||
// Do another round
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// to send numbers instead of strings with suffixes
|
||||
@@ -692,6 +781,90 @@ void misc::loadBencodedFile(const QString &filename, std::vector<char> &buffer,
|
||||
lazy_bdecode(&buffer[0], &buffer[0] + buffer.size(), entry, ec);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
// Open the given path with an appropriate application
|
||||
void misc::openPath(const QString& absolutePath)
|
||||
{
|
||||
const QString path = fsutils::fromNativePath(absolutePath);
|
||||
// Hack to access samba shares with QDesktopServices::openUrl
|
||||
if (path.startsWith("//"))
|
||||
QDesktopServices::openUrl(fsutils::toNativePath("file:" + path));
|
||||
else
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||
}
|
||||
|
||||
// Open the parent directory of the given path with a file manager and select
|
||||
// (if possible) the item at the given path
|
||||
void misc::openFolderSelect(const QString& absolutePath)
|
||||
{
|
||||
const QString path = fsutils::fromNativePath(absolutePath);
|
||||
#ifdef Q_OS_WIN
|
||||
if (QFileInfo(path).exists()) {
|
||||
// Syntax is: explorer /select, "C:\Folder1\Folder2\file_to_select"
|
||||
// Dir separators MUST be win-style slashes
|
||||
|
||||
// QProcess::startDetached() has an obscure bug. If the path has
|
||||
// no spaces and a comma(and maybe other special characters) it doesn't
|
||||
// get wrapped in quotes. So explorer.exe can't find the correct path and
|
||||
// displays the default one. If we wrap the path in quotes and pass it to
|
||||
// QProcess::startDetached() explorer.exe still shows the default path. In
|
||||
// this case QProcess::startDetached() probably puts its own quotes around ours.
|
||||
|
||||
STARTUPINFO startupInfo;
|
||||
::ZeroMemory(&startupInfo, sizeof(startupInfo));
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
PROCESS_INFORMATION processInfo;
|
||||
::ZeroMemory(&processInfo, sizeof(processInfo));
|
||||
|
||||
QString cmd = QString("explorer.exe /select,\"%1\"").arg(fsutils::toNativePath(absolutePath));
|
||||
LPWSTR lpCmd = new WCHAR[cmd.size() + 1];
|
||||
cmd.toWCharArray(lpCmd);
|
||||
lpCmd[cmd.size()] = 0;
|
||||
|
||||
bool ret = ::CreateProcessW(NULL, lpCmd, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
|
||||
delete [] lpCmd;
|
||||
|
||||
if (ret) {
|
||||
::CloseHandle(processInfo.hProcess);
|
||||
::CloseHandle(processInfo.hThread);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If the item to select doesn't exist, try to open its parent
|
||||
openPath(path.left(path.lastIndexOf("/")));
|
||||
}
|
||||
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
|
||||
if (QFileInfo(path).exists()) {
|
||||
QProcess proc;
|
||||
QString output;
|
||||
proc.start("xdg-mime", QStringList() << "query" << "default" << "inode/directory");
|
||||
proc.waitForFinished();
|
||||
output = proc.readLine().simplified();
|
||||
if (output == "dolphin.desktop" || output == "org.kde.dolphin.desktop")
|
||||
proc.startDetached("dolphin", QStringList() << "--select" << fsutils::toNativePath(path));
|
||||
else if (output == "nautilus.desktop" || output == "org.gnome.Nautilus.desktop"
|
||||
|| output == "nautilus-folder-handler.desktop")
|
||||
proc.startDetached("nautilus", QStringList() << "--no-desktop" << fsutils::toNativePath(path));
|
||||
else if (output == "caja-folder-handler.desktop")
|
||||
proc.startDetached("caja", QStringList() << "--no-desktop" << fsutils::toNativePath(path));
|
||||
else if (output == "nemo.desktop")
|
||||
proc.startDetached("nemo", QStringList() << "--no-desktop" << fsutils::toNativePath(path));
|
||||
else if (output == "konqueror.desktop" || output == "kfmclient_dir.desktop")
|
||||
proc.startDetached("konqueror", QStringList() << "--select" << fsutils::toNativePath(path));
|
||||
else
|
||||
openPath(path.left(path.lastIndexOf("/")));
|
||||
}
|
||||
else {
|
||||
// If the item to select doesn't exist, try to open its parent
|
||||
openPath(path.left(path.lastIndexOf("/")));
|
||||
}
|
||||
#else
|
||||
openPath(path.left(path.lastIndexOf("/")));
|
||||
#endif
|
||||
}
|
||||
#endif // DISABLE_GUI
|
||||
|
||||
namespace {
|
||||
// Trick to get a portable sleep() function
|
||||
class SleeperThread: public QThread {
|
||||
|
@@ -41,6 +41,9 @@
|
||||
#include <QUrl>
|
||||
#ifndef DISABLE_GUI
|
||||
#include <QIcon>
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
|
||||
#include <QCollator>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
@@ -106,7 +109,19 @@ namespace misc
|
||||
QString accurateDoubleToString(const double &n, const int &precision);
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
bool naturalSort(QString left, QString right, bool& result);
|
||||
bool naturalSort(const QString &left, const QString &right, bool &result);
|
||||
|
||||
class NaturalCompare
|
||||
{
|
||||
public:
|
||||
NaturalCompare();
|
||||
bool operator()(const QString &l, const QString &r);
|
||||
bool lessThan(const QString &left, const QString &right);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
|
||||
private:
|
||||
QCollator m_collator;
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
// Implements constant-time comparison to protect against timing attacks
|
||||
@@ -114,6 +129,11 @@ namespace misc
|
||||
bool slowEquals(const QByteArray &a, const QByteArray &b);
|
||||
void loadBencodedFile(const QString &filename, std::vector<char> &buffer, libtorrent::lazy_entry &entry, libtorrent::error_code &ec);
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
void openPath(const QString& absolutePath);
|
||||
void openFolderSelect(const QString& absolutePath);
|
||||
#endif
|
||||
|
||||
void msleep(unsigned long msecs);
|
||||
}
|
||||
|
||||
|
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "preferences.h"
|
||||
#include "qinisettings.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QPair>
|
||||
@@ -67,12 +68,12 @@ Preferences::Preferences()
|
||||
QStringList keys = settings_new->allKeys();
|
||||
bool use_new = false;
|
||||
|
||||
|
||||
// This means that the PC closed either due to power outage
|
||||
// or because the disk was full. In any case the settings weren't transfered
|
||||
// in their final position. So assume that qbittorrent_new.ini/qbittorrent_new.conf
|
||||
// contains the most recent settings.
|
||||
if (!keys.isEmpty()) {
|
||||
Logger::instance()->addMessage(tr("Detected unclean program exit. Using fallback file to restore settings."), Log::WARNING);
|
||||
use_new = true;
|
||||
dirty = true;
|
||||
}
|
||||
@@ -100,7 +101,9 @@ Preferences::Preferences()
|
||||
//Ensures sync to disk before we attempt to manipulate the files from save().
|
||||
delete settings;
|
||||
#ifndef Q_OS_MAC
|
||||
QString new_path = settings_new->fileName();
|
||||
delete settings_new;
|
||||
fsutils::forceRemove(new_path);
|
||||
|
||||
if (use_new)
|
||||
save();
|
||||
@@ -134,7 +137,7 @@ void Preferences::drop()
|
||||
|
||||
void Preferences::save()
|
||||
{
|
||||
QReadLocker locker(&lock);
|
||||
QWriteLocker locker(&lock);
|
||||
|
||||
if (!dirty)
|
||||
return;
|
||||
@@ -158,11 +161,19 @@ void Preferences::save()
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
settings->sync(); // Important to get error status
|
||||
if (settings->status() == QSettings::AccessError) {
|
||||
QString new_path = settings->fileName();
|
||||
QSettings::Status status = settings->status();
|
||||
|
||||
if (status != QSettings::NoError) {
|
||||
if (status == QSettings::AccessError)
|
||||
Logger::instance()->addMessage(tr("An access error occurred while trying to write the configuration file."), Log::CRITICAL);
|
||||
else
|
||||
Logger::instance()->addMessage(tr("A format error occurred while trying to write the configuration file."), Log::CRITICAL);
|
||||
|
||||
delete settings;
|
||||
fsutils::forceRemove(new_path);
|
||||
return;
|
||||
}
|
||||
QString new_path = settings->fileName();
|
||||
delete settings;
|
||||
QString final_path = new_path;
|
||||
int index = final_path.lastIndexOf("_new", -1, Qt::CaseInsensitive);
|
||||
@@ -1417,12 +1428,12 @@ void Preferences::setOutgoingPortsMax(uint val)
|
||||
setValue("Preferences/Advanced/OutgoingPortsMax", val);
|
||||
}
|
||||
|
||||
bool Preferences::ignoreLimitsOnLAN() const
|
||||
bool Preferences::getIgnoreLimitsOnLAN() const
|
||||
{
|
||||
return value("Preferences/Advanced/IgnoreLimitsLAN", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::ignoreLimitsOnLAN(bool ignore)
|
||||
void Preferences::setIgnoreLimitsOnLAN(bool ignore)
|
||||
{
|
||||
setValue("Preferences/Advanced/IgnoreLimitsLAN", ignore);
|
||||
}
|
||||
@@ -1594,6 +1605,13 @@ void Preferences::setTorrentLabels(const QStringList& labels)
|
||||
setValue("TransferListFilters/customLabels", labels);
|
||||
}
|
||||
|
||||
void Preferences::addTorrentLabelExternal(const QString &label)
|
||||
{
|
||||
addTorrentLabel(label);
|
||||
QString toEmit = label;
|
||||
emit externalLabelAdded(toEmit);
|
||||
}
|
||||
|
||||
void Preferences::addTorrentLabel(const QString& label)
|
||||
{
|
||||
QStringList labels = value("TransferListFilters/customLabels").toStringList();
|
||||
@@ -2197,36 +2215,36 @@ void Preferences::setRssOpenFolders(const QStringList &folders)
|
||||
QByteArray Preferences::getRssHSplitterState() const
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
||||
return value("rss/qt5/splitter_h").toByteArray();
|
||||
return value("Rss/qt5/splitter_h").toByteArray();
|
||||
#else
|
||||
return value("rss/splitter_h").toByteArray();
|
||||
return value("Rss/splitter_h").toByteArray();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Preferences::setRssHSplitterState(const QByteArray &state)
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
||||
setValue("rss/qt5/splitter_h", state);
|
||||
setValue("Rss/qt5/splitter_h", state);
|
||||
#else
|
||||
setValue("rss/splitter_h", state);
|
||||
setValue("Rss/splitter_h", state);
|
||||
#endif
|
||||
}
|
||||
|
||||
QByteArray Preferences::getRssVSplitterState() const
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
||||
return value("rss/qt5/splitter_v").toByteArray();
|
||||
return value("Rss/qt5/splitter_v").toByteArray();
|
||||
#else
|
||||
return value("rss/splitter_v").toByteArray();
|
||||
return value("Rss/splitter_v").toByteArray();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Preferences::setRssVSplitterState(const QByteArray &state)
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
||||
setValue("rss/qt5/splitter_v", state);
|
||||
setValue("Rss/qt5/splitter_v", state);
|
||||
#else
|
||||
setValue("rss/splitter_v", state);
|
||||
setValue("Rss/splitter_v", state);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -113,6 +113,7 @@ private:
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
void externalLabelAdded(QString&);
|
||||
|
||||
public slots:
|
||||
void save();
|
||||
@@ -367,8 +368,8 @@ public:
|
||||
void setOutgoingPortsMin(uint val);
|
||||
uint outgoingPortsMax() const;
|
||||
void setOutgoingPortsMax(uint val);
|
||||
bool ignoreLimitsOnLAN() const;
|
||||
void ignoreLimitsOnLAN(bool ignore);
|
||||
bool getIgnoreLimitsOnLAN() const;
|
||||
void setIgnoreLimitsOnLAN(bool ignore);
|
||||
bool includeOverheadInLimits() const;
|
||||
void includeOverheadInLimits(bool include);
|
||||
bool trackerExchangeEnabled() const;
|
||||
@@ -403,6 +404,7 @@ public:
|
||||
#endif
|
||||
QStringList getTorrentLabels() const;
|
||||
void setTorrentLabels(const QStringList& labels);
|
||||
void addTorrentLabelExternal(const QString &label);
|
||||
void addTorrentLabel(const QString& label);
|
||||
void removeTorrentLabel(const QString& label);
|
||||
bool recursiveDownloadDisabled() const;
|
||||
|
@@ -51,7 +51,7 @@ int FilterParserThread::parseDATFilterFile(QString filePath, libtorrent::ip_filt
|
||||
QFile file(filePath);
|
||||
if (file.exists()) {
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
|
||||
std::cerr << "I/O Error: Could not open ip filter file in read mode." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
unsigned int nbLine = 0;
|
||||
@@ -137,7 +137,7 @@ int FilterParserThread::parseP2PFilterFile(QString filePath, libtorrent::ip_filt
|
||||
QFile file(filePath);
|
||||
if (file.exists()) {
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
|
||||
std::cerr << "I/O Error: Could not open ip filter file in read mode." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
unsigned int nbLine = 0;
|
||||
@@ -229,7 +229,7 @@ int FilterParserThread::parseP2BFilterFile(QString filePath, libtorrent::ip_filt
|
||||
QFile file(filePath);
|
||||
if (file.exists()) {
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
|
||||
std::cerr << "I/O Error: Could not open ip filter file in read mode." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
QDataStream stream(&file);
|
||||
|
@@ -52,6 +52,7 @@
|
||||
#include "scannedfoldersmodel.h"
|
||||
#include "qtracker.h"
|
||||
#include "logger.h"
|
||||
#include "unicodestrings.h"
|
||||
#ifndef DISABLE_GUI
|
||||
#include "shutdownconfirm.h"
|
||||
#include "geoipmanager.h"
|
||||
@@ -449,23 +450,17 @@ void QBtSession::configureSession() {
|
||||
if (pref->isQueueingSystemEnabled()) {
|
||||
int max_downloading = pref->getMaxActiveDownloads();
|
||||
int max_active = pref->getMaxActiveTorrents();
|
||||
|
||||
if (max_downloading > -1)
|
||||
sessionSettings.active_downloads = max_downloading + HiddenData::getDownloadingSize();
|
||||
else
|
||||
sessionSettings.active_downloads = max_downloading;
|
||||
if (max_active > -1) {
|
||||
int limit = max_active + HiddenData::getDownloadingSize();
|
||||
sessionSettings.active_limit = limit;
|
||||
sessionSettings.active_tracker_limit = limit;
|
||||
sessionSettings.active_dht_limit = limit;
|
||||
sessionSettings.active_lsd_limit = limit;
|
||||
}
|
||||
else {
|
||||
|
||||
if (max_active > -1)
|
||||
sessionSettings.active_limit = max_active + HiddenData::getDownloadingSize();
|
||||
else
|
||||
sessionSettings.active_limit = max_active;
|
||||
sessionSettings.active_tracker_limit = max_active;
|
||||
sessionSettings.active_dht_limit = max_active;
|
||||
sessionSettings.active_lsd_limit = max_active;
|
||||
}
|
||||
|
||||
sessionSettings.active_seeds = pref->getMaxActiveUploads();
|
||||
sessionSettings.dont_count_slow_torrents = pref->ignoreSlowTorrentsForQueueing();
|
||||
setQueueingEnabled(true);
|
||||
@@ -473,16 +468,16 @@ void QBtSession::configureSession() {
|
||||
sessionSettings.active_downloads = -1;
|
||||
sessionSettings.active_seeds = -1;
|
||||
sessionSettings.active_limit = -1;
|
||||
sessionSettings.active_tracker_limit = -1;
|
||||
sessionSettings.active_dht_limit = -1;
|
||||
sessionSettings.active_lsd_limit = -1;
|
||||
setQueueingEnabled(false);
|
||||
}
|
||||
sessionSettings.active_tracker_limit = -1;
|
||||
sessionSettings.active_dht_limit = -1;
|
||||
sessionSettings.active_lsd_limit = -1;
|
||||
// Outgoing ports
|
||||
sessionSettings.outgoing_ports = std::make_pair(pref->outgoingPortsMin(), pref->outgoingPortsMax());
|
||||
// Ignore limits on LAN
|
||||
qDebug() << "Ignore limits on LAN" << pref->ignoreLimitsOnLAN();
|
||||
sessionSettings.ignore_limits_on_local_network = pref->ignoreLimitsOnLAN();
|
||||
qDebug() << "Ignore limits on LAN" << pref->getIgnoreLimitsOnLAN();
|
||||
sessionSettings.ignore_limits_on_local_network = pref->getIgnoreLimitsOnLAN();
|
||||
// Include overhead in transfer limits
|
||||
sessionSettings.rate_limit_ip_overhead = pref->includeOverheadInLimits();
|
||||
// IP address to announce to trackers
|
||||
@@ -1957,7 +1952,7 @@ void QBtSession::updateRatioTimer()
|
||||
|
||||
// Enable IP Filtering
|
||||
void QBtSession::enableIPFilter(const QString &filter_path, bool force) {
|
||||
qDebug("Enabling IPFiler");
|
||||
qDebug("Enabling IPFilter");
|
||||
if (!filterParser) {
|
||||
filterParser = new FilterParserThread(this, s);
|
||||
connect(filterParser.data(), SIGNAL(IPFilterParsed(int)), SLOT(handleIPFilterParsed(int)));
|
||||
@@ -2568,10 +2563,10 @@ void QBtSession::handlePeerBlockedAlert(libtorrent::peer_blocked_alert* p)
|
||||
reason = tr("because it has a low port.", "this peer was blocked because it has a low port.");
|
||||
break;
|
||||
case peer_blocked_alert::utp_disabled:
|
||||
reason = tr("because μTP is disabled.", "this peer was blocked because μTP is disabled.");
|
||||
reason = trUtf8("because %1 is disabled.", "this peer was blocked because uTP is disabled.").arg(QString::fromUtf8(C_UTP)); // don't translate μTP
|
||||
break;
|
||||
case peer_blocked_alert::tcp_disabled:
|
||||
reason = tr("because TCP is disabled.", "this peer was blocked because TCP is disabled.");
|
||||
reason = tr("because %1 is disabled.", "this peer was blocked because TCP is disabled.").arg("TCP"); // don't translate TCP
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -208,32 +208,36 @@ QIcon TorrentModelItem::getIconByState(State state) {
|
||||
}
|
||||
|
||||
QColor TorrentModelItem::getColorByState(State state) {
|
||||
// Color names taken from http://cloford.com/resources/colours/500col.htm
|
||||
bool dark = isDarkTheme();
|
||||
switch (state) {
|
||||
case STATE_DOWNLOADING:
|
||||
case STATE_DOWNLOADING_META:
|
||||
case STATE_FORCED_DL:
|
||||
return QColor(34, 139, 34); // Forest Green
|
||||
if (!dark)
|
||||
return QColor(34, 139, 34); // Forest Green
|
||||
else
|
||||
return QColor(50, 205, 50); // Lime Green
|
||||
case STATE_ALLOCATING:
|
||||
case STATE_STALLED_DL:
|
||||
case STATE_STALLED_UP:
|
||||
if (!dark)
|
||||
return QColor(0, 0, 0); // Black
|
||||
else
|
||||
return QColor(255, 255, 255); // White
|
||||
return QColor(204, 204, 204); // Gray 80
|
||||
case STATE_SEEDING:
|
||||
case STATE_FORCED_UP:
|
||||
if (!dark)
|
||||
return QColor(65, 105, 225); // Royal Blue
|
||||
else
|
||||
return QColor(100, 149, 237); // Cornflower Blue
|
||||
return QColor(99, 184, 255); // Steel Blue 1
|
||||
case STATE_PAUSED_DL:
|
||||
return QColor(250, 128, 114); // Salmon
|
||||
case STATE_PAUSED_UP:
|
||||
if (!dark)
|
||||
return QColor(0, 0, 139); // Dark Blue
|
||||
else
|
||||
return QColor(65, 105, 225); // Royal Blue
|
||||
return QColor(79, 148, 205); // Steel Blue 3
|
||||
case STATE_PAUSED_MISSING:
|
||||
return QColor(255, 0, 0); // red
|
||||
case STATE_QUEUED_DL:
|
||||
@@ -242,7 +246,10 @@ QColor TorrentModelItem::getColorByState(State state) {
|
||||
case STATE_CHECKING_DL:
|
||||
case STATE_QUEUED_CHECK:
|
||||
case STATE_QUEUED_FASTCHECK:
|
||||
return QColor(0, 128, 128); // Teal
|
||||
if (!dark)
|
||||
return QColor(0, 128, 128); // Teal
|
||||
else
|
||||
return QColor(0, 205, 205); // Cyan 3
|
||||
case STATE_INVALID:
|
||||
return QColor(255, 0, 0); // red
|
||||
default:
|
||||
|
@@ -38,9 +38,11 @@ const char C_INFINITY[] = "∞";
|
||||
const char C_UP[] = "▲";
|
||||
const char C_DOWN[] = "▼";
|
||||
const char C_COPYRIGHT[] = "©";
|
||||
const char C_UTP[] = "μTP";
|
||||
const char C_LOCALE_ENGLISH[] = "English";
|
||||
const char C_LOCALE_ENGLISH_AUSTRALIA[] = "English(Australia)";
|
||||
const char C_LOCALE_ENGLISH_UNITEDKINGDOM[] = "English(United Kingdom)";
|
||||
const char C_LOCALE_ESPERANTO[] = "Esperanto";
|
||||
const char C_LOCALE_FRENCH[] = "Français";
|
||||
const char C_LOCALE_GERMAN[] = "Deutsch";
|
||||
const char C_LOCALE_HUNGARIAN[] = "Magyar";
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -223,7 +223,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
|
||||
vboxLayout->addWidget(tabs);
|
||||
|
||||
prioSeparator = toolBar->insertSeparator(actionBottomPriority);
|
||||
prioSeparator = toolBar->insertSeparator(actionTopPriority);
|
||||
prioSeparatorMenu = menu_Edit->insertSeparator(actionTopPriority);
|
||||
|
||||
// Transfer list slots
|
||||
@@ -1558,7 +1558,7 @@ void MainWindow::handleUpdateCheckFinished(bool update_available, QString new_ve
|
||||
|
||||
void MainWindow::on_actionDonate_money_triggered()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl("http://sourceforge.net/donate/index.php?group_id=163414"));
|
||||
QDesktopServices::openUrl(QUrl("http://www.qbittorrent.org/donate"));
|
||||
}
|
||||
|
||||
void MainWindow::showConnectionSettings()
|
||||
|
@@ -131,10 +131,10 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionStart"/>
|
||||
<addaction name="actionPause"/>
|
||||
<addaction name="actionBottomPriority"/>
|
||||
<addaction name="actionDecreasePriority"/>
|
||||
<addaction name="actionIncreasePriority"/>
|
||||
<addaction name="actionTopPriority"/>
|
||||
<addaction name="actionIncreasePriority"/>
|
||||
<addaction name="actionDecreasePriority"/>
|
||||
<addaction name="actionBottomPriority"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionOptions"/>
|
||||
<addaction name="actionLock_qBittorrent"/>
|
||||
|
@@ -255,6 +255,16 @@
|
||||
<string>Transfer List</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="confirmDeletion">
|
||||
<property name="text">
|
||||
<string>Confirm when deleting torrents</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkAltRowColors">
|
||||
<property name="text">
|
||||
@@ -1679,6 +1689,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkLimitLocalPeerRate">
|
||||
<property name="text">
|
||||
<string>Apply rate limit to peers on LAN</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@@ -135,6 +135,7 @@ options_imp::options_imp(QWidget *parent):
|
||||
// Apply button is activated when a value is changed
|
||||
// General tab
|
||||
connect(comboI18n, SIGNAL(currentIndexChanged(int)), this, SLOT(enableApplyButton()));
|
||||
connect(confirmDeletion, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(checkAltRowColors, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(checkShowSystray, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(checkCloseToSystray, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
@@ -200,6 +201,7 @@ options_imp::options_imp(QWidget *parent):
|
||||
connect(checkuTP, SIGNAL(toggled(bool)), SLOT(enableApplyButton()));
|
||||
connect(checkLimituTPConnections, SIGNAL(toggled(bool)), SLOT(enableApplyButton()));
|
||||
connect(checkLimitTransportOverhead, SIGNAL(toggled(bool)), SLOT(enableApplyButton()));
|
||||
connect(checkLimitLocalPeerRate, SIGNAL(toggled(bool)), SLOT(enableApplyButton()));
|
||||
// Bittorrent tab
|
||||
connect(checkMaxConnecs, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(checkMaxConnecsPerTorrent, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
@@ -373,6 +375,7 @@ void options_imp::saveOptions() {
|
||||
|
||||
// General preferences
|
||||
pref->setLocale(locale);
|
||||
pref->setConfirmTorrentDeletion(confirmDeletion->isChecked());
|
||||
pref->setAlternatingRowColors(checkAltRowColors->isChecked());
|
||||
pref->setSystrayIntegration(systrayIntegration());
|
||||
pref->setTrayIconStyle(TrayIcon::Style(comboTrayIcon->currentIndex()));
|
||||
@@ -426,6 +429,7 @@ void options_imp::saveOptions() {
|
||||
pref->setuTPEnabled(checkuTP->isChecked());
|
||||
pref->setuTPRateLimited(checkLimituTPConnections->isChecked());
|
||||
pref->includeOverheadInLimits(checkLimitTransportOverhead->isChecked());
|
||||
pref->setIgnoreLimitsOnLAN(!checkLimitLocalPeerRate->isChecked());
|
||||
const QPair<int, int> alt_down_up_limit = getAltGlobalBandwidthLimits();
|
||||
pref->setAltGlobalDownloadLimit(alt_down_up_limit.first);
|
||||
pref->setAltGlobalUploadLimit(alt_down_up_limit.second);
|
||||
@@ -535,6 +539,7 @@ void options_imp::loadOptions() {
|
||||
// General preferences
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
setLocale(pref->getLocale());
|
||||
confirmDeletion->setChecked(pref->confirmTorrentDeletion());
|
||||
checkAltRowColors->setChecked(pref->useAlternatingRowColors());
|
||||
|
||||
checkShowSplash->setChecked(!pref->isSplashScreenDisabled());
|
||||
@@ -664,6 +669,7 @@ void options_imp::loadOptions() {
|
||||
checkuTP->setChecked(pref->isuTPEnabled());
|
||||
checkLimituTPConnections->setChecked(pref->isuTPRateLimited());
|
||||
checkLimitTransportOverhead->setChecked(pref->includeOverheadInLimits());
|
||||
checkLimitLocalPeerRate->setChecked(!pref->getIgnoreLimitsOnLAN());
|
||||
// Scheduler
|
||||
check_schedule->setChecked(pref->isSchedulerEnabled());
|
||||
schedule_from->setTime(pref->getSchedulerStartTime());
|
||||
@@ -1323,6 +1329,7 @@ QString options_imp::languageToLocalizedString(const QLocale &locale)
|
||||
return QString::fromUtf8(C_LOCALE_ENGLISH_UNITEDKINGDOM);
|
||||
return QString::fromUtf8(C_LOCALE_ENGLISH);
|
||||
}
|
||||
case QLocale::Esperanto: return QString::fromUtf8(C_LOCALE_ESPERANTO);
|
||||
case QLocale::French: return QString::fromUtf8(C_LOCALE_FRENCH);
|
||||
case QLocale::German: return QString::fromUtf8(C_LOCALE_GERMAN);
|
||||
case QLocale::Hungarian: return QString::fromUtf8(C_LOCALE_HUNGARIAN);
|
||||
|
@@ -59,24 +59,17 @@ std::vector<float> DownloadedPiecesBar::bitfieldToFloatVector(const libtorrent::
|
||||
// image.x(1) = pieces.x(1.7 >= x < 3.4)
|
||||
|
||||
for (int x = 0; x < reqSize; ++x) {
|
||||
|
||||
// don't use previously calculated value "ratio" here!!!
|
||||
// float cannot save irrational number like 7/9, if this number will be rounded up by std::ceil
|
||||
// give you x2 == pieces.size(), and index out of range: pieces[x2]
|
||||
// this code is safe, so keep that in mind when you try optimize more.
|
||||
// tested with size = 3000000ul
|
||||
|
||||
// R - real
|
||||
const float fromR = (x * vecin.size()) / (float)reqSize;
|
||||
const float toR = ((x + 1) * vecin.size()) / (float)reqSize;
|
||||
const float fromR = x * ratio;
|
||||
const float toR = (x + 1) * ratio;
|
||||
|
||||
// C - integer
|
||||
int fromC = fromR;// std::floor not needed
|
||||
int toC = std::ceil(toR);
|
||||
if (toC > vecin.size())
|
||||
--toC;
|
||||
|
||||
// position in pieces table
|
||||
// libtorrent::bitfield::m_size is unsigned int(31 bits), so qlonglong is not needed
|
||||
// tested with size = 3000000ul
|
||||
int x2 = fromC;
|
||||
|
||||
// little speed up for really big pieces table, 10K+ size
|
||||
@@ -88,7 +81,7 @@ std::vector<float> DownloadedPiecesBar::bitfieldToFloatVector(const libtorrent::
|
||||
// case when calculated range is (15.2 >= x < 15.7)
|
||||
if (x2 == toCMinusOne) {
|
||||
if (vecin[x2]) {
|
||||
value += toR - fromR;
|
||||
value += ratio;
|
||||
}
|
||||
++x2;
|
||||
}
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include "iconprovider.h"
|
||||
#include "qtorrenthandle.h"
|
||||
#include "logger.h"
|
||||
#include "unicodestrings.h"
|
||||
#include <QStandardItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QSet>
|
||||
@@ -460,7 +461,7 @@ QString PeerListWidget::getConnectionString(const peer_info& peer)
|
||||
#else
|
||||
if (peer.flags & peer_info::utp_socket) {
|
||||
#endif
|
||||
return QString::fromUtf8("μTP");
|
||||
return QString::fromUtf8(C_UTP);
|
||||
}
|
||||
|
||||
QString connection;
|
||||
@@ -578,7 +579,7 @@ void PeerListWidget::getFlags(const peer_info& peer, QString& flags, QString& to
|
||||
if (peer.flags & peer_info::utp_socket) {
|
||||
#endif
|
||||
flags += "P ";
|
||||
tooltip += QString::fromUtf8("μTP");
|
||||
tooltip += QString::fromUtf8(C_UTP);
|
||||
tooltip += ", ";
|
||||
}
|
||||
|
||||
|
@@ -28,6 +28,7 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
#include "pieceavailabilitybar.h"
|
||||
|
||||
//#include <QDebug>
|
||||
@@ -69,23 +70,17 @@ std::vector<float> PieceAvailabilityBar::intToFloatVector(const std::vector<int>
|
||||
|
||||
for (int x = 0; x < reqSize; ++x) {
|
||||
|
||||
// don't use previously calculated value "ratio" here!!!
|
||||
// float cannot save irrational number like 7/9, if this number will be rounded up by std::ceil
|
||||
// give you x2 == pieces.size(), and index out of range: pieces[x2]
|
||||
// this code is safe, so keep that in mind when you try optimize more.
|
||||
// tested with size = 3000000ul
|
||||
|
||||
// R - real
|
||||
const float fromR = (x * vecin.size()) / (float)reqSize;
|
||||
const float toR = ((x + 1) * vecin.size()) / (float)reqSize;
|
||||
const float fromR = x * ratio;
|
||||
const float toR = (x + 1) * ratio;
|
||||
|
||||
// C - integer
|
||||
int fromC = fromR;// std::floor not needed
|
||||
int toC = std::ceil(toR);
|
||||
if (toC > vecin.size())
|
||||
--toC;
|
||||
|
||||
// position in pieces table
|
||||
// libtorrent::bitfield::m_size is unsigned int(31 bits), so qlonglong is not needed
|
||||
// tested with size = 3000000ul
|
||||
int x2 = fromC;
|
||||
|
||||
// little speed up for really big pieces table, 10K+ size
|
||||
@@ -97,7 +92,7 @@ std::vector<float> PieceAvailabilityBar::intToFloatVector(const std::vector<int>
|
||||
// case when calculated range is (15.2 >= x < 15.7)
|
||||
if (x2 == toCMinusOne) {
|
||||
if (vecin[x2]) {
|
||||
value += (toR - fromR) * vecin[x2];
|
||||
value += ratio * vecin[x2];
|
||||
}
|
||||
++x2;
|
||||
}
|
||||
@@ -159,8 +154,11 @@ int PieceAvailabilityBar::mixTwoColors(int &rgb1, int &rgb2, float ratio)
|
||||
|
||||
void PieceAvailabilityBar::updateImage()
|
||||
{
|
||||
// qDebug() << "updateImageAv";
|
||||
QImage image2(width() - 2, 1, QImage::Format_RGB888);
|
||||
if (image2.isNull()) {
|
||||
qDebug() << "QImage image2() allocation failed, width():" << width();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pieces.empty()) {
|
||||
image2.fill(0xffffff);
|
||||
|
@@ -39,7 +39,6 @@
|
||||
#include <QMessageBox>
|
||||
#include <QMenu>
|
||||
#include <QFileDialog>
|
||||
#include <QDesktopServices>
|
||||
#include <libtorrent/version.hpp>
|
||||
#include "propertieswidget.h"
|
||||
#include "transferlistwidget.h"
|
||||
@@ -80,10 +79,10 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, Tra
|
||||
filesList->setItemDelegate(PropDelegate);
|
||||
filesList->setSortingEnabled(true);
|
||||
// Torrent content filtering
|
||||
m_contentFilerLine = new LineEdit(this);
|
||||
m_contentFilerLine->setPlaceholderText(tr("Filter files..."));
|
||||
connect(m_contentFilerLine, SIGNAL(textChanged(QString)), this, SLOT(filterText(QString)));
|
||||
contentFilterLayout->insertWidget(4, m_contentFilerLine);
|
||||
m_contentFilterLine = new LineEdit(this);
|
||||
m_contentFilterLine->setPlaceholderText(tr("Filter files..."));
|
||||
connect(m_contentFilterLine, SIGNAL(textChanged(QString)), this, SLOT(filterText(QString)));
|
||||
contentFilterLayout->insertWidget(4, m_contentFilterLine);
|
||||
|
||||
// SIGNAL/SLOTS
|
||||
connect(filesList, SIGNAL(clicked(const QModelIndex&)), filesList, SLOT(edit(const QModelIndex&)));
|
||||
@@ -228,7 +227,7 @@ void PropertiesWidget::clear() {
|
||||
reannounce_lbl->clear();
|
||||
shareRatio->clear();
|
||||
listWebSeeds->clear();
|
||||
m_contentFilerLine->clear();
|
||||
m_contentFilterLine->clear();
|
||||
PropListModel->model()->clear();
|
||||
label_eta_val->clear();
|
||||
label_seeds_val->clear();
|
||||
@@ -501,15 +500,7 @@ void PropertiesWidget::openFile(const QModelIndex &index) {
|
||||
qDebug("Trying to open file at %s", qPrintable(file_path));
|
||||
// Flush data
|
||||
h.flush_cache();
|
||||
if (QFile::exists(file_path)) {
|
||||
if (file_path.startsWith("//"))
|
||||
QDesktopServices::openUrl(fsutils::toNativePath("file:" + file_path));
|
||||
else
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(file_path));
|
||||
}
|
||||
else {
|
||||
QMessageBox::warning(this, tr("I/O Error"), tr("This file does not exist yet."));
|
||||
}
|
||||
misc::openPath(file_path);
|
||||
}
|
||||
|
||||
void PropertiesWidget::openFolder(const QModelIndex &index, bool containing_folder) {
|
||||
@@ -526,10 +517,6 @@ void PropertiesWidget::openFolder(const QModelIndex &index, bool containing_fold
|
||||
}
|
||||
if (path_items.isEmpty())
|
||||
return;
|
||||
#if !(defined(Q_OS_WIN) || (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)))
|
||||
if (containing_folder)
|
||||
path_items.removeLast();
|
||||
#endif
|
||||
const QDir saveDir(h.save_path());
|
||||
const QString relative_path = path_items.join("/");
|
||||
absolute_path = fsutils::expandPath(saveDir.absoluteFilePath(relative_path));
|
||||
@@ -539,54 +526,14 @@ void PropertiesWidget::openFolder(const QModelIndex &index, bool containing_fold
|
||||
const QDir saveDir(h.save_path());
|
||||
const QString relative_path = h.filepath_at(i);
|
||||
absolute_path = fsutils::expandPath(saveDir.absoluteFilePath(relative_path));
|
||||
|
||||
#if !(defined(Q_OS_WIN) || (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)))
|
||||
if (containing_folder)
|
||||
absolute_path = fsutils::folderName(absolute_path);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Flush data
|
||||
h.flush_cache();
|
||||
if (!QFile::exists(absolute_path))
|
||||
return;
|
||||
qDebug("Trying to open folder at %s", qPrintable(absolute_path));
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (containing_folder) {
|
||||
// Syntax is: explorer /select, "C:\Folder1\Folder2\file_to_select"
|
||||
// Dir separators MUST be win-style slashes
|
||||
QProcess::startDetached("explorer.exe", QStringList() << "/select," << fsutils::toNativePath(absolute_path));
|
||||
} else {
|
||||
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
|
||||
if (containing_folder) {
|
||||
QProcess proc;
|
||||
QString output;
|
||||
proc.start("xdg-mime", QStringList() << "query" << "default" << "inode/directory");
|
||||
proc.waitForFinished();
|
||||
output = proc.readLine().simplified();
|
||||
if (output == "dolphin.desktop")
|
||||
proc.startDetached("dolphin", QStringList() << "--select" << fsutils::toNativePath(absolute_path));
|
||||
else if (output == "nautilus-folder-handler.desktop")
|
||||
proc.startDetached("nautilus", QStringList() << "--no-desktop" << fsutils::toNativePath(absolute_path));
|
||||
else if (output == "kfmclient_dir.desktop")
|
||||
proc.startDetached("konqueror", QStringList() << "--select" << fsutils::toNativePath(absolute_path));
|
||||
else
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(absolute_path).absolutePath()));
|
||||
} else {
|
||||
#endif
|
||||
if (QFile::exists(absolute_path)) {
|
||||
// Hack to access samba shares with QDesktopServices::openUrl
|
||||
if (absolute_path.startsWith("//"))
|
||||
QDesktopServices::openUrl(fsutils::toNativePath("file:" + absolute_path));
|
||||
else
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(absolute_path));
|
||||
} else {
|
||||
QMessageBox::warning(this, tr("I/O Error"), tr("This folder does not exist yet."));
|
||||
}
|
||||
#if defined(Q_OS_WIN) || (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
}
|
||||
#endif
|
||||
if (containing_folder)
|
||||
misc::openFolderSelect(absolute_path);
|
||||
else
|
||||
misc::openPath(absolute_path);
|
||||
}
|
||||
|
||||
void PropertiesWidget::displayFilesListMenu(const QPoint&) {
|
||||
|
@@ -123,7 +123,7 @@ private:
|
||||
DownloadedPiecesBar *downloaded_pieces;
|
||||
PieceAvailabilityBar *pieces_availability;
|
||||
PropTabBar *m_tabBar;
|
||||
LineEdit *m_contentFilerLine;
|
||||
LineEdit *m_contentFilterLine;
|
||||
QShortcut *editHotkeyFile;
|
||||
QShortcut *editHotkeyWeb;
|
||||
QShortcut *deleteHotkeyWeb;
|
||||
|
@@ -43,6 +43,7 @@
|
||||
#include "iconprovider.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "fs_utils.h"
|
||||
#include "misc.h"
|
||||
|
||||
AutomatedRssDownloader::AutomatedRssDownloader(const QWeakPointer<RssManager>& manager, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
@@ -248,7 +249,9 @@ void AutomatedRssDownloader::updateRuleDefinitionBox()
|
||||
ui->lineEFilter->clear();
|
||||
ui->saveDiffDir_check->setChecked(!rule->savePath().isEmpty());
|
||||
ui->lineSavePath->setText(fsutils::toNativePath(rule->savePath()));
|
||||
ui->checkRegex->blockSignals(true);
|
||||
ui->checkRegex->setChecked(rule->useRegex());
|
||||
ui->checkRegex->blockSignals(false);
|
||||
if (rule->label().isEmpty()) {
|
||||
ui->comboLabel->setCurrentIndex(-1);
|
||||
ui->comboLabel->clearEditText();
|
||||
@@ -308,10 +311,10 @@ RssDownloadRulePtr AutomatedRssDownloader::getCurrentRule() const
|
||||
void AutomatedRssDownloader::initLabelCombobox()
|
||||
{
|
||||
// Load custom labels
|
||||
const QStringList customLabels = Preferences::instance()->getTorrentLabels();
|
||||
foreach (const QString& label, customLabels) {
|
||||
ui->comboLabel->addItem(label);
|
||||
}
|
||||
QStringList customLabels = Preferences::instance()->getTorrentLabels();
|
||||
std::sort(customLabels.begin(), customLabels.end(), misc::NaturalCompare());
|
||||
foreach (const QString& l, customLabels)
|
||||
ui->comboLabel->addItem(l);
|
||||
}
|
||||
|
||||
void AutomatedRssDownloader::saveEditedRule()
|
||||
@@ -344,7 +347,7 @@ void AutomatedRssDownloader::saveEditedRule()
|
||||
rule->setAddPaused(RssDownloadRule::AddPausedState(ui->comboAddPaused->currentIndex()));
|
||||
// Save new label
|
||||
if (!rule->label().isEmpty())
|
||||
Preferences::instance()->addTorrentLabel(rule->label());
|
||||
Preferences::instance()->addTorrentLabelExternal(rule->label());
|
||||
rule->setIgnoreDays(ui->spinIgnorePeriod->value());
|
||||
//rule->setRssFeeds(getSelectedFeeds());
|
||||
// Save it
|
||||
|
@@ -116,16 +116,12 @@
|
||||
<widget class="QLabel" name="news_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Torrents:</span> <span style=" font-style:italic;">(double-click to download)</span></p></body></html></string>
|
||||
<string>Torrents: (double-click to download)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -139,7 +135,7 @@ p, li { white-space: pre-wrap; }
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectItems</enum>
|
||||
|
@@ -110,20 +110,31 @@ void RSSImp::displayItemsListMenu(const QPoint&)
|
||||
{
|
||||
QMenu myItemListMenu(this);
|
||||
QList<QListWidgetItem*> selectedItems = listArticles->selectedItems();
|
||||
if (selectedItems.size() > 0) {
|
||||
bool has_attachment = false;
|
||||
foreach (const QListWidgetItem* item, selectedItems) {
|
||||
if (m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString())
|
||||
->getItem(item->data(Article::IdRole).toString())->hasAttachment()) {
|
||||
has_attachment = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_attachment)
|
||||
myItemListMenu.addAction(actionDownload_torrent);
|
||||
myItemListMenu.addAction(actionOpen_news_URL);
|
||||
if (selectedItems.size() <= 0)
|
||||
return;
|
||||
|
||||
bool hasTorrent = false;
|
||||
bool hasLink = false;
|
||||
foreach (const QListWidgetItem* item, selectedItems) {
|
||||
if (!item) continue;
|
||||
RssFeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
if (!feed) continue;
|
||||
RssArticlePtr article = feed->getItem(item->data(Article::IdRole).toString());
|
||||
if (!article) continue;
|
||||
|
||||
if (!article->torrentUrl().isEmpty())
|
||||
hasTorrent = true;
|
||||
if (!article->link().isEmpty())
|
||||
hasLink = true;
|
||||
if (hasTorrent && hasLink)
|
||||
break;
|
||||
}
|
||||
myItemListMenu.exec(QCursor::pos());
|
||||
if (hasTorrent)
|
||||
myItemListMenu.addAction(actionDownload_torrent);
|
||||
if (hasLink)
|
||||
myItemListMenu.addAction(actionOpen_news_URL);
|
||||
if (hasTorrent || hasLink)
|
||||
myItemListMenu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void RSSImp::on_actionManage_cookies_triggered()
|
||||
@@ -225,7 +236,6 @@ void RSSImp::on_newFeedButton_clicked()
|
||||
// Notify TreeWidget
|
||||
m_feedList->itemAdded(item, stream);
|
||||
|
||||
stream->refresh();
|
||||
m_rssManager->saveStreamList();
|
||||
}
|
||||
|
||||
@@ -235,29 +245,16 @@ void RSSImp::deleteSelectedItems()
|
||||
QList<QTreeWidgetItem*> selectedItems = m_feedList->selectedItems();
|
||||
if (selectedItems.isEmpty())
|
||||
return;
|
||||
if ((selectedItems.size() == 1) && (selectedItems.first() == m_feedList->stickyUnreadItem()))
|
||||
return;
|
||||
|
||||
int ret;
|
||||
if (selectedItems.size() > 1) {
|
||||
ret = QMessageBox::question(this, tr("Are you sure? -- qBittorrent"), tr("Are you sure you want to delete these elements from the list?"),
|
||||
tr("&Yes"), tr("&No"),
|
||||
QString(), 0, 1);
|
||||
}
|
||||
else {
|
||||
if (selectedItems.first() == m_feedList->stickyUnreadItem())
|
||||
return;
|
||||
ret = QMessageBox::question(this, tr("Are you sure? -- qBittorrent"), tr("Are you sure you want to delete this element from the list?"),
|
||||
tr("&Yes"), tr("&No"),
|
||||
QString(), 0, 1);
|
||||
}
|
||||
if (ret)
|
||||
QMessageBox::StandardButton answer = QMessageBox::question(this, tr("Deletion confirmation"),
|
||||
tr("Are you sure you want to delete the selected RSS feeds?"),
|
||||
QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
|
||||
if (answer == QMessageBox::No)
|
||||
return;
|
||||
|
||||
foreach (QTreeWidgetItem* item, selectedItems) {
|
||||
if (m_feedList->currentFeed() == item) {
|
||||
textBrowser->clear();
|
||||
m_currentArticle = 0;
|
||||
listArticles->clear();
|
||||
}
|
||||
if (item == m_feedList->stickyUnreadItem())
|
||||
continue;
|
||||
RssFilePtr rss_item = m_feedList->getRSSItem(item);
|
||||
@@ -280,6 +277,9 @@ void RSSImp::deleteSelectedItems()
|
||||
m_rssManager->saveStreamList();
|
||||
// Update Unread items
|
||||
updateItemInfos(m_feedList->stickyUnreadItem());
|
||||
if (m_feedList->currentItem() == m_feedList->stickyUnreadItem())
|
||||
populateArticleList(m_feedList->stickyUnreadItem());
|
||||
|
||||
}
|
||||
|
||||
void RSSImp::loadFoldersOpenState()
|
||||
@@ -334,13 +334,22 @@ void RSSImp::refreshAllFeeds()
|
||||
void RSSImp::downloadSelectedTorrents()
|
||||
{
|
||||
QList<QListWidgetItem*> selected_items = listArticles->selectedItems();
|
||||
foreach (const QListWidgetItem* item, selected_items) {
|
||||
if (selected_items.size() <= 0)
|
||||
return;
|
||||
foreach (QListWidgetItem* item, selected_items) {
|
||||
if (!item) continue;
|
||||
RssFeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
if (!feed) continue;
|
||||
RssArticlePtr article = feed->getItem(item->data(Article::IdRole).toString());
|
||||
if (!article) continue;
|
||||
|
||||
// Mark as read
|
||||
article->markAsRead();
|
||||
item->setData(Article::ColorRole, QVariant(QColor("grey")));
|
||||
item->setData(Article::IconRole, QVariant(QIcon(":/icons/sphere.png")));
|
||||
|
||||
if (article->torrentUrl().isEmpty())
|
||||
continue;
|
||||
QString torrentLink = article->torrentUrl();
|
||||
// Check if it is a magnet link
|
||||
if (torrentLink.startsWith("magnet:", Qt::CaseInsensitive)) {
|
||||
@@ -355,19 +364,36 @@ void RSSImp::downloadSelectedTorrents()
|
||||
QBtSession::instance()->downloadFromUrl(torrentLink, cookies);
|
||||
}
|
||||
}
|
||||
// Decrement feed nb unread news
|
||||
updateItemInfos(m_feedList->stickyUnreadItem());
|
||||
updateItemInfos(m_feedList->getTreeItemFromUrl(selected_items.first()->data(Article::FeedUrlRole).toString()));
|
||||
}
|
||||
|
||||
// open the url of the selected RSS articles in the Web browser
|
||||
void RSSImp::openSelectedArticlesUrls()
|
||||
{
|
||||
QList<QListWidgetItem *> selected_items = listArticles->selectedItems();
|
||||
foreach (const QListWidgetItem* item, selected_items) {
|
||||
RssArticlePtr news = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString())
|
||||
->getItem(item->data(Article::IdRole).toString());
|
||||
const QString link = news->link();
|
||||
if (selected_items.size() <= 0)
|
||||
return;
|
||||
foreach (QListWidgetItem* item, selected_items) {
|
||||
if (!item) continue;
|
||||
RssFeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
if (!feed) continue;
|
||||
RssArticlePtr article = feed->getItem(item->data(Article::IdRole).toString());
|
||||
if (!article) continue;
|
||||
|
||||
// Mark as read
|
||||
article->markAsRead();
|
||||
item->setData(Article::ColorRole, QVariant(QColor("grey")));
|
||||
item->setData(Article::IconRole, QVariant(QIcon(":/icons/sphere.png")));
|
||||
|
||||
const QString link = article->link();
|
||||
if (!link.isEmpty())
|
||||
QDesktopServices::openUrl(QUrl(link));
|
||||
}
|
||||
// Decrement feed nb unread news
|
||||
updateItemInfos(m_feedList->stickyUnreadItem());
|
||||
updateItemInfos(m_feedList->getTreeItemFromUrl(selected_items.first()->data(Article::FeedUrlRole).toString()));
|
||||
}
|
||||
|
||||
//right-click on stream : give it an alias
|
||||
@@ -544,23 +570,15 @@ void RSSImp::refreshTextBrowser()
|
||||
{
|
||||
QList<QListWidgetItem*> selection = listArticles->selectedItems();
|
||||
if (selection.empty()) return;
|
||||
Q_ASSERT(selection.size() == 1);
|
||||
QListWidgetItem *item = selection.first();
|
||||
Q_ASSERT(item);
|
||||
if (item == m_currentArticle) return;
|
||||
// Stop displaying previous news if necessary
|
||||
if (m_feedList->currentFeed() == m_feedList->stickyUnreadItem()) {
|
||||
if (m_currentArticle) {
|
||||
disconnect(listArticles, SIGNAL(itemSelectionChanged()), this, SLOT(refreshTextBrowser()));
|
||||
listArticles->removeItemWidget(m_currentArticle);
|
||||
Q_ASSERT(m_currentArticle);
|
||||
delete m_currentArticle;
|
||||
connect(listArticles, SIGNAL(itemSelectionChanged()), this, SLOT(refreshTextBrowser()));
|
||||
}
|
||||
m_currentArticle = item;
|
||||
}
|
||||
RssFeedPtr stream = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
RssArticlePtr article = stream->getItem(item->data(Article::IdRole).toString());
|
||||
m_currentArticle = item;
|
||||
|
||||
RssFeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
if (!feed) return;
|
||||
RssArticlePtr article = feed->getItem(item->data(Article::IdRole).toString());
|
||||
if (!article) return;
|
||||
QString html;
|
||||
html += "<div style='border: 2px solid red; margin-left: 5px; margin-right: 5px; margin-bottom: 5px;'>";
|
||||
html += "<div style='background-color: #678db2; font-weight: bold; color: #fff;'>" + article->title() + "</div>";
|
||||
@@ -622,11 +640,11 @@ void RSSImp::saveSlidersPosition()
|
||||
void RSSImp::restoreSlidersPosition()
|
||||
{
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
QByteArray pos_h = pref->getRssHSplitterState();
|
||||
if (!pos_h.isNull())
|
||||
const QByteArray pos_h = pref->getRssHSplitterState();
|
||||
if (!pos_h.isEmpty())
|
||||
splitter_h->restoreState(pos_h);
|
||||
QByteArray pos_v = pref->getRssVSplitterState();
|
||||
if (!pos_v.isNull())
|
||||
const QByteArray pos_v = pref->getRssVSplitterState();
|
||||
if (!pos_v.isEmpty())
|
||||
splitter_v->restoreState(pos_v);
|
||||
}
|
||||
|
||||
@@ -681,14 +699,11 @@ void RSSImp::onFeedContentChanged(const QString& url)
|
||||
qDebug() << Q_FUNC_INFO << url;
|
||||
QTreeWidgetItem *item = m_feedList->getTreeItemFromUrl(url);
|
||||
// If the feed is selected, update the displayed news
|
||||
if (m_feedList->currentItem() == item ) {
|
||||
if (m_feedList->currentItem() == item)
|
||||
populateArticleList(item);
|
||||
}
|
||||
else {
|
||||
// Update unread items
|
||||
if (m_feedList->currentItem() == m_feedList->stickyUnreadItem())
|
||||
populateArticleList(m_feedList->stickyUnreadItem());
|
||||
}
|
||||
// Update unread items
|
||||
else if (m_feedList->currentItem() == m_feedList->stickyUnreadItem())
|
||||
populateArticleList(m_feedList->stickyUnreadItem());
|
||||
}
|
||||
|
||||
void RSSImp::updateRefreshInterval(uint val)
|
||||
@@ -721,8 +736,6 @@ RSSImp::RSSImp(QWidget *parent):
|
||||
|
||||
m_feedList = new FeedListWidget(splitter_h, m_rssManager);
|
||||
splitter_h->insertWidget(0, m_feedList);
|
||||
listArticles->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||
listArticles->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
editHotkey = new QShortcut(QKeySequence("F2"), m_feedList, 0, 0, Qt::WidgetShortcut);
|
||||
connect(editHotkey, SIGNAL(activated()), SLOT(renameSelectedRssFile()));
|
||||
connect(m_feedList, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedRssFile()));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user