mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-02-02 09:55:55 +00:00
parent
d05d5a85a5
commit
dd34663224
@ -229,7 +229,7 @@ void Application::processParams(const QStringList ¶ms)
|
||||
foreach (QString param, params) {
|
||||
param = param.trimmed();
|
||||
#ifndef DISABLE_GUI
|
||||
if (Preferences::instance()->useAdditionDialog())
|
||||
if (AddNewTorrentDialog::isEnabled())
|
||||
AddNewTorrentDialog::show(param, m_window);
|
||||
else
|
||||
#endif
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include <libtorrent/session.hpp>
|
||||
|
||||
#include "base/qinisettings.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/bittorrent/sessionstatus.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "statistics.h"
|
||||
@ -76,40 +75,9 @@ void Statistics::save() const
|
||||
|
||||
void Statistics::load()
|
||||
{
|
||||
// Temp code. Versions v3.1.4 and v3.1.5 saved the data in the qbittorrent.ini file.
|
||||
// This code reads the data from there, writes it to the new file, and removes the keys
|
||||
// from the old file. This code should be removed after some time has passed.
|
||||
// e.g. When we reach v3.3.0
|
||||
// Don't forget to remove:
|
||||
// 1. Preferences::getStats()
|
||||
// 2. Preferences::removeStats()
|
||||
// 3. #include "base/preferences.h"
|
||||
Preferences* const pref = Preferences::instance();
|
||||
QIniSettings s("qBittorrent", "qBittorrent-data");
|
||||
QVariantHash v = pref->getStats();
|
||||
|
||||
// Let's test if the qbittorrent.ini holds the key
|
||||
if (!v.isEmpty()) {
|
||||
m_dirty = true;
|
||||
|
||||
// If the user has used qbt > 3.1.5 and then reinstalled/used
|
||||
// qbt < 3.1.6, there will be stats in qbittorrent-data.ini too
|
||||
// so we need to merge those 2.
|
||||
if (s.contains("Stats/AllStats")) {
|
||||
QVariantHash tmp = s.value("Stats/AllStats").toHash();
|
||||
v["AlltimeDL"] = v["AlltimeDL"].toULongLong() + tmp["AlltimeDL"].toULongLong();
|
||||
v["AlltimeUL"] = v["AlltimeUL"].toULongLong() + tmp["AlltimeUL"].toULongLong();
|
||||
}
|
||||
}
|
||||
else {
|
||||
v = s.value("Stats/AllStats").toHash();
|
||||
}
|
||||
QVariantHash v = s.value("Stats/AllStats").toHash();
|
||||
|
||||
m_alltimeDL = v["AlltimeDL"].toULongLong();
|
||||
m_alltimeUL = v["AlltimeUL"].toULongLong();
|
||||
|
||||
if (m_dirty) {
|
||||
save();
|
||||
pref->removeStats();
|
||||
}
|
||||
}
|
||||
|
@ -28,10 +28,6 @@
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "session.h"
|
||||
|
||||
using namespace BitTorrent;
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QDateTime>
|
||||
@ -44,6 +40,7 @@ using namespace BitTorrent;
|
||||
#include <QProcess>
|
||||
#include <QCoreApplication>
|
||||
#include <QThread>
|
||||
#include <QRegExp>
|
||||
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
@ -70,6 +67,7 @@ using namespace BitTorrent;
|
||||
#include "base/utils/string.h"
|
||||
#include "base/unicodestrings.h"
|
||||
#include "base/logger.h"
|
||||
#include "base/settingsstorage.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/torrentfilter.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
@ -94,20 +92,73 @@ static const char RESUME_FOLDER[] = "BT_backup";
|
||||
namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
static bool readFile(const QString &path, QByteArray &buf);
|
||||
static bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &out, int &prio, MagnetUri &magnetUri);
|
||||
#define SETTINGS_KEY(name) "BitTorrent/Session/" name
|
||||
const QString KEY_CATEGORIES = SETTINGS_KEY("Categories");
|
||||
const QString KEY_MAXRATIOACTION = SETTINGS_KEY("MaxRatioAction");
|
||||
const QString KEY_DEFAULTSAVEPATH = SETTINGS_KEY("DefaultSavePath");
|
||||
const QString KEY_TEMPPATH = SETTINGS_KEY("TempPath");
|
||||
const QString KEY_SUBCATEGORIESENABLED = SETTINGS_KEY("SubcategoriesEnabled");
|
||||
const QString KEY_TEMPPATHENABLED = SETTINGS_KEY("TempPathEnabled");
|
||||
const QString KEY_DISABLEASMBYDEFAULT = SETTINGS_KEY("DisableASMByDefault");
|
||||
const QString KEY_DISABLEASMONCATEGORYCHANGED = SETTINGS_KEY("DisableASMTriggers/CategoryChanged");
|
||||
const QString KEY_DISABLEASMONDEFAULTSAVEPATHCHANGED = SETTINGS_KEY("DisableASMTriggers/DefaultSavePathChanged");
|
||||
const QString KEY_DISABLEASMONCATEGORYSAVEPATHCHANGED = SETTINGS_KEY("DisableASMTriggers/CategorySavePathChanged");
|
||||
const QString KEY_ADDTORRENTPAUSED = SETTINGS_KEY("AddTorrentPaused");
|
||||
|
||||
static void torrentQueuePositionUp(const libt::torrent_handle &handle);
|
||||
static void torrentQueuePositionDown(const libt::torrent_handle &handle);
|
||||
static void torrentQueuePositionTop(const libt::torrent_handle &handle);
|
||||
static void torrentQueuePositionBottom(const libt::torrent_handle &handle);
|
||||
namespace
|
||||
{
|
||||
bool readFile(const QString &path, QByteArray &buf);
|
||||
bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &torrentData, int &prio, MagnetUri &magnetUri);
|
||||
|
||||
void torrentQueuePositionUp(const libt::torrent_handle &handle);
|
||||
void torrentQueuePositionDown(const libt::torrent_handle &handle);
|
||||
void torrentQueuePositionTop(const libt::torrent_handle &handle);
|
||||
void torrentQueuePositionBottom(const libt::torrent_handle &handle);
|
||||
|
||||
QStringMap map_cast(const QVariantMap &map)
|
||||
{
|
||||
QStringMap result;
|
||||
foreach (const QString &key, map.keys())
|
||||
result[key] = map.value(key).toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariantMap map_cast(const QStringMap &map)
|
||||
{
|
||||
QVariantMap result;
|
||||
foreach (const QString &key, map.keys())
|
||||
result[key] = map.value(key);
|
||||
return result;
|
||||
}
|
||||
|
||||
QString normalizePath(QString path, const QString &defaultPath = Utils::Fs::QDesktopServicesDownloadLocation())
|
||||
{
|
||||
path = Utils::Fs::fromNativePath(path.trimmed());
|
||||
return !path.isEmpty() ? path : defaultPath;
|
||||
}
|
||||
|
||||
QStringMap expandCategories(const QStringMap &categories)
|
||||
{
|
||||
QStringMap expanded = categories;
|
||||
|
||||
foreach (const QString &category, categories.keys()) {
|
||||
foreach (const QString &subcat, Session::expandCategory(category)) {
|
||||
if (!expanded.contains(subcat))
|
||||
expanded[subcat] = "";
|
||||
}
|
||||
}
|
||||
|
||||
return expanded;
|
||||
}
|
||||
}
|
||||
|
||||
// Session
|
||||
|
||||
Session *Session::m_instance = 0;
|
||||
Session *Session::m_instance = nullptr;
|
||||
|
||||
Session::Session(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_settings(SettingsStorage::instance())
|
||||
, m_LSDEnabled(false)
|
||||
, m_DHTEnabled(false)
|
||||
, m_PeXEnabled(false)
|
||||
@ -118,10 +169,8 @@ Session::Session(QObject *parent)
|
||||
, m_globalMaxRatio(-1)
|
||||
, m_numResumeData(0)
|
||||
, m_extraLimit(0)
|
||||
, m_appendLabelToSavePath(false)
|
||||
, m_appendExtension(false)
|
||||
, m_refreshInterval(0)
|
||||
, m_highRatioAction(MaxRatioAction::Pause)
|
||||
{
|
||||
Preferences* const pref = Preferences::instance();
|
||||
Logger* const logger = Logger::instance();
|
||||
@ -174,6 +223,13 @@ Session::Session(QObject *parent)
|
||||
m_nativeSession->add_extension(&libt::create_ut_pex_plugin);
|
||||
m_nativeSession->add_extension(&libt::create_smart_ban_plugin);
|
||||
|
||||
m_categories = map_cast(m_settings->loadValue(KEY_CATEGORIES).toMap());
|
||||
if (isSubcategoriesEnabled()) {
|
||||
// if subcategories support changed manually
|
||||
m_categories = expandCategories(m_categories);
|
||||
m_settings->storeValue(KEY_CATEGORIES, map_cast(m_categories));
|
||||
}
|
||||
|
||||
m_refreshTimer = new QTimer(this);
|
||||
m_refreshTimer->setInterval(2000);
|
||||
connect(m_refreshTimer, SIGNAL(timeout()), SLOT(refresh()));
|
||||
@ -185,6 +241,10 @@ Session::Session(QObject *parent)
|
||||
|
||||
m_statistics = new Statistics(this);
|
||||
|
||||
m_maxRatioAction = static_cast<MaxRatioAction>(m_settings->loadValue(KEY_MAXRATIOACTION, Pause).toInt());
|
||||
m_defaultSavePath = normalizePath(m_settings->loadValue(KEY_DEFAULTSAVEPATH).toString());
|
||||
m_tempPath = normalizePath(m_settings->loadValue(KEY_TEMPPATH).toString(), m_defaultSavePath + "/temp");
|
||||
|
||||
// Apply user settings to BitTorrent session
|
||||
configure();
|
||||
connect(pref, SIGNAL(changed()), SLOT(configure()));
|
||||
@ -231,7 +291,14 @@ bool Session::isQueueingEnabled() const
|
||||
|
||||
bool Session::isTempPathEnabled() const
|
||||
{
|
||||
return !m_tempPath.isEmpty();
|
||||
return m_settings->loadValue(KEY_TEMPPATHENABLED, false).toBool();
|
||||
}
|
||||
|
||||
void Session::setTempPathEnabled(bool enabled)
|
||||
{
|
||||
m_settings->storeValue(KEY_TEMPPATHENABLED, enabled);
|
||||
foreach (TorrentHandle *const torrent, m_torrents)
|
||||
torrent->handleTempPathChanged();
|
||||
}
|
||||
|
||||
bool Session::isAppendExtensionEnabled() const
|
||||
@ -239,11 +306,6 @@ bool Session::isAppendExtensionEnabled() const
|
||||
return m_appendExtension;
|
||||
}
|
||||
|
||||
bool Session::useAppendLabelToSavePath() const
|
||||
{
|
||||
return m_appendLabelToSavePath;
|
||||
}
|
||||
|
||||
QString Session::defaultSavePath() const
|
||||
{
|
||||
return m_defaultSavePath;
|
||||
@ -254,6 +316,200 @@ QString Session::tempPath() const
|
||||
return m_tempPath;
|
||||
}
|
||||
|
||||
bool Session::isValidCategoryName(const QString &name)
|
||||
{
|
||||
QRegExp re(R"#(^([^\\\/]|[^\\\/]([^\\\/]|\/(?=[^\/]))*[^\\\/])$)#");
|
||||
if (!name.isEmpty() && (re.indexIn(name) != 0)) {
|
||||
qDebug() << "Incorrect category name:" << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList Session::expandCategory(const QString &category)
|
||||
{
|
||||
QStringList result;
|
||||
if (!isValidCategoryName(category))
|
||||
return result;
|
||||
|
||||
int index = 0;
|
||||
while ((index = category.indexOf('/', index)) >= 0) {
|
||||
result << category.left(index);
|
||||
++index;
|
||||
}
|
||||
result << category;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList Session::categories() const
|
||||
{
|
||||
return m_categories.keys();
|
||||
}
|
||||
|
||||
QString Session::categorySavePath(const QString &categoryName) const
|
||||
{
|
||||
QString basePath = m_defaultSavePath;
|
||||
QString path = m_categories.value(categoryName);
|
||||
if (categoryName.isEmpty()) return basePath;
|
||||
|
||||
if (path.isEmpty()) // use implicit save path
|
||||
path = Utils::Fs::toValidFileSystemName(categoryName, true);
|
||||
|
||||
if (!QDir::isAbsolutePath(path))
|
||||
path = QString("%1/%2").arg(basePath).arg(path);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
bool Session::addCategory(const QString &name, const QString &savePath)
|
||||
{
|
||||
if (name.isEmpty()) return false;
|
||||
if (!isValidCategoryName(name) || m_categories.contains(name))
|
||||
return false;
|
||||
|
||||
if (isSubcategoriesEnabled()) {
|
||||
foreach (const QString &parent, expandCategory(name)) {
|
||||
if ((parent != name) && !m_categories.contains(parent)) {
|
||||
m_categories[parent] = "";
|
||||
emit categoryAdded(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_categories[name] = savePath;
|
||||
m_settings->storeValue(KEY_CATEGORIES, map_cast(m_categories));
|
||||
emit categoryAdded(name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Session::editCategory(const QString &name, const QString &savePath)
|
||||
{
|
||||
if (!m_categories.contains(name)) return false;
|
||||
if (categorySavePath(name) == savePath) return false;
|
||||
|
||||
m_categories[name] = savePath;
|
||||
if (isDisableASMWhenCategorySavePathChanged()) {
|
||||
foreach (TorrentHandle *const torrent, torrents())
|
||||
if (torrent->category() == name)
|
||||
torrent->setASMEnabled(false);
|
||||
}
|
||||
else {
|
||||
foreach (TorrentHandle *const torrent, torrents())
|
||||
if (torrent->category() == name)
|
||||
torrent->handleCategorySavePathChanged();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Session::removeCategory(const QString &name)
|
||||
{
|
||||
foreach (TorrentHandle *const torrent, torrents())
|
||||
if (torrent->belongsToCategory(name))
|
||||
torrent->setCategory("");
|
||||
|
||||
// remove stored category and its subcategories if exist
|
||||
bool result = false;
|
||||
if (isSubcategoriesEnabled()) {
|
||||
// remove subcategories
|
||||
QString test = name + "/";
|
||||
foreach (const QString &category, m_categories.keys()) {
|
||||
if (category.startsWith(test)) {
|
||||
m_categories.remove(category);
|
||||
result = true;
|
||||
emit categoryRemoved(category);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = (m_categories.remove(name) > 0) || result;
|
||||
|
||||
if (result) {
|
||||
// update stored categories
|
||||
m_settings->storeValue(KEY_CATEGORIES, map_cast(m_categories));
|
||||
emit categoryRemoved(name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Session::isSubcategoriesEnabled() const
|
||||
{
|
||||
return m_settings->loadValue(KEY_SUBCATEGORIESENABLED, false).toBool();
|
||||
}
|
||||
|
||||
void Session::setSubcategoriesEnabled(bool value)
|
||||
{
|
||||
if (isSubcategoriesEnabled() == value) return;
|
||||
|
||||
if (value) {
|
||||
// expand categories to include all parent categories
|
||||
m_categories = expandCategories(m_categories);
|
||||
// update stored categories
|
||||
m_settings->storeValue(KEY_CATEGORIES, map_cast(m_categories));
|
||||
}
|
||||
else {
|
||||
// reload categories
|
||||
m_categories = map_cast(m_settings->loadValue(KEY_CATEGORIES).toMap());
|
||||
}
|
||||
|
||||
m_settings->storeValue(KEY_SUBCATEGORIESENABLED, value);
|
||||
emit subcategoriesSupportChanged();
|
||||
}
|
||||
|
||||
bool Session::isASMDisabledByDefault() const
|
||||
{
|
||||
return m_settings->loadValue(KEY_DISABLEASMBYDEFAULT, true).toBool();
|
||||
}
|
||||
|
||||
void Session::setASMDisabledByDefault(bool value)
|
||||
{
|
||||
m_settings->storeValue(KEY_DISABLEASMBYDEFAULT, value);
|
||||
}
|
||||
|
||||
bool Session::isDisableASMWhenCategoryChanged() const
|
||||
{
|
||||
return m_settings->loadValue(KEY_DISABLEASMONCATEGORYCHANGED, false).toBool();
|
||||
}
|
||||
|
||||
void Session::setDisableASMWhenCategoryChanged(bool value)
|
||||
{
|
||||
m_settings->storeValue(KEY_DISABLEASMONCATEGORYCHANGED, value);
|
||||
}
|
||||
|
||||
bool Session::isDisableASMWhenDefaultSavePathChanged() const
|
||||
{
|
||||
return m_settings->loadValue(KEY_DISABLEASMONDEFAULTSAVEPATHCHANGED, true).toBool();
|
||||
}
|
||||
|
||||
void Session::setDisableASMWhenDefaultSavePathChanged(bool value)
|
||||
{
|
||||
m_settings->storeValue(KEY_DISABLEASMONDEFAULTSAVEPATHCHANGED, value);
|
||||
}
|
||||
|
||||
bool Session::isDisableASMWhenCategorySavePathChanged() const
|
||||
{
|
||||
return m_settings->loadValue(KEY_DISABLEASMONCATEGORYSAVEPATHCHANGED, true).toBool();
|
||||
}
|
||||
|
||||
void Session::setDisableASMWhenCategorySavePathChanged(bool value)
|
||||
{
|
||||
m_settings->storeValue(KEY_DISABLEASMONCATEGORYSAVEPATHCHANGED, value);
|
||||
}
|
||||
|
||||
bool Session::isAddTorrentPaused() const
|
||||
{
|
||||
return m_settings->loadValue(KEY_ADDTORRENTPAUSED, false).toBool();
|
||||
}
|
||||
|
||||
void Session::setAddTorrentPaused(bool value)
|
||||
{
|
||||
m_settings->storeValue(KEY_ADDTORRENTPAUSED, value);
|
||||
}
|
||||
|
||||
qreal Session::globalMaxRatio() const
|
||||
{
|
||||
return m_globalMaxRatio;
|
||||
@ -442,22 +698,12 @@ void Session::configure()
|
||||
setListeningPort();
|
||||
}
|
||||
|
||||
// * Save path
|
||||
setDefaultSavePath(pref->getSavePath());
|
||||
|
||||
// * Temp path
|
||||
if (pref->isTempPathEnabled())
|
||||
setDefaultTempPath(pref->getTempPath());
|
||||
else
|
||||
setDefaultTempPath();
|
||||
|
||||
uint newRefreshInterval = pref->getRefreshInterval();
|
||||
if (newRefreshInterval != m_refreshInterval) {
|
||||
m_refreshInterval = newRefreshInterval;
|
||||
m_refreshTimer->setInterval(m_refreshInterval);
|
||||
}
|
||||
|
||||
setAppendLabelToSavePath(pref->appendTorrentLabel());
|
||||
setAppendExtension(pref->useIncompleteFilesExtension());
|
||||
preAllocateAllFiles(pref->preAllocateAllFiles());
|
||||
|
||||
@ -587,7 +833,6 @@ void Session::configure()
|
||||
}
|
||||
|
||||
// * Maximum ratio
|
||||
m_highRatioAction = pref->getMaxRatioAction();
|
||||
setGlobalMaxRatio(pref->getGlobalMaxRatio());
|
||||
|
||||
// Ip Filter
|
||||
@ -690,7 +935,7 @@ void Session::processBigRatios()
|
||||
|
||||
if ((ratio <= TorrentHandle::MAX_RATIO) && (ratio >= ratioLimit)) {
|
||||
Logger* const logger = Logger::instance();
|
||||
if (m_highRatioAction == MaxRatioAction::Remove) {
|
||||
if (m_maxRatioAction == Remove) {
|
||||
logger->addMessage(tr("'%1' reached the maximum ratio you set. Removing...").arg(torrent->name()));
|
||||
deleteTorrent(torrent->hash());
|
||||
}
|
||||
@ -974,18 +1219,19 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
|
||||
const TorrentInfo &torrentInfo, const QByteArray &fastresumeData)
|
||||
{
|
||||
if (!addData.resumed) {
|
||||
// manage save path
|
||||
QString defaultSavePath = this->defaultSavePath();
|
||||
if (addData.savePath.isEmpty())
|
||||
addData.savePath = defaultSavePath;
|
||||
if (!addData.savePath.endsWith("/"))
|
||||
addData.savePath += "/";
|
||||
if (useAppendLabelToSavePath()) {
|
||||
if ((addData.savePath == defaultSavePath) && !addData.label.isEmpty())
|
||||
addData.savePath += QString("%1/").arg(addData.label);
|
||||
if (addData.savePath.isEmpty() && isASMDisabledByDefault())
|
||||
addData.savePath = m_defaultSavePath;
|
||||
}
|
||||
|
||||
if (!addData.category.isEmpty()) {
|
||||
if (!m_categories.contains(addData.category) && !addCategory(addData.category)) {
|
||||
qWarning() << "Couldn't create category" << addData.category;
|
||||
addData.category = "";
|
||||
}
|
||||
}
|
||||
|
||||
addData.savePath = Utils::Fs::fromNativePath(addData.savePath);
|
||||
|
||||
libt::add_torrent_params p;
|
||||
InfoHash hash;
|
||||
std::vector<char> buf(fastresumeData.constData(), fastresumeData.constData() + fastresumeData.size());
|
||||
@ -1082,7 +1328,9 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
|
||||
// Set actual save path (e.g. temporary folder)
|
||||
if (isTempPathEnabled() && !addData.disableTempPath && !addData.hasSeedStatus)
|
||||
savePath = m_tempPath;
|
||||
else
|
||||
else if (addData.savePath.isEmpty()) // using Advanced mode
|
||||
savePath = categorySavePath(addData.category);
|
||||
else // using Simple mode
|
||||
savePath = addData.savePath;
|
||||
|
||||
p.save_path = Utils::String::toStdString(Utils::Fs::toNativePath(savePath));
|
||||
@ -1341,51 +1589,32 @@ void Session::saveResumeData()
|
||||
}
|
||||
}
|
||||
|
||||
void Session::setDefaultSavePath(const QString &path)
|
||||
void Session::setDefaultSavePath(QString path)
|
||||
{
|
||||
if (path.isEmpty()) return;
|
||||
path = normalizePath(path);
|
||||
if (m_defaultSavePath == path) return;
|
||||
|
||||
m_defaultSavePath = Utils::Fs::fromNativePath(path);
|
||||
if (!m_defaultSavePath.endsWith("/"))
|
||||
m_defaultSavePath += "/";
|
||||
m_defaultSavePath = path;
|
||||
m_settings->storeValue(KEY_DEFAULTSAVEPATH, m_defaultSavePath);
|
||||
|
||||
if (isDisableASMWhenDefaultSavePathChanged())
|
||||
foreach (TorrentHandle *const torrent, torrents())
|
||||
torrent->setASMEnabled(false);
|
||||
else
|
||||
foreach (TorrentHandle *const torrent, torrents())
|
||||
torrent->handleCategorySavePathChanged();
|
||||
}
|
||||
|
||||
void Session::setDefaultTempPath(const QString &path)
|
||||
void Session::setTempPath(QString path)
|
||||
{
|
||||
QString tempPath;
|
||||
path = normalizePath(path, m_defaultSavePath + "/temp");
|
||||
if (m_tempPath == path) return;
|
||||
|
||||
if (!path.isEmpty()) {
|
||||
tempPath = Utils::Fs::fromNativePath(path);
|
||||
if (!tempPath.endsWith("/"))
|
||||
tempPath += "/";
|
||||
}
|
||||
m_tempPath = path;
|
||||
m_settings->storeValue(KEY_TEMPPATH, m_tempPath);
|
||||
|
||||
if (m_tempPath != tempPath) {
|
||||
m_tempPath = tempPath;
|
||||
foreach (TorrentHandle *const torrent, m_torrents)
|
||||
torrent->handleTempPathChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void Session::setAppendLabelToSavePath(bool append)
|
||||
{
|
||||
if (m_appendLabelToSavePath != append) {
|
||||
m_appendLabelToSavePath = append;
|
||||
foreach (TorrentHandle *const torrent, m_torrents) {
|
||||
QString label = torrent->label();
|
||||
if (label.isEmpty()) continue;
|
||||
|
||||
QString testedOldSavePath = m_defaultSavePath;
|
||||
QString newSavePath = m_defaultSavePath;
|
||||
if (!m_appendLabelToSavePath)
|
||||
testedOldSavePath += QString("%1/").arg(label);
|
||||
else
|
||||
newSavePath += QString("%1/").arg(label);
|
||||
|
||||
if (torrent->savePath() == testedOldSavePath)
|
||||
torrent->move(newSavePath);
|
||||
}
|
||||
}
|
||||
foreach (TorrentHandle *const torrent, m_torrents)
|
||||
torrent->handleTempPathChanged();
|
||||
}
|
||||
|
||||
void Session::setAppendExtension(bool append)
|
||||
@ -1536,6 +1765,19 @@ bool Session::isListening() const
|
||||
return m_nativeSession->is_listening();
|
||||
}
|
||||
|
||||
MaxRatioAction Session::maxRatioAction() const
|
||||
{
|
||||
return m_maxRatioAction;
|
||||
}
|
||||
|
||||
void Session::setMaxRatioAction(MaxRatioAction act)
|
||||
{
|
||||
if (m_maxRatioAction != act) {
|
||||
m_maxRatioAction = act;
|
||||
m_settings->storeValue(KEY_MAXRATIOACTION, act);
|
||||
}
|
||||
}
|
||||
|
||||
// Torrents will a ratio superior to the given value will
|
||||
// be automatically deleted
|
||||
void Session::setGlobalMaxRatio(qreal ratio)
|
||||
@ -1586,22 +1828,14 @@ void Session::handleTorrentSavePathChanged(TorrentHandle *const torrent)
|
||||
emit torrentSavePathChanged(torrent);
|
||||
}
|
||||
|
||||
void Session::handleTorrentLabelChanged(TorrentHandle *const torrent, const QString &oldLabel)
|
||||
void Session::handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory)
|
||||
{
|
||||
if (m_appendLabelToSavePath) {
|
||||
QString testedOldSavePath = m_defaultSavePath;
|
||||
if (!oldLabel.isEmpty())
|
||||
testedOldSavePath += QString("%1/").arg(oldLabel);
|
||||
QString newLabel = torrent->label();
|
||||
if (torrent->savePath() == testedOldSavePath) {
|
||||
QString newSavePath = m_defaultSavePath;
|
||||
if (!newLabel.isEmpty())
|
||||
newSavePath += QString("%1/").arg(newLabel);
|
||||
torrent->move(newSavePath);
|
||||
}
|
||||
}
|
||||
emit torrentCategoryChanged(torrent, oldCategory);
|
||||
}
|
||||
|
||||
emit torrentLabelChanged(torrent, oldLabel);
|
||||
void Session::handleTorrentSavingModeChanged(TorrentHandle * const torrent)
|
||||
{
|
||||
emit torrentSavingModeChanged(torrent);
|
||||
}
|
||||
|
||||
void Session::handleTorrentTrackersAdded(TorrentHandle *const torrent, const QList<TrackerEntry> &newTrackers)
|
||||
@ -2138,7 +2372,7 @@ void Session::createTorrentHandle(const libt::torrent_handle &nativeHandle)
|
||||
|
||||
bool addPaused = data.addPaused;
|
||||
if (data.addPaused == TriStateBool::Undefined)
|
||||
addPaused = pref->addTorrentsInPause();
|
||||
addPaused = isAddTorrentPaused();
|
||||
|
||||
// Start torrent because it was added in paused state
|
||||
if (!addPaused)
|
||||
@ -2351,86 +2585,90 @@ void Session::handleStateUpdateAlert(libt::state_update_alert *p)
|
||||
emit torrentsUpdated();
|
||||
}
|
||||
|
||||
bool readFile(const QString &path, QByteArray &buf)
|
||||
namespace
|
||||
{
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qDebug("Cannot read file %s: %s", qPrintable(path), qPrintable(file.errorString()));
|
||||
return false;
|
||||
bool readFile(const QString &path, QByteArray &buf)
|
||||
{
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qDebug("Cannot read file %s: %s", qPrintable(path), qPrintable(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
buf = file.readAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
buf = file.readAll();
|
||||
return true;
|
||||
}
|
||||
bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &torrentData, int &prio, MagnetUri &magnetUri)
|
||||
{
|
||||
torrentData = AddTorrentData();
|
||||
torrentData.resumed = true;
|
||||
torrentData.skipChecking = false;
|
||||
|
||||
bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &out, int &prio, MagnetUri &magnetUri)
|
||||
{
|
||||
out = AddTorrentData();
|
||||
out.resumed = true;
|
||||
out.skipChecking = false;
|
||||
libt::lazy_entry fast;
|
||||
libt::error_code ec;
|
||||
libt::lazy_bdecode(data.constData(), data.constData() + data.size(), fast, ec);
|
||||
if (ec || (fast.type() != libt::lazy_entry::dict_t)) return false;
|
||||
|
||||
libt::lazy_entry fast;
|
||||
libt::error_code ec;
|
||||
libt::lazy_bdecode(data.constData(), data.constData() + data.size(), fast, ec);
|
||||
if (ec || (fast.type() != libt::lazy_entry::dict_t)) return false;
|
||||
torrentData.savePath = Utils::Fs::fromNativePath(Utils::String::fromStdString(fast.dict_find_string_value("qBt-savePath")));
|
||||
torrentData.ratioLimit = Utils::String::fromStdString(fast.dict_find_string_value("qBt-ratioLimit")).toDouble();
|
||||
// **************************************************************************************
|
||||
// Workaround to convert legacy label to category
|
||||
// TODO: Should be removed in future
|
||||
torrentData.category = Utils::String::fromStdString(fast.dict_find_string_value("qBt-label"));
|
||||
if (torrentData.category.isEmpty())
|
||||
// **************************************************************************************
|
||||
torrentData.category = Utils::String::fromStdString(fast.dict_find_string_value("qBt-category"));
|
||||
torrentData.name = Utils::String::fromStdString(fast.dict_find_string_value("qBt-name"));
|
||||
torrentData.hasSeedStatus = fast.dict_find_int_value("qBt-seedStatus");
|
||||
torrentData.disableTempPath = fast.dict_find_int_value("qBt-tempPathDisabled");
|
||||
|
||||
out.savePath = Utils::Fs::fromNativePath(Utils::String::fromStdString(fast.dict_find_string_value("qBt-savePath")));
|
||||
if (out.savePath.isEmpty()) {
|
||||
Logger::instance()->addMessage("Empty torrent save path was loaded from .fastresume file! Using default one...", Log::WARNING);
|
||||
out.savePath = Preferences::instance()->getSavePath();
|
||||
magnetUri = MagnetUri(Utils::String::fromStdString(fast.dict_find_string_value("qBt-magnetUri")));
|
||||
torrentData.addPaused = fast.dict_find_int_value("qBt-paused");
|
||||
torrentData.addForced = fast.dict_find_int_value("qBt-forced");
|
||||
|
||||
prio = fast.dict_find_int_value("qBt-queuePosition");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
out.ratioLimit = Utils::String::fromStdString(fast.dict_find_string_value("qBt-ratioLimit")).toDouble();
|
||||
out.label = Utils::String::fromStdString(fast.dict_find_string_value("qBt-label"));
|
||||
out.name = Utils::String::fromStdString(fast.dict_find_string_value("qBt-name"));
|
||||
out.hasSeedStatus = fast.dict_find_int_value("qBt-seedStatus");
|
||||
out.disableTempPath = fast.dict_find_int_value("qBt-tempPathDisabled");
|
||||
|
||||
magnetUri = MagnetUri(Utils::String::fromStdString(fast.dict_find_string_value("qBt-magnetUri")));
|
||||
out.addPaused = fast.dict_find_int_value("qBt-paused");
|
||||
out.addForced = fast.dict_find_int_value("qBt-forced");
|
||||
|
||||
prio = fast.dict_find_int_value("qBt-queuePosition");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void torrentQueuePositionUp(const libt::torrent_handle &handle)
|
||||
{
|
||||
try {
|
||||
handle.queue_position_up();
|
||||
void torrentQueuePositionUp(const libt::torrent_handle &handle)
|
||||
{
|
||||
try {
|
||||
handle.queue_position_up();
|
||||
}
|
||||
catch (std::exception &exc) {
|
||||
qDebug() << Q_FUNC_INFO << " fails: " << exc.what();
|
||||
}
|
||||
}
|
||||
catch (std::exception &exc) {
|
||||
qDebug() << Q_FUNC_INFO << " fails: " << exc.what();
|
||||
}
|
||||
}
|
||||
|
||||
void torrentQueuePositionDown(const libt::torrent_handle &handle)
|
||||
{
|
||||
try {
|
||||
handle.queue_position_down();
|
||||
}
|
||||
catch (std::exception &exc) {
|
||||
qDebug() << Q_FUNC_INFO << " fails: " << exc.what();
|
||||
}
|
||||
}
|
||||
|
||||
void torrentQueuePositionTop(const libt::torrent_handle &handle)
|
||||
{
|
||||
try {
|
||||
handle.queue_position_top();
|
||||
}
|
||||
catch (std::exception &exc) {
|
||||
qDebug() << Q_FUNC_INFO << " fails: " << exc.what();
|
||||
}
|
||||
}
|
||||
|
||||
void torrentQueuePositionBottom(const libt::torrent_handle &handle)
|
||||
{
|
||||
try {
|
||||
handle.queue_position_bottom();
|
||||
}
|
||||
catch (std::exception &exc) {
|
||||
qDebug() << Q_FUNC_INFO << " fails: " << exc.what();
|
||||
|
||||
void torrentQueuePositionDown(const libt::torrent_handle &handle)
|
||||
{
|
||||
try {
|
||||
handle.queue_position_down();
|
||||
}
|
||||
catch (std::exception &exc) {
|
||||
qDebug() << Q_FUNC_INFO << " fails: " << exc.what();
|
||||
}
|
||||
}
|
||||
|
||||
void torrentQueuePositionTop(const libt::torrent_handle &handle)
|
||||
{
|
||||
try {
|
||||
handle.queue_position_top();
|
||||
}
|
||||
catch (std::exception &exc) {
|
||||
qDebug() << Q_FUNC_INFO << " fails: " << exc.what();
|
||||
}
|
||||
}
|
||||
|
||||
void torrentQueuePositionBottom(const libt::torrent_handle &handle)
|
||||
{
|
||||
try {
|
||||
handle.queue_position_bottom();
|
||||
}
|
||||
catch (std::exception &exc) {
|
||||
qDebug() << Q_FUNC_INFO << " fails: " << exc.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
#include <QFile>
|
||||
#include <QHash>
|
||||
#include <QMap>
|
||||
#include <QPointer>
|
||||
#include <QVector>
|
||||
#include <QMutex>
|
||||
@ -110,8 +111,19 @@ class FilterParserThread;
|
||||
class BandwidthScheduler;
|
||||
class Statistics;
|
||||
class ResumeDataSavingManager;
|
||||
class SettingsStorage;
|
||||
|
||||
typedef QPair<QString, QString> QStringPair;
|
||||
enum MaxRatioAction
|
||||
{
|
||||
Pause,
|
||||
Remove
|
||||
};
|
||||
|
||||
enum TorrentExportFolder
|
||||
{
|
||||
Regular,
|
||||
Finished
|
||||
};
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
@ -127,7 +139,7 @@ namespace BitTorrent
|
||||
struct AddTorrentParams
|
||||
{
|
||||
QString name;
|
||||
QString label;
|
||||
QString category;
|
||||
QString savePath;
|
||||
bool disableTempPath = false; // e.g. for imported torrents
|
||||
bool sequential = false;
|
||||
@ -165,11 +177,49 @@ namespace BitTorrent
|
||||
bool isPexEnabled() const;
|
||||
bool isQueueingEnabled() const;
|
||||
qreal globalMaxRatio() const;
|
||||
bool isTempPathEnabled() const;
|
||||
bool isAppendExtensionEnabled() const;
|
||||
bool useAppendLabelToSavePath() const;
|
||||
|
||||
QString defaultSavePath() const;
|
||||
void setDefaultSavePath(QString path);
|
||||
QString tempPath() const;
|
||||
void setTempPath(QString path);
|
||||
bool isTempPathEnabled() const;
|
||||
void setTempPathEnabled(bool enabled);
|
||||
|
||||
static bool isValidCategoryName(const QString &name);
|
||||
// returns category itself and all top level categories
|
||||
static QStringList expandCategory(const QString &category);
|
||||
|
||||
QStringList categories() const;
|
||||
QString categorySavePath(const QString &categoryName) const;
|
||||
bool addCategory(const QString &name, const QString &savePath = "");
|
||||
bool editCategory(const QString &name, const QString &savePath);
|
||||
bool removeCategory(const QString &name);
|
||||
bool isSubcategoriesEnabled() const;
|
||||
void setSubcategoriesEnabled(bool value);
|
||||
|
||||
// Advanced Saving Management subsystem (ASM)
|
||||
//
|
||||
// Each torrent can be either in Simple mode or in Advanced mode
|
||||
// In Simple mode torrent has explicit save path
|
||||
// In Advanced Mode torrent has implicit save path (based on Default
|
||||
// save path and Category save path)
|
||||
// In Advanced Mode torrent save path can be changed in following cases:
|
||||
// 1. Default save path changed
|
||||
// 2. Torrent category save path changed
|
||||
// 3. Torrent category changed
|
||||
// (unless otherwise is specified)
|
||||
bool isASMDisabledByDefault() const;
|
||||
void setASMDisabledByDefault(bool value);
|
||||
bool isDisableASMWhenCategoryChanged() const;
|
||||
void setDisableASMWhenCategoryChanged(bool value);
|
||||
bool isDisableASMWhenDefaultSavePathChanged() const;
|
||||
void setDisableASMWhenDefaultSavePathChanged(bool value);
|
||||
bool isDisableASMWhenCategorySavePathChanged() const;
|
||||
void setDisableASMWhenCategorySavePathChanged(bool value);
|
||||
|
||||
bool isAddTorrentPaused() const;
|
||||
void setAddTorrentPaused(bool value);
|
||||
|
||||
TorrentHandle *findTorrent(const InfoHash &hash) const;
|
||||
QHash<InfoHash, TorrentHandle *> torrents() const;
|
||||
@ -184,6 +234,9 @@ namespace BitTorrent
|
||||
int uploadRateLimit() const;
|
||||
bool isListening() const;
|
||||
|
||||
MaxRatioAction maxRatioAction() const;
|
||||
void setMaxRatioAction(MaxRatioAction act);
|
||||
|
||||
void changeSpeedLimitMode(bool alternative);
|
||||
void setDownloadRateLimit(int rate);
|
||||
void setUploadRateLimit(int rate);
|
||||
@ -208,7 +261,8 @@ namespace BitTorrent
|
||||
// TorrentHandle interface
|
||||
void handleTorrentRatioLimitChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentSavePathChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentLabelChanged(TorrentHandle *const torrent, const QString &oldLabel);
|
||||
void handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory);
|
||||
void handleTorrentSavingModeChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentMetadataReceived(TorrentHandle *const torrent);
|
||||
void handleTorrentPaused(TorrentHandle *const torrent);
|
||||
void handleTorrentResumed(TorrentHandle *const torrent);
|
||||
@ -236,7 +290,8 @@ namespace BitTorrent
|
||||
void torrentFinished(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentFinishedChecking(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentSavePathChanged(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentLabelChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel);
|
||||
void torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory);
|
||||
void torrentSavingModeChanged(BitTorrent::TorrentHandle *const torrent);
|
||||
void allTorrentsFinished();
|
||||
void metadataLoaded(const BitTorrent::TorrentInfo &info);
|
||||
void torrentMetadataLoaded(BitTorrent::TorrentHandle *const torrent);
|
||||
@ -254,6 +309,9 @@ namespace BitTorrent
|
||||
void trackerlessStateChanged(BitTorrent::TorrentHandle *const torrent, bool trackerless);
|
||||
void downloadFromUrlFailed(const QString &url, const QString &reason);
|
||||
void downloadFromUrlFinished(const QString &url);
|
||||
void categoryAdded(const QString &categoryName);
|
||||
void categoryRemoved(const QString &categoryName);
|
||||
void subcategoriesSupportChanged();
|
||||
|
||||
private slots:
|
||||
void configure();
|
||||
@ -287,8 +345,6 @@ namespace BitTorrent
|
||||
void adjustLimits(libtorrent::session_settings &sessionSettings);
|
||||
const QStringList getListeningIPs();
|
||||
void setListeningPort();
|
||||
void setDefaultSavePath(const QString &path);
|
||||
void setDefaultTempPath(const QString &path = QString());
|
||||
void preAllocateAllFiles(bool b);
|
||||
void setMaxConnectionsPerTorrent(int max);
|
||||
void setMaxUploadsPerTorrent(int max);
|
||||
@ -296,7 +352,6 @@ namespace BitTorrent
|
||||
void enableDHT(bool enable);
|
||||
void changeSpeedLimitMode_impl(bool alternative);
|
||||
|
||||
void setAppendLabelToSavePath(bool append);
|
||||
void setAppendExtension(bool append);
|
||||
|
||||
void startUpTorrents();
|
||||
@ -333,6 +388,8 @@ namespace BitTorrent
|
||||
void dispatchAlerts(std::auto_ptr<libtorrent::alert> alertPtr);
|
||||
void getPendingAlerts(QVector<libtorrent::alert *> &out, ulong time = 0);
|
||||
|
||||
SettingsStorage *m_settings;
|
||||
|
||||
// BitTorrent
|
||||
libtorrent::session *m_nativeSession;
|
||||
|
||||
@ -346,10 +403,9 @@ namespace BitTorrent
|
||||
qreal m_globalMaxRatio;
|
||||
int m_numResumeData;
|
||||
int m_extraLimit;
|
||||
bool m_appendLabelToSavePath;
|
||||
bool m_appendExtension;
|
||||
uint m_refreshInterval;
|
||||
MaxRatioAction m_highRatioAction;
|
||||
MaxRatioAction m_maxRatioAction;
|
||||
QList<BitTorrent::TrackerEntry> m_additionalTrackers;
|
||||
QString m_defaultSavePath;
|
||||
QString m_tempPath;
|
||||
@ -376,6 +432,7 @@ namespace BitTorrent
|
||||
QHash<InfoHash, AddTorrentData> m_addingTorrents;
|
||||
QHash<QString, AddTorrentParams> m_downloadedTorrents;
|
||||
TorrentStatusReport m_torrentStatusReport;
|
||||
QStringMap m_categories;
|
||||
|
||||
QMutex m_alertsMutex;
|
||||
QWaitCondition m_alertsWaitCondition;
|
||||
|
@ -80,7 +80,7 @@ AddTorrentData::AddTorrentData()
|
||||
AddTorrentData::AddTorrentData(const AddTorrentParams ¶ms)
|
||||
: resumed(false)
|
||||
, name(params.name)
|
||||
, label(params.label)
|
||||
, category(params.category)
|
||||
, savePath(params.savePath)
|
||||
, disableTempPath(params.disableTempPath)
|
||||
, sequential(params.sequential)
|
||||
@ -201,7 +201,8 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
|
||||
, m_renameCount(0)
|
||||
, m_name(data.name)
|
||||
, m_savePath(Utils::Fs::toNativePath(data.savePath))
|
||||
, m_label(data.label)
|
||||
, m_category(data.category)
|
||||
, m_useASM(data.savePath.isEmpty())
|
||||
, m_hasSeedStatus(data.hasSeedStatus)
|
||||
, m_ratioLimit(data.ratioLimit)
|
||||
, m_tempPathDisabled(data.disableTempPath)
|
||||
@ -209,7 +210,8 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
|
||||
, m_pauseAfterRecheck(false)
|
||||
, m_needSaveResumeData(false)
|
||||
{
|
||||
Q_ASSERT(!m_savePath.isEmpty());
|
||||
if (m_useASM)
|
||||
m_savePath = Utils::Fs::toNativePath(m_session->categorySavePath(m_category));
|
||||
|
||||
updateStatus();
|
||||
m_hash = InfoHash(m_nativeStatus.info_hash);
|
||||
@ -330,6 +332,22 @@ QString TorrentHandle::contentPath(bool actual) const
|
||||
return rootPath(actual);
|
||||
}
|
||||
|
||||
bool TorrentHandle::isASMEnabled() const
|
||||
{
|
||||
return m_useASM;
|
||||
}
|
||||
|
||||
void TorrentHandle::setASMEnabled(bool enabled)
|
||||
{
|
||||
if (m_useASM == enabled) return;
|
||||
|
||||
m_useASM = enabled;
|
||||
m_session->handleTorrentSavingModeChanged(this);
|
||||
|
||||
if (m_useASM)
|
||||
move_impl(m_session->categorySavePath(m_category));
|
||||
}
|
||||
|
||||
QString TorrentHandle::nativeActualSavePath() const
|
||||
{
|
||||
return Utils::String::fromStdString(m_nativeStatus.save_path);
|
||||
@ -507,9 +525,22 @@ qreal TorrentHandle::progress() const
|
||||
return progress;
|
||||
}
|
||||
|
||||
QString TorrentHandle::label() const
|
||||
QString TorrentHandle::category() const
|
||||
{
|
||||
return m_label;
|
||||
return m_category;
|
||||
}
|
||||
|
||||
bool TorrentHandle::belongsToCategory(const QString &category) const
|
||||
{
|
||||
if (m_category.isEmpty()) return category.isEmpty();
|
||||
if (!Session::isValidCategoryName(category)) return false;
|
||||
|
||||
if (m_category == category) return true;
|
||||
|
||||
if (m_session->isSubcategoriesEnabled() && m_category.startsWith(category + "/"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QDateTime TorrentHandle::addedTime() const
|
||||
@ -1110,17 +1141,41 @@ void TorrentHandle::setName(const QString &name)
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentHandle::setLabel(const QString &label)
|
||||
bool TorrentHandle::setCategory(const QString &category)
|
||||
{
|
||||
if (m_label != label) {
|
||||
QString oldLabel = m_label;
|
||||
m_label = label;
|
||||
if (m_category != category) {
|
||||
if (!category.isEmpty()) {
|
||||
if (!Session::isValidCategoryName(category)) return false;
|
||||
if (!m_session->categories().contains(category))
|
||||
if (!m_session->addCategory(category))
|
||||
return false;
|
||||
}
|
||||
|
||||
QString oldCategory = m_category;
|
||||
m_category = category;
|
||||
m_needSaveResumeData = true;
|
||||
m_session->handleTorrentLabelChanged(this, oldLabel);
|
||||
m_session->handleTorrentCategoryChanged(this, oldCategory);
|
||||
|
||||
if (m_useASM) {
|
||||
if (!m_session->isDisableASMWhenCategoryChanged())
|
||||
move_impl(m_session->categorySavePath(m_category));
|
||||
else
|
||||
setASMEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TorrentHandle::move(QString path)
|
||||
{
|
||||
m_useASM = false;
|
||||
m_session->handleTorrentSavingModeChanged(this);
|
||||
|
||||
move_impl(path);
|
||||
}
|
||||
|
||||
void TorrentHandle::move_impl(QString path)
|
||||
{
|
||||
path = Utils::Fs::toNativePath(path);
|
||||
if (path == savePath()) return;
|
||||
@ -1469,9 +1524,9 @@ void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert
|
||||
resumeData["qBt-paused"] = isPaused();
|
||||
resumeData["qBt-forced"] = isForced();
|
||||
}
|
||||
resumeData["qBt-savePath"] = Utils::String::toStdString(m_savePath);
|
||||
resumeData["qBt-savePath"] = m_useASM ? "" : Utils::String::toStdString(m_savePath);
|
||||
resumeData["qBt-ratioLimit"] = Utils::String::toStdString(QString::number(m_ratioLimit));
|
||||
resumeData["qBt-label"] = Utils::String::toStdString(m_label);
|
||||
resumeData["qBt-category"] = Utils::String::toStdString(m_category);
|
||||
resumeData["qBt-name"] = Utils::String::toStdString(m_name);
|
||||
resumeData["qBt-seedStatus"] = m_hasSeedStatus;
|
||||
resumeData["qBt-tempPathDisabled"] = m_tempPathDisabled;
|
||||
@ -1532,12 +1587,6 @@ void TorrentHandle::handleFileRenamedAlert(libtorrent::file_renamed_alert *p)
|
||||
|
||||
updateStatus();
|
||||
|
||||
if (filesCount() == 1) {
|
||||
// Single-file torrent
|
||||
// Renaming a file corresponds to changing the save path
|
||||
m_session->handleTorrentSavePathChanged(this);
|
||||
}
|
||||
|
||||
--m_renameCount;
|
||||
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
|
||||
m_moveFinishedTriggers.takeFirst()();
|
||||
@ -1598,6 +1647,12 @@ void TorrentHandle::handleTempPathChanged()
|
||||
adjustActualSavePath();
|
||||
}
|
||||
|
||||
void TorrentHandle::handleCategorySavePathChanged()
|
||||
{
|
||||
if (m_useASM)
|
||||
move_impl(m_session->categorySavePath(m_category));
|
||||
}
|
||||
|
||||
void TorrentHandle::handleAppendExtensionToggled()
|
||||
{
|
||||
if (!hasMetadata()) return;
|
||||
|
@ -90,7 +90,7 @@ namespace BitTorrent
|
||||
bool resumed;
|
||||
// for both new and resumed torrents
|
||||
QString name;
|
||||
QString label;
|
||||
QString category;
|
||||
QString savePath;
|
||||
bool disableTempPath;
|
||||
bool sequential;
|
||||
@ -227,11 +227,16 @@ namespace BitTorrent
|
||||
QString rootPath(bool actual = false) const;
|
||||
QString contentPath(bool actual = false) const;
|
||||
|
||||
bool isASMEnabled() const;
|
||||
void setASMEnabled(bool enabled);
|
||||
QString category() const;
|
||||
bool belongsToCategory(const QString &category) const;
|
||||
bool setCategory(const QString &category);
|
||||
|
||||
int filesCount() const;
|
||||
int piecesCount() const;
|
||||
int piecesHave() const;
|
||||
qreal progress() const;
|
||||
QString label() const;
|
||||
QDateTime addedTime() const;
|
||||
qreal ratioLimit() const;
|
||||
|
||||
@ -307,7 +312,6 @@ namespace BitTorrent
|
||||
qlonglong nextAnnounce() const;
|
||||
|
||||
void setName(const QString &name);
|
||||
void setLabel(const QString &label);
|
||||
void setSequentialDownload(bool b);
|
||||
void toggleSequentialDownload();
|
||||
void setFirstLastPiecePriority(bool b);
|
||||
@ -344,6 +348,7 @@ namespace BitTorrent
|
||||
void handleAlert(libtorrent::alert *a);
|
||||
void handleStateUpdate(const libtorrent::torrent_status &nativeStatus);
|
||||
void handleTempPathChanged();
|
||||
void handleCategorySavePathChanged();
|
||||
void handleAppendExtensionToggled();
|
||||
void saveResumeData();
|
||||
|
||||
@ -379,6 +384,7 @@ namespace BitTorrent
|
||||
|
||||
void adjustActualSavePath();
|
||||
void adjustActualSavePath_impl();
|
||||
void move_impl(QString path);
|
||||
void moveStorage(const QString &newPath);
|
||||
void appendExtensionsToIncompleteFiles();
|
||||
void removeExtensionsFromIncompleteFiles();
|
||||
@ -405,10 +411,12 @@ namespace BitTorrent
|
||||
QQueue<EventTrigger> m_moveFinishedTriggers;
|
||||
int m_renameCount;
|
||||
|
||||
bool m_useASM;
|
||||
|
||||
// Persistent data
|
||||
QString m_name;
|
||||
QString m_savePath;
|
||||
QString m_label;
|
||||
QString m_category;
|
||||
bool m_hasSeedStatus;
|
||||
qreal m_ratioLimit;
|
||||
bool m_tempPathDisabled;
|
||||
|
@ -44,8 +44,8 @@ namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
TorrentInfo::TorrentInfo(NativeConstPtr nativeInfo)
|
||||
: m_nativeInfo(nativeInfo)
|
||||
{
|
||||
m_nativeInfo = boost::const_pointer_cast<libt::torrent_info>(nativeInfo);
|
||||
}
|
||||
|
||||
TorrentInfo::TorrentInfo(const TorrentInfo &other)
|
||||
@ -219,5 +219,5 @@ void TorrentInfo::renameFile(uint index, const QString &newPath)
|
||||
|
||||
TorrentInfo::NativePtr TorrentInfo::nativeInfo() const
|
||||
{
|
||||
return *reinterpret_cast<const NativePtr *>(&m_nativeInfo);
|
||||
return m_nativeInfo;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ namespace BitTorrent
|
||||
NativePtr nativeInfo() const;
|
||||
|
||||
private:
|
||||
NativeConstPtr m_nativeInfo;
|
||||
NativePtr m_nativeInfo;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include <QHostAddress>
|
||||
#include <QVector>
|
||||
|
||||
typedef QMap<QString, QString> QStringMap;
|
||||
#include "base/types.h"
|
||||
|
||||
namespace Http
|
||||
{
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <QCryptographicHash>
|
||||
#include <QPair>
|
||||
#include <QDir>
|
||||
#include <QSettings>
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
#include <QApplication>
|
||||
@ -62,7 +63,6 @@ Preferences* Preferences::m_instance = 0;
|
||||
Preferences::Preferences()
|
||||
: m_randomPort(rand() % 64512 + 1024)
|
||||
{
|
||||
qRegisterMetaTypeStreamOperators<MaxRatioAction>("MaxRatioAction");
|
||||
}
|
||||
|
||||
Preferences *Preferences::instance()
|
||||
@ -277,40 +277,6 @@ void Preferences::setWinStartup(bool b)
|
||||
#endif
|
||||
|
||||
// Downloads
|
||||
QString Preferences::getSavePath() const
|
||||
{
|
||||
QString save_path = value("Preferences/Downloads/SavePath").toString();
|
||||
if (!save_path.isEmpty())
|
||||
return Utils::Fs::fromNativePath(save_path);
|
||||
return Utils::Fs::QDesktopServicesDownloadLocation();
|
||||
}
|
||||
|
||||
void Preferences::setSavePath(const QString &save_path)
|
||||
{
|
||||
setValue("Preferences/Downloads/SavePath", Utils::Fs::fromNativePath(save_path));
|
||||
}
|
||||
|
||||
bool Preferences::isTempPathEnabled() const
|
||||
{
|
||||
return value("Preferences/Downloads/TempPathEnabled", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setTempPathEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Downloads/TempPathEnabled", enabled);
|
||||
}
|
||||
|
||||
QString Preferences::getTempPath() const
|
||||
{
|
||||
const QString temp = QDir(getSavePath()).absoluteFilePath("temp");
|
||||
return Utils::Fs::fromNativePath(value("Preferences/Downloads/TempPath", temp).toString());
|
||||
}
|
||||
|
||||
void Preferences::setTempPath(const QString &path)
|
||||
{
|
||||
setValue("Preferences/Downloads/TempPath", Utils::Fs::fromNativePath(path));
|
||||
}
|
||||
|
||||
bool Preferences::useIncompleteFilesExtension() const
|
||||
{
|
||||
return value("Preferences/Downloads/UseIncompleteExtension", false).toBool();
|
||||
@ -321,16 +287,6 @@ void Preferences::useIncompleteFilesExtension(bool enabled)
|
||||
setValue("Preferences/Downloads/UseIncompleteExtension", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::appendTorrentLabel() const
|
||||
{
|
||||
return value("Preferences/Downloads/AppendLabel", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setAppendTorrentLabel(bool b)
|
||||
{
|
||||
setValue("Preferences/Downloads/AppendLabel", b);
|
||||
}
|
||||
|
||||
QString Preferences::lastLocationPath() const
|
||||
{
|
||||
return Utils::Fs::fromNativePath(value("Preferences/Downloads/LastLocationPath").toString());
|
||||
@ -351,36 +307,6 @@ void Preferences::preAllocateAllFiles(bool enabled)
|
||||
return setValue("Preferences/Downloads/PreAllocation", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::useAdditionDialog() const
|
||||
{
|
||||
return value("Preferences/Downloads/NewAdditionDialog", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::useAdditionDialog(bool b)
|
||||
{
|
||||
setValue("Preferences/Downloads/NewAdditionDialog", b);
|
||||
}
|
||||
|
||||
bool Preferences::additionDialogFront() const
|
||||
{
|
||||
return value("Preferences/Downloads/NewAdditionDialogFront", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::additionDialogFront(bool b)
|
||||
{
|
||||
setValue("Preferences/Downloads/NewAdditionDialogFront", b);
|
||||
}
|
||||
|
||||
bool Preferences::addTorrentsInPause() const
|
||||
{
|
||||
return value("Preferences/Downloads/StartInPause", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::addTorrentsInPause(bool b)
|
||||
{
|
||||
setValue("Preferences/Downloads/StartInPause", b);
|
||||
}
|
||||
|
||||
QVariantHash Preferences::getScanDirs() const
|
||||
{
|
||||
return value("Preferences/Downloads/ScanDirsV2").toHash();
|
||||
@ -878,16 +804,6 @@ void Preferences::setGlobalMaxRatio(qreal ratio)
|
||||
setValue("Preferences/Bittorrent/MaxRatio", ratio);
|
||||
}
|
||||
|
||||
MaxRatioAction Preferences::getMaxRatioAction() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/MaxRatioAction", QVariant::fromValue(MaxRatioAction::Pause)).value<MaxRatioAction>();
|
||||
}
|
||||
|
||||
void Preferences::setMaxRatioAction(MaxRatioAction act)
|
||||
{
|
||||
setValue("Preferences/Bittorrent/MaxRatioAction", QVariant::fromValue(act));
|
||||
}
|
||||
|
||||
// IP Filter
|
||||
bool Preferences::isFilteringEnabled() const
|
||||
{
|
||||
@ -1501,51 +1417,6 @@ void Preferences::useSystemIconTheme(bool enabled)
|
||||
}
|
||||
#endif
|
||||
|
||||
QStringList Preferences::getTorrentLabels() const
|
||||
{
|
||||
return value("TransferListFilters/customLabels").toStringList();
|
||||
}
|
||||
|
||||
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();
|
||||
if (labels.contains(label))
|
||||
return;
|
||||
labels << label;
|
||||
setValue("TransferListFilters/customLabels", labels);
|
||||
}
|
||||
|
||||
void Preferences::removeTorrentLabel(const QString& label)
|
||||
{
|
||||
QStringList labels = value("TransferListFilters/customLabels").toStringList();
|
||||
if (!labels.contains(label))
|
||||
return;
|
||||
labels.removeOne(label);
|
||||
setValue("TransferListFilters/customLabels", labels);
|
||||
}
|
||||
|
||||
QString Preferences::getDefaultLabel() const
|
||||
{
|
||||
return value("Preferences/Downloads/DefaultLabel").toString();
|
||||
}
|
||||
|
||||
void Preferences::setDefaultLabel(const QString &defaultLabel)
|
||||
{
|
||||
setValue("Preferences/Downloads/DefaultLabel", defaultLabel);
|
||||
}
|
||||
|
||||
bool Preferences::recursiveDownloadDisabled() const
|
||||
{
|
||||
return value("Preferences/Advanced/DisableRecursiveDownload", false).toBool();
|
||||
@ -1904,63 +1775,6 @@ void Preferences::setTrayIconStyle(TrayIcon::Style style)
|
||||
|
||||
// Stuff that don't appear in the Options GUI but are saved
|
||||
// in the same file.
|
||||
QByteArray Preferences::getAddNewTorrentDialogState() const
|
||||
{
|
||||
#ifdef QBT_USES_QT5
|
||||
return value("AddNewTorrentDialog/qt5/treeHeaderState").toByteArray();
|
||||
#else
|
||||
return value("AddNewTorrentDialog/treeHeaderState").toByteArray();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Preferences::setAddNewTorrentDialogState(const QByteArray &state)
|
||||
{
|
||||
#ifdef QBT_USES_QT5
|
||||
setValue("AddNewTorrentDialog/qt5/treeHeaderState", state);
|
||||
#else
|
||||
setValue("AddNewTorrentDialog/treeHeaderState", state);
|
||||
#endif
|
||||
}
|
||||
|
||||
int Preferences::getAddNewTorrentDialogPos() const
|
||||
{
|
||||
return value("AddNewTorrentDialog/y", -1).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setAddNewTorrentDialogPos(const int &pos)
|
||||
{
|
||||
setValue("AddNewTorrentDialog/y", pos);
|
||||
}
|
||||
|
||||
int Preferences::getAddNewTorrentDialogWidth() const
|
||||
{
|
||||
return value("AddNewTorrentDialog/width", -1).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setAddNewTorrentDialogWidth(const int &width)
|
||||
{
|
||||
setValue("AddNewTorrentDialog/width", width);
|
||||
}
|
||||
|
||||
bool Preferences::getAddNewTorrentDialogExpanded() const
|
||||
{
|
||||
return value("AddNewTorrentDialog/expanded", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setAddNewTorrentDialogExpanded(const bool expanded)
|
||||
{
|
||||
setValue("AddNewTorrentDialog/expanded", expanded);
|
||||
}
|
||||
|
||||
QStringList Preferences::getAddNewTorrentDialogPathHistory() const
|
||||
{
|
||||
return value("TorrentAdditionDlg/save_path_history").toStringList();
|
||||
}
|
||||
|
||||
void Preferences::setAddNewTorrentDialogPathHistory(const QStringList &history)
|
||||
{
|
||||
setValue("TorrentAdditionDlg/save_path_history", history);
|
||||
}
|
||||
|
||||
QDateTime Preferences::getDNSLastUpd() const
|
||||
{
|
||||
@ -2320,14 +2134,14 @@ void Preferences::setStatusFilterState(const bool checked)
|
||||
setValue("TransferListFilters/statusFilterState", checked);
|
||||
}
|
||||
|
||||
bool Preferences::getLabelFilterState() const
|
||||
bool Preferences::getCategoryFilterState() const
|
||||
{
|
||||
return value("TransferListFilters/labelFilterState", true).toBool();
|
||||
return value("TransferListFilters/CategoryFilterState", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setLabelFilterState(const bool checked)
|
||||
void Preferences::setCategoryFilterState(const bool checked)
|
||||
{
|
||||
setValue("TransferListFilters/labelFilterState", checked);
|
||||
setValue("TransferListFilters/CategoryFilterState", checked);
|
||||
}
|
||||
|
||||
bool Preferences::getTrackerFilterState() const
|
||||
@ -2499,7 +2313,19 @@ void Preferences::upgrade()
|
||||
|
||||
setNetworkCookies(cookies);
|
||||
|
||||
QStringList labels = value("TransferListFilters/customLabels").toStringList();
|
||||
if (!labels.isEmpty()) {
|
||||
QVariantMap categories = value("BitTorrent/Session/Categories").toMap();
|
||||
foreach (const QString &label, labels) {
|
||||
if (!categories.contains(label))
|
||||
categories[label] = "";
|
||||
}
|
||||
setValue("BitTorrent/Session/Categories", categories);
|
||||
SettingsStorage::instance()->removeValue("TransferListFilters/customLabels");
|
||||
}
|
||||
|
||||
SettingsStorage::instance()->removeValue("Rss/hosts_cookies");
|
||||
SettingsStorage::instance()->removeValue("Preferences/Downloads/AppendLabel");
|
||||
}
|
||||
|
||||
void Preferences::apply()
|
||||
|
@ -106,7 +106,6 @@ class Preferences: public QObject
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
void externalLabelAdded(QString&);
|
||||
|
||||
public:
|
||||
static void initInstance();
|
||||
@ -152,28 +151,12 @@ public:
|
||||
#endif
|
||||
|
||||
// Downloads
|
||||
QString getSavePath() const;
|
||||
void setSavePath(const QString &save_path);
|
||||
bool isTempPathEnabled() const;
|
||||
void setTempPathEnabled(bool enabled);
|
||||
QString getTempPath() const;
|
||||
void setTempPath(const QString &path);
|
||||
QString getDefaultLabel() const;
|
||||
void setDefaultLabel(const QString &defaultLabel);
|
||||
bool useIncompleteFilesExtension() const;
|
||||
void useIncompleteFilesExtension(bool enabled);
|
||||
bool appendTorrentLabel() const;
|
||||
void setAppendTorrentLabel(bool b);
|
||||
QString lastLocationPath() const;
|
||||
void setLastLocationPath(const QString &path);
|
||||
bool preAllocateAllFiles() const;
|
||||
void preAllocateAllFiles(bool enabled);
|
||||
bool useAdditionDialog() const;
|
||||
void useAdditionDialog(bool b);
|
||||
bool additionDialogFront() const;
|
||||
void additionDialogFront(bool b);
|
||||
bool addTorrentsInPause() const;
|
||||
void addTorrentsInPause(bool b);
|
||||
QVariantHash getScanDirs() const;
|
||||
void setScanDirs(const QVariantHash &dirs);
|
||||
QString getScanDirsLastPath() const;
|
||||
@ -275,8 +258,6 @@ public:
|
||||
void setTrackersList(const QString &val);
|
||||
qreal getGlobalMaxRatio() const;
|
||||
void setGlobalMaxRatio(qreal ratio);
|
||||
MaxRatioAction getMaxRatioAction() const;
|
||||
void setMaxRatioAction(MaxRatioAction act);
|
||||
|
||||
// IP Filter
|
||||
bool isFilteringEnabled() const;
|
||||
@ -400,11 +381,6 @@ public:
|
||||
bool useSystemIconTheme() const;
|
||||
void useSystemIconTheme(bool enabled);
|
||||
#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;
|
||||
void disableRecursiveDownload(bool disable = true);
|
||||
#ifdef Q_OS_WIN
|
||||
@ -437,19 +413,8 @@ public:
|
||||
TrayIcon::Style trayIconStyle() const;
|
||||
void setTrayIconStyle(TrayIcon::Style style);
|
||||
|
||||
|
||||
// Stuff that don't appear in the Options GUI but are saved
|
||||
// in the same file.
|
||||
QByteArray getAddNewTorrentDialogState() const;
|
||||
void setAddNewTorrentDialogState(const QByteArray &state);
|
||||
int getAddNewTorrentDialogPos() const;
|
||||
void setAddNewTorrentDialogPos(const int &pos);
|
||||
int getAddNewTorrentDialogWidth() const;
|
||||
void setAddNewTorrentDialogWidth(const int &width);
|
||||
bool getAddNewTorrentDialogExpanded() const;
|
||||
void setAddNewTorrentDialogExpanded(const bool expanded);
|
||||
QStringList getAddNewTorrentDialogPathHistory() const;
|
||||
void setAddNewTorrentDialogPathHistory(const QStringList &history);
|
||||
QDateTime getDNSLastUpd() const;
|
||||
void setDNSLastUpd(const QDateTime &date);
|
||||
QString getDNSLastIP() const;
|
||||
@ -511,7 +476,7 @@ public:
|
||||
QByteArray getTorImportGeometry() const;
|
||||
void setTorImportGeometry(const QByteArray &geometry);
|
||||
bool getStatusFilterState() const;
|
||||
bool getLabelFilterState() const;
|
||||
bool getCategoryFilterState() const;
|
||||
bool getTrackerFilterState() const;
|
||||
int getTransSelFilter() const;
|
||||
void setTransSelFilter(const int &index);
|
||||
@ -548,7 +513,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void setStatusFilterState(bool checked);
|
||||
void setLabelFilterState(bool checked);
|
||||
void setCategoryFilterState(bool checked);
|
||||
void setTrackerFilterState(bool checked);
|
||||
|
||||
void apply();
|
||||
|
@ -178,7 +178,7 @@ DownloadRulePtr DownloadRule::fromVariantHash(const QVariantHash &ruleHash)
|
||||
rule->setRssFeeds(ruleHash.value("affected_feeds").toStringList());
|
||||
rule->setEnabled(ruleHash.value("enabled", false).toBool());
|
||||
rule->setSavePath(ruleHash.value("save_path").toString());
|
||||
rule->setLabel(ruleHash.value("label_assigned").toString());
|
||||
rule->setCategory(ruleHash.value("category_assigned").toString());
|
||||
rule->setAddPaused(AddPausedState(ruleHash.value("add_paused").toUInt()));
|
||||
rule->setLastMatch(ruleHash.value("last_match").toDateTime());
|
||||
rule->setIgnoreDays(ruleHash.value("ignore_days").toInt());
|
||||
@ -194,7 +194,7 @@ QVariantHash DownloadRule::toVariantHash() const
|
||||
hash["save_path"] = m_savePath;
|
||||
hash["affected_feeds"] = m_rssFeeds;
|
||||
hash["enabled"] = m_enabled;
|
||||
hash["label_assigned"] = m_label;
|
||||
hash["category_assigned"] = m_category;
|
||||
hash["use_regex"] = m_useRegex;
|
||||
hash["add_paused"] = m_apstate;
|
||||
hash["episode_filter"] = m_episodeFilter;
|
||||
@ -210,10 +210,7 @@ bool DownloadRule::operator==(const DownloadRule &other) const
|
||||
|
||||
void DownloadRule::setSavePath(const QString &savePath)
|
||||
{
|
||||
if (!savePath.isEmpty() && (QDir(savePath) != QDir(Preferences::instance()->getSavePath())))
|
||||
m_savePath = Utils::Fs::fromNativePath(savePath);
|
||||
else
|
||||
m_savePath = QString();
|
||||
m_savePath = Utils::Fs::fromNativePath(savePath);
|
||||
}
|
||||
|
||||
DownloadRule::AddPausedState DownloadRule::addPaused() const
|
||||
@ -226,14 +223,14 @@ void DownloadRule::setAddPaused(const DownloadRule::AddPausedState &aps)
|
||||
m_apstate = aps;
|
||||
}
|
||||
|
||||
QString DownloadRule::label() const
|
||||
QString DownloadRule::category() const
|
||||
{
|
||||
return m_label;
|
||||
return m_category;
|
||||
}
|
||||
|
||||
void DownloadRule::setLabel(const QString &label)
|
||||
void DownloadRule::setCategory(const QString &category)
|
||||
{
|
||||
m_label = label;
|
||||
m_category = category;
|
||||
}
|
||||
|
||||
bool DownloadRule::isEnabled() const
|
||||
|
@ -69,8 +69,8 @@ namespace Rss
|
||||
void setSavePath(const QString &savePath);
|
||||
AddPausedState addPaused() const;
|
||||
void setAddPaused(const AddPausedState &aps);
|
||||
QString label() const;
|
||||
void setLabel(const QString &label);
|
||||
QString category() const;
|
||||
void setCategory(const QString &category);
|
||||
bool isEnabled() const;
|
||||
void setEnabled(bool enable);
|
||||
void setLastMatch(const QDateTime &d);
|
||||
@ -93,7 +93,7 @@ namespace Rss
|
||||
QStringList m_mustNotContain;
|
||||
QString m_episodeFilter;
|
||||
QString m_savePath;
|
||||
QString m_label;
|
||||
QString m_category;
|
||||
bool m_enabled;
|
||||
QStringList m_rssFeeds;
|
||||
bool m_useRegex;
|
||||
|
@ -391,7 +391,7 @@ void Feed::downloadArticleTorrentIfMatching(const ArticlePtr &article)
|
||||
|
||||
BitTorrent::AddTorrentParams params;
|
||||
params.savePath = matchingRule->savePath();
|
||||
params.label = matchingRule->label();
|
||||
params.category = matchingRule->category();
|
||||
if (matchingRule->addPaused() == DownloadRule::ALWAYS_PAUSED)
|
||||
params.addPaused = TriStateBool::True;
|
||||
else if (matchingRule->addPaused() == DownloadRule::NEVER_PAUSED)
|
||||
|
@ -47,9 +47,44 @@ namespace
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef QBT_USES_QT5
|
||||
typedef QHash<QString, QString> MappingTable;
|
||||
#else
|
||||
class MappingTable: public QHash<QString, QString>
|
||||
{
|
||||
public:
|
||||
MappingTable(std::initializer_list<std::pair<QString, QString>> list)
|
||||
{
|
||||
reserve(static_cast<int>(list.size()));
|
||||
for (std::initializer_list<std::pair<QString, QString>>::const_iterator it = list.begin(); it != list.end(); ++it)
|
||||
insert(it->first, it->second);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
QString mapKey(const QString &key)
|
||||
{
|
||||
static const QHash<QString, QString> keyMapping = {};
|
||||
static const MappingTable keyMapping = {
|
||||
|
||||
{ "BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction" },
|
||||
{ "BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath" },
|
||||
{ "BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath" },
|
||||
{ "BitTorrent/Session/TempPathEnabled", "Preferences/Downloads/TempPathEnabled" },
|
||||
{ "BitTorrent/Session/AddTorrentPaused", "Preferences/Downloads/StartInPause" },
|
||||
#ifdef QBT_USES_QT5
|
||||
{ "AddNewTorrentDialog/TreeHeaderState", "AddNewTorrentDialog/qt5/treeHeaderState" },
|
||||
#else
|
||||
{ "AddNewTorrentDialog/TreeHeaderState", "AddNewTorrentDialog/treeHeaderState" },
|
||||
#endif
|
||||
{ "AddNewTorrentDialog/Width", "AddNewTorrentDialog/width" },
|
||||
{ "AddNewTorrentDialog/Position", "AddNewTorrentDialog/y" },
|
||||
{ "AddNewTorrentDialog/Expanded", "AddNewTorrentDialog/expanded" },
|
||||
{ "AddNewTorrentDialog/SavePathHistory", "TorrentAdditionDlg/save_path_history" },
|
||||
{ "AddNewTorrentDialog/Enabled", "Preferences/Downloads/NewAdditionDialog" },
|
||||
{ "AddNewTorrentDialog/TopLevel", "Preferences/Downloads/NewAdditionDialogFront" }
|
||||
|
||||
};
|
||||
|
||||
return keyMapping.value(key, key);
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "bittorrent/torrenthandle.h"
|
||||
#include "torrentfilter.h"
|
||||
|
||||
const QString TorrentFilter::AnyLabel;
|
||||
const QString TorrentFilter::AnyCategory;
|
||||
const QStringSet TorrentFilter::AnyHash = (QStringSet() << QString());
|
||||
|
||||
const TorrentFilter TorrentFilter::DownloadingTorrent(TorrentFilter::Downloading);
|
||||
@ -49,16 +49,16 @@ TorrentFilter::TorrentFilter()
|
||||
{
|
||||
}
|
||||
|
||||
TorrentFilter::TorrentFilter(Type type, QStringSet hashSet, QString label)
|
||||
TorrentFilter::TorrentFilter(Type type, QStringSet hashSet, QString category)
|
||||
: m_type(type)
|
||||
, m_label(label)
|
||||
, m_category(category)
|
||||
, m_hashSet(hashSet)
|
||||
{
|
||||
}
|
||||
|
||||
TorrentFilter::TorrentFilter(QString filter, QStringSet hashSet, QString label)
|
||||
TorrentFilter::TorrentFilter(QString filter, QStringSet hashSet, QString category)
|
||||
: m_type(All)
|
||||
, m_label(label)
|
||||
, m_category(category)
|
||||
, m_hashSet(hashSet)
|
||||
{
|
||||
setTypeByName(filter);
|
||||
@ -108,13 +108,13 @@ bool TorrentFilter::setHashSet(const QStringSet &hashSet)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TorrentFilter::setLabel(const QString &label)
|
||||
bool TorrentFilter::setCategory(const QString &category)
|
||||
{
|
||||
// QString::operator==() doesn't distinguish between empty and null strings.
|
||||
if ((m_label != label)
|
||||
|| (m_label.isNull() && !label.isNull())
|
||||
|| (!m_label.isNull() && label.isNull())) {
|
||||
m_label = label;
|
||||
if ((m_category != category)
|
||||
|| (m_category.isNull() && !category.isNull())
|
||||
|| (!m_category.isNull() && category.isNull())) {
|
||||
m_category = category;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ bool TorrentFilter::match(TorrentHandle *const torrent) const
|
||||
{
|
||||
if (!torrent) return false;
|
||||
|
||||
return (matchState(torrent) && matchHash(torrent) && matchLabel(torrent));
|
||||
return (matchState(torrent) && matchHash(torrent) && matchCategory(torrent));
|
||||
}
|
||||
|
||||
bool TorrentFilter::matchState(BitTorrent::TorrentHandle *const torrent) const
|
||||
@ -160,9 +160,8 @@ bool TorrentFilter::matchHash(BitTorrent::TorrentHandle *const torrent) const
|
||||
else return m_hashSet.contains(torrent->hash());
|
||||
}
|
||||
|
||||
bool TorrentFilter::matchLabel(BitTorrent::TorrentHandle *const torrent) const
|
||||
bool TorrentFilter::matchCategory(BitTorrent::TorrentHandle *const torrent) const
|
||||
{
|
||||
if (m_label.isNull()) return true;
|
||||
else if (m_label.isEmpty()) return torrent->label().isEmpty();
|
||||
else return (torrent->label() == m_label);
|
||||
if (m_category.isNull()) return true;
|
||||
else return (torrent->belongsToCategory(m_category));
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
Errored
|
||||
};
|
||||
|
||||
static const QString AnyLabel;
|
||||
static const QString AnyCategory;
|
||||
static const QStringSet AnyHash;
|
||||
|
||||
static const TorrentFilter DownloadingTorrent;
|
||||
@ -71,24 +71,24 @@ public:
|
||||
static const TorrentFilter ErroredTorrent;
|
||||
|
||||
TorrentFilter();
|
||||
// label: pass empty string for "no label" or null string (QString()) for "any label"
|
||||
TorrentFilter(Type type, QStringSet hashSet = AnyHash, QString label = AnyLabel);
|
||||
TorrentFilter(QString filter, QStringSet hashSet = AnyHash, QString label = AnyLabel);
|
||||
// category: pass empty string for "no category" or null string (QString()) for "any category"
|
||||
TorrentFilter(Type type, QStringSet hashSet = AnyHash, QString category = AnyCategory);
|
||||
TorrentFilter(QString filter, QStringSet hashSet = AnyHash, QString category = AnyCategory);
|
||||
|
||||
bool setType(Type type);
|
||||
bool setTypeByName(const QString &filter);
|
||||
bool setHashSet(const QStringSet &hashSet);
|
||||
bool setLabel(const QString &label);
|
||||
bool setCategory(const QString &category);
|
||||
|
||||
bool match(BitTorrent::TorrentHandle *const torrent) const;
|
||||
|
||||
private:
|
||||
bool matchState(BitTorrent::TorrentHandle *const torrent) const;
|
||||
bool matchHash(BitTorrent::TorrentHandle *const torrent) const;
|
||||
bool matchLabel(BitTorrent::TorrentHandle *const torrent) const;
|
||||
bool matchCategory(BitTorrent::TorrentHandle *const torrent) const;
|
||||
|
||||
Type m_type;
|
||||
QString m_label;
|
||||
QString m_category;
|
||||
QStringSet m_hashSet;
|
||||
};
|
||||
|
||||
|
@ -29,25 +29,10 @@
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
#include <QVariant>
|
||||
#include <QDataStream>
|
||||
#include <QMap>
|
||||
|
||||
const qlonglong MAX_ETA = 8640000;
|
||||
|
||||
enum class MaxRatioAction
|
||||
{
|
||||
Pause,
|
||||
Remove
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(MaxRatioAction)
|
||||
|
||||
enum class TorrentExportFolder
|
||||
{
|
||||
Regular,
|
||||
Finished
|
||||
};
|
||||
|
||||
enum class ShutdownAction
|
||||
{
|
||||
None,
|
||||
@ -56,19 +41,6 @@ enum class ShutdownAction
|
||||
Hibernate
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline QDataStream &operator<<(QDataStream &out, const T &val)
|
||||
{
|
||||
return (out << static_cast<int>(val));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline QDataStream &operator>>(QDataStream &in, T &val)
|
||||
{
|
||||
int tmp;
|
||||
in >> tmp;
|
||||
val = static_cast<T>(tmp);
|
||||
return in;
|
||||
}
|
||||
typedef QMap<QString, QString> QStringMap;
|
||||
|
||||
#endif // TYPES_H
|
||||
|
@ -250,22 +250,23 @@ bool Utils::Fs::sameFiles(const QString& path1, const QString& path2)
|
||||
return same;
|
||||
}
|
||||
|
||||
QString Utils::Fs::toValidFileSystemName(const QString &filename)
|
||||
QString Utils::Fs::toValidFileSystemName(const QString &name, bool allowSeparators)
|
||||
{
|
||||
static const QRegExp regex("[\\\\/:?\"*<>|]");
|
||||
QRegExp regex(allowSeparators ? "[:?\"*<>|]+" : "[\\\\/:?\"*<>|]+");
|
||||
|
||||
QString validName = filename.trimmed();
|
||||
QString validName = name.trimmed();
|
||||
validName.replace(regex, " ");
|
||||
qDebug() << "toValidFileSystemName:" << filename << "=>" << validName;
|
||||
qDebug() << "toValidFileSystemName:" << name << "=>" << validName;
|
||||
|
||||
return validName;
|
||||
}
|
||||
|
||||
bool Utils::Fs::isValidFileSystemName(const QString& filename)
|
||||
bool Utils::Fs::isValidFileSystemName(const QString &name, bool allowSeparators)
|
||||
{
|
||||
if (filename.isEmpty()) return false;
|
||||
const QRegExp regex("[\\\\/:?\"*<>|]");
|
||||
return !filename.contains(regex);
|
||||
if (name.isEmpty()) return false;
|
||||
|
||||
QRegExp regex(allowSeparators ? "[:?\"*<>|]" : "[\\\\/:?\"*<>|]");
|
||||
return !name.contains(regex);
|
||||
}
|
||||
|
||||
qlonglong Utils::Fs::freeDiskSpaceOnPath(QString path)
|
||||
|
@ -48,8 +48,8 @@ namespace Utils
|
||||
QString folderName(const QString& file_path);
|
||||
qint64 computePathSize(const QString& path);
|
||||
bool sameFiles(const QString& path1, const QString& path2);
|
||||
QString toValidFileSystemName(const QString &filename);
|
||||
bool isValidFileSystemName(const QString& filename);
|
||||
QString toValidFileSystemName(const QString &name, bool allowSeparators = false);
|
||||
bool isValidFileSystemName(const QString& name, bool allowSeparators = false);
|
||||
qlonglong freeDiskSpaceOnPath(QString path);
|
||||
QString branchPath(const QString& file_path, QString* removed = 0);
|
||||
bool sameFileNames(const QString& first, const QString& second);
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QUrl>
|
||||
#include <QSize>
|
||||
#include "base/types.h"
|
||||
|
||||
/* Miscellaneous functions that can be useful */
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include <QMenu>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "base/preferences.h"
|
||||
#include "base/settingsstorage.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/net/downloadhandler.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
@ -44,16 +44,34 @@
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/utils/string.h"
|
||||
#include "base/unicodestrings.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "messageboxraised.h"
|
||||
#include "ui_addnewtorrentdialog.h"
|
||||
#include "proplistdelegate.h"
|
||||
#include "torrentcontentmodel.h"
|
||||
#include "torrentcontentfiltermodel.h"
|
||||
#include "ui_addnewtorrentdialog.h"
|
||||
#include "addnewtorrentdialog.h"
|
||||
|
||||
#define SETTINGS_KEY(name) "AddNewTorrentDialog/" name
|
||||
const QString KEY_ENABLED = SETTINGS_KEY("Enabled");
|
||||
const QString KEY_DEFAULTSAVEPATH = SETTINGS_KEY("DefaultSavePath");
|
||||
const QString KEY_DEFAULTCATEGORY = SETTINGS_KEY("DefaultCategory");
|
||||
const QString KEY_TREEHEADERSTATE = SETTINGS_KEY("TreeHeaderState");
|
||||
const QString KEY_WIDTH = SETTINGS_KEY("Width");
|
||||
const QString KEY_EXPANDED = SETTINGS_KEY("Expanded");
|
||||
const QString KEY_POSITION = SETTINGS_KEY("Position");
|
||||
const QString KEY_TOPLEVEL = SETTINGS_KEY("TopLevel");
|
||||
const QString KEY_SAVEPATHHISTORY = SETTINGS_KEY("SavePathHistory");
|
||||
|
||||
namespace
|
||||
{
|
||||
//just a shortcut
|
||||
inline SettingsStorage *settings() { return SettingsStorage::instance(); }
|
||||
}
|
||||
|
||||
AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::AddNewTorrentDialog)
|
||||
@ -67,34 +85,36 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
|
||||
ui->lblMetaLoading->setVisible(false);
|
||||
ui->progMetaLoading->setVisible(false);
|
||||
|
||||
Preferences* const pref = Preferences::instance();
|
||||
ui->start_torrent_cb->setChecked(!pref->addTorrentsInPause());
|
||||
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(pref->getSavePath()), pref->getSavePath());
|
||||
loadSavePathHistory();
|
||||
auto session = BitTorrent::Session::instance();
|
||||
|
||||
ui->startTorrentCheckBox->setChecked(!session->isAddTorrentPaused());
|
||||
(session->isASMDisabledByDefault() ? ui->simpleModeRadioButton : ui->advancedModeRadioButton)->setChecked(true);
|
||||
populateSavePathComboBox();
|
||||
connect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), SLOT(onSavePathChanged(int)));
|
||||
connect(ui->browse_button, SIGNAL(clicked()), SLOT(browseButton_clicked()));
|
||||
ui->default_save_path_cb->setVisible(false); // Default path is selected by default
|
||||
connect(ui->browseButton, SIGNAL(clicked()), SLOT(browseButton_clicked()));
|
||||
ui->defaultSavePathCheckBox->setVisible(false); // Default path is selected by default
|
||||
|
||||
// Load labels
|
||||
const QStringList customLabels = pref->getTorrentLabels();
|
||||
const QString defaultLabel = pref->getDefaultLabel();
|
||||
// Load categories
|
||||
QStringList categories = session->categories();
|
||||
std::sort(categories.begin(), categories.end(), Utils::String::NaturalCompare());
|
||||
QString defaultCategory = settings()->loadValue(KEY_DEFAULTCATEGORY).toString();
|
||||
|
||||
if (!defaultLabel.isEmpty())
|
||||
ui->label_combo->addItem(defaultLabel);
|
||||
ui->label_combo->addItem("");
|
||||
if (!defaultCategory.isEmpty())
|
||||
ui->categoryComboBox->addItem(defaultCategory);
|
||||
ui->categoryComboBox->addItem("");
|
||||
|
||||
foreach (const QString& label, customLabels)
|
||||
if (label != defaultLabel)
|
||||
ui->label_combo->addItem(label);
|
||||
foreach (const QString &category, categories)
|
||||
if (category != defaultCategory)
|
||||
ui->categoryComboBox->addItem(category);
|
||||
|
||||
ui->label_combo->model()->sort(0);
|
||||
ui->content_tree->header()->setSortIndicator(0, Qt::AscendingOrder);
|
||||
ui->categoryComboBox->model()->sort(0);
|
||||
ui->contentTreeView->header()->setSortIndicator(0, Qt::AscendingOrder);
|
||||
loadState();
|
||||
// Signal / slots
|
||||
connect(ui->adv_button, SIGNAL(clicked(bool)), SLOT(showAdvancedSettings(bool)));
|
||||
editHotkey = new QShortcut(QKeySequence("F2"), ui->content_tree, 0, 0, Qt::WidgetShortcut);
|
||||
editHotkey = new QShortcut(QKeySequence("F2"), ui->contentTreeView, 0, 0, Qt::WidgetShortcut);
|
||||
connect(editHotkey, SIGNAL(activated()), SLOT(renameSelectedFile()));
|
||||
connect(ui->content_tree, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedFile()));
|
||||
connect(ui->contentTreeView, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedFile()));
|
||||
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
|
||||
}
|
||||
@ -108,27 +128,45 @@ AddNewTorrentDialog::~AddNewTorrentDialog()
|
||||
delete editHotkey;
|
||||
}
|
||||
|
||||
bool AddNewTorrentDialog::isEnabled()
|
||||
{
|
||||
return SettingsStorage::instance()->loadValue(KEY_ENABLED, true).toBool();
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::setEnabled(bool value)
|
||||
{
|
||||
SettingsStorage::instance()->storeValue(KEY_ENABLED, value);
|
||||
}
|
||||
|
||||
bool AddNewTorrentDialog::isTopLevel()
|
||||
{
|
||||
return SettingsStorage::instance()->loadValue(KEY_TOPLEVEL, true).toBool();
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::setTopLevel(bool value)
|
||||
{
|
||||
SettingsStorage::instance()->storeValue(KEY_TOPLEVEL, value);
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::loadState()
|
||||
{
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
m_headerState = pref->getAddNewTorrentDialogState();
|
||||
int width = pref->getAddNewTorrentDialogWidth();
|
||||
m_headerState = settings()->loadValue(KEY_TREEHEADERSTATE).toByteArray();
|
||||
int width = settings()->loadValue(KEY_WIDTH, -1).toInt();
|
||||
if (width >= 0) {
|
||||
QRect geo = geometry();
|
||||
geo.setWidth(width);
|
||||
setGeometry(geo);
|
||||
}
|
||||
ui->adv_button->setChecked(pref->getAddNewTorrentDialogExpanded());
|
||||
ui->adv_button->setChecked(settings()->loadValue(KEY_EXPANDED).toBool());
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::saveState()
|
||||
{
|
||||
Preferences* const pref = Preferences::instance();
|
||||
if (m_contentModel)
|
||||
pref->setAddNewTorrentDialogState(ui->content_tree->header()->saveState());
|
||||
pref->setAddNewTorrentDialogPos(pos().y());
|
||||
pref->setAddNewTorrentDialogWidth(width());
|
||||
pref->setAddNewTorrentDialogExpanded(ui->adv_button->isChecked());
|
||||
settings()->storeValue(KEY_TREEHEADERSTATE, ui->contentTreeView->header()->saveState());
|
||||
settings()->storeValue(KEY_POSITION, pos().y());
|
||||
settings()->storeValue(KEY_WIDTH, width());
|
||||
settings()->storeValue(KEY_EXPANDED, ui->adv_button->isChecked());
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::show(QString source, QWidget *parent)
|
||||
@ -256,9 +294,8 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri)
|
||||
void AddNewTorrentDialog::showEvent(QShowEvent *event)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
Preferences* const pref = Preferences::instance();
|
||||
if (!pref->additionDialogFront())
|
||||
return;
|
||||
if (!isTopLevel()) return;
|
||||
|
||||
activateWindow();
|
||||
raise();
|
||||
}
|
||||
@ -272,7 +309,7 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
|
||||
ui->adv_button->setText(QString::fromUtf8(C_UP));
|
||||
ui->settings_group->setVisible(true);
|
||||
ui->infoGroup->setVisible(true);
|
||||
ui->content_tree->setVisible(m_hasMetadata);
|
||||
ui->contentTreeView->setVisible(m_hasMetadata);
|
||||
static_cast<QVBoxLayout*>(layout())->insertWidget(layout()->indexOf(ui->never_show_cb) + 1, ui->adv_button);
|
||||
}
|
||||
else {
|
||||
@ -287,21 +324,20 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
|
||||
|
||||
void AddNewTorrentDialog::saveSavePathHistory() const
|
||||
{
|
||||
QDir selected_save_path(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString());
|
||||
Preferences* const pref = Preferences::instance();
|
||||
QDir selectedSavePath(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString());
|
||||
// Get current history
|
||||
QStringList history = pref->getAddNewTorrentDialogPathHistory();
|
||||
QList<QDir> history_dirs;
|
||||
QStringList history = settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList();
|
||||
QList<QDir> historyDirs;
|
||||
foreach(const QString dir, history)
|
||||
history_dirs << QDir(dir);
|
||||
if (!history_dirs.contains(selected_save_path)) {
|
||||
historyDirs << QDir(dir);
|
||||
if (!historyDirs.contains(selectedSavePath)) {
|
||||
// Add save path to history
|
||||
history.push_front(selected_save_path.absolutePath());
|
||||
history.push_front(selectedSavePath.absolutePath());
|
||||
// Limit list size
|
||||
if (history.size() > 8)
|
||||
history.pop_back();
|
||||
// Save history
|
||||
pref->setAddNewTorrentDialogPathHistory(history);
|
||||
settings()->storeValue(KEY_SAVEPATHHISTORY, history);
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,8 +381,10 @@ void AddNewTorrentDialog::updateDiskSpaceLabel()
|
||||
void AddNewTorrentDialog::onSavePathChanged(int index)
|
||||
{
|
||||
// Toggle default save path setting checkbox visibility
|
||||
ui->default_save_path_cb->setChecked(false);
|
||||
ui->default_save_path_cb->setVisible(QDir(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString()) != QDir(Preferences::instance()->getSavePath()));
|
||||
ui->defaultSavePathCheckBox->setChecked(false);
|
||||
ui->defaultSavePathCheckBox->setVisible(
|
||||
QDir(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString())
|
||||
!= QDir(defaultSavePath()));
|
||||
|
||||
// Remember index
|
||||
m_oldIndex = index;
|
||||
@ -354,6 +392,17 @@ void AddNewTorrentDialog::onSavePathChanged(int index)
|
||||
updateDiskSpaceLabel();
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::categoryChanged(int index)
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
|
||||
if (ui->advancedModeRadioButton->isChecked()) {
|
||||
QString savePath = BitTorrent::Session::instance()->categorySavePath(ui->categoryComboBox->currentText());
|
||||
ui->savePathComboBox->setItemText(0, Utils::Fs::toNativePath(savePath));
|
||||
ui->savePathComboBox->setItemData(0, savePath);
|
||||
}
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::browseButton_clicked()
|
||||
{
|
||||
disconnect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onSavePathChanged(int)));
|
||||
@ -390,7 +439,7 @@ void AddNewTorrentDialog::browseButton_clicked()
|
||||
|
||||
void AddNewTorrentDialog::renameSelectedFile()
|
||||
{
|
||||
const QModelIndexList selectedIndexes = ui->content_tree->selectionModel()->selectedRows(0);
|
||||
const QModelIndexList selectedIndexes = ui->contentTreeView->selectionModel()->selectedRows(0);
|
||||
if (selectedIndexes.size() != 1)
|
||||
return;
|
||||
const QModelIndex &index = selectedIndexes.first();
|
||||
@ -490,7 +539,7 @@ void AddNewTorrentDialog::setdialogPosition()
|
||||
qApp->processEvents();
|
||||
QPoint center(Utils::Misc::screenCenter(this));
|
||||
// Adjust y
|
||||
int y = Preferences::instance()->getAddNewTorrentDialogPos();
|
||||
int y = settings()->loadValue(KEY_POSITION, -1).toInt();
|
||||
if (y >= 0) {
|
||||
center.setY(y);
|
||||
}
|
||||
@ -502,20 +551,23 @@ void AddNewTorrentDialog::setdialogPosition()
|
||||
move(center);
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::loadSavePathHistory()
|
||||
void AddNewTorrentDialog::populateSavePathComboBox()
|
||||
{
|
||||
QDir default_save_path(Preferences::instance()->getSavePath());
|
||||
QString defSavePath = defaultSavePath();
|
||||
|
||||
ui->savePathComboBox->clear();
|
||||
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(defSavePath), defSavePath);
|
||||
QDir defaultSaveDir(defSavePath);
|
||||
// Load save path history
|
||||
QStringList raw_path_history = Preferences::instance()->getAddNewTorrentDialogPathHistory();
|
||||
foreach (const QString &sp, raw_path_history)
|
||||
if (QDir(sp) != default_save_path)
|
||||
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(sp), sp);
|
||||
foreach (const QString &savePath, settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList())
|
||||
if (QDir(savePath) != defaultSaveDir)
|
||||
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(savePath), savePath);
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::displayContentTreeMenu(const QPoint&)
|
||||
{
|
||||
QMenu myFilesLlistMenu;
|
||||
const QModelIndexList selectedRows = ui->content_tree->selectionModel()->selectedRows(0);
|
||||
const QModelIndexList selectedRows = ui->contentTreeView->selectionModel()->selectedRows(0);
|
||||
QAction *actRename = 0;
|
||||
if (selectedRows.size() == 1) {
|
||||
actRename = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
|
||||
@ -557,39 +609,34 @@ void AddNewTorrentDialog::accept()
|
||||
if (!m_hasMetadata)
|
||||
disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo &)));
|
||||
|
||||
Preferences *const pref = Preferences::instance();
|
||||
BitTorrent::AddTorrentParams params;
|
||||
|
||||
if (ui->skip_check_cb->isChecked())
|
||||
// TODO: Check if destination actually exists
|
||||
params.skipChecking = true;
|
||||
|
||||
// Label
|
||||
params.label = ui->label_combo->currentText();
|
||||
// Category
|
||||
params.category = ui->categoryComboBox->currentText();
|
||||
|
||||
if (ui->defaultLabel->isChecked())
|
||||
pref->setDefaultLabel(params.label);
|
||||
if (ui->defaultCategoryCheckbox->isChecked())
|
||||
settings()->storeValue(KEY_DEFAULTCATEGORY, params.category);
|
||||
|
||||
// Save file priorities
|
||||
if (m_contentModel)
|
||||
params.filePriorities = m_contentModel->model()->getFilePriorities();
|
||||
|
||||
params.addPaused = !ui->start_torrent_cb->isChecked();
|
||||
|
||||
saveSavePathHistory();
|
||||
pref->useAdditionDialog(!ui->never_show_cb->isChecked());
|
||||
params.addPaused = !ui->startTorrentCheckBox->isChecked();
|
||||
|
||||
QString savePath = ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString();
|
||||
if (ui->default_save_path_cb->isChecked()) {
|
||||
pref->setSavePath(savePath);
|
||||
pref->apply();
|
||||
}
|
||||
else {
|
||||
// if we don't use default save path...
|
||||
if (QDir(savePath) != QDir(pref->getSavePath()))
|
||||
params.savePath = savePath;
|
||||
if (ui->simpleModeRadioButton->isChecked()) {
|
||||
params.savePath = savePath;
|
||||
saveSavePathHistory();
|
||||
if (ui->defaultSavePathCheckBox->isChecked())
|
||||
settings()->storeValue(KEY_DEFAULTSAVEPATH, savePath);
|
||||
}
|
||||
|
||||
setEnabled(!ui->never_show_cb->isChecked());
|
||||
|
||||
// Add torrent
|
||||
if (!m_hasMetadata)
|
||||
BitTorrent::Session::instance()->addTorrent(m_hash, params);
|
||||
@ -656,28 +703,35 @@ void AddNewTorrentDialog::setupTreeview()
|
||||
// Prepare content tree
|
||||
m_contentModel = new TorrentContentFilterModel(this);
|
||||
connect(m_contentModel->model(), SIGNAL(filteredFilesChanged()), SLOT(updateDiskSpaceLabel()));
|
||||
ui->content_tree->setModel(m_contentModel);
|
||||
ui->content_tree->hideColumn(PROGRESS);
|
||||
ui->contentTreeView->setModel(m_contentModel);
|
||||
ui->contentTreeView->hideColumn(PROGRESS);
|
||||
m_contentDelegate = new PropListDelegate();
|
||||
ui->content_tree->setItemDelegate(m_contentDelegate);
|
||||
connect(ui->content_tree, SIGNAL(clicked(const QModelIndex &)), ui->content_tree, SLOT(edit(const QModelIndex &)));
|
||||
connect(ui->content_tree, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(displayContentTreeMenu(const QPoint &)));
|
||||
ui->contentTreeView->setItemDelegate(m_contentDelegate);
|
||||
connect(ui->contentTreeView, SIGNAL(clicked(const QModelIndex &)), ui->contentTreeView, SLOT(edit(const QModelIndex &)));
|
||||
connect(ui->contentTreeView, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(displayContentTreeMenu(const QPoint &)));
|
||||
|
||||
// List files in torrent
|
||||
m_contentModel->model()->setupModelData(m_torrentInfo);
|
||||
if (!m_headerState.isEmpty())
|
||||
ui->content_tree->header()->restoreState(m_headerState);
|
||||
ui->contentTreeView->header()->restoreState(m_headerState);
|
||||
|
||||
// Expand root folder
|
||||
ui->content_tree->setExpanded(m_contentModel->index(0, 0), true);
|
||||
ui->contentTreeView->setExpanded(m_contentModel->index(0, 0), true);
|
||||
}
|
||||
|
||||
updateDiskSpaceLabel();
|
||||
showAdvancedSettings(Preferences::instance()->getAddNewTorrentDialogExpanded());
|
||||
showAdvancedSettings(settings()->loadValue(KEY_EXPANDED, false).toBool());
|
||||
// Set dialog position
|
||||
setdialogPosition();
|
||||
}
|
||||
|
||||
QString AddNewTorrentDialog::defaultSavePath() const
|
||||
{
|
||||
return Utils::Fs::fromNativePath(
|
||||
settings()->loadValue(KEY_DEFAULTSAVEPATH,
|
||||
BitTorrent::Session::instance()->defaultSavePath()).toString());
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::handleDownloadFailed(const QString &url, const QString &reason)
|
||||
{
|
||||
MessageBoxRaised::critical(0, tr("Download Error"), QString("Cannot download '%1': %2").arg(url).arg(reason));
|
||||
@ -701,3 +755,25 @@ void AddNewTorrentDialog::handleDownloadFinished(const QString &url, const QStri
|
||||
else
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::savingModeChanged(bool enabled)
|
||||
{
|
||||
if (!enabled) return;
|
||||
|
||||
if (ui->simpleModeRadioButton->isChecked()) {
|
||||
populateSavePathComboBox();
|
||||
ui->savePathComboBox->setEnabled(true);
|
||||
ui->browseButton->setEnabled(true);
|
||||
ui->savePathComboBox->blockSignals(false);
|
||||
ui->savePathComboBox->setCurrentIndex(m_oldIndex < ui->savePathComboBox->count() ? m_oldIndex : ui->savePathComboBox->count() - 1);
|
||||
}
|
||||
else {
|
||||
ui->savePathComboBox->blockSignals(true);
|
||||
ui->savePathComboBox->clear();
|
||||
QString savePath = BitTorrent::Session::instance()->categorySavePath(ui->categoryComboBox->currentText());
|
||||
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(savePath), savePath);
|
||||
ui->savePathComboBox->setEnabled(false);
|
||||
ui->browseButton->setEnabled(false);
|
||||
ui->defaultSavePathCheckBox->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
@ -58,10 +58,12 @@ class AddNewTorrentDialog: public QDialog
|
||||
public:
|
||||
~AddNewTorrentDialog();
|
||||
|
||||
static void show(QString source, QWidget *parent = 0);
|
||||
static bool isEnabled();
|
||||
static void setEnabled(bool value);
|
||||
static bool isTopLevel();
|
||||
static void setTopLevel(bool value);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event);
|
||||
static void show(QString source, QWidget *parent = 0);
|
||||
|
||||
private slots:
|
||||
void showAdvancedSettings(bool show);
|
||||
@ -75,24 +77,27 @@ private slots:
|
||||
void handleDownloadFailed(const QString &url, const QString &reason);
|
||||
void handleRedirectedToMagnet(const QString &url, const QString &magnetUri);
|
||||
void handleDownloadFinished(const QString &url, const QString &filePath);
|
||||
void savingModeChanged(bool enabled);
|
||||
void categoryChanged(int index);
|
||||
|
||||
protected slots:
|
||||
virtual void accept();
|
||||
virtual void reject();
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
private:
|
||||
explicit AddNewTorrentDialog(QWidget *parent = 0);
|
||||
bool loadTorrent(const QString &torrentPath);
|
||||
bool loadMagnet(const BitTorrent::MagnetUri &magnetUri);
|
||||
void loadSavePathHistory();
|
||||
void populateSavePathComboBox();
|
||||
void saveSavePathHistory() const;
|
||||
int indexOfSavePath(const QString& save_path);
|
||||
void loadState();
|
||||
void saveState();
|
||||
void setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText = QString());
|
||||
void setupTreeview();
|
||||
QString defaultSavePath() const;
|
||||
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private:
|
||||
Ui::AddNewTorrentDialog *ui;
|
||||
TorrentContentFilterModel *m_contentModel;
|
||||
PropListDelegate *m_contentDelegate;
|
||||
|
@ -17,6 +17,50 @@
|
||||
<string>Save at</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="savingModeLabel">
|
||||
<property name="text">
|
||||
<string>Saving Management:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="simpleModeRadioButton">
|
||||
<property name="text">
|
||||
<string>Simple</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="advancedModeRadioButton">
|
||||
<property name="text">
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
@ -33,7 +77,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="browse_button">
|
||||
<widget class="QPushButton" name="browseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
@ -42,7 +86,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="default_save_path_cb">
|
||||
<widget class="QCheckBox" name="defaultSavePathCheckBox">
|
||||
<property name="text">
|
||||
<string>Set as default save path</string>
|
||||
</property>
|
||||
@ -75,14 +119,14 @@
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="2">
|
||||
<widget class="QCheckBox" name="defaultLabel">
|
||||
<widget class="QCheckBox" name="defaultCategoryCheckbox">
|
||||
<property name="text">
|
||||
<string>Set as default label</string>
|
||||
<string>Set as default category</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_1">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="sizePolicy">
|
||||
@ -92,12 +136,12 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set label:</string>
|
||||
<string>Category:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="label_combo">
|
||||
<widget class="QComboBox" name="categoryComboBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
@ -115,7 +159,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="start_torrent_cb">
|
||||
<widget class="QCheckBox" name="startTorrentCheckBox">
|
||||
<property name="text">
|
||||
<string>Start torrent</string>
|
||||
</property>
|
||||
@ -231,7 +275,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="TorrentContentTreeView" name="content_tree">
|
||||
<widget class="TorrentContentTreeView" name="contentTreeView">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
@ -311,6 +355,20 @@
|
||||
<header>torrentcontenttreeview.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>savePathComboBox</tabstop>
|
||||
<tabstop>browseButton</tabstop>
|
||||
<tabstop>simpleModeRadioButton</tabstop>
|
||||
<tabstop>advancedModeRadioButton</tabstop>
|
||||
<tabstop>defaultSavePathCheckBox</tabstop>
|
||||
<tabstop>never_show_cb</tabstop>
|
||||
<tabstop>adv_button</tabstop>
|
||||
<tabstop>startTorrentCheckBox</tabstop>
|
||||
<tabstop>categoryComboBox</tabstop>
|
||||
<tabstop>defaultCategoryCheckbox</tabstop>
|
||||
<tabstop>skip_check_cb</tabstop>
|
||||
<tabstop>contentTreeView</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
@ -320,8 +378,8 @@
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
<x>403</x>
|
||||
<y>579</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
@ -336,8 +394,8 @@
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
<x>403</x>
|
||||
<y>579</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
@ -345,5 +403,57 @@
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>simpleModeRadioButton</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>AddNewTorrentDialog</receiver>
|
||||
<slot>savingModeChanged(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>154</x>
|
||||
<y>39</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>122</x>
|
||||
<y>6</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>advancedModeRadioButton</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>AddNewTorrentDialog</receiver>
|
||||
<slot>savingModeChanged(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>218</x>
|
||||
<y>44</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>209</x>
|
||||
<y>7</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>categoryComboBox</sender>
|
||||
<signal>currentIndexChanged(int)</signal>
|
||||
<receiver>AddNewTorrentDialog</receiver>
|
||||
<slot>categoryChanged(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>337</x>
|
||||
<y>205</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>403</x>
|
||||
<y>160</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>savingModeChanged(bool)</slot>
|
||||
<slot>categoryChanged(int)</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
|
@ -1004,7 +1004,7 @@ void MainWindow::dropEvent(QDropEvent *event)
|
||||
}
|
||||
|
||||
// Add file to download list
|
||||
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
|
||||
const bool useTorrentAdditionDialog = AddNewTorrentDialog::isEnabled();
|
||||
foreach (QString file, files) {
|
||||
qDebug("Dropped file %s on download list", qPrintable(file));
|
||||
if (useTorrentAdditionDialog)
|
||||
@ -1039,7 +1039,7 @@ void MainWindow::on_actionOpen_triggered()
|
||||
const QStringList pathsList =
|
||||
QFileDialog::getOpenFileNames(0, tr("Open Torrent Files"), pref->getMainLastDir(),
|
||||
tr("Torrent Files") + QString::fromUtf8(" (*.torrent)"));
|
||||
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
|
||||
const bool useTorrentAdditionDialog = AddNewTorrentDialog::isEnabled();
|
||||
if (!pathsList.isEmpty()) {
|
||||
foreach (QString file, pathsList) {
|
||||
qDebug("Dropped file %s on download list", qPrintable(file));
|
||||
@ -1249,7 +1249,7 @@ void MainWindow::showNotificationBaloon(QString title, QString msg) const
|
||||
|
||||
void MainWindow::downloadFromURLList(const QStringList& url_list)
|
||||
{
|
||||
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
|
||||
const bool useTorrentAdditionDialog = AddNewTorrentDialog::isEnabled();
|
||||
foreach (QString url, url_list) {
|
||||
if ((url.size() == 40 && !url.contains(QRegExp("[^0-9A-Fa-f]")))
|
||||
|| (url.size() == 32 && !url.contains(QRegExp("[^2-7A-Za-z]"))))
|
||||
|
@ -546,8 +546,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>487</width>
|
||||
<height>1040</height>
|
||||
<width>454</width>
|
||||
<height>1212</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
@ -599,7 +599,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="fileSystemBox">
|
||||
<widget class="QGroupBox" name="groupSavingManagement">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@ -607,13 +607,57 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Hard Disk</string>
|
||||
<string>Saving Management</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_25">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Default Saving Mode:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioBtnSimpleMode">
|
||||
<property name="text">
|
||||
<string>Simple</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioBtnAdvancedMode">
|
||||
<property name="text">
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_16">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupDefaultSavePath">
|
||||
<property name="title">
|
||||
<string>Save files to location:</string>
|
||||
<string>Default Save Path</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_26">
|
||||
<property name="bottomMargin">
|
||||
@ -658,10 +702,134 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkAppendLabel">
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelEnableSubcategories">
|
||||
<property name="text">
|
||||
<string>Enable Subcategories:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioBtnEnableSubcategories">
|
||||
<property name="text">
|
||||
<string>Yes</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioBtnDisableSubcategories">
|
||||
<property name="text">
|
||||
<string>No</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_17">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupCategoryChanged">
|
||||
<property name="title">
|
||||
<string>When Torrent Category changed</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_6">
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="radioBtnRelocateOnCategoryChanged">
|
||||
<property name="text">
|
||||
<string>Append the label of the torrent to the save path</string>
|
||||
<string>Relocate torrent</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="radioBtnDisableASMOnCategoryChanged">
|
||||
<property name="text">
|
||||
<string>Switch torrent to Simple Mode</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupDefaultSavePathChanged">
|
||||
<property name="title">
|
||||
<string>When Default Save Path changed</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_7">
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="radioBtnRelocateOnDefaultSavePathChanged">
|
||||
<property name="text">
|
||||
<string>Relocate affected torrents</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="radioBtnDisableASMOnDefaultSavePathChanged">
|
||||
<property name="text">
|
||||
<string>Switch affected torrents to Simple Mode</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupCategorySavePathChanged">
|
||||
<property name="title">
|
||||
<string>When Category changed</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_8">
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="radioBtnRelocateOnCategorySavePathChanged">
|
||||
<property name="text">
|
||||
<string>Relocate affected torrents</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="radioBtnDisableASMOnCategorySavePathChanged">
|
||||
<property name="text">
|
||||
<string>Switch affected torrents to Simple Mode</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -728,93 +896,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Automatically add torrents from:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_38">
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_16">
|
||||
<item>
|
||||
<widget class="QTreeView" name="scanFoldersView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::AllEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="textElideMode">
|
||||
<enum>Qt::ElideNone</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="headerDefaultSectionSize">
|
||||
<number>80</number>
|
||||
</attribute>
|
||||
<attribute name="headerStretchLastSection">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_37">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addScanFolderButton">
|
||||
<property name="text">
|
||||
<string>Add folder...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeScanFolderButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="checkExportDir">
|
||||
<property name="sizePolicy">
|
||||
@ -926,6 +1007,93 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Automatically add torrents from:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_38">
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_16">
|
||||
<item>
|
||||
<widget class="QTreeView" name="scanFoldersView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::AllEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="textElideMode">
|
||||
<enum>Qt::ElideNone</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="headerDefaultSectionSize">
|
||||
<number>80</number>
|
||||
</attribute>
|
||||
<attribute name="headerStretchLastSection">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_37">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addScanFolderButton">
|
||||
<property name="text">
|
||||
<string>Add folder...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeScanFolderButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupMailNotification">
|
||||
<property name="title">
|
||||
@ -1062,8 +1230,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>450</width>
|
||||
<height>658</height>
|
||||
<width>361</width>
|
||||
<height>586</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_20">
|
||||
@ -1592,8 +1760,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>376</width>
|
||||
<height>444</height>
|
||||
<width>275</width>
|
||||
<height>401</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
@ -1979,8 +2147,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>555</width>
|
||||
<height>527</height>
|
||||
<width>440</width>
|
||||
<height>481</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
@ -2376,8 +2544,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>419</width>
|
||||
<height>537</height>
|
||||
<width>332</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_23">
|
||||
@ -2950,4 +3118,7 @@
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="buttonGroup"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "advancedsettings.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "scanfoldersdelegate.h"
|
||||
#include "addnewtorrentdialog.h"
|
||||
#include "options_imp.h"
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
@ -168,8 +169,12 @@ options_imp::options_imp(QWidget *parent)
|
||||
#endif
|
||||
// Downloads tab
|
||||
connect(textSavePath, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
|
||||
connect(radioBtnEnableSubcategories, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(radioBtnAdvancedMode, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(radioBtnRelocateOnCategoryChanged, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(radioBtnRelocateOnCategorySavePathChanged, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(radioBtnRelocateOnDefaultSavePathChanged, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(textTempPath, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
|
||||
connect(checkAppendLabel, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(checkAppendqB, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(checkPreallocateAll, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(checkAdditionDialog, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
@ -197,7 +202,7 @@ options_imp::options_imp(QWidget *parent)
|
||||
autoRun_param->setText(QString::fromUtf8("%1\n %2\n %3\n %4\n %5\n %6\n %7\n %8\n %9\n %10")
|
||||
.arg(tr("Supported parameters (case sensitive):"))
|
||||
.arg(tr("%N: Torrent name"))
|
||||
.arg(tr("%L: Label"))
|
||||
.arg(tr("%L: Category"))
|
||||
.arg(tr("%F: Content path (same as root path for multifile torrent)"))
|
||||
.arg(tr("%R: Root path (first torrent subdirectory path)"))
|
||||
.arg(tr("%D: Save path"))
|
||||
@ -429,16 +434,22 @@ void options_imp::saveOptions()
|
||||
#endif
|
||||
// End General preferences
|
||||
|
||||
auto session = BitTorrent::Session::instance();
|
||||
|
||||
// Downloads preferences
|
||||
pref->setSavePath(getSavePath());
|
||||
pref->setTempPathEnabled(isTempPathEnabled());
|
||||
pref->setTempPath(getTempPath());
|
||||
pref->setAppendTorrentLabel(checkAppendLabel->isChecked());
|
||||
session->setDefaultSavePath(Utils::Fs::expandPathAbs(textSavePath->text()));
|
||||
session->setSubcategoriesEnabled(radioBtnEnableSubcategories->isChecked());
|
||||
session->setASMDisabledByDefault(radioBtnSimpleMode->isChecked());
|
||||
session->setDisableASMWhenCategoryChanged(radioBtnDisableASMOnCategoryChanged->isChecked());
|
||||
session->setDisableASMWhenCategorySavePathChanged(radioBtnDisableASMOnCategorySavePathChanged->isChecked());
|
||||
session->setDisableASMWhenDefaultSavePathChanged(radioBtnDisableASMOnDefaultSavePathChanged->isChecked());
|
||||
session->setTempPathEnabled(checkTempFolder->isChecked());
|
||||
session->setTempPath(Utils::Fs::expandPathAbs(textTempPath->text()));
|
||||
pref->useIncompleteFilesExtension(checkAppendqB->isChecked());
|
||||
pref->preAllocateAllFiles(preAllocateAllFiles());
|
||||
pref->useAdditionDialog(useAdditionDialog());
|
||||
pref->additionDialogFront(checkAdditionDialogFront->isChecked());
|
||||
pref->addTorrentsInPause(addTorrentsInPause());
|
||||
AddNewTorrentDialog::setEnabled(useAdditionDialog());
|
||||
AddNewTorrentDialog::setTopLevel(checkAdditionDialogFront->isChecked());
|
||||
session->setAddTorrentPaused(addTorrentsInPause());
|
||||
ScanFoldersModel::instance()->removeFromFSWatcher(removedScanDirs);
|
||||
ScanFoldersModel::instance()->addToFSWatcher(addedScanDirs);
|
||||
ScanFoldersModel::instance()->makePersistent();
|
||||
@ -500,7 +511,7 @@ void options_imp::saveOptions()
|
||||
pref->setAddTrackersEnabled(checkEnableAddTrackers->isChecked());
|
||||
pref->setTrackersList(textTrackers->toPlainText());
|
||||
pref->setGlobalMaxRatio(getMaxRatio());
|
||||
pref->setMaxRatioAction(static_cast<MaxRatioAction>(comboRatioLimitAct->currentIndex()));
|
||||
session->setMaxRatioAction(static_cast<MaxRatioAction>(comboRatioLimitAct->currentIndex()));
|
||||
// End Bittorrent preferences
|
||||
// Misc preferences
|
||||
// * IPFilter
|
||||
@ -610,18 +621,21 @@ void options_imp::loadOptions()
|
||||
#endif
|
||||
// End General preferences
|
||||
|
||||
// Downloads preferences
|
||||
checkAdditionDialog->setChecked(pref->useAdditionDialog());
|
||||
checkAdditionDialogFront->setChecked(pref->additionDialogFront());
|
||||
checkStartPaused->setChecked(pref->addTorrentsInPause());
|
||||
auto session = BitTorrent::Session::instance();
|
||||
|
||||
textSavePath->setText(Utils::Fs::toNativePath(pref->getSavePath()));
|
||||
if (pref->isTempPathEnabled())
|
||||
checkTempFolder->setChecked(true);
|
||||
else
|
||||
checkTempFolder->setChecked(false);
|
||||
textTempPath->setText(Utils::Fs::toNativePath(pref->getTempPath()));
|
||||
checkAppendLabel->setChecked(pref->appendTorrentLabel());
|
||||
// Downloads preferences
|
||||
checkAdditionDialog->setChecked(AddNewTorrentDialog::isEnabled());
|
||||
checkAdditionDialogFront->setChecked(AddNewTorrentDialog::isTopLevel());
|
||||
checkStartPaused->setChecked(session->isAddTorrentPaused());
|
||||
|
||||
textSavePath->setText(Utils::Fs::toNativePath(session->defaultSavePath()));
|
||||
(session->isSubcategoriesEnabled() ? radioBtnEnableSubcategories : radioBtnDisableSubcategories)->setChecked(true);
|
||||
(session->isASMDisabledByDefault() ? radioBtnSimpleMode : radioBtnAdvancedMode)->setChecked(true);
|
||||
(session->isDisableASMWhenCategoryChanged() ? radioBtnDisableASMOnCategoryChanged : radioBtnRelocateOnCategoryChanged)->setChecked(true);
|
||||
(session->isDisableASMWhenCategorySavePathChanged() ? radioBtnDisableASMOnCategorySavePathChanged : radioBtnRelocateOnCategorySavePathChanged)->setChecked(true);
|
||||
(session->isDisableASMWhenDefaultSavePathChanged() ? radioBtnDisableASMOnDefaultSavePathChanged : radioBtnRelocateOnDefaultSavePathChanged)->setChecked(true);
|
||||
checkTempFolder->setChecked(session->isTempPathEnabled());
|
||||
textTempPath->setText(Utils::Fs::toNativePath(session->tempPath()));
|
||||
checkAppendqB->setChecked(pref->useIncompleteFilesExtension());
|
||||
checkPreallocateAll->setChecked(pref->preAllocateAllFiles());
|
||||
|
||||
@ -844,7 +858,7 @@ void options_imp::loadOptions()
|
||||
spinMaxRatio->setEnabled(false);
|
||||
comboRatioLimitAct->setEnabled(false);
|
||||
}
|
||||
comboRatioLimitAct->setCurrentIndex(static_cast<int>(pref->getMaxRatioAction()));
|
||||
comboRatioLimitAct->setCurrentIndex(session->maxRatioAction());
|
||||
// End Bittorrent preferences
|
||||
|
||||
// Web UI preferences
|
||||
@ -974,26 +988,6 @@ qreal options_imp::getMaxRatio() const
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return Save Path
|
||||
QString options_imp::getSavePath() const
|
||||
{
|
||||
if (textSavePath->text().trimmed().isEmpty()) {
|
||||
QString save_path = Preferences::instance()->getSavePath();
|
||||
textSavePath->setText(Utils::Fs::toNativePath(save_path));
|
||||
}
|
||||
return Utils::Fs::expandPathAbs(textSavePath->text());
|
||||
}
|
||||
|
||||
QString options_imp::getTempPath() const
|
||||
{
|
||||
return Utils::Fs::expandPathAbs(textTempPath->text());
|
||||
}
|
||||
|
||||
bool options_imp::isTempPathEnabled() const
|
||||
{
|
||||
return checkTempFolder->isChecked();
|
||||
}
|
||||
|
||||
// Return max connections number
|
||||
int options_imp::getMaxConnecs() const
|
||||
{
|
||||
|
@ -114,9 +114,6 @@ private:
|
||||
bool WinStartup() const;
|
||||
#endif
|
||||
// Downloads
|
||||
QString getSavePath() const;
|
||||
bool isTempPathEnabled() const;
|
||||
QString getTempPath() const;
|
||||
bool preAllocateAllFiles() const;
|
||||
bool useAdditionDialog() const;
|
||||
bool addTorrentsInPause() const;
|
||||
|
@ -34,17 +34,18 @@
|
||||
#include <QMenu>
|
||||
#include <QCursor>
|
||||
|
||||
#include "automatedrssdownloader.h"
|
||||
#include "ui_automatedrssdownloader.h"
|
||||
#include "base/rss/rssdownloadrulelist.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/rss/rssdownloadrulelist.h"
|
||||
#include "base/rss/rssmanager.h"
|
||||
#include "base/rss/rssfolder.h"
|
||||
#include "base/rss/rssfeed.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/string.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "ui_automatedrssdownloader.h"
|
||||
#include "automatedrssdownloader.h"
|
||||
|
||||
AutomatedRssDownloader::AutomatedRssDownloader(const QWeakPointer<Rss::Manager>& manager, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
@ -85,7 +86,7 @@ AutomatedRssDownloader::AutomatedRssDownloader(const QWeakPointer<Rss::Manager>&
|
||||
"<li>" + tr("Normal range: <b>1x25-40;</b> matches episodes 25 through 40 of season one") + "</li>" +
|
||||
"<li>" + tr("Infinite range: <b>1x25-;</b> matches episodes 25 and upward of season one") + "</li>" + "</ul></li></ul>";
|
||||
ui->lineEFilter->setToolTip(tip);
|
||||
initLabelCombobox();
|
||||
initCategoryCombobox();
|
||||
loadFeedList();
|
||||
loadSettings();
|
||||
ok = connect(ui->listRules, SIGNAL(itemSelectionChanged()), SLOT(updateRuleDefinitionBox()));
|
||||
@ -253,11 +254,11 @@ void AutomatedRssDownloader::updateRuleDefinitionBox()
|
||||
ui->checkRegex->blockSignals(true);
|
||||
ui->checkRegex->setChecked(rule->useRegex());
|
||||
ui->checkRegex->blockSignals(false);
|
||||
if (rule->label().isEmpty()) {
|
||||
ui->comboLabel->setCurrentIndex(-1);
|
||||
ui->comboLabel->clearEditText();
|
||||
if (rule->category().isEmpty()) {
|
||||
ui->comboCategory->setCurrentIndex(-1);
|
||||
ui->comboCategory->clearEditText();
|
||||
} else {
|
||||
ui->comboLabel->setCurrentIndex(ui->comboLabel->findText(rule->label()));
|
||||
ui->comboCategory->setCurrentIndex(ui->comboCategory->findText(rule->category()));
|
||||
}
|
||||
ui->comboAddPaused->setCurrentIndex(rule->addPaused());
|
||||
ui->spinIgnorePeriod->setValue(rule->ignoreDays());
|
||||
@ -293,7 +294,7 @@ void AutomatedRssDownloader::clearRuleDefinitionBox()
|
||||
ui->lineNotContains->clear();
|
||||
ui->saveDiffDir_check->setChecked(false);
|
||||
ui->lineSavePath->clear();
|
||||
ui->comboLabel->clearEditText();
|
||||
ui->comboCategory->clearEditText();
|
||||
ui->checkRegex->setChecked(false);
|
||||
ui->spinIgnorePeriod->setValue(0);
|
||||
updateFieldsToolTips(ui->checkRegex->isChecked());
|
||||
@ -309,13 +310,12 @@ Rss::DownloadRulePtr AutomatedRssDownloader::getCurrentRule() const
|
||||
return Rss::DownloadRulePtr();
|
||||
}
|
||||
|
||||
void AutomatedRssDownloader::initLabelCombobox()
|
||||
void AutomatedRssDownloader::initCategoryCombobox()
|
||||
{
|
||||
// Load custom labels
|
||||
QStringList customLabels = Preferences::instance()->getTorrentLabels();
|
||||
std::sort(customLabels.begin(), customLabels.end(), Utils::String::NaturalCompare());
|
||||
foreach (const QString& l, customLabels)
|
||||
ui->comboLabel->addItem(l);
|
||||
// Load torrent categories
|
||||
QStringList categories = BitTorrent::Session::instance()->categories();
|
||||
std::sort(categories.begin(), categories.end(), Utils::String::NaturalCompare());
|
||||
ui->comboCategory->addItems(categories);
|
||||
}
|
||||
|
||||
void AutomatedRssDownloader::saveEditedRule()
|
||||
@ -344,11 +344,9 @@ void AutomatedRssDownloader::saveEditedRule()
|
||||
rule->setSavePath(ui->lineSavePath->text());
|
||||
else
|
||||
rule->setSavePath("");
|
||||
rule->setLabel(ui->comboLabel->currentText());
|
||||
rule->setCategory(ui->comboCategory->currentText());
|
||||
|
||||
rule->setAddPaused(Rss::DownloadRule::AddPausedState(ui->comboAddPaused->currentIndex()));
|
||||
// Save new label
|
||||
if (!rule->label().isEmpty())
|
||||
Preferences::instance()->addTorrentLabelExternal(rule->label());
|
||||
rule->setIgnoreDays(ui->spinIgnorePeriod->value());
|
||||
//rule->setRssFeeds(getSelectedFeeds());
|
||||
// Save it
|
||||
|
@ -90,7 +90,7 @@ private slots:
|
||||
|
||||
private:
|
||||
Rss::DownloadRulePtr getCurrentRule() const;
|
||||
void initLabelCombobox();
|
||||
void initCategoryCombobox();
|
||||
void addFeedArticlesToTree(const Rss::FeedPtr& feed, const QStringList& articles);
|
||||
|
||||
private:
|
||||
|
@ -177,14 +177,14 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Assign Label:</string>
|
||||
<string>Assign Category:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboLabel">
|
||||
<widget class="QComboBox" name="comboCategory">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -352,7 +352,7 @@ void RSSImp::downloadSelectedTorrents()
|
||||
|
||||
if (article->torrentUrl().isEmpty())
|
||||
continue;
|
||||
if (Preferences::instance()->useAdditionDialog())
|
||||
if (AddNewTorrentDialog::isEnabled())
|
||||
AddNewTorrentDialog::show(article->torrentUrl());
|
||||
else
|
||||
BitTorrent::Session::instance()->addTorrent(article->torrentUrl());
|
||||
|
@ -36,7 +36,7 @@
|
||||
#include <QItemSelectionModel>
|
||||
|
||||
#include "base/scanfoldersmodel.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "scanfoldersdelegate.h"
|
||||
|
||||
|
||||
@ -102,7 +102,7 @@ void ScanFoldersDelegate::setModelData(QWidget *editor, QAbstractItemModel *mode
|
||||
0, tr("Choose save path"),
|
||||
index.data(Qt::UserRole).toInt() == ScanFoldersModel::CUSTOM_LOCATION ?
|
||||
index.data().toString() :
|
||||
Preferences::instance()->getSavePath()),
|
||||
BitTorrent::Session::instance()->defaultSavePath()),
|
||||
Qt::DisplayRole);
|
||||
break;
|
||||
|
||||
|
@ -259,7 +259,7 @@ void SearchWidget::saveResultsColumnsWidth()
|
||||
|
||||
void SearchWidget::downloadTorrent(QString url)
|
||||
{
|
||||
if (Preferences::instance()->useAdditionDialog())
|
||||
if (AddNewTorrentDialog::isEnabled())
|
||||
AddNewTorrentDialog::show(url, this);
|
||||
else
|
||||
BitTorrent::Session::instance()->addTorrent(url);
|
||||
|
@ -104,7 +104,7 @@ QVariant TorrentModel::headerData(int section, Qt::Orientation orientation, int
|
||||
case TR_UPSPEED: return tr("Up Speed", "i.e: Upload speed");
|
||||
case TR_RATIO: return tr("Ratio", "Share ratio");
|
||||
case TR_ETA: return tr("ETA", "i.e: Estimated Time of Arrival / Time left");
|
||||
case TR_LABEL: return tr("Label");
|
||||
case TR_CATEGORY: return tr("Category");
|
||||
case TR_ADD_DATE: return tr("Added On", "Torrent was added to transfer list on 01/01/2010 08:00");
|
||||
case TR_SEED_DATE: return tr("Completed On", "Torrent was completed on 01/01/2010 08:00");
|
||||
case TR_TRACKER: return tr("Tracker");
|
||||
@ -196,8 +196,8 @@ QVariant TorrentModel::data(const QModelIndex &index, int role) const
|
||||
return torrent->eta();
|
||||
case TR_RATIO:
|
||||
return torrent->realRatio();
|
||||
case TR_LABEL:
|
||||
return torrent->label();
|
||||
case TR_CATEGORY:
|
||||
return torrent->category();
|
||||
case TR_ADD_DATE:
|
||||
return torrent->addedTime();
|
||||
case TR_SEED_DATE:
|
||||
@ -250,13 +250,13 @@ bool TorrentModel::setData(const QModelIndex &index, const QVariant &value, int
|
||||
BitTorrent::TorrentHandle *const torrent = m_torrents.value(index.row());
|
||||
if (!torrent) return false;
|
||||
|
||||
// Label, seed date and Name columns can be edited
|
||||
// Category, seed date and Name columns can be edited
|
||||
switch(index.column()) {
|
||||
case TR_NAME:
|
||||
torrent->setName(value.toString());
|
||||
break;
|
||||
case TR_LABEL:
|
||||
torrent->setLabel(value.toString());
|
||||
case TR_CATEGORY:
|
||||
torrent->setCategory(value.toString());
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
@ -61,7 +61,7 @@ public:
|
||||
TR_UPSPEED,
|
||||
TR_ETA,
|
||||
TR_RATIO,
|
||||
TR_LABEL,
|
||||
TR_CATEGORY,
|
||||
TR_ADD_DATE,
|
||||
TR_SEED_DATE,
|
||||
TR_TRACKER,
|
||||
|
@ -177,162 +177,156 @@ void StatusFiltersWidget::handleNewTorrent(BitTorrent::TorrentHandle *const) {}
|
||||
|
||||
void StatusFiltersWidget::torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const) {}
|
||||
|
||||
LabelFiltersList::LabelFiltersList(QWidget *parent, TransferListWidget *transferList)
|
||||
CategoryFiltersList::CategoryFiltersList(QWidget *parent, TransferListWidget *transferList)
|
||||
: FiltersBase(parent, transferList)
|
||||
, m_totalTorrents(0)
|
||||
, m_totalLabeled(0)
|
||||
{
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentLabelChanged(BitTorrent::TorrentHandle *const, QString)), SLOT(torrentChangedLabel(BitTorrent::TorrentHandle *const, QString)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString)), SLOT(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(categoryAdded(QString)), SLOT(addItem(QString)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(categoryRemoved(QString)), SLOT(categoryRemoved(QString)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(subcategoriesSupportChanged()), SLOT(subcategoriesSupportChanged()));
|
||||
|
||||
// Add Label filters
|
||||
QListWidgetItem *allLabels = new QListWidgetItem(this);
|
||||
allLabels->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the label filter")));
|
||||
allLabels->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
|
||||
QListWidgetItem *noLabel = new QListWidgetItem(this);
|
||||
noLabel->setData(Qt::DisplayRole, QVariant(tr("Unlabeled (0)")));
|
||||
noLabel->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
|
||||
refresh();
|
||||
toggleFilter(Preferences::instance()->getCategoryFilterState());
|
||||
}
|
||||
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
QStringList labelList = pref->getTorrentLabels();
|
||||
for (int i=0; i < labelList.size(); ++i)
|
||||
addItem(labelList[i], false);
|
||||
void CategoryFiltersList::refresh()
|
||||
{
|
||||
clear();
|
||||
m_categories.clear();
|
||||
m_totalTorrents = 0;
|
||||
m_totalCategorized = 0;
|
||||
|
||||
QListWidgetItem *allCategories = new QListWidgetItem(this);
|
||||
allCategories->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the category filter")));
|
||||
allCategories->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
|
||||
QListWidgetItem *noCategory = new QListWidgetItem(this);
|
||||
noCategory->setData(Qt::DisplayRole, QVariant(tr("Uncategorized (0)")));
|
||||
noCategory->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
|
||||
|
||||
foreach (const QString &category, BitTorrent::Session::instance()->categories())
|
||||
addItem(category, false);
|
||||
|
||||
foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents())
|
||||
handleNewTorrent(torrent);
|
||||
|
||||
setCurrentRow(0, QItemSelectionModel::SelectCurrent);
|
||||
toggleFilter(pref->getLabelFilterState());
|
||||
}
|
||||
|
||||
LabelFiltersList::~LabelFiltersList()
|
||||
void CategoryFiltersList::addItem(const QString &category, bool hasTorrent)
|
||||
{
|
||||
Preferences::instance()->setTorrentLabels(m_labels.keys());
|
||||
}
|
||||
if (category.isEmpty()) return;
|
||||
|
||||
void LabelFiltersList::addItem(QString &label, bool hasTorrent)
|
||||
{
|
||||
int labelCount = 0;
|
||||
QListWidgetItem *labelItem = 0;
|
||||
label = Utils::Fs::toValidFileSystemName(label.trimmed());
|
||||
item(0)->setText(tr("All (%1)", "this is for the label filter").arg(m_totalTorrents));
|
||||
int torrentsInCategory = 0;
|
||||
QListWidgetItem *categoryItem = 0;
|
||||
|
||||
if (label.isEmpty()) {
|
||||
item(1)->setText(tr("Unlabeled (%1)").arg(m_totalTorrents - m_totalLabeled));
|
||||
return;
|
||||
}
|
||||
|
||||
bool exists = m_labels.contains(label);
|
||||
bool exists = m_categories.contains(category);
|
||||
if (exists) {
|
||||
labelCount = m_labels.value(label);
|
||||
labelItem = item(rowFromLabel(label));
|
||||
torrentsInCategory = m_categories.value(category);
|
||||
categoryItem = item(rowFromCategory(category));
|
||||
}
|
||||
else {
|
||||
labelItem = new QListWidgetItem();
|
||||
labelItem->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
|
||||
categoryItem = new QListWidgetItem();
|
||||
categoryItem->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
|
||||
}
|
||||
|
||||
if (hasTorrent) {
|
||||
++m_totalLabeled;
|
||||
++labelCount;
|
||||
}
|
||||
item(1)->setText(tr("Unlabeled (%1)").arg(m_totalTorrents - m_totalLabeled));
|
||||
if (hasTorrent)
|
||||
++torrentsInCategory;
|
||||
|
||||
Preferences::instance()->addTorrentLabel(label);
|
||||
m_labels.insert(label, labelCount);
|
||||
labelItem->setText(tr("%1 (%2)", "label_name (10)").arg(label).arg(labelCount));
|
||||
if (exists)
|
||||
return;
|
||||
m_categories.insert(category, torrentsInCategory);
|
||||
categoryItem->setText(tr("%1 (%2)", "category_name (10)").arg(category).arg(torrentsInCategory));
|
||||
if (exists) return;
|
||||
|
||||
Q_ASSERT(count() >= 2);
|
||||
for (int i = 2; i<count(); ++i) {
|
||||
for (int i = 2; i < count(); ++i) {
|
||||
bool less = false;
|
||||
if (!(Utils::String::naturalSort(label, item(i)->text(), less)))
|
||||
less = (label.localeAwareCompare(item(i)->text()) < 0);
|
||||
if (!(Utils::String::naturalSort(category, item(i)->text(), less)))
|
||||
less = (category.localeAwareCompare(item(i)->text()) < 0);
|
||||
if (less) {
|
||||
insertItem(i, labelItem);
|
||||
insertItem(i, categoryItem);
|
||||
updateGeometry();
|
||||
return;
|
||||
}
|
||||
}
|
||||
QListWidget::addItem(labelItem);
|
||||
QListWidget::addItem(categoryItem);
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void LabelFiltersList::removeItem(const QString &label)
|
||||
void CategoryFiltersList::removeItem(const QString &category)
|
||||
{
|
||||
item(0)->setText(tr("All (%1)", "this is for the label filter").arg(m_totalTorrents));
|
||||
if (label.isEmpty()) {
|
||||
// In case we here from torrentAboutToBeDeleted()
|
||||
item(1)->setText(tr("Unlabeled (%1)").arg(m_totalTorrents - m_totalLabeled));
|
||||
return;
|
||||
}
|
||||
if (category.isEmpty()) return;
|
||||
|
||||
--m_totalLabeled;
|
||||
item(1)->setText(tr("Unlabeled (%1)").arg(m_totalTorrents - m_totalLabeled));
|
||||
int torrentsInCategory = m_categories.value(category) - 1;
|
||||
int row = rowFromCategory(category);
|
||||
if (row < 2) return;
|
||||
|
||||
int labelCount = m_labels.value(label) - 1;
|
||||
int row = rowFromLabel(label);
|
||||
if (row < 2)
|
||||
return;
|
||||
|
||||
QListWidgetItem *labelItem = item(row);
|
||||
labelItem->setText(tr("%1 (%2)", "label_name (10)").arg(label).arg(labelCount));
|
||||
m_labels.insert(label, labelCount);
|
||||
QListWidgetItem *categoryItem = item(row);
|
||||
categoryItem->setText(tr("%1 (%2)", "category_name (10)").arg(category).arg(torrentsInCategory));
|
||||
m_categories.insert(category, torrentsInCategory);
|
||||
}
|
||||
|
||||
void LabelFiltersList::removeSelectedLabel()
|
||||
void CategoryFiltersList::removeSelectedCategory()
|
||||
{
|
||||
QList<QListWidgetItem*> items = selectedItems();
|
||||
if (items.size() == 0) return;
|
||||
|
||||
const int labelRow = row(items.first());
|
||||
if (labelRow < 2) return;
|
||||
const int categoryRow = row(items.first());
|
||||
if (categoryRow < 2) return;
|
||||
|
||||
const QString &label = labelFromRow(labelRow);
|
||||
Q_ASSERT(m_labels.contains(label));
|
||||
m_labels.remove(label);
|
||||
// Select first label
|
||||
setCurrentRow(0, QItemSelectionModel::SelectCurrent);
|
||||
// Un display filter
|
||||
delete takeItem(labelRow);
|
||||
transferList->removeLabelFromRows(label);
|
||||
// Save custom labels to remember it was deleted
|
||||
Preferences::instance()->removeTorrentLabel(label);
|
||||
BitTorrent::Session::instance()->removeCategory(categoryFromRow(categoryRow));
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void LabelFiltersList::removeUnusedLabels()
|
||||
void CategoryFiltersList::removeUnusedCategories()
|
||||
{
|
||||
QStringList unusedLabels;
|
||||
QHash<QString, int>::const_iterator i;
|
||||
for (i = m_labels.begin(); i != m_labels.end(); ++i) {
|
||||
if (i.value() == 0)
|
||||
unusedLabels << i.key();
|
||||
}
|
||||
foreach (const QString &label, unusedLabels) {
|
||||
m_labels.remove(label);
|
||||
delete takeItem(rowFromLabel(label));
|
||||
Preferences::instance()->removeTorrentLabel(label);
|
||||
}
|
||||
|
||||
if (!unusedLabels.isEmpty())
|
||||
updateGeometry();
|
||||
foreach (const QString &category, m_categories.keys())
|
||||
if (m_categories[category] == 0)
|
||||
BitTorrent::Session::instance()->removeCategory(category);
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void LabelFiltersList::torrentChangedLabel(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel)
|
||||
void CategoryFiltersList::torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory)
|
||||
{
|
||||
qDebug("Torrent label changed from %s to %s", qPrintable(oldLabel), qPrintable(torrent->label()));
|
||||
removeItem(oldLabel);
|
||||
QString newLabel = torrent->label();
|
||||
addItem(newLabel, true);
|
||||
qDebug() << "Torrent category changed from" << oldCategory << "to" << torrent->category();
|
||||
|
||||
if (torrent->category().isEmpty() && !oldCategory.isEmpty())
|
||||
--m_totalCategorized;
|
||||
else if (!torrent->category().isEmpty() && oldCategory.isEmpty())
|
||||
++m_totalCategorized;
|
||||
|
||||
item(1)->setText(tr("Uncategorized (%1)").arg(m_totalTorrents - m_totalCategorized));
|
||||
|
||||
if (BitTorrent::Session::instance()->isSubcategoriesEnabled()) {
|
||||
foreach (const QString &subcategory, BitTorrent::Session::expandCategory(oldCategory))
|
||||
removeItem(subcategory);
|
||||
foreach (const QString &subcategory, BitTorrent::Session::expandCategory(torrent->category()))
|
||||
addItem(subcategory, true);
|
||||
}
|
||||
else {
|
||||
removeItem(oldCategory);
|
||||
addItem(torrent->category(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void LabelFiltersList::showMenu(QPoint)
|
||||
void CategoryFiltersList::categoryRemoved(const QString &category)
|
||||
{
|
||||
m_categories.remove(category);
|
||||
delete takeItem(rowFromCategory(category));
|
||||
}
|
||||
|
||||
void CategoryFiltersList::subcategoriesSupportChanged()
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void CategoryFiltersList::showMenu(QPoint)
|
||||
{
|
||||
QMenu menu(this);
|
||||
QAction *addAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("Add label..."));
|
||||
QAction *addAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("Add category..."));
|
||||
QAction *removeAct = 0;
|
||||
QAction *removeUnusedAct = 0;
|
||||
if (!selectedItems().empty() && row(selectedItems().first()) > 1)
|
||||
removeAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove label"));
|
||||
removeUnusedAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove unused labels"));
|
||||
removeAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove category"));
|
||||
removeUnusedAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove unused categories"));
|
||||
menu.addSeparator();
|
||||
QAction *startAct = menu.addAction(GuiIconProvider::instance()->getIcon("media-playback-start"), tr("Resume torrents"));
|
||||
QAction *pauseAct = menu.addAction(GuiIconProvider::instance()->getIcon("media-playback-pause"), tr("Pause torrents"));
|
||||
@ -343,10 +337,10 @@ void LabelFiltersList::showMenu(QPoint)
|
||||
return;
|
||||
|
||||
if (act == removeAct) {
|
||||
removeSelectedLabel();
|
||||
removeSelectedCategory();
|
||||
}
|
||||
else if (act == removeUnusedAct) {
|
||||
removeUnusedLabels();
|
||||
removeUnusedCategories();
|
||||
}
|
||||
else if (act == deleteTorrentsAct) {
|
||||
transferList->deleteVisibleTorrents();
|
||||
@ -359,64 +353,90 @@ void LabelFiltersList::showMenu(QPoint)
|
||||
}
|
||||
else if (act == addAct) {
|
||||
bool ok;
|
||||
QString label = "";
|
||||
QString category = "";
|
||||
bool invalid;
|
||||
do {
|
||||
invalid = false;
|
||||
label = AutoExpandableDialog::getText(this, tr("New Label"), tr("Label:"), QLineEdit::Normal, label, &ok);
|
||||
if (ok && !label.isEmpty()) {
|
||||
if (Utils::Fs::isValidFileSystemName(label)) {
|
||||
addItem(label, false);
|
||||
category = AutoExpandableDialog::getText(this, tr("New Category"), tr("Category:"), QLineEdit::Normal, category, &ok);
|
||||
if (ok && !category.isEmpty()) {
|
||||
if (!BitTorrent::Session::isValidCategoryName(category)) {
|
||||
QMessageBox::warning(this, tr("Invalid category name"),
|
||||
tr("Category name must not contain '\\'.\n"
|
||||
"Category name must not start/end with '/'.\n"
|
||||
"Category name must not contain '//' sequence."));
|
||||
invalid = true;
|
||||
}
|
||||
else {
|
||||
QMessageBox::warning(this, tr("Invalid label name"), tr("Please don't use any special characters in the label name."));
|
||||
invalid = true;
|
||||
BitTorrent::Session::instance()->addCategory(category);
|
||||
}
|
||||
}
|
||||
} while (invalid);
|
||||
}
|
||||
}
|
||||
|
||||
void LabelFiltersList::applyFilter(int row)
|
||||
void CategoryFiltersList::applyFilter(int row)
|
||||
{
|
||||
transferList->applyLabelFilter(labelFromRow(row));
|
||||
if (row >= 0)
|
||||
transferList->applyCategoryFilter(categoryFromRow(row));
|
||||
}
|
||||
|
||||
void LabelFiltersList::handleNewTorrent(BitTorrent::TorrentHandle *const torrent)
|
||||
void CategoryFiltersList::handleNewTorrent(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
Q_ASSERT(torrent);
|
||||
|
||||
++m_totalTorrents;
|
||||
QString label = torrent->label();
|
||||
addItem(label, true);
|
||||
// FIXME: Drop this confusion.
|
||||
// labelFilters->addItem() may have changed the label, update the model accordingly.
|
||||
torrent->setLabel(label);
|
||||
if (!torrent->category().isEmpty())
|
||||
++m_totalCategorized;
|
||||
|
||||
item(0)->setText(tr("All (%1)", "this is for the category filter").arg(m_totalTorrents));
|
||||
item(1)->setText(tr("Uncategorized (%1)").arg(m_totalTorrents - m_totalCategorized));
|
||||
|
||||
if (BitTorrent::Session::instance()->isSubcategoriesEnabled()) {
|
||||
foreach (const QString &subcategory, BitTorrent::Session::expandCategory(torrent->category()))
|
||||
addItem(subcategory, true);
|
||||
}
|
||||
else {
|
||||
addItem(torrent->category(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void LabelFiltersList::torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent)
|
||||
void CategoryFiltersList::torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
Q_ASSERT(torrent);
|
||||
|
||||
--m_totalTorrents;
|
||||
removeItem(torrent->label());
|
||||
if (!torrent->category().isEmpty())
|
||||
--m_totalCategorized;
|
||||
|
||||
item(0)->setText(tr("All (%1)", "this is for the category filter").arg(m_totalTorrents));
|
||||
item(1)->setText(tr("Uncategorized (%1)").arg(m_totalTorrents - m_totalCategorized));
|
||||
|
||||
if (BitTorrent::Session::instance()->isSubcategoriesEnabled()) {
|
||||
foreach (const QString &subcategory, BitTorrent::Session::expandCategory(torrent->category()))
|
||||
removeItem(subcategory);
|
||||
}
|
||||
else {
|
||||
removeItem(torrent->category());
|
||||
}
|
||||
}
|
||||
|
||||
QString LabelFiltersList::labelFromRow(int row) const
|
||||
QString CategoryFiltersList::categoryFromRow(int row) const
|
||||
{
|
||||
if (row == 0) return QString(); // All
|
||||
if (row == 1) return QLatin1String(""); // Unlabeled
|
||||
if (row == 1) return QLatin1String(""); // Uncategorized
|
||||
|
||||
const QString &label = item(row)->text();
|
||||
QStringList parts = label.split(" ");
|
||||
const QString &category = item(row)->text();
|
||||
QStringList parts = category.split(" ");
|
||||
Q_ASSERT(parts.size() >= 2);
|
||||
parts.removeLast(); // Remove trailing number
|
||||
return parts.join(" ");
|
||||
}
|
||||
|
||||
int LabelFiltersList::rowFromLabel(const QString &label) const
|
||||
int CategoryFiltersList::rowFromCategory(const QString &category) const
|
||||
{
|
||||
Q_ASSERT(!label.isEmpty());
|
||||
Q_ASSERT(!category.isEmpty());
|
||||
for (int i = 2; i<count(); ++i)
|
||||
if (label == labelFromRow(i)) return i;
|
||||
if (category == categoryFromRow(i)) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -425,7 +445,7 @@ TrackerFiltersList::TrackerFiltersList(QWidget *parent, TransferListWidget *tran
|
||||
, m_totalTorrents(0)
|
||||
{
|
||||
QListWidgetItem *allTrackers = new QListWidgetItem(this);
|
||||
allTrackers->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the label filter")));
|
||||
allTrackers->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the tracker filter")));
|
||||
allTrackers->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("network-server"));
|
||||
QListWidgetItem *noTracker = new QListWidgetItem(this);
|
||||
noTracker->setData(Qt::DisplayRole, QVariant(tr("Trackerless (0)")));
|
||||
@ -799,13 +819,13 @@ TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferLi
|
||||
StatusFiltersWidget *statusFilters = new StatusFiltersWidget(this, transferList);
|
||||
frameLayout->addWidget(statusFilters);
|
||||
|
||||
QCheckBox *labelLabel = new QCheckBox(tr("Labels"), this);
|
||||
labelLabel->setChecked(pref->getLabelFilterState());
|
||||
labelLabel->setFont(font);
|
||||
frameLayout->addWidget(labelLabel);
|
||||
QCheckBox *categoryLabel = new QCheckBox(tr("Categories"), this);
|
||||
categoryLabel->setChecked(pref->getCategoryFilterState());
|
||||
categoryLabel->setFont(font);
|
||||
frameLayout->addWidget(categoryLabel);
|
||||
|
||||
LabelFiltersList *labelFilters = new LabelFiltersList(this, transferList);
|
||||
frameLayout->addWidget(labelFilters);
|
||||
CategoryFiltersList *categoryFilters = new CategoryFiltersList(this, transferList);
|
||||
frameLayout->addWidget(categoryFilters);
|
||||
|
||||
QCheckBox *trackerLabel = new QCheckBox(tr("Trackers"), this);
|
||||
trackerLabel->setChecked(pref->getTrackerFilterState());
|
||||
@ -817,9 +837,8 @@ TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferLi
|
||||
|
||||
connect(statusLabel, SIGNAL(toggled(bool)), statusFilters, SLOT(toggleFilter(bool)));
|
||||
connect(statusLabel, SIGNAL(toggled(bool)), pref, SLOT(setStatusFilterState(const bool)));
|
||||
connect(labelLabel, SIGNAL(toggled(bool)), labelFilters, SLOT(toggleFilter(bool)));
|
||||
connect(labelLabel, SIGNAL(toggled(bool)), pref, SLOT(setLabelFilterState(const bool)));
|
||||
connect(pref, SIGNAL(externalLabelAdded(QString&)), labelFilters, SLOT(addItem(QString&)));
|
||||
connect(categoryLabel, SIGNAL(toggled(bool)), categoryFilters, SLOT(toggleFilter(bool)));
|
||||
connect(categoryLabel, SIGNAL(toggled(bool)), pref, SLOT(setCategoryFilterState(const bool)));
|
||||
connect(trackerLabel, SIGNAL(toggled(bool)), trackerFilters, SLOT(toggleFilter(bool)));
|
||||
connect(trackerLabel, SIGNAL(toggled(bool)), pref, SLOT(setTrackerFilterState(const bool)));
|
||||
connect(this, SIGNAL(trackerSuccess(const QString &, const QString &)), trackerFilters, SLOT(trackerSuccess(const QString &, const QString &)));
|
||||
|
@ -90,22 +90,22 @@ private:
|
||||
virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const);
|
||||
};
|
||||
|
||||
class LabelFiltersList: public FiltersBase
|
||||
class CategoryFiltersList: public FiltersBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LabelFiltersList(QWidget *parent, TransferListWidget *transferList);
|
||||
~LabelFiltersList();
|
||||
CategoryFiltersList(QWidget *parent, TransferListWidget *transferList);
|
||||
|
||||
private slots:
|
||||
// Redefine addItem() to make sure the list stays sorted
|
||||
void addItem(QString &label, bool hasTorrent = false);
|
||||
void removeItem(const QString &label);
|
||||
void removeSelectedLabel();
|
||||
void removeUnusedLabels();
|
||||
void torrentChangedLabel(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel);
|
||||
|
||||
void addItem(const QString &category, bool hasTorrent = false);
|
||||
void removeItem(const QString &category);
|
||||
void removeSelectedCategory();
|
||||
void removeUnusedCategories();
|
||||
void torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory);
|
||||
void categoryRemoved(const QString &category);
|
||||
void subcategoriesSupportChanged();
|
||||
|
||||
private:
|
||||
// These 4 methods are virtual slots in the base class.
|
||||
@ -114,13 +114,14 @@ private:
|
||||
virtual void applyFilter(int row);
|
||||
virtual void handleNewTorrent(BitTorrent::TorrentHandle *const torrent);
|
||||
virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent);
|
||||
QString labelFromRow(int row) const;
|
||||
int rowFromLabel(const QString &label) const;
|
||||
QString categoryFromRow(int row) const;
|
||||
int rowFromCategory(const QString &category) const;
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
QHash<QString, int> m_labels;
|
||||
QHash<QString, int> m_categories;
|
||||
int m_totalTorrents;
|
||||
int m_totalLabeled;
|
||||
int m_totalCategorized;
|
||||
};
|
||||
|
||||
class TrackerFiltersList: public FiltersBase
|
||||
|
@ -47,15 +47,15 @@ void TransferListSortModel::setStatusFilter(TorrentFilter::Type filter)
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void TransferListSortModel::setLabelFilter(const QString &label)
|
||||
void TransferListSortModel::setCategoryFilter(const QString &category)
|
||||
{
|
||||
if (m_filter.setLabel(label))
|
||||
if (m_filter.setCategory(category))
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void TransferListSortModel::disableLabelFilter()
|
||||
void TransferListSortModel::disableCategoryFilter()
|
||||
{
|
||||
if (m_filter.setLabel(TorrentFilter::AnyLabel))
|
||||
if (m_filter.setCategory(TorrentFilter::AnyCategory))
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
|
@ -44,8 +44,8 @@ public:
|
||||
TransferListSortModel(QObject *parent = 0);
|
||||
|
||||
void setStatusFilter(TorrentFilter::Type filter);
|
||||
void setLabelFilter(const QString &label);
|
||||
void disableLabelFilter();
|
||||
void setCategoryFilter(const QString &category);
|
||||
void disableCategoryFilter();
|
||||
void setTrackerFilter(const QStringList &hashes);
|
||||
void disableTrackerFilter();
|
||||
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include "propertieswidget.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/string.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "transferlistsortmodel.h"
|
||||
|
||||
@ -565,21 +566,30 @@ void TransferListWidget::toggleSelectedFirstLastPiecePrio() const
|
||||
torrent->toggleFirstLastPiecePriority();
|
||||
}
|
||||
|
||||
void TransferListWidget::askNewLabelForSelection()
|
||||
void TransferListWidget::setSelectedASMEnabled(bool enabled) const
|
||||
{
|
||||
// Ask for label
|
||||
foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents())
|
||||
torrent->setASMEnabled(enabled);
|
||||
}
|
||||
|
||||
void TransferListWidget::askNewCategoryForSelection()
|
||||
{
|
||||
// Ask for category
|
||||
bool ok;
|
||||
bool invalid;
|
||||
do {
|
||||
invalid = false;
|
||||
const QString label = AutoExpandableDialog::getText(this, tr("New Label"), tr("Label:"), QLineEdit::Normal, "", &ok).trimmed();
|
||||
if (ok && !label.isEmpty()) {
|
||||
if (Utils::Fs::isValidFileSystemName(label)) {
|
||||
setSelectionLabel(label);
|
||||
const QString category = AutoExpandableDialog::getText(this, tr("New Category"), tr("Category:"), QLineEdit::Normal, "", &ok).trimmed();
|
||||
if (ok && !category.isEmpty()) {
|
||||
if (!BitTorrent::Session::isValidCategoryName(category)) {
|
||||
QMessageBox::warning(this, tr("Invalid category name"),
|
||||
tr("Category name must not contain '\\'.\n"
|
||||
"Category name must not start/end with '/'.\n"
|
||||
"Category name must not contain '//' sequence."));
|
||||
invalid = true;
|
||||
}
|
||||
else {
|
||||
QMessageBox::warning(this, tr("Invalid label name"), tr("Please don't use any special characters in the label name."));
|
||||
invalid = true;
|
||||
setSelectionCategory(category);
|
||||
}
|
||||
}
|
||||
} while(invalid);
|
||||
@ -605,19 +615,10 @@ void TransferListWidget::renameSelectedTorrent()
|
||||
}
|
||||
}
|
||||
|
||||
void TransferListWidget::setSelectionLabel(QString label)
|
||||
void TransferListWidget::setSelectionCategory(QString category)
|
||||
{
|
||||
foreach (const QModelIndex &index, selectionModel()->selectedRows())
|
||||
listModel->setData(listModel->index(mapToSource(index).row(), TorrentModel::TR_LABEL), label, Qt::DisplayRole);
|
||||
}
|
||||
|
||||
void TransferListWidget::removeLabelFromRows(QString label)
|
||||
{
|
||||
for (int i = 0; i < listModel->rowCount(); ++i) {
|
||||
if (listModel->data(listModel->index(i, TorrentModel::TR_LABEL)) == label) {
|
||||
listModel->setData(listModel->index(i, TorrentModel::TR_LABEL), "", Qt::DisplayRole);
|
||||
}
|
||||
}
|
||||
listModel->setData(listModel->index(mapToSource(index).row(), TorrentModel::TR_CATEGORY), category, Qt::DisplayRole);
|
||||
}
|
||||
|
||||
void TransferListWidget::displayListMenu(const QPoint&)
|
||||
@ -671,6 +672,9 @@ void TransferListWidget::displayListMenu(const QPoint&)
|
||||
QAction actionFirstLastPiece_prio(tr("Download first and last pieces first"), 0);
|
||||
actionFirstLastPiece_prio.setCheckable(true);
|
||||
connect(&actionFirstLastPiece_prio, SIGNAL(triggered()), this, SLOT(toggleSelectedFirstLastPiecePrio()));
|
||||
QAction actionEnableASM(tr("Enable Advanced Saving Management"), 0);
|
||||
actionEnableASM.setCheckable(true);
|
||||
connect(&actionEnableASM, SIGNAL(triggered(bool)), this, SLOT(setSelectedASMEnabled(bool)));
|
||||
// End of actions
|
||||
|
||||
// Enable/disable pause/start action given the DL state
|
||||
@ -680,8 +684,10 @@ void TransferListWidget::displayListMenu(const QPoint&)
|
||||
bool all_same_sequential_download_mode = true, all_same_prio_firstlast = true;
|
||||
bool sequential_download_mode = false, prioritize_first_last = false;
|
||||
bool one_has_metadata = false, one_not_seed = false;
|
||||
bool all_same_label = true;
|
||||
QString first_label;
|
||||
bool allSameCategory = true;
|
||||
bool allSameASM = true;
|
||||
bool firstASM = false;
|
||||
QString firstCategory;
|
||||
bool first = true;
|
||||
|
||||
BitTorrent::TorrentHandle *torrent;
|
||||
@ -692,10 +698,15 @@ void TransferListWidget::displayListMenu(const QPoint&)
|
||||
torrent = listModel->torrentHandle(mapToSource(index));
|
||||
if (!torrent) continue;
|
||||
|
||||
if (first_label.isEmpty() && first)
|
||||
first_label = torrent->label();
|
||||
if (firstCategory.isEmpty() && first)
|
||||
firstCategory = torrent->category();
|
||||
if (firstCategory != torrent->category())
|
||||
allSameCategory = false;
|
||||
|
||||
all_same_label = (first_label == torrent->label());
|
||||
if (first)
|
||||
firstASM = torrent->isASMEnabled();
|
||||
if (firstASM != torrent->isASMEnabled())
|
||||
allSameASM = false;
|
||||
|
||||
if (torrent->hasMetadata())
|
||||
one_has_metadata = true;
|
||||
@ -738,8 +749,8 @@ void TransferListWidget::displayListMenu(const QPoint&)
|
||||
first = false;
|
||||
|
||||
if (one_has_metadata && one_not_seed && !all_same_sequential_download_mode
|
||||
&& !all_same_prio_firstlast && !all_same_super_seeding && !all_same_label
|
||||
&& needs_start && needs_force && needs_pause && needs_preview) {
|
||||
&& !all_same_prio_firstlast && !all_same_super_seeding && !allSameCategory
|
||||
&& needs_start && needs_force && needs_pause && needs_preview && !allSameASM) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -756,24 +767,30 @@ void TransferListWidget::displayListMenu(const QPoint&)
|
||||
listMenu.addAction(&actionSetTorrentPath);
|
||||
if (selectedIndexes.size() == 1)
|
||||
listMenu.addAction(&actionRename);
|
||||
// Label Menu
|
||||
QStringList customLabels = Preferences::instance()->getTorrentLabels();
|
||||
customLabels.sort();
|
||||
QList<QAction*> labelActions;
|
||||
QMenu *labelMenu = listMenu.addMenu(GuiIconProvider::instance()->getIcon("view-categories"), tr("Label"));
|
||||
labelActions << labelMenu->addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("New...", "New label..."));
|
||||
labelActions << labelMenu->addAction(GuiIconProvider::instance()->getIcon("edit-clear"), tr("Reset", "Reset label"));
|
||||
labelMenu->addSeparator();
|
||||
foreach (QString label, customLabels) {
|
||||
label.replace('&', "&&"); // avoid '&' becomes accelerator key
|
||||
QAction *lb = new QAction(GuiIconProvider::instance()->getIcon("inode-directory"), label, labelMenu);
|
||||
if (all_same_label && (label == first_label)) {
|
||||
lb->setCheckable(true);
|
||||
lb->setChecked(true);
|
||||
// Category Menu
|
||||
QStringList categories = BitTorrent::Session::instance()->categories();
|
||||
std::sort(categories.begin(), categories.end(), Utils::String::NaturalCompare());
|
||||
QList<QAction*> categoryActions;
|
||||
QMenu *categoryMenu = listMenu.addMenu(GuiIconProvider::instance()->getIcon("view-categories"), tr("Category"));
|
||||
categoryActions << categoryMenu->addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("New...", "New category..."));
|
||||
categoryActions << categoryMenu->addAction(GuiIconProvider::instance()->getIcon("edit-clear"), tr("Reset", "Reset category"));
|
||||
categoryMenu->addSeparator();
|
||||
foreach (QString category, categories) {
|
||||
category.replace('&', "&&"); // avoid '&' becomes accelerator key
|
||||
QAction *cat = new QAction(GuiIconProvider::instance()->getIcon("inode-directory"), category, categoryMenu);
|
||||
if (allSameCategory && (category == firstCategory)) {
|
||||
cat->setCheckable(true);
|
||||
cat->setChecked(true);
|
||||
}
|
||||
labelMenu->addAction(lb);
|
||||
labelActions << lb;
|
||||
categoryMenu->addAction(cat);
|
||||
categoryActions << cat;
|
||||
}
|
||||
|
||||
if (allSameASM) {
|
||||
actionEnableASM.setChecked(firstASM);
|
||||
listMenu.addAction(&actionEnableASM);
|
||||
}
|
||||
|
||||
listMenu.addSeparator();
|
||||
if (one_not_seed)
|
||||
listMenu.addAction(&actionSet_download_limit);
|
||||
@ -801,6 +818,7 @@ void TransferListWidget::displayListMenu(const QPoint&)
|
||||
added_preview_action = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (added_preview_action)
|
||||
listMenu.addSeparator();
|
||||
if (one_has_metadata) {
|
||||
@ -823,20 +841,20 @@ void TransferListWidget::displayListMenu(const QPoint&)
|
||||
QAction *act = 0;
|
||||
act = listMenu.exec(QCursor::pos());
|
||||
if (act) {
|
||||
// Parse label actions only (others have slots assigned)
|
||||
int i = labelActions.indexOf(act);
|
||||
// Parse category actions only (others have slots assigned)
|
||||
int i = categoryActions.indexOf(act);
|
||||
if (i >= 0) {
|
||||
// Label action
|
||||
// Category action
|
||||
if (i == 0) {
|
||||
// New Label
|
||||
askNewLabelForSelection();
|
||||
// New Category
|
||||
askNewCategoryForSelection();
|
||||
}
|
||||
else {
|
||||
QString label = "";
|
||||
QString category = "";
|
||||
if (i > 1)
|
||||
label = customLabels.at(i - 2);
|
||||
// Update Label
|
||||
setSelectionLabel(label);
|
||||
category = categories.at(i - 2);
|
||||
// Update Category
|
||||
setSelectionCategory(category);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -854,12 +872,12 @@ void TransferListWidget::currentChanged(const QModelIndex& current, const QModel
|
||||
emit currentTorrentChanged(torrent);
|
||||
}
|
||||
|
||||
void TransferListWidget::applyLabelFilter(QString label)
|
||||
void TransferListWidget::applyCategoryFilter(QString category)
|
||||
{
|
||||
if (label.isNull())
|
||||
nameFilterModel->disableLabelFilter();
|
||||
if (category.isNull())
|
||||
nameFilterModel->disableCategoryFilter();
|
||||
else
|
||||
nameFilterModel->setLabelFilter(label);
|
||||
nameFilterModel->setCategoryFilter(category);
|
||||
}
|
||||
|
||||
void TransferListWidget::applyTrackerFilterAll()
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
TorrentModel* getSourceModel() const;
|
||||
|
||||
public slots:
|
||||
void setSelectionLabel(QString label);
|
||||
void setSelectionCategory(QString category);
|
||||
void setSelectedTorrentsLocation();
|
||||
void pauseAllTorrents();
|
||||
void resumeAllTorrents();
|
||||
@ -86,11 +86,10 @@ public slots:
|
||||
void displayDLHoSMenu(const QPoint&);
|
||||
void applyNameFilter(const QString& name);
|
||||
void applyStatusFilter(int f);
|
||||
void applyLabelFilter(QString label);
|
||||
void applyCategoryFilter(QString category);
|
||||
void applyTrackerFilterAll();
|
||||
void applyTrackerFilter(const QStringList &hashes);
|
||||
void previewFile(QString filePath);
|
||||
void removeLabelFromRows(QString label);
|
||||
void renameSelectedTorrent();
|
||||
|
||||
protected:
|
||||
@ -106,7 +105,8 @@ protected slots:
|
||||
void toggleSelectedTorrentsSuperSeeding() const;
|
||||
void toggleSelectedTorrentsSequentialDownload() const;
|
||||
void toggleSelectedFirstLastPiecePrio() const;
|
||||
void askNewLabelForSelection();
|
||||
void setSelectedASMEnabled(bool enabled) const;
|
||||
void askNewCategoryForSelection();
|
||||
void saveSettings();
|
||||
|
||||
signals:
|
||||
|
@ -243,7 +243,7 @@ void AbstractWebApplication::translateDocument(QString& data)
|
||||
"options_imp", "Preferences", "TrackersAdditionDlg", "ScanFoldersModel",
|
||||
"PropTabBar", "TorrentModel", "downloadFromURL", "MainWindow", "misc",
|
||||
"StatusBar", "AboutDlg", "about", "PeerListWidget", "StatusFiltersWidget",
|
||||
"LabelFiltersList"
|
||||
"CategoryFiltersList"
|
||||
};
|
||||
const size_t context_count = sizeof(contexts) / sizeof(contexts[0]);
|
||||
int i = 0;
|
||||
|
@ -102,7 +102,7 @@ static const char KEY_TORRENT_ETA[] = "eta";
|
||||
static const char KEY_TORRENT_STATE[] = "state";
|
||||
static const char KEY_TORRENT_SEQUENTIAL_DOWNLOAD[] = "seq_dl";
|
||||
static const char KEY_TORRENT_FIRST_LAST_PIECE_PRIO[] = "f_l_piece_prio";
|
||||
static const char KEY_TORRENT_LABEL[] = "label";
|
||||
static const char KEY_TORRENT_CATEGORY[] = "category";
|
||||
static const char KEY_TORRENT_SUPER_SEEDING[] = "super_seeding";
|
||||
static const char KEY_TORRENT_FORCE_START[] = "force_start";
|
||||
static const char KEY_TORRENT_SAVE_PATH[] = "save_path";
|
||||
@ -279,13 +279,13 @@ private:
|
||||
* - "seq_dl": Torrent sequential download state
|
||||
* - "f_l_piece_prio": Torrent first last piece priority state
|
||||
* - "force_start": Torrent force start state
|
||||
* - "label": Torrent label
|
||||
* - "category": Torrent category
|
||||
*/
|
||||
QByteArray btjson::getTorrents(QString filter, QString label,
|
||||
QByteArray btjson::getTorrents(QString filter, QString category,
|
||||
QString sortedColumn, bool reverse, int limit, int offset)
|
||||
{
|
||||
QVariantList torrentList;
|
||||
TorrentFilter torrentFilter(filter, TorrentFilter::AnyHash, label);
|
||||
TorrentFilter torrentFilter(filter, TorrentFilter::AnyHash, category);
|
||||
foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents()) {
|
||||
if (torrentFilter.match(torrent))
|
||||
torrentList.append(toMap(torrent));
|
||||
@ -317,8 +317,8 @@ QByteArray btjson::getTorrents(QString filter, QString label,
|
||||
* - "full_update": full data update flag
|
||||
* - "torrents": dictionary contains information about torrents.
|
||||
* - "torrents_removed": a list of hashes of removed torrents
|
||||
* - "labels": list of labels
|
||||
* - "labels_removed": list of removed labels
|
||||
* - "categories": list of categories
|
||||
* - "categories_removed": list of removed categories
|
||||
* - "server_state": map contains information about the state of the server
|
||||
* The keys of the 'torrents' dictionary are hashes of torrents.
|
||||
* Each value of the 'torrents' dictionary contains map. The map can contain following keys:
|
||||
@ -362,11 +362,11 @@ QByteArray btjson::getSyncMainData(int acceptedResponseId, QVariantMap &lastData
|
||||
|
||||
data["torrents"] = torrents;
|
||||
|
||||
QVariantList labels;
|
||||
foreach (QString s, Preferences::instance()->getTorrentLabels())
|
||||
labels << s;
|
||||
QVariantList categories;
|
||||
foreach (const QString &category, BitTorrent::Session::instance()->categories())
|
||||
categories << category;
|
||||
|
||||
data["labels"] = labels;
|
||||
data["categories"] = categories;
|
||||
|
||||
QVariantMap serverState = getTranserInfoMap();
|
||||
serverState[KEY_SYNC_MAINDATA_QUEUEING] = BitTorrent::Session::instance()->isQueueingEnabled();
|
||||
@ -705,7 +705,7 @@ QVariantMap toMap(BitTorrent::TorrentHandle *const torrent)
|
||||
ret[KEY_TORRENT_SEQUENTIAL_DOWNLOAD] = torrent->isSequentialDownload();
|
||||
if (torrent->hasMetadata())
|
||||
ret[KEY_TORRENT_FIRST_LAST_PIECE_PRIO] = torrent->hasFirstLastPiecePriority();
|
||||
ret[KEY_TORRENT_LABEL] = torrent->label();
|
||||
ret[KEY_TORRENT_CATEGORY] = torrent->category();
|
||||
ret[KEY_TORRENT_SUPER_SEEDING] = torrent->superSeeding();
|
||||
ret[KEY_TORRENT_FORCE_START] = torrent->isForced();
|
||||
ret[KEY_TORRENT_SAVE_PATH] = Utils::Fs::toNativePath(torrent->savePath());
|
||||
@ -760,6 +760,7 @@ void processMap(QVariantMap prevData, QVariantMap data, QVariantMap &syncData)
|
||||
case QMetaType::Double:
|
||||
case QMetaType::ULongLong:
|
||||
case QMetaType::UInt:
|
||||
case QMetaType::QDateTime:
|
||||
if (prevData[key] != data[key])
|
||||
syncData[key] = data[key];
|
||||
break;
|
||||
|
@ -43,7 +43,7 @@ private:
|
||||
btjson() {}
|
||||
|
||||
public:
|
||||
static QByteArray getTorrents(QString filter = "all", QString label = QString(),
|
||||
static QByteArray getTorrents(QString filter = "all", QString category = QString(),
|
||||
QString sortedColumn = "name", bool reverse = false, int limit = 0, int offset = 0);
|
||||
static QByteArray getSyncMainData(int acceptedResponseId, QVariantMap &lastData, QVariantMap &lastAcceptedData);
|
||||
static QByteArray getSyncTorrentPeersData(int acceptedResponseId, QString hash, QVariantMap &lastData, QVariantMap &lastAcceptedData);
|
||||
|
@ -84,7 +84,7 @@ static const char *__TRANSLATIONS__[] = {
|
||||
QT_TRANSLATE_NOOP("HttpServer", "Active"),
|
||||
QT_TRANSLATE_NOOP("HttpServer", "Inactive"),
|
||||
QT_TRANSLATE_NOOP("HttpServer", "Save files to location:"),
|
||||
QT_TRANSLATE_NOOP("HttpServer", "Label:"),
|
||||
QT_TRANSLATE_NOOP("HttpServer", "Category:"),
|
||||
QT_TRANSLATE_NOOP("HttpServer", "Cookie:"),
|
||||
QT_TRANSLATE_NOOP("HttpServer", "Type folder here"),
|
||||
QT_TRANSLATE_NOOP("HttpServer", "Run an external program on torrent completion"),
|
||||
|
@ -28,11 +28,6 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "prefjson.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/scanfoldersmodel.h"
|
||||
#include "base/utils/fs.h"
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#include <QSslCertificate>
|
||||
#include <QSslKey>
|
||||
@ -40,7 +35,13 @@
|
||||
#include <QStringList>
|
||||
#include <QTranslator>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "base/preferences.h"
|
||||
#include "base/scanfoldersmodel.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "jsonutils.h"
|
||||
#include "prefjson.h"
|
||||
|
||||
prefjson::prefjson()
|
||||
{
|
||||
@ -49,13 +50,14 @@ prefjson::prefjson()
|
||||
QByteArray prefjson::getPreferences()
|
||||
{
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
auto session = BitTorrent::Session::instance();
|
||||
QVariantMap data;
|
||||
|
||||
// Downloads
|
||||
// Hard Disk
|
||||
data["save_path"] = Utils::Fs::toNativePath(pref->getSavePath());
|
||||
data["temp_path_enabled"] = pref->isTempPathEnabled();
|
||||
data["temp_path"] = Utils::Fs::toNativePath(pref->getTempPath());
|
||||
data["save_path"] = Utils::Fs::toNativePath(session->defaultSavePath());
|
||||
data["temp_path_enabled"] = session->isTempPathEnabled();
|
||||
data["temp_path"] = Utils::Fs::toNativePath(session->tempPath());
|
||||
data["preallocate_all"] = pref->preAllocateAllFiles();
|
||||
data["incomplete_files_ext"] = pref->useIncompleteFilesExtension();
|
||||
QVariantHash dirs = pref->getScanDirs();
|
||||
@ -140,7 +142,7 @@ QByteArray prefjson::getPreferences()
|
||||
// Share Ratio Limiting
|
||||
data["max_ratio_enabled"] = (pref->getGlobalMaxRatio() >= 0.);
|
||||
data["max_ratio"] = pref->getGlobalMaxRatio();
|
||||
data["max_ratio_act"] = static_cast<int>(pref->getMaxRatioAction());
|
||||
data["max_ratio_act"] = BitTorrent::Session::instance()->maxRatioAction();
|
||||
|
||||
// Web UI
|
||||
// Language
|
||||
@ -168,16 +170,17 @@ QByteArray prefjson::getPreferences()
|
||||
void prefjson::setPreferences(const QString& json)
|
||||
{
|
||||
Preferences* const pref = Preferences::instance();
|
||||
auto session = BitTorrent::Session::instance();
|
||||
const QVariantMap m = json::fromJson(json).toMap();
|
||||
|
||||
// Downloads
|
||||
// Hard Disk
|
||||
if (m.contains("save_path"))
|
||||
pref->setSavePath(m["save_path"].toString());
|
||||
session->setDefaultSavePath(m["save_path"].toString());
|
||||
if (m.contains("temp_path_enabled"))
|
||||
pref->setTempPathEnabled(m["temp_path_enabled"].toBool());
|
||||
session->setTempPathEnabled(m["temp_path_enabled"].toBool());
|
||||
if (m.contains("temp_path"))
|
||||
pref->setTempPath(m["temp_path"].toString());
|
||||
session->setTempPath(m["temp_path"].toString());
|
||||
if (m.contains("preallocate_all"))
|
||||
pref->preAllocateAllFiles(m["preallocate_all"].toBool());
|
||||
if (m.contains("incomplete_files_ext"))
|
||||
@ -351,7 +354,8 @@ void prefjson::setPreferences(const QString& json)
|
||||
else
|
||||
pref->setGlobalMaxRatio(-1);
|
||||
if (m.contains("max_ratio_act"))
|
||||
pref->setMaxRatioAction(static_cast<MaxRatioAction>(m["max_ratio_act"].toInt()));
|
||||
BitTorrent::Session::instance()->setMaxRatioAction(
|
||||
static_cast<MaxRatioAction>(m["max_ratio_act"].toInt()));
|
||||
|
||||
// Web UI
|
||||
// Language
|
||||
|
@ -49,8 +49,8 @@
|
||||
#include "websessiondata.h"
|
||||
#include "webapplication.h"
|
||||
|
||||
static const int API_VERSION = 8;
|
||||
static const int API_VERSION_MIN = 8;
|
||||
static const int API_VERSION = 9;
|
||||
static const int API_VERSION_MIN = 9;
|
||||
|
||||
const QString WWW_FOLDER = ":/www/public/";
|
||||
const QString PRIVATE_FOLDER = ":/www/private/";
|
||||
@ -114,7 +114,7 @@ QMap<QString, QMap<QString, WebApplication::Action> > WebApplication::initialize
|
||||
ADD_ACTION(command, topPrio);
|
||||
ADD_ACTION(command, bottomPrio);
|
||||
ADD_ACTION(command, recheck);
|
||||
ADD_ACTION(command, setLabel);
|
||||
ADD_ACTION(command, setCategory);
|
||||
ADD_ACTION(command, getSavePath);
|
||||
ADD_ACTION(version, api);
|
||||
ADD_ACTION(version, api_min);
|
||||
@ -216,7 +216,7 @@ void WebApplication::action_public_images()
|
||||
|
||||
// GET params:
|
||||
// - filter (string): all, downloading, seeding, completed, paused, resumed, active, inactive
|
||||
// - label (string): torrent label for filtering by it (empty string means "unlabeled"; no "label" param presented means "any label")
|
||||
// - category (string): torrent category for filtering by it (empty string means "uncategorized"; no "category" param presented means "any category")
|
||||
// - sort (string): name of column for sorting by its value
|
||||
// - reverse (bool): enable reverse sorting
|
||||
// - limit (int): set limit number of torrents returned (if greater than 0, otherwise - unlimited)
|
||||
@ -227,7 +227,7 @@ void WebApplication::action_query_torrents()
|
||||
const QStringMap& gets = request().gets;
|
||||
|
||||
print(btjson::getTorrents(
|
||||
gets["filter"], gets["label"], gets["sort"], gets["reverse"] == "true",
|
||||
gets["filter"], gets["category"], gets["sort"], gets["reverse"] == "true",
|
||||
gets["limit"].toInt(), gets["offset"].toInt()
|
||||
), Http::CONTENT_TYPE_JSON);
|
||||
}
|
||||
@ -326,7 +326,7 @@ void WebApplication::action_command_download()
|
||||
QString urls = request().posts["urls"];
|
||||
QStringList list = urls.split('\n');
|
||||
QString savepath = request().posts["savepath"];
|
||||
QString label = request().posts["label"];
|
||||
QString category = request().posts["category"];
|
||||
QString cookie = request().posts["cookie"];
|
||||
QList<QNetworkCookie> cookies;
|
||||
if (!cookie.isEmpty()) {
|
||||
@ -345,11 +345,11 @@ void WebApplication::action_command_download()
|
||||
}
|
||||
|
||||
savepath = savepath.trimmed();
|
||||
label = label.trimmed();
|
||||
category = category.trimmed();
|
||||
|
||||
BitTorrent::AddTorrentParams params;
|
||||
params.savePath = savepath;
|
||||
params.label = label;
|
||||
params.category = category;
|
||||
|
||||
foreach (QString url, list) {
|
||||
url = url.trimmed();
|
||||
@ -365,10 +365,10 @@ void WebApplication::action_command_upload()
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
CHECK_URI(0);
|
||||
QString savepath = request().posts["savepath"];
|
||||
QString label = request().posts["label"];
|
||||
QString category = request().posts["category"];
|
||||
|
||||
savepath = savepath.trimmed();
|
||||
label = label.trimmed();
|
||||
category = category.trimmed();
|
||||
|
||||
foreach(const Http::UploadedFile& torrent, request().files) {
|
||||
QString filePath = saveTmpFile(torrent.data);
|
||||
@ -382,7 +382,7 @@ void WebApplication::action_command_upload()
|
||||
else {
|
||||
BitTorrent::AddTorrentParams params;
|
||||
params.savePath = savepath;
|
||||
params.label = label;
|
||||
params.category = category;
|
||||
if (!BitTorrent::Session::instance()->addTorrent(torrentInfo, params)) {
|
||||
status(500, "Internal Server Error");
|
||||
print(QObject::tr("Error: Could not add torrent to session."), Http::CONTENT_TYPE_TXT);
|
||||
@ -709,29 +709,29 @@ void WebApplication::action_command_recheck()
|
||||
torrent->forceRecheck();
|
||||
}
|
||||
|
||||
void WebApplication::action_command_setLabel()
|
||||
void WebApplication::action_command_setCategory()
|
||||
{
|
||||
CHECK_URI(0);
|
||||
CHECK_PARAMETERS("hashes" << "label");
|
||||
CHECK_PARAMETERS("hashes" << "category");
|
||||
|
||||
QStringList hashes = request().posts["hashes"].split("|");
|
||||
QString label = request().posts["label"].trimmed();
|
||||
if (!Utils::Fs::isValidFileSystemName(label) && !label.isEmpty()) {
|
||||
status(400, "Labels must not contain special characters");
|
||||
return;
|
||||
}
|
||||
QString category = request().posts["category"].trimmed();
|
||||
|
||||
foreach (const QString &hash, hashes) {
|
||||
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
|
||||
if (torrent)
|
||||
torrent->setLabel(label);
|
||||
if (torrent) {
|
||||
if (!torrent->setCategory(category)) {
|
||||
status(400, "Incorrect category name");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebApplication::action_command_getSavePath()
|
||||
{
|
||||
CHECK_URI(0);
|
||||
print(Preferences::instance()->getSavePath());
|
||||
print(BitTorrent::Session::instance()->defaultSavePath());
|
||||
}
|
||||
|
||||
bool WebApplication::isPublicScope()
|
||||
|
@ -87,7 +87,7 @@ private:
|
||||
void action_command_topPrio();
|
||||
void action_command_bottomPrio();
|
||||
void action_command_recheck();
|
||||
void action_command_setLabel();
|
||||
void action_command_setCategory();
|
||||
void action_command_getSavePath();
|
||||
void action_version_api();
|
||||
void action_version_api_min();
|
||||
|
@ -1,43 +1,43 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>www/private/index.html</file>
|
||||
<file>www/private/login.html</file>
|
||||
<file>www/public/css/Core.css</file>
|
||||
<file>www/public/css/dynamicTable.css</file>
|
||||
<file>www/public/css/Layout.css</file>
|
||||
<file>www/public/css/style.css</file>
|
||||
<file>www/public/css/Tabs.css</file>
|
||||
<file>www/public/css/Window.css</file>
|
||||
<file>www/public/scripts/client.js</file>
|
||||
<file>www/public/scripts/contextmenu.js</file>
|
||||
<file>www/public/scripts/download.js</file>
|
||||
<file>www/public/scripts/dynamicTable.js</file>
|
||||
<file>www/public/scripts/excanvas-compressed.js</file>
|
||||
<file>www/public/scripts/misc.js</file>
|
||||
<file>www/public/scripts/mocha.js</file>
|
||||
<file>www/public/scripts/mocha-init.js</file>
|
||||
<file>www/public/scripts/mocha-yc.js</file>
|
||||
<file>www/public/scripts/mootools-1.2-core-yc.js</file>
|
||||
<file>www/public/scripts/mootools-1.2-more.js</file>
|
||||
<file>www/public/scripts/parametrics.js</file>
|
||||
<file>www/public/scripts/progressbar.js</file>
|
||||
<file>www/public/about.html</file>
|
||||
<file>www/public/addtrackers.html</file>
|
||||
<file>www/public/confirmdeletion.html</file>
|
||||
<file>www/public/download.html</file>
|
||||
<file>www/public/downloadlimit.html</file>
|
||||
<file>www/public/filters.html</file>
|
||||
<file>www/public/newlabel.html</file>
|
||||
<file>www/public/preferences.html</file>
|
||||
<file>www/public/preferences_content.html</file>
|
||||
<file>www/public/properties.html</file>
|
||||
<file>www/public/properties_content.html</file>
|
||||
<file>www/public/scripts/prop-general.js</file>
|
||||
<file>www/public/scripts/prop-trackers.js</file>
|
||||
<file>www/public/scripts/prop-webseeds.js</file>
|
||||
<file>www/public/scripts/prop-files.js</file>
|
||||
<file>www/public/transferlist.html</file>
|
||||
<file>www/public/upload.html</file>
|
||||
<file>www/public/uploadlimit.html</file>
|
||||
</qresource>
|
||||
<qresource prefix="/">
|
||||
<file>www/private/index.html</file>
|
||||
<file>www/private/login.html</file>
|
||||
<file>www/public/css/Core.css</file>
|
||||
<file>www/public/css/dynamicTable.css</file>
|
||||
<file>www/public/css/Layout.css</file>
|
||||
<file>www/public/css/style.css</file>
|
||||
<file>www/public/css/Tabs.css</file>
|
||||
<file>www/public/css/Window.css</file>
|
||||
<file>www/public/scripts/client.js</file>
|
||||
<file>www/public/scripts/contextmenu.js</file>
|
||||
<file>www/public/scripts/download.js</file>
|
||||
<file>www/public/scripts/dynamicTable.js</file>
|
||||
<file>www/public/scripts/excanvas-compressed.js</file>
|
||||
<file>www/public/scripts/misc.js</file>
|
||||
<file>www/public/scripts/mocha.js</file>
|
||||
<file>www/public/scripts/mocha-init.js</file>
|
||||
<file>www/public/scripts/mocha-yc.js</file>
|
||||
<file>www/public/scripts/mootools-1.2-core-yc.js</file>
|
||||
<file>www/public/scripts/mootools-1.2-more.js</file>
|
||||
<file>www/public/scripts/parametrics.js</file>
|
||||
<file>www/public/scripts/progressbar.js</file>
|
||||
<file>www/public/about.html</file>
|
||||
<file>www/public/addtrackers.html</file>
|
||||
<file>www/public/confirmdeletion.html</file>
|
||||
<file>www/public/download.html</file>
|
||||
<file>www/public/downloadlimit.html</file>
|
||||
<file>www/public/filters.html</file>
|
||||
<file>www/public/preferences.html</file>
|
||||
<file>www/public/preferences_content.html</file>
|
||||
<file>www/public/properties.html</file>
|
||||
<file>www/public/properties_content.html</file>
|
||||
<file>www/public/scripts/prop-general.js</file>
|
||||
<file>www/public/scripts/prop-trackers.js</file>
|
||||
<file>www/public/scripts/prop-webseeds.js</file>
|
||||
<file>www/public/scripts/prop-files.js</file>
|
||||
<file>www/public/transferlist.html</file>
|
||||
<file>www/public/upload.html</file>
|
||||
<file>www/public/uploadlimit.html</file>
|
||||
<file>www/public/newcategory.html</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -106,8 +106,8 @@
|
||||
<li><a href="#ForceStart"><img src="theme/media-seek-forward" alt="QBT_TR(Force Resume)QBT_TR"/> QBT_TR(Force Resume)QBT_TR</a></li>
|
||||
<li class="separator"><a href="#Delete"><img src="theme/list-remove" alt="QBT_TR(Delete)QBT_TR"/> QBT_TR(Delete)QBT_TR</a></li>
|
||||
<li class="separator">
|
||||
<a href="#Label" class="arrow-right"><img src="theme/view-categories" alt="QBT_TR(Label)QBT_TR"/> QBT_TR(Label)QBT_TR</a>
|
||||
<ul id="contextLabelList"></ul>
|
||||
<a href="#Category" class="arrow-right"><img src="theme/view-categories" alt="QBT_TR(Category)QBT_TR"/> QBT_TR(Category)QBT_TR</a>
|
||||
<ul id="contextCategoryList"></ul>
|
||||
</li>
|
||||
<li id="queueingMenuItems" class="separator">
|
||||
<a href="#priority" class="arrow-right"><span style="display: inline-block; width:16px"></span> QBT_TR(Priority)QBT_TR</a>
|
||||
|
@ -1,33 +1,33 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>QBT_TR(Add Torrent Link)QBT_TR</title>
|
||||
<link rel="stylesheet" href="css/style.css" type="text/css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>QBT_TR(Add Torrent Link)QBT_TR</title>
|
||||
<link rel="stylesheet" href="css/style.css" type="text/css" />
|
||||
<link rel="stylesheet" href="css/Window.css" type="text/css" />
|
||||
<script type="text/javascript" src="scripts/mootools-1.2-core-yc.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="scripts/download.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="scripts/mootools-1.2-core-yc.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="scripts/download.js" charset="utf-8"></script>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="download_frame" name="download_frame" class="invisible" src="javascript:false;"></iframe>
|
||||
<form action="command/download" enctype="multipart/form-data" method="post" id="downloadForm" style="text-align: center;" target="download_frame">
|
||||
<center>
|
||||
<br/>
|
||||
<h2 class="vcenter">QBT_TR(Download Torrents from their URLs or Magnet links)QBT_TR</h2>
|
||||
<textarea id="urls" rows="10" name="urls"></textarea>
|
||||
<br/>
|
||||
<h2 class="vcenter">QBT_TR(Download Torrents from their URLs or Magnet links)QBT_TR</h2>
|
||||
<textarea id="urls" rows="10" name="urls"></textarea>
|
||||
<p>QBT_TR(Only one link per line)QBT_TR</p>
|
||||
<fieldset class="settings" style="border: 0; text-align: left;">
|
||||
<div class="formRow" style="margin-top: 6px;">
|
||||
<label for="savepath" class="leftLabelLarge">QBT_TR(Save files to location:)QBT_TR</label>
|
||||
<input type="text" id="savepath" name="savepath" style="width: 16em;"/>
|
||||
<label for="savepath" class="leftLabelLarge">QBT_TR(Save files to location:)QBT_TR</label>
|
||||
<input type="text" id="savepath" name="savepath" style="width: 16em;"/>
|
||||
</div>
|
||||
<div class="formRow">
|
||||
<label for="cookie" class="leftLabelLarge">QBT_TR(Cookie:)QBT_TR</label>
|
||||
<input type="text" id="cookie" name="cookie" style="width: 16em;"/>
|
||||
<label for="cookie" class="leftLabelLarge">QBT_TR(Cookie:)QBT_TR</label>
|
||||
<input type="text" id="cookie" name="cookie" style="width: 16em;"/>
|
||||
</div>
|
||||
<div class="formRow">
|
||||
<label for="label" class="leftLabelLarge">QBT_TR(Label:)QBT_TR</label>
|
||||
<input type="text" id="label" name="label" style="width: 16em;"/>
|
||||
<label for="category" class="leftLabelLarge">QBT_TR(Category:)QBT_TR</label>
|
||||
<input type="text" id="category" name="category" style="width: 16em;"/>
|
||||
</div>
|
||||
<div id="submitbutton" style="margin-top: 12px; text-align: center;">
|
||||
<button type="submit" id="submitButton">QBT_TR(Download)QBT_TR</button>
|
||||
@ -39,13 +39,13 @@
|
||||
var submitted = false;
|
||||
|
||||
$('downloadForm').addEventListener("submit", function() {
|
||||
$('download_spinner').style.display = "block";
|
||||
$('download_spinner').style.display = "block";
|
||||
submitted = true;
|
||||
});
|
||||
|
||||
$('download_frame').addEventListener("load", function() {
|
||||
if (submitted)
|
||||
window.parent.closeWindows();
|
||||
if (submitted)
|
||||
window.parent.closeWindows();
|
||||
});
|
||||
</script>
|
||||
<div id="download_spinner" class="mochaSpinner"></div>
|
||||
|
@ -11,6 +11,6 @@
|
||||
<li id="errored_filter"><a href="#" onclick="setFilter('errored');return false;"><img src="images/skin/error.png"/>QBT_TR(Errored (0))QBT_TR</a></li>
|
||||
</ul>
|
||||
<br/>
|
||||
<span class="filterTitle">QBT_TR(Labels)QBT_TR</span>
|
||||
<ul id="filterLabelList" class="filterList">
|
||||
<span class="filterTitle">QBT_TR(Categories)QBT_TR</span>
|
||||
<ul id="filterCategoryList" class="filterList">
|
||||
</ul>
|
||||
|
@ -2,41 +2,41 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>QBT_TR(New Label)QBT_TR</title>
|
||||
<title>QBT_TR(New Category)QBT_TR</title>
|
||||
<link rel="stylesheet" href="css/style.css" type="text/css" />
|
||||
<script type="text/javascript" src="scripts/mootools-1.2-core-yc.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="scripts/mootools-1.2-more.js" charset="utf-8"></script>
|
||||
<script type="text/javascript">
|
||||
var newLabelKeyboardEvents = new Keyboard({
|
||||
var newCategoryKeyboardEvents = new Keyboard({
|
||||
defaultEventType: 'keydown',
|
||||
events: {
|
||||
'enter': function (event) {
|
||||
$('newLabelButton').click();
|
||||
$('newCategoryButton').click();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
newLabelKeyboardEvents.activate();
|
||||
newCategoryKeyboardEvents.activate();
|
||||
|
||||
window.addEvent('domready', function() {
|
||||
$('newLabel').focus();
|
||||
$('newLabelButton').addEvent('click', function(e) {
|
||||
$('newCategory').focus();
|
||||
$('newCategoryButton').addEvent('click', function(e) {
|
||||
new Event(e).stop();
|
||||
// check field
|
||||
var labelName = $('newLabel').value.trim();
|
||||
if (labelName == null || labelName == "")
|
||||
var categoryName = $('newCategory').value.trim();
|
||||
if (categoryName == null || categoryName == "")
|
||||
return false;
|
||||
if (labelName.match("[\\\\/:?\"*<>|]") !== null) {
|
||||
alert("QBT_TR(Invalid label name:\nPlease do not use any special characters in the label name.)QBT_TR");
|
||||
if (categoryName.match("^([^\\\\\\/]|[^\\\\\\/]([^\\\\\\/]|\\/(?=[^\\/]))*[^\\\\\\/])$") === null) {
|
||||
alert("QBT_TR(Invalid category name:\nPlease do not use any special characters in the category name.)QBT_TR");
|
||||
return false;
|
||||
}
|
||||
var hashesList = new URI().getData('hashes');
|
||||
new Request({
|
||||
url: 'command/setLabel',
|
||||
url: 'command/setCategory',
|
||||
method: 'post',
|
||||
data: {
|
||||
hashes: hashesList,
|
||||
label: labelName
|
||||
category: categoryName
|
||||
},
|
||||
onComplete: function() {
|
||||
window.parent.closeWindows();
|
||||
@ -48,10 +48,10 @@
|
||||
</head>
|
||||
<body>
|
||||
<div style="padding: 10px 10px 0px 10px;">
|
||||
<p style="font-weight: bold;">QBT_TR(Label)QBT_TR:</p>
|
||||
<input type="text" id="newLabel" value="" maxlength="100" style="width: 220px;"/>
|
||||
<p style="font-weight: bold;">QBT_TR(Category)QBT_TR:</p>
|
||||
<input type="text" id="newCategory" value="" maxlength="100" style="width: 220px;"/>
|
||||
<div style="text-align: center;">
|
||||
<input type="button" value="QBT_TR(Add)QBT_TR" id="newLabelButton"/>
|
||||
<input type="button" value="QBT_TR(Add)QBT_TR" id="newCategoryButton"/>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
@ -73,7 +73,7 @@
|
||||
<i>QBT_TR(Supported parameters (case sensitive):)QBT_TR
|
||||
<ul>
|
||||
<li>QBT_TR(%N: Torrent name)QBT_TR</li>
|
||||
<li>QBT_TR(%L: Label)QBT_TR</li>
|
||||
<li>QBT_TR(%L: Category)QBT_TR</li>
|
||||
<li>QBT_TR(%F: Content path (same as root path for multifile torrent))QBT_TR</li>
|
||||
<li>QBT_TR(%R: Root path (first torrent subdirectory path))QBT_TR</li>
|
||||
<li>QBT_TR(%D: Save path)QBT_TR</li>
|
||||
@ -1263,19 +1263,19 @@ applyPreferences = function() {
|
||||
var json_str = JSON.encode(settings);
|
||||
|
||||
new Request({url: 'command/setPreferences',
|
||||
method: 'post',
|
||||
data: {'json': json_str,
|
||||
method: 'post',
|
||||
data: {'json': json_str,
|
||||
},
|
||||
onFailure: function() {
|
||||
alert("QBT_TR(Unable to save program preferences, qBittorrent is probably unreachable.)QBT_TR");
|
||||
window.parent.closeWindows();
|
||||
},
|
||||
onSuccess: function() {
|
||||
onSuccess: function() {
|
||||
// Close window
|
||||
window.parent.location.reload();
|
||||
window.parent.closeWindows();
|
||||
}
|
||||
}).send();
|
||||
window.parent.closeWindows();
|
||||
}
|
||||
}).send();
|
||||
};
|
||||
|
||||
loadPreferences();
|
||||
|
@ -38,21 +38,21 @@ var alternativeSpeedLimits = false;
|
||||
var queueing_enabled = true;
|
||||
var syncMainDataTimerPeriod = 1500;
|
||||
|
||||
var LABELS_ALL = 1;
|
||||
var LABELS_UNLABELLED = 2;
|
||||
var CATEGORIES_ALL = 1;
|
||||
var CATEGORIES_UNCATEGORIZED = 2;
|
||||
|
||||
var label_list = {};
|
||||
var category_list = {};
|
||||
|
||||
var selected_label = LABELS_ALL;
|
||||
var setLabelFilter = function(){};
|
||||
var selected_category = CATEGORIES_ALL;
|
||||
var setCategoryFilter = function(){};
|
||||
|
||||
var selected_filter = getLocalStorageItem('selected_filter', 'all');
|
||||
var setFilter = function(){};
|
||||
|
||||
var loadSelectedLabel = function () {
|
||||
selected_label = getLocalStorageItem('selected_label', LABELS_ALL);
|
||||
var loadSelectedCategory = function () {
|
||||
selected_category = getLocalStorageItem('selected_category', CATEGORIES_ALL);
|
||||
};
|
||||
loadSelectedLabel();
|
||||
loadSelectedCategory();
|
||||
|
||||
function genHash(string) {
|
||||
var hash = 0;
|
||||
@ -103,10 +103,10 @@ window.addEvent('load', function () {
|
||||
resizeLimit : [100, 300]
|
||||
});
|
||||
|
||||
setLabelFilter = function(hash) {
|
||||
selected_label = hash;
|
||||
localStorage.setItem('selected_label', selected_label);
|
||||
highlightSelectedLabel();
|
||||
setCategoryFilter = function(hash) {
|
||||
selected_category = hash;
|
||||
localStorage.setItem('selected_category', selected_category);
|
||||
highlightSelectedCategory();
|
||||
if (typeof torrentsTable.table != 'undefined')
|
||||
updateMainData();
|
||||
};
|
||||
@ -170,59 +170,59 @@ window.addEvent('load', function () {
|
||||
var syncMainDataLastResponseId = 0;
|
||||
var serverState = {};
|
||||
|
||||
var removeTorrentFromLabelList = function(hash) {
|
||||
var removeTorrentFromCategoryList = function(hash) {
|
||||
if (hash == null || hash == "")
|
||||
return false;
|
||||
var removed = false;
|
||||
Object.each(label_list, function(label) {
|
||||
if (Object.contains(label.torrents, hash)) {
|
||||
Object.each(category_list, function(category) {
|
||||
if (Object.contains(category.torrents, hash)) {
|
||||
removed = true;
|
||||
label.torrents.splice(label.torrents.indexOf(hash), 1);
|
||||
category.torrents.splice(category.torrents.indexOf(hash), 1);
|
||||
}
|
||||
});
|
||||
return removed;
|
||||
};
|
||||
|
||||
var addTorrentToLabelList = function(torrent) {
|
||||
var label = torrent['label'];
|
||||
if (label == null)
|
||||
var addTorrentToCategoryList = function(torrent) {
|
||||
var category = torrent['category'];
|
||||
if (category == null)
|
||||
return false;
|
||||
if (label.length === 0) { // Empty label
|
||||
removeTorrentFromLabelList(torrent['hash']);
|
||||
if (category.length === 0) { // Empty category
|
||||
removeTorrentFromCategoryList(torrent['hash']);
|
||||
return true;
|
||||
}
|
||||
var labelHash = genHash(label);
|
||||
if (label_list[labelHash] == null) // This should not happen
|
||||
label_list[labelHash] = {name: label, torrents: []};
|
||||
if (!Object.contains(label_list[labelHash].torrents, torrent['hash'])) {
|
||||
removeTorrentFromLabelList(torrent['hash']);
|
||||
label_list[labelHash].torrents = label_list[labelHash].torrents.combine([torrent['hash']]);
|
||||
var categoryHash = genHash(category);
|
||||
if (category_list[categoryHash] == null) // This should not happen
|
||||
category_list[categoryHash] = {name: category, torrents: []};
|
||||
if (!Object.contains(category_list[categoryHash].torrents, torrent['hash'])) {
|
||||
removeTorrentFromCategoryList(torrent['hash']);
|
||||
category_list[categoryHash].torrents = category_list[categoryHash].torrents.combine([torrent['hash']]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var updateContextMenu = function () {
|
||||
var labelList = $('contextLabelList');
|
||||
labelList.empty();
|
||||
labelList.appendChild(new Element('li', {html: '<a href="javascript:newLabelFN();"><img src="theme/list-add" alt="QBT_TR(New...)QBT_TR"/> QBT_TR(New...)QBT_TR</a>'}));
|
||||
labelList.appendChild(new Element('li', {html: '<a href="javascript:updateLabelFN(0);"><img src="theme/edit-clear" alt="QBT_TR(Reset)QBT_TR"/> QBT_TR(Reset)QBT_TR</a>'}));
|
||||
var categoryList = $('contextCategoryList');
|
||||
categoryList.empty();
|
||||
categoryList.appendChild(new Element('li', {html: '<a href="javascript:newCategoryFN();"><img src="theme/list-add" alt="QBT_TR(New...)QBT_TR"/> QBT_TR(New...)QBT_TR</a>'}));
|
||||
categoryList.appendChild(new Element('li', {html: '<a href="javascript:updateCategoryFN(0);"><img src="theme/edit-clear" alt="QBT_TR(Reset)QBT_TR"/> QBT_TR(Reset)QBT_TR</a>'}));
|
||||
|
||||
var sortedLabels = []
|
||||
Object.each(label_list, function(label) {
|
||||
sortedLabels.push(label.name);
|
||||
var sortedCategories = []
|
||||
Object.each(category_list, function(category) {
|
||||
sortedCategories.push(category.name);
|
||||
});
|
||||
sortedLabels.sort();
|
||||
sortedCategories.sort();
|
||||
|
||||
var first = true;
|
||||
Object.each(sortedLabels, function(labelName) {
|
||||
var labelHash = genHash(labelName);
|
||||
var el = new Element('li', {html: '<a href="javascript:updateLabelFN(\'' + labelHash + '\');"><img src="theme/inode-directory"/> ' + labelName + '</a>'});
|
||||
Object.each(sortedCategories, function(categoryName) {
|
||||
var categoryHash = genHash(categoryName);
|
||||
var el = new Element('li', {html: '<a href="javascript:updateCategoryFN(\'' + categoryHash + '\');"><img src="theme/inode-directory"/> ' + categoryName + '</a>'});
|
||||
if (first) {
|
||||
el.addClass('separator');
|
||||
first = false;
|
||||
}
|
||||
labelList.appendChild(el);
|
||||
categoryList.appendChild(el);
|
||||
});
|
||||
};
|
||||
|
||||
@ -242,50 +242,50 @@ window.addEvent('load', function () {
|
||||
updateFilter('errored', 'QBT_TR(Errored (%1))QBT_TR');
|
||||
};
|
||||
|
||||
var updateLabelList = function() {
|
||||
var labelList = $('filterLabelList');
|
||||
if (!labelList)
|
||||
var updateCategoryList = function() {
|
||||
var categoryList = $('filterCategoryList');
|
||||
if (!categoryList)
|
||||
return;
|
||||
labelList.empty();
|
||||
categoryList.empty();
|
||||
|
||||
var create_link = function(hash, text, count) {
|
||||
var html = '<a href="#" onclick="setLabelFilter(' + hash + ');return false;">' +
|
||||
var html = '<a href="#" onclick="setCategoryFilter(' + hash + ');return false;">' +
|
||||
'<img src="theme/inode-directory"/>' +
|
||||
text + ' (' + count + ')' + '</a>';
|
||||
return new Element('li', {id: hash, html: html});
|
||||
};
|
||||
|
||||
var all = torrentsTable.getRowIds().length;
|
||||
var unlabelled = 0;
|
||||
var uncategorized = 0;
|
||||
Object.each(torrentsTable.rows, function(row) {
|
||||
if (row['full_data'].label.length === 0)
|
||||
unlabelled += 1;
|
||||
if (row['full_data'].category.length === 0)
|
||||
uncategorized += 1;
|
||||
});
|
||||
labelList.appendChild(create_link(LABELS_ALL, 'QBT_TR(All (0))QBT_TR'.replace(' (0)', ''), all));
|
||||
labelList.appendChild(create_link(LABELS_UNLABELLED, 'QBT_TR(Unlabeled (0))QBT_TR'.replace(' (0)', ''), unlabelled));
|
||||
categoryList.appendChild(create_link(CATEGORIES_ALL, 'QBT_TR(All (0))QBT_TR'.replace(' (0)', ''), all));
|
||||
categoryList.appendChild(create_link(CATEGORIES_UNCATEGORIZED, 'QBT_TR(Uncategorized (0))QBT_TR'.replace(' (0)', ''), uncategorized));
|
||||
|
||||
var sortedLabels = []
|
||||
Object.each(label_list, function(label) {
|
||||
sortedLabels.push(label.name);
|
||||
var sortedCategories = []
|
||||
Object.each(category_list, function(category) {
|
||||
sortedCategories.push(category.name);
|
||||
});
|
||||
sortedLabels.sort();
|
||||
sortedCategories.sort();
|
||||
|
||||
Object.each(sortedLabels, function(labelName) {
|
||||
var labelHash = genHash(labelName);
|
||||
var labelCount = label_list[labelHash].torrents.length;
|
||||
labelList.appendChild(create_link(labelHash, labelName, labelCount));
|
||||
Object.each(sortedCategories, function(categoryName) {
|
||||
var categoryHash = genHash(categoryName);
|
||||
var categoryCount = category_list[categoryHash].torrents.length;
|
||||
categoryList.appendChild(create_link(categoryHash, categoryName, categoryCount));
|
||||
});
|
||||
|
||||
highlightSelectedLabel();
|
||||
highlightSelectedCategory();
|
||||
};
|
||||
|
||||
var highlightSelectedLabel = function() {
|
||||
var labelList = $('filterLabelList');
|
||||
if (!labelList)
|
||||
var highlightSelectedCategory = function() {
|
||||
var categoryList = $('filterCategoryList');
|
||||
if (!categoryList)
|
||||
return;
|
||||
var childrens = labelList.childNodes;
|
||||
var childrens = categoryList.childNodes;
|
||||
for (var i in childrens) {
|
||||
if (childrens[i].id == selected_label)
|
||||
if (childrens[i].id == selected_category)
|
||||
childrens[i].className = "selectedFilter";
|
||||
else
|
||||
childrens[i].className = "";
|
||||
@ -308,43 +308,43 @@ window.addEvent('load', function () {
|
||||
onSuccess : function (response) {
|
||||
$('error_div').set('html', '');
|
||||
if (response) {
|
||||
var update_labels = false;
|
||||
var update_categories = false;
|
||||
var full_update = (response['full_update'] == true);
|
||||
if (full_update) {
|
||||
torrentsTable.clear();
|
||||
label_list = {};
|
||||
category_list = {};
|
||||
}
|
||||
if (response['rid']) {
|
||||
syncMainDataLastResponseId = response['rid'];
|
||||
}
|
||||
if (response['labels']) {
|
||||
response['labels'].each(function(label) {
|
||||
var labelHash = genHash(label);
|
||||
label_list[labelHash] = {name: label, torrents: []};
|
||||
if (response['categories']) {
|
||||
response['categories'].each(function(category) {
|
||||
var categoryHash = genHash(category);
|
||||
category_list[categoryHash] = {name: category, torrents: []};
|
||||
});
|
||||
update_labels = true;
|
||||
update_categories = true;
|
||||
}
|
||||
if (response['labels_removed']) {
|
||||
response['labels_removed'].each(function(label) {
|
||||
var labelHash = genHash(label);
|
||||
delete label_list[labelHash];
|
||||
if (response['categories_removed']) {
|
||||
response['categories_removed'].each(function(category) {
|
||||
var categoryHash = genHash(category);
|
||||
delete category_list[categoryHash];
|
||||
});
|
||||
update_labels = true;
|
||||
update_categories = true;
|
||||
}
|
||||
if (response['torrents']) {
|
||||
for (var key in response['torrents']) {
|
||||
response['torrents'][key]['hash'] = key;
|
||||
response['torrents'][key]['rowId'] = key;
|
||||
torrentsTable.updateRowData(response['torrents'][key]);
|
||||
if (addTorrentToLabelList(response['torrents'][key]))
|
||||
update_labels = true;
|
||||
if (addTorrentToCategoryList(response['torrents'][key]))
|
||||
update_categories = true;
|
||||
}
|
||||
}
|
||||
if (response['torrents_removed'])
|
||||
response['torrents_removed'].each(function (hash) {
|
||||
torrentsTable.removeRow(hash);
|
||||
removeTorrentFromLabelList(hash);
|
||||
update_labels = true; // Allways to update All label
|
||||
removeTorrentFromCategoryList(hash);
|
||||
update_categories = true; // Allways to update All category
|
||||
});
|
||||
torrentsTable.updateTable(full_update);
|
||||
torrentsTable.altRow();
|
||||
@ -355,8 +355,8 @@ window.addEvent('load', function () {
|
||||
processServerState();
|
||||
}
|
||||
updateFiltersList();
|
||||
if (update_labels) {
|
||||
updateLabelList();
|
||||
if (update_categories) {
|
||||
updateCategoryList();
|
||||
updateContextMenu();
|
||||
}
|
||||
}
|
||||
@ -683,4 +683,4 @@ var loadTorrentPeersData = function(){
|
||||
updateTorrentPeersData = function(){
|
||||
clearTimeout(loadTorrentPeersTimer);
|
||||
loadTorrentPeersData();
|
||||
};
|
||||
};
|
||||
|
@ -452,7 +452,7 @@ var TorrentsTable = new Class({
|
||||
this.newColumn('upspeed', 'width: 100px', 'QBT_TR(Up Speed)QBT_TR');
|
||||
this.newColumn('eta', 'width: 100px', 'QBT_TR(ETA)QBT_TR');
|
||||
this.newColumn('ratio', 'width: 100px', 'QBT_TR(Ratio)QBT_TR');
|
||||
this.newColumn('label', 'width: 100px', 'QBT_TR(Label)QBT_TR');
|
||||
this.newColumn('category', 'width: 100px', 'QBT_TR(Category)QBT_TR');
|
||||
|
||||
this.columns['state_icon'].onclick = '';
|
||||
this.columns['state_icon'].dataProperties[0] = 'state';
|
||||
@ -620,7 +620,7 @@ var TorrentsTable = new Class({
|
||||
};
|
||||
},
|
||||
|
||||
applyFilter : function (row, filterName, labelName) {
|
||||
applyFilter : function (row, filterName, categoryName) {
|
||||
var state = row['full_data'].state;
|
||||
var inactive = false;
|
||||
var r;
|
||||
@ -662,13 +662,13 @@ var TorrentsTable = new Class({
|
||||
break;
|
||||
}
|
||||
|
||||
if (labelName == LABELS_ALL)
|
||||
if (categoryName == CATEGORIES_ALL)
|
||||
return true;
|
||||
|
||||
if (labelName == LABELS_UNLABELLED && row['full_data'].label.length === 0)
|
||||
if (categoryName == CATEGORIES_UNCATEGORIZED && row['full_data'].category.length === 0)
|
||||
return true;
|
||||
|
||||
if (labelName != genHash( row['full_data'].label) )
|
||||
if (categoryName != genHash(row['full_data'].category))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -679,7 +679,7 @@ var TorrentsTable = new Class({
|
||||
var rows = this.rows.getValues();
|
||||
|
||||
for (i = 0; i < rows.length; i++)
|
||||
if (this.applyFilter(rows[i], filterName, LABELS_ALL)) cnt++;
|
||||
if (this.applyFilter(rows[i], filterName, CATEGORIES_ALL)) cnt++;
|
||||
|
||||
return cnt;
|
||||
},
|
||||
@ -690,7 +690,7 @@ var TorrentsTable = new Class({
|
||||
var rows = this.rows.getValues();
|
||||
|
||||
for (i = 0; i < rows.length; i++)
|
||||
if (this.applyFilter(rows[i], selected_filter, selected_label)) {
|
||||
if (this.applyFilter(rows[i], selected_filter, selected_category)) {
|
||||
filteredRows.push(rows[i]);
|
||||
filteredRows[rows[i].rowId] = rows[i];
|
||||
}
|
||||
|
@ -304,14 +304,14 @@ initializeWindows = function() {
|
||||
}
|
||||
};
|
||||
|
||||
newLabelFN = function () {
|
||||
newCategoryFN = function () {
|
||||
var h = torrentsTable.selectedRowsIds();
|
||||
if (h.length) {
|
||||
new MochaUI.Window({
|
||||
id: 'newLabelPage',
|
||||
title: "QBT_TR(New Label)QBT_TR",
|
||||
id: 'newCategoryPage',
|
||||
title: "QBT_TR(New Category)QBT_TR",
|
||||
loadMethod: 'iframe',
|
||||
contentURL: 'newlabel.html?hashes=' + h.join('|'),
|
||||
contentURL: 'newcategory.html?hashes=' + h.join('|'),
|
||||
scrollbars: false,
|
||||
resizable: false,
|
||||
maximizable: false,
|
||||
@ -323,18 +323,18 @@ initializeWindows = function() {
|
||||
}
|
||||
};
|
||||
|
||||
updateLabelFN = function (labelHash) {
|
||||
var labelName = '';
|
||||
if (labelHash != 0)
|
||||
var labelName = label_list[labelHash].name;
|
||||
updateCategoryFN = function (categoryHash) {
|
||||
var categoryName = '';
|
||||
if (categoryHash != 0)
|
||||
var categoryName = category_list[categoryHash].name;
|
||||
var h = torrentsTable.selectedRowsIds();
|
||||
if (h.length) {
|
||||
new Request({
|
||||
url: 'command/setLabel',
|
||||
url: 'command/setCategory',
|
||||
method: 'post',
|
||||
data: {
|
||||
hashes: h.join("|"),
|
||||
label: labelName
|
||||
category: categoryName
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
<input type="text" id="savepath" name="savepath" style="width: 16em;"/>
|
||||
</div>
|
||||
<div class="formRow">
|
||||
<label for="label" class="leftLabelLarge">QBT_TR(Label:)QBT_TR</label>
|
||||
<label for="label" class="leftLabelLarge">QBT_TR(Category:)QBT_TR</label>
|
||||
<input type="text" id="label" name="label"/ style="width: 16em;"/>
|
||||
</div>
|
||||
<div id="submitbutton" style="margin-top: 30px; text-align: center;">
|
||||
|
Loading…
x
Reference in New Issue
Block a user