mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-09 09:02:31 -06:00
Merge pull request #18824 from glassez/atp-edit
Unify/improve "add torrent parameters" template editing UI
This commit is contained in:
@@ -110,6 +110,7 @@ add_library(qbt_base STATIC
|
|||||||
applicationcomponent.cpp
|
applicationcomponent.cpp
|
||||||
asyncfilestorage.cpp
|
asyncfilestorage.cpp
|
||||||
bittorrent/abstractfilestorage.cpp
|
bittorrent/abstractfilestorage.cpp
|
||||||
|
bittorrent/addtorrentparams.cpp
|
||||||
bittorrent/bandwidthscheduler.cpp
|
bittorrent/bandwidthscheduler.cpp
|
||||||
bittorrent/bencoderesumedatastorage.cpp
|
bittorrent/bencoderesumedatastorage.cpp
|
||||||
bittorrent/categoryoptions.cpp
|
bittorrent/categoryoptions.cpp
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ SOURCES += \
|
|||||||
$$PWD/applicationcomponent.cpp \
|
$$PWD/applicationcomponent.cpp \
|
||||||
$$PWD/asyncfilestorage.cpp \
|
$$PWD/asyncfilestorage.cpp \
|
||||||
$$PWD/bittorrent/abstractfilestorage.cpp \
|
$$PWD/bittorrent/abstractfilestorage.cpp \
|
||||||
|
$$PWD/bittorrent/addtorrentparams.cpp \
|
||||||
$$PWD/bittorrent/bandwidthscheduler.cpp \
|
$$PWD/bittorrent/bandwidthscheduler.cpp \
|
||||||
$$PWD/bittorrent/bencoderesumedatastorage.cpp \
|
$$PWD/bittorrent/bencoderesumedatastorage.cpp \
|
||||||
$$PWD/bittorrent/categoryoptions.cpp \
|
$$PWD/bittorrent/categoryoptions.cpp \
|
||||||
|
|||||||
170
src/base/bittorrent/addtorrentparams.cpp
Normal file
170
src/base/bittorrent/addtorrentparams.cpp
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
|
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give permission to
|
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||||
|
* and distribute the linked executables. You must obey the GNU General Public
|
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||||
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
|
* exception statement from your version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "addtorrentparams.h"
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonValue>
|
||||||
|
|
||||||
|
#include "base/utils/string.h"
|
||||||
|
|
||||||
|
const QString PARAM_CATEGORY = u"category"_qs;
|
||||||
|
const QString PARAM_TAGS = u"tags"_qs;
|
||||||
|
const QString PARAM_SAVEPATH = u"save_path"_qs;
|
||||||
|
const QString PARAM_USEDOWNLOADPATH = u"use_download_path"_qs;
|
||||||
|
const QString PARAM_DOWNLOADPATH = u"download_path"_qs;
|
||||||
|
const QString PARAM_OPERATINGMODE = u"operating_mode"_qs;
|
||||||
|
const QString PARAM_QUEUETOP = u"add_to_top_of_queue"_qs;
|
||||||
|
const QString PARAM_STOPPED = u"stopped"_qs;
|
||||||
|
const QString PARAM_SKIPCHECKING = u"skip_checking"_qs;
|
||||||
|
const QString PARAM_CONTENTLAYOUT = u"content_layout"_qs;
|
||||||
|
const QString PARAM_AUTOTMM = u"use_auto_tmm"_qs;
|
||||||
|
const QString PARAM_UPLOADLIMIT = u"upload_limit"_qs;
|
||||||
|
const QString PARAM_DOWNLOADLIMIT = u"download_limit"_qs;
|
||||||
|
const QString PARAM_SEEDINGTIMELIMIT = u"seeding_time_limit"_qs;
|
||||||
|
const QString PARAM_RATIOLIMIT = u"ratio_limit"_qs;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
TagSet parseTagSet(const QJsonArray &jsonArr)
|
||||||
|
{
|
||||||
|
TagSet tags;
|
||||||
|
for (const QJsonValue &jsonVal : jsonArr)
|
||||||
|
tags.insert(jsonVal.toString());
|
||||||
|
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray serializeTagSet(const TagSet &tags)
|
||||||
|
{
|
||||||
|
QJsonArray arr;
|
||||||
|
for (const QString &tag : tags)
|
||||||
|
arr.append(tag);
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<bool> getOptionalBool(const QJsonObject &jsonObj, const QString &key)
|
||||||
|
{
|
||||||
|
const QJsonValue jsonVal = jsonObj.value(key);
|
||||||
|
if (jsonVal.isUndefined() || jsonVal.isNull())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return jsonVal.toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Enum>
|
||||||
|
std::optional<Enum> getOptionalEnum(const QJsonObject &jsonObj, const QString &key)
|
||||||
|
{
|
||||||
|
const QJsonValue jsonVal = jsonObj.value(key);
|
||||||
|
if (jsonVal.isUndefined() || jsonVal.isNull())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return Utils::String::toEnum<Enum>(jsonVal.toString(), {});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Enum>
|
||||||
|
Enum getEnum(const QJsonObject &jsonObj, const QString &key)
|
||||||
|
{
|
||||||
|
const QJsonValue jsonVal = jsonObj.value(key);
|
||||||
|
return Utils::String::toEnum<Enum>(jsonVal.toString(), {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BitTorrent::operator==(const AddTorrentParams &lhs, const AddTorrentParams &rhs)
|
||||||
|
{
|
||||||
|
return std::tie(lhs.name, lhs.category, lhs.tags,
|
||||||
|
lhs.savePath, lhs.useDownloadPath, lhs.downloadPath,
|
||||||
|
lhs.sequential, lhs.firstLastPiecePriority, lhs.addForced,
|
||||||
|
lhs.addToQueueTop, lhs.addPaused, lhs.stopCondition,
|
||||||
|
lhs.filePaths, lhs.filePriorities, lhs.skipChecking,
|
||||||
|
lhs.contentLayout, lhs.useAutoTMM, lhs.uploadLimit,
|
||||||
|
lhs.downloadLimit, lhs.seedingTimeLimit, lhs.ratioLimit)
|
||||||
|
== std::tie(rhs.name, rhs.category, rhs.tags,
|
||||||
|
rhs.savePath, rhs.useDownloadPath, rhs.downloadPath,
|
||||||
|
rhs.sequential, rhs.firstLastPiecePriority, rhs.addForced,
|
||||||
|
rhs.addToQueueTop, rhs.addPaused, rhs.stopCondition,
|
||||||
|
rhs.filePaths, rhs.filePriorities, rhs.skipChecking,
|
||||||
|
rhs.contentLayout, rhs.useAutoTMM, rhs.uploadLimit,
|
||||||
|
rhs.downloadLimit, rhs.seedingTimeLimit, rhs.ratioLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
BitTorrent::AddTorrentParams BitTorrent::parseAddTorrentParams(const QJsonObject &jsonObj)
|
||||||
|
{
|
||||||
|
AddTorrentParams params;
|
||||||
|
params.category = jsonObj.value(PARAM_CATEGORY).toString();
|
||||||
|
params.tags = parseTagSet(jsonObj.value(PARAM_TAGS).toArray());
|
||||||
|
params.savePath = Path(jsonObj.value(PARAM_SAVEPATH).toString());
|
||||||
|
params.useDownloadPath = getOptionalBool(jsonObj, PARAM_USEDOWNLOADPATH);
|
||||||
|
params.downloadPath = Path(jsonObj.value(PARAM_DOWNLOADPATH).toString());
|
||||||
|
params.addForced = (getEnum<BitTorrent::TorrentOperatingMode>(jsonObj, PARAM_OPERATINGMODE) == BitTorrent::TorrentOperatingMode::Forced);
|
||||||
|
params.addToQueueTop = getOptionalBool(jsonObj, PARAM_QUEUETOP);
|
||||||
|
params.addPaused = getOptionalBool(jsonObj, PARAM_STOPPED);
|
||||||
|
params.skipChecking = jsonObj.value(PARAM_SKIPCHECKING).toBool();
|
||||||
|
params.contentLayout = getOptionalEnum<BitTorrent::TorrentContentLayout>(jsonObj, PARAM_CONTENTLAYOUT);
|
||||||
|
params.useAutoTMM = getOptionalBool(jsonObj, PARAM_AUTOTMM);
|
||||||
|
params.uploadLimit = jsonObj.value(PARAM_UPLOADLIMIT).toInt(-1);
|
||||||
|
params.downloadLimit = jsonObj.value(PARAM_DOWNLOADLIMIT).toInt(-1);
|
||||||
|
params.seedingTimeLimit = jsonObj.value(PARAM_SEEDINGTIMELIMIT).toInt(BitTorrent::Torrent::USE_GLOBAL_SEEDING_TIME);
|
||||||
|
params.ratioLimit = jsonObj.value(PARAM_RATIOLIMIT).toDouble(BitTorrent::Torrent::USE_GLOBAL_RATIO);
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject BitTorrent::serializeAddTorrentParams(const AddTorrentParams ¶ms)
|
||||||
|
{
|
||||||
|
QJsonObject jsonObj {
|
||||||
|
{PARAM_CATEGORY, params.category},
|
||||||
|
{PARAM_TAGS, serializeTagSet(params.tags)},
|
||||||
|
{PARAM_SAVEPATH, params.savePath.data()},
|
||||||
|
{PARAM_DOWNLOADPATH, params.downloadPath.data()},
|
||||||
|
{PARAM_OPERATINGMODE, Utils::String::fromEnum(params.addForced
|
||||||
|
? BitTorrent::TorrentOperatingMode::Forced : BitTorrent::TorrentOperatingMode::AutoManaged)},
|
||||||
|
{PARAM_SKIPCHECKING, params.skipChecking},
|
||||||
|
{PARAM_UPLOADLIMIT, params.uploadLimit},
|
||||||
|
{PARAM_DOWNLOADLIMIT, params.downloadLimit},
|
||||||
|
{PARAM_SEEDINGTIMELIMIT, params.seedingTimeLimit},
|
||||||
|
{PARAM_RATIOLIMIT, params.ratioLimit}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (params.addToQueueTop)
|
||||||
|
jsonObj[PARAM_QUEUETOP] = *params.addToQueueTop;
|
||||||
|
if (params.addPaused)
|
||||||
|
jsonObj[PARAM_STOPPED] = *params.addPaused;
|
||||||
|
if (params.contentLayout)
|
||||||
|
jsonObj[PARAM_CONTENTLAYOUT] = Utils::String::fromEnum(*params.contentLayout);
|
||||||
|
if (params.useAutoTMM)
|
||||||
|
jsonObj[PARAM_AUTOTMM] = *params.useAutoTMM;
|
||||||
|
if (params.useDownloadPath)
|
||||||
|
jsonObj[PARAM_USEDOWNLOADPATH] = *params.useDownloadPath;
|
||||||
|
|
||||||
|
return jsonObj;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -39,6 +39,8 @@
|
|||||||
#include "torrent.h"
|
#include "torrent.h"
|
||||||
#include "torrentcontentlayout.h"
|
#include "torrentcontentlayout.h"
|
||||||
|
|
||||||
|
class QJsonObject;
|
||||||
|
|
||||||
namespace BitTorrent
|
namespace BitTorrent
|
||||||
{
|
{
|
||||||
enum class DownloadPriority;
|
enum class DownloadPriority;
|
||||||
@@ -67,6 +69,11 @@ namespace BitTorrent
|
|||||||
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
|
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
|
||||||
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
|
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool operator==(const AddTorrentParams &lhs, const AddTorrentParams &rhs);
|
||||||
|
|
||||||
|
AddTorrentParams parseAddTorrentParams(const QJsonObject &jsonObj);
|
||||||
|
QJsonObject serializeAddTorrentParams(const AddTorrentParams ¶ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(BitTorrent::AddTorrentParams)
|
Q_DECLARE_METATYPE(BitTorrent::AddTorrentParams)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2015-2022 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
@@ -170,6 +170,9 @@ namespace BitTorrent
|
|||||||
virtual bool useCategoryPathsInManualMode() const = 0;
|
virtual bool useCategoryPathsInManualMode() const = 0;
|
||||||
virtual void setUseCategoryPathsInManualMode(bool value) = 0;
|
virtual void setUseCategoryPathsInManualMode(bool value) = 0;
|
||||||
|
|
||||||
|
virtual Path suggestedSavePath(const QString &categoryName, std::optional<bool> useAutoTMM) const = 0;
|
||||||
|
virtual Path suggestedDownloadPath(const QString &categoryName, std::optional<bool> useAutoTMM) const = 0;
|
||||||
|
|
||||||
static bool isValidTag(const QString &tag);
|
static bool isValidTag(const QString &tag);
|
||||||
virtual QSet<QString> tags() const = 0;
|
virtual QSet<QString> tags() const = 0;
|
||||||
virtual bool hasTag(const QString &tag) const = 0;
|
virtual bool hasTag(const QString &tag) const = 0;
|
||||||
|
|||||||
@@ -759,11 +759,13 @@ void SessionImpl::setFinishedTorrentExportDirectory(const Path &path)
|
|||||||
|
|
||||||
Path SessionImpl::savePath() const
|
Path SessionImpl::savePath() const
|
||||||
{
|
{
|
||||||
|
// TODO: Make sure it is always non-empty
|
||||||
return m_savePath;
|
return m_savePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
Path SessionImpl::downloadPath() const
|
Path SessionImpl::downloadPath() const
|
||||||
{
|
{
|
||||||
|
// TODO: Make sure it is always non-empty
|
||||||
return m_downloadPath;
|
return m_downloadPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -943,6 +945,21 @@ void SessionImpl::setUseCategoryPathsInManualMode(const bool value)
|
|||||||
m_useCategoryPathsInManualMode = value;
|
m_useCategoryPathsInManualMode = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Path SessionImpl::suggestedSavePath(const QString &categoryName, std::optional<bool> useAutoTMM) const
|
||||||
|
{
|
||||||
|
const bool useCategoryPaths = useAutoTMM.value_or(!isAutoTMMDisabledByDefault()) || useCategoryPathsInManualMode();
|
||||||
|
const auto path = (useCategoryPaths ? categorySavePath(categoryName) : savePath());
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path SessionImpl::suggestedDownloadPath(const QString &categoryName, std::optional<bool> useAutoTMM) const
|
||||||
|
{
|
||||||
|
const bool useCategoryPaths = useAutoTMM.value_or(!isAutoTMMDisabledByDefault()) || useCategoryPathsInManualMode();
|
||||||
|
const auto categoryDownloadPath = this->categoryDownloadPath(categoryName);
|
||||||
|
const auto path = ((useCategoryPaths && !categoryDownloadPath.isEmpty()) ? categoryDownloadPath : downloadPath());
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
QSet<QString> SessionImpl::tags() const
|
QSet<QString> SessionImpl::tags() const
|
||||||
{
|
{
|
||||||
return m_tags;
|
return m_tags;
|
||||||
@@ -2560,14 +2577,13 @@ LoadTorrentParams SessionImpl::initLoadTorrentParams(const AddTorrentParams &add
|
|||||||
LoadTorrentParams loadTorrentParams;
|
LoadTorrentParams loadTorrentParams;
|
||||||
|
|
||||||
loadTorrentParams.name = addTorrentParams.name;
|
loadTorrentParams.name = addTorrentParams.name;
|
||||||
loadTorrentParams.useAutoTMM = addTorrentParams.useAutoTMM.value_or(!isAutoTMMDisabledByDefault());
|
|
||||||
loadTorrentParams.firstLastPiecePriority = addTorrentParams.firstLastPiecePriority;
|
loadTorrentParams.firstLastPiecePriority = addTorrentParams.firstLastPiecePriority;
|
||||||
loadTorrentParams.hasFinishedStatus = addTorrentParams.skipChecking; // do not react on 'torrent_finished_alert' when skipping
|
loadTorrentParams.hasFinishedStatus = addTorrentParams.skipChecking; // do not react on 'torrent_finished_alert' when skipping
|
||||||
loadTorrentParams.contentLayout = addTorrentParams.contentLayout.value_or(torrentContentLayout());
|
loadTorrentParams.contentLayout = addTorrentParams.contentLayout.value_or(torrentContentLayout());
|
||||||
loadTorrentParams.operatingMode = (addTorrentParams.addForced ? TorrentOperatingMode::Forced : TorrentOperatingMode::AutoManaged);
|
loadTorrentParams.operatingMode = (addTorrentParams.addForced ? TorrentOperatingMode::Forced : TorrentOperatingMode::AutoManaged);
|
||||||
loadTorrentParams.stopped = addTorrentParams.addPaused.value_or(isAddTorrentPaused());
|
loadTorrentParams.stopped = addTorrentParams.addPaused.value_or(isAddTorrentPaused());
|
||||||
loadTorrentParams.stopCondition = addTorrentParams.stopCondition.value_or(torrentStopCondition());
|
loadTorrentParams.stopCondition = addTorrentParams.stopCondition.value_or(torrentStopCondition());
|
||||||
loadTorrentParams.addToQueueTop = addTorrentParams.addToQueueTop.value_or(false);
|
loadTorrentParams.addToQueueTop = addTorrentParams.addToQueueTop.value_or(isAddTorrentToQueueTop());
|
||||||
loadTorrentParams.ratioLimit = addTorrentParams.ratioLimit;
|
loadTorrentParams.ratioLimit = addTorrentParams.ratioLimit;
|
||||||
loadTorrentParams.seedingTimeLimit = addTorrentParams.seedingTimeLimit;
|
loadTorrentParams.seedingTimeLimit = addTorrentParams.seedingTimeLimit;
|
||||||
|
|
||||||
@@ -2577,29 +2593,53 @@ LoadTorrentParams SessionImpl::initLoadTorrentParams(const AddTorrentParams &add
|
|||||||
else
|
else
|
||||||
loadTorrentParams.category = category;
|
loadTorrentParams.category = category;
|
||||||
|
|
||||||
if (!loadTorrentParams.useAutoTMM)
|
const auto defaultSavePath = suggestedSavePath(loadTorrentParams.category, addTorrentParams.useAutoTMM);
|
||||||
{
|
const auto defaultDownloadPath = suggestedDownloadPath(loadTorrentParams.category, addTorrentParams.useAutoTMM);
|
||||||
if (addTorrentParams.savePath.isAbsolute())
|
|
||||||
{
|
|
||||||
loadTorrentParams.savePath = addTorrentParams.savePath;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const Path basePath = useCategoryPathsInManualMode() ? categorySavePath(loadTorrentParams.category) : savePath();
|
|
||||||
loadTorrentParams.savePath = basePath / addTorrentParams.savePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool useDownloadPath = addTorrentParams.useDownloadPath.value_or(isDownloadPathEnabled());
|
loadTorrentParams.useAutoTMM = addTorrentParams.useAutoTMM.value_or(!isAutoTMMDisabledByDefault());
|
||||||
if (useDownloadPath)
|
|
||||||
|
if (!addTorrentParams.useAutoTMM.has_value())
|
||||||
|
{
|
||||||
|
// Default TMM settings
|
||||||
|
|
||||||
|
if (!loadTorrentParams.useAutoTMM)
|
||||||
{
|
{
|
||||||
if (addTorrentParams.downloadPath.isAbsolute())
|
loadTorrentParams.savePath = defaultSavePath;
|
||||||
{
|
if (isDownloadPathEnabled())
|
||||||
loadTorrentParams.downloadPath = addTorrentParams.downloadPath;
|
loadTorrentParams.downloadPath = (!defaultDownloadPath.isEmpty() ? defaultDownloadPath : downloadPath());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Overridden TMM settings
|
||||||
|
|
||||||
|
if (!loadTorrentParams.useAutoTMM)
|
||||||
|
{
|
||||||
|
if (addTorrentParams.savePath.isAbsolute())
|
||||||
|
loadTorrentParams.savePath = addTorrentParams.savePath;
|
||||||
else
|
else
|
||||||
|
loadTorrentParams.savePath = defaultSavePath / addTorrentParams.savePath;
|
||||||
|
|
||||||
|
if (!addTorrentParams.useDownloadPath.has_value())
|
||||||
{
|
{
|
||||||
const Path basePath = useCategoryPathsInManualMode() ? categoryDownloadPath(loadTorrentParams.category) : downloadPath();
|
// Default "Download path" settings
|
||||||
loadTorrentParams.downloadPath = basePath / addTorrentParams.downloadPath;
|
|
||||||
|
if (isDownloadPathEnabled())
|
||||||
|
loadTorrentParams.downloadPath = (!defaultDownloadPath.isEmpty() ? defaultDownloadPath : downloadPath());
|
||||||
|
}
|
||||||
|
else if (addTorrentParams.useDownloadPath.value())
|
||||||
|
{
|
||||||
|
// Overridden "Download path" settings
|
||||||
|
|
||||||
|
if (addTorrentParams.downloadPath.isAbsolute())
|
||||||
|
{
|
||||||
|
loadTorrentParams.downloadPath = addTorrentParams.downloadPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const Path basePath = (!defaultDownloadPath.isEmpty() ? defaultDownloadPath : downloadPath());
|
||||||
|
loadTorrentParams.downloadPath = basePath / addTorrentParams.downloadPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2015-2022 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
@@ -160,6 +160,9 @@ namespace BitTorrent
|
|||||||
bool useCategoryPathsInManualMode() const override;
|
bool useCategoryPathsInManualMode() const override;
|
||||||
void setUseCategoryPathsInManualMode(bool value) override;
|
void setUseCategoryPathsInManualMode(bool value) override;
|
||||||
|
|
||||||
|
Path suggestedSavePath(const QString &categoryName, std::optional<bool> useAutoTMM) const override;
|
||||||
|
Path suggestedDownloadPath(const QString &categoryName, std::optional<bool> useAutoTMM) const override;
|
||||||
|
|
||||||
QSet<QString> tags() const override;
|
QSet<QString> tags() const override;
|
||||||
bool hasTag(const QString &tag) const override;
|
bool hasTag(const QString &tag) const override;
|
||||||
bool addTag(const QString &tag) override;
|
bool addTag(const QString &tag) override;
|
||||||
|
|||||||
@@ -430,15 +430,8 @@ void AutoDownloader::processJob(const QSharedPointer<ProcessingJob> &job)
|
|||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
storeDeferred();
|
storeDeferred();
|
||||||
|
|
||||||
BitTorrent::AddTorrentParams params;
|
|
||||||
params.savePath = rule.savePath();
|
|
||||||
params.category = rule.assignedCategory();
|
|
||||||
params.addPaused = rule.addPaused();
|
|
||||||
params.contentLayout = rule.torrentContentLayout();
|
|
||||||
if (!rule.savePath().isEmpty())
|
|
||||||
params.useAutoTMM = false;
|
|
||||||
const auto torrentURL = job->articleData.value(Article::KeyTorrentURL).toString();
|
const auto torrentURL = job->articleData.value(Article::KeyTorrentURL).toString();
|
||||||
BitTorrent::Session::instance()->addTorrent(torrentURL, params);
|
BitTorrent::Session::instance()->addTorrent(torrentURL, rule.addTorrentParams());
|
||||||
|
|
||||||
if (BitTorrent::MagnetUri(torrentURL).isValid())
|
if (BitTorrent::MagnetUri(torrentURL).isValid())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2017-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
@@ -101,22 +101,24 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString Str_Name = u"name"_qs;
|
const QString S_NAME = u"name"_qs;
|
||||||
const QString Str_Enabled = u"enabled"_qs;
|
const QString S_ENABLED = u"enabled"_qs;
|
||||||
const QString Str_UseRegex = u"useRegex"_qs;
|
const QString S_USE_REGEX = u"useRegex"_qs;
|
||||||
const QString Str_MustContain = u"mustContain"_qs;
|
const QString S_MUST_CONTAIN = u"mustContain"_qs;
|
||||||
const QString Str_MustNotContain = u"mustNotContain"_qs;
|
const QString S_MUST_NOT_CONTAIN = u"mustNotContain"_qs;
|
||||||
const QString Str_EpisodeFilter = u"episodeFilter"_qs;
|
const QString S_EPISODE_FILTER = u"episodeFilter"_qs;
|
||||||
const QString Str_AffectedFeeds = u"affectedFeeds"_qs;
|
const QString S_AFFECTED_FEEDS = u"affectedFeeds"_qs;
|
||||||
const QString Str_SavePath = u"savePath"_qs;
|
const QString S_LAST_MATCH = u"lastMatch"_qs;
|
||||||
const QString Str_AssignedCategory = u"assignedCategory"_qs;
|
const QString S_IGNORE_DAYS = u"ignoreDays"_qs;
|
||||||
const QString Str_LastMatch = u"lastMatch"_qs;
|
const QString S_SMART_FILTER = u"smartFilter"_qs;
|
||||||
const QString Str_IgnoreDays = u"ignoreDays"_qs;
|
const QString S_PREVIOUSLY_MATCHED = u"previouslyMatchedEpisodes"_qs;
|
||||||
const QString Str_AddPaused = u"addPaused"_qs;
|
|
||||||
const QString Str_CreateSubfolder = u"createSubfolder"_qs;
|
const QString S_SAVE_PATH = u"savePath"_qs;
|
||||||
const QString Str_ContentLayout = u"torrentContentLayout"_qs;
|
const QString S_ASSIGNED_CATEGORY = u"assignedCategory"_qs;
|
||||||
const QString Str_SmartFilter = u"smartFilter"_qs;
|
const QString S_ADD_PAUSED = u"addPaused"_qs;
|
||||||
const QString Str_PreviouslyMatched = u"previouslyMatchedEpisodes"_qs;
|
const QString S_CONTENT_LAYOUT = u"torrentContentLayout"_qs;
|
||||||
|
|
||||||
|
const QString S_TORRENT_PARAMS = u"torrentParams"_qs;
|
||||||
|
|
||||||
namespace RSS
|
namespace RSS
|
||||||
{
|
{
|
||||||
@@ -133,10 +135,7 @@ namespace RSS
|
|||||||
int ignoreDays = 0;
|
int ignoreDays = 0;
|
||||||
QDateTime lastMatch;
|
QDateTime lastMatch;
|
||||||
|
|
||||||
Path savePath;
|
BitTorrent::AddTorrentParams addTorrentParams;
|
||||||
QString category;
|
|
||||||
std::optional<bool> addPaused;
|
|
||||||
std::optional<BitTorrent::TorrentContentLayout> contentLayout;
|
|
||||||
|
|
||||||
bool smartFilter = false;
|
bool smartFilter = false;
|
||||||
QStringList previouslyMatchedEpisodes;
|
QStringList previouslyMatchedEpisodes;
|
||||||
@@ -155,11 +154,8 @@ namespace RSS
|
|||||||
&& (left.useRegex == right.useRegex)
|
&& (left.useRegex == right.useRegex)
|
||||||
&& (left.ignoreDays == right.ignoreDays)
|
&& (left.ignoreDays == right.ignoreDays)
|
||||||
&& (left.lastMatch == right.lastMatch)
|
&& (left.lastMatch == right.lastMatch)
|
||||||
&& (left.savePath == right.savePath)
|
&& (left.smartFilter == right.smartFilter)
|
||||||
&& (left.category == right.category)
|
&& (left.addTorrentParams == right.addTorrentParams);
|
||||||
&& (left.addPaused == right.addPaused)
|
|
||||||
&& (left.contentLayout == right.contentLayout)
|
|
||||||
&& (left.smartFilter == right.smartFilter);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -458,64 +454,45 @@ AutoDownloadRule &AutoDownloadRule::operator=(const AutoDownloadRule &other)
|
|||||||
|
|
||||||
QJsonObject AutoDownloadRule::toJsonObject() const
|
QJsonObject AutoDownloadRule::toJsonObject() const
|
||||||
{
|
{
|
||||||
return {{Str_Enabled, isEnabled()}
|
const BitTorrent::AddTorrentParams &addTorrentParams = m_dataPtr->addTorrentParams;
|
||||||
, {Str_UseRegex, useRegex()}
|
|
||||||
, {Str_MustContain, mustContain()}
|
return {{S_ENABLED, isEnabled()}
|
||||||
, {Str_MustNotContain, mustNotContain()}
|
, {S_USE_REGEX, useRegex()}
|
||||||
, {Str_EpisodeFilter, episodeFilter()}
|
, {S_MUST_CONTAIN, mustContain()}
|
||||||
, {Str_AffectedFeeds, QJsonArray::fromStringList(feedURLs())}
|
, {S_MUST_NOT_CONTAIN, mustNotContain()}
|
||||||
, {Str_SavePath, savePath().toString()}
|
, {S_EPISODE_FILTER, episodeFilter()}
|
||||||
, {Str_AssignedCategory, assignedCategory()}
|
, {S_AFFECTED_FEEDS, QJsonArray::fromStringList(feedURLs())}
|
||||||
, {Str_LastMatch, lastMatch().toString(Qt::RFC2822Date)}
|
, {S_LAST_MATCH, lastMatch().toString(Qt::RFC2822Date)}
|
||||||
, {Str_IgnoreDays, ignoreDays()}
|
, {S_IGNORE_DAYS, ignoreDays()}
|
||||||
, {Str_AddPaused, toJsonValue(addPaused())}
|
, {S_SMART_FILTER, useSmartFilter()}
|
||||||
, {Str_ContentLayout, contentLayoutToJsonValue(torrentContentLayout())}
|
, {S_PREVIOUSLY_MATCHED, QJsonArray::fromStringList(previouslyMatchedEpisodes())}
|
||||||
, {Str_SmartFilter, useSmartFilter()}
|
|
||||||
, {Str_PreviouslyMatched, QJsonArray::fromStringList(previouslyMatchedEpisodes())}};
|
// TODO: The following code is deprecated. Replace with the commented one after several releases in 4.6.x.
|
||||||
|
// === BEGIN DEPRECATED CODE === //
|
||||||
|
, {S_ADD_PAUSED, toJsonValue(addTorrentParams.addPaused)}
|
||||||
|
, {S_CONTENT_LAYOUT, contentLayoutToJsonValue(addTorrentParams.contentLayout)}
|
||||||
|
, {S_SAVE_PATH, addTorrentParams.savePath.toString()}
|
||||||
|
, {S_ASSIGNED_CATEGORY, addTorrentParams.category}
|
||||||
|
// === END DEPRECATED CODE === //
|
||||||
|
|
||||||
|
, {S_TORRENT_PARAMS, BitTorrent::serializeAddTorrentParams(addTorrentParams)}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoDownloadRule AutoDownloadRule::fromJsonObject(const QJsonObject &jsonObj, const QString &name)
|
AutoDownloadRule AutoDownloadRule::fromJsonObject(const QJsonObject &jsonObj, const QString &name)
|
||||||
{
|
{
|
||||||
AutoDownloadRule rule(name.isEmpty() ? jsonObj.value(Str_Name).toString() : name);
|
AutoDownloadRule rule {(name.isEmpty() ? jsonObj.value(S_NAME).toString() : name)};
|
||||||
|
|
||||||
rule.setUseRegex(jsonObj.value(Str_UseRegex).toBool(false));
|
rule.setUseRegex(jsonObj.value(S_USE_REGEX).toBool(false));
|
||||||
rule.setMustContain(jsonObj.value(Str_MustContain).toString());
|
rule.setMustContain(jsonObj.value(S_MUST_CONTAIN).toString());
|
||||||
rule.setMustNotContain(jsonObj.value(Str_MustNotContain).toString());
|
rule.setMustNotContain(jsonObj.value(S_MUST_NOT_CONTAIN).toString());
|
||||||
rule.setEpisodeFilter(jsonObj.value(Str_EpisodeFilter).toString());
|
rule.setEpisodeFilter(jsonObj.value(S_EPISODE_FILTER).toString());
|
||||||
rule.setEnabled(jsonObj.value(Str_Enabled).toBool(true));
|
rule.setEnabled(jsonObj.value(S_ENABLED).toBool(true));
|
||||||
rule.setSavePath(Path(jsonObj.value(Str_SavePath).toString()));
|
rule.setLastMatch(QDateTime::fromString(jsonObj.value(S_LAST_MATCH).toString(), Qt::RFC2822Date));
|
||||||
rule.setCategory(jsonObj.value(Str_AssignedCategory).toString());
|
rule.setIgnoreDays(jsonObj.value(S_IGNORE_DAYS).toInt());
|
||||||
rule.setAddPaused(toOptionalBool(jsonObj.value(Str_AddPaused)));
|
rule.setUseSmartFilter(jsonObj.value(S_SMART_FILTER).toBool(false));
|
||||||
|
|
||||||
// TODO: The following code is deprecated. Replace with the commented one after several releases in 4.4.x.
|
const QJsonValue feedsVal = jsonObj.value(S_AFFECTED_FEEDS);
|
||||||
// === BEGIN DEPRECATED CODE === //
|
|
||||||
if (jsonObj.contains(Str_ContentLayout))
|
|
||||||
{
|
|
||||||
rule.setTorrentContentLayout(jsonValueToContentLayout(jsonObj.value(Str_ContentLayout)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const std::optional<bool> createSubfolder = toOptionalBool(jsonObj.value(Str_CreateSubfolder));
|
|
||||||
std::optional<BitTorrent::TorrentContentLayout> contentLayout;
|
|
||||||
if (createSubfolder.has_value())
|
|
||||||
{
|
|
||||||
contentLayout = (*createSubfolder
|
|
||||||
? BitTorrent::TorrentContentLayout::Original
|
|
||||||
: BitTorrent::TorrentContentLayout::NoSubfolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
rule.setTorrentContentLayout(contentLayout);
|
|
||||||
}
|
|
||||||
// === END DEPRECATED CODE === //
|
|
||||||
// === BEGIN REPLACEMENT CODE === //
|
|
||||||
// rule.setTorrentContentLayout(jsonValueToContentLayout(jsonObj.value(Str_ContentLayout)));
|
|
||||||
// === END REPLACEMENT CODE === //
|
|
||||||
|
|
||||||
rule.setLastMatch(QDateTime::fromString(jsonObj.value(Str_LastMatch).toString(), Qt::RFC2822Date));
|
|
||||||
rule.setIgnoreDays(jsonObj.value(Str_IgnoreDays).toInt());
|
|
||||||
rule.setUseSmartFilter(jsonObj.value(Str_SmartFilter).toBool(false));
|
|
||||||
|
|
||||||
const QJsonValue feedsVal = jsonObj.value(Str_AffectedFeeds);
|
|
||||||
QStringList feedURLs;
|
QStringList feedURLs;
|
||||||
if (feedsVal.isString())
|
if (feedsVal.isString())
|
||||||
feedURLs << feedsVal.toString();
|
feedURLs << feedsVal.toString();
|
||||||
@@ -523,7 +500,7 @@ AutoDownloadRule AutoDownloadRule::fromJsonObject(const QJsonObject &jsonObj, co
|
|||||||
feedURLs << urlVal.toString();
|
feedURLs << urlVal.toString();
|
||||||
rule.setFeedURLs(feedURLs);
|
rule.setFeedURLs(feedURLs);
|
||||||
|
|
||||||
const QJsonValue previouslyMatchedVal = jsonObj.value(Str_PreviouslyMatched);
|
const QJsonValue previouslyMatchedVal = jsonObj.value(S_PREVIOUSLY_MATCHED);
|
||||||
QStringList previouslyMatched;
|
QStringList previouslyMatched;
|
||||||
if (previouslyMatchedVal.isString())
|
if (previouslyMatchedVal.isString())
|
||||||
{
|
{
|
||||||
@@ -536,20 +513,61 @@ AutoDownloadRule AutoDownloadRule::fromJsonObject(const QJsonObject &jsonObj, co
|
|||||||
}
|
}
|
||||||
rule.setPreviouslyMatchedEpisodes(previouslyMatched);
|
rule.setPreviouslyMatchedEpisodes(previouslyMatched);
|
||||||
|
|
||||||
|
// TODO: The following code is deprecated. Replace with the commented one after several releases in 4.6.x.
|
||||||
|
// === BEGIN DEPRECATED CODE === //
|
||||||
|
BitTorrent::AddTorrentParams addTorrentParams;
|
||||||
|
if (auto it = jsonObj.find(S_TORRENT_PARAMS); it != jsonObj.end())
|
||||||
|
{
|
||||||
|
addTorrentParams = BitTorrent::parseAddTorrentParams(it->toObject());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addTorrentParams.savePath = Path(jsonObj.value(S_SAVE_PATH).toString());
|
||||||
|
addTorrentParams.category = jsonObj.value(S_ASSIGNED_CATEGORY).toString();
|
||||||
|
addTorrentParams.addPaused = toOptionalBool(jsonObj.value(S_ADD_PAUSED));
|
||||||
|
if (!addTorrentParams.savePath.isEmpty())
|
||||||
|
addTorrentParams.useAutoTMM = false;
|
||||||
|
|
||||||
|
if (jsonObj.contains(S_CONTENT_LAYOUT))
|
||||||
|
{
|
||||||
|
addTorrentParams.contentLayout = jsonValueToContentLayout(jsonObj.value(S_CONTENT_LAYOUT));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const std::optional<bool> createSubfolder = toOptionalBool(jsonObj.value(u"createSubfolder"));
|
||||||
|
std::optional<BitTorrent::TorrentContentLayout> contentLayout;
|
||||||
|
if (createSubfolder.has_value())
|
||||||
|
{
|
||||||
|
contentLayout = (*createSubfolder
|
||||||
|
? BitTorrent::TorrentContentLayout::Original
|
||||||
|
: BitTorrent::TorrentContentLayout::NoSubfolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
addTorrentParams.contentLayout = contentLayout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rule.setAddTorrentParams(addTorrentParams);
|
||||||
|
// === END DEPRECATED CODE === //
|
||||||
|
// === BEGIN REPLACEMENT CODE === //
|
||||||
|
// rule.setAddTorrentParams(BitTorrent::parseAddTorrentParams(jsonObj.value(S_TORRENT_PARAMS).object()));
|
||||||
|
// === END REPLACEMENT CODE === //
|
||||||
|
|
||||||
return rule;
|
return rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantHash AutoDownloadRule::toLegacyDict() const
|
QVariantHash AutoDownloadRule::toLegacyDict() const
|
||||||
{
|
{
|
||||||
|
const BitTorrent::AddTorrentParams &addTorrentParams = m_dataPtr->addTorrentParams;
|
||||||
|
|
||||||
return {{u"name"_qs, name()},
|
return {{u"name"_qs, name()},
|
||||||
{u"must_contain"_qs, mustContain()},
|
{u"must_contain"_qs, mustContain()},
|
||||||
{u"must_not_contain"_qs, mustNotContain()},
|
{u"must_not_contain"_qs, mustNotContain()},
|
||||||
{u"save_path"_qs, savePath().toString()},
|
{u"save_path"_qs, addTorrentParams.savePath.toString()},
|
||||||
{u"affected_feeds"_qs, feedURLs()},
|
{u"affected_feeds"_qs, feedURLs()},
|
||||||
{u"enabled"_qs, isEnabled()},
|
{u"enabled"_qs, isEnabled()},
|
||||||
{u"category_assigned"_qs, assignedCategory()},
|
{u"category_assigned"_qs, addTorrentParams.category},
|
||||||
{u"use_regex"_qs, useRegex()},
|
{u"use_regex"_qs, useRegex()},
|
||||||
{u"add_paused"_qs, toAddPausedLegacy(addPaused())},
|
{u"add_paused"_qs, toAddPausedLegacy(addTorrentParams.addPaused)},
|
||||||
{u"episode_filter"_qs, episodeFilter()},
|
{u"episode_filter"_qs, episodeFilter()},
|
||||||
{u"last_match"_qs, lastMatch()},
|
{u"last_match"_qs, lastMatch()},
|
||||||
{u"ignore_days"_qs, ignoreDays()}};
|
{u"ignore_days"_qs, ignoreDays()}};
|
||||||
@@ -557,7 +575,14 @@ QVariantHash AutoDownloadRule::toLegacyDict() const
|
|||||||
|
|
||||||
AutoDownloadRule AutoDownloadRule::fromLegacyDict(const QVariantHash &dict)
|
AutoDownloadRule AutoDownloadRule::fromLegacyDict(const QVariantHash &dict)
|
||||||
{
|
{
|
||||||
AutoDownloadRule rule(dict.value(u"name"_qs).toString());
|
BitTorrent::AddTorrentParams addTorrentParams;
|
||||||
|
addTorrentParams.savePath = Path(dict.value(u"save_path"_qs).toString());
|
||||||
|
addTorrentParams.category = dict.value(u"category_assigned"_qs).toString();
|
||||||
|
addTorrentParams.addPaused = addPausedLegacyToOptionalBool(dict.value(u"add_paused"_qs).toInt());
|
||||||
|
if (!addTorrentParams.savePath.isEmpty())
|
||||||
|
addTorrentParams.useAutoTMM = false;
|
||||||
|
|
||||||
|
AutoDownloadRule rule {dict.value(u"name"_qs).toString()};
|
||||||
|
|
||||||
rule.setUseRegex(dict.value(u"use_regex"_qs, false).toBool());
|
rule.setUseRegex(dict.value(u"use_regex"_qs, false).toBool());
|
||||||
rule.setMustContain(dict.value(u"must_contain"_qs).toString());
|
rule.setMustContain(dict.value(u"must_contain"_qs).toString());
|
||||||
@@ -565,11 +590,9 @@ AutoDownloadRule AutoDownloadRule::fromLegacyDict(const QVariantHash &dict)
|
|||||||
rule.setEpisodeFilter(dict.value(u"episode_filter"_qs).toString());
|
rule.setEpisodeFilter(dict.value(u"episode_filter"_qs).toString());
|
||||||
rule.setFeedURLs(dict.value(u"affected_feeds"_qs).toStringList());
|
rule.setFeedURLs(dict.value(u"affected_feeds"_qs).toStringList());
|
||||||
rule.setEnabled(dict.value(u"enabled"_qs, false).toBool());
|
rule.setEnabled(dict.value(u"enabled"_qs, false).toBool());
|
||||||
rule.setSavePath(Path(dict.value(u"save_path"_qs).toString()));
|
|
||||||
rule.setCategory(dict.value(u"category_assigned"_qs).toString());
|
|
||||||
rule.setAddPaused(addPausedLegacyToOptionalBool(dict.value(u"add_paused"_qs).toInt()));
|
|
||||||
rule.setLastMatch(dict.value(u"last_match"_qs).toDateTime());
|
rule.setLastMatch(dict.value(u"last_match"_qs).toDateTime());
|
||||||
rule.setIgnoreDays(dict.value(u"ignore_days"_qs).toInt());
|
rule.setIgnoreDays(dict.value(u"ignore_days"_qs).toInt());
|
||||||
|
rule.setAddTorrentParams(addTorrentParams);
|
||||||
|
|
||||||
return rule;
|
return rule;
|
||||||
}
|
}
|
||||||
@@ -622,44 +645,14 @@ void AutoDownloadRule::setName(const QString &name)
|
|||||||
m_dataPtr->name = name;
|
m_dataPtr->name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
Path AutoDownloadRule::savePath() const
|
BitTorrent::AddTorrentParams AutoDownloadRule::addTorrentParams() const
|
||||||
{
|
{
|
||||||
return m_dataPtr->savePath;
|
return m_dataPtr->addTorrentParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoDownloadRule::setSavePath(const Path &savePath)
|
void AutoDownloadRule::setAddTorrentParams(BitTorrent::AddTorrentParams addTorrentParams)
|
||||||
{
|
{
|
||||||
m_dataPtr->savePath = savePath;
|
m_dataPtr->addTorrentParams = std::move(addTorrentParams);
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<bool> AutoDownloadRule::addPaused() const
|
|
||||||
{
|
|
||||||
return m_dataPtr->addPaused;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDownloadRule::setAddPaused(const std::optional<bool> addPaused)
|
|
||||||
{
|
|
||||||
m_dataPtr->addPaused = addPaused;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<BitTorrent::TorrentContentLayout> AutoDownloadRule::torrentContentLayout() const
|
|
||||||
{
|
|
||||||
return m_dataPtr->contentLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDownloadRule::setTorrentContentLayout(const std::optional<BitTorrent::TorrentContentLayout> contentLayout)
|
|
||||||
{
|
|
||||||
m_dataPtr->contentLayout = contentLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString AutoDownloadRule::assignedCategory() const
|
|
||||||
{
|
|
||||||
return m_dataPtr->category;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDownloadRule::setCategory(const QString &category)
|
|
||||||
{
|
|
||||||
m_dataPtr->category = category;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AutoDownloadRule::isEnabled() const
|
bool AutoDownloadRule::isEnabled() const
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2017-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
#include "base/global.h"
|
#include "base/global.h"
|
||||||
#include "base/bittorrent/torrentcontentlayout.h"
|
#include "base/bittorrent/addtorrentparams.h"
|
||||||
#include "base/pathfwd.h"
|
#include "base/pathfwd.h"
|
||||||
|
|
||||||
class QDateTime;
|
class QDateTime;
|
||||||
@@ -81,14 +81,8 @@ namespace RSS
|
|||||||
QStringList previouslyMatchedEpisodes() const;
|
QStringList previouslyMatchedEpisodes() const;
|
||||||
void setPreviouslyMatchedEpisodes(const QStringList &previouslyMatchedEpisodes);
|
void setPreviouslyMatchedEpisodes(const QStringList &previouslyMatchedEpisodes);
|
||||||
|
|
||||||
Path savePath() const;
|
BitTorrent::AddTorrentParams addTorrentParams() const;
|
||||||
void setSavePath(const Path &savePath);
|
void setAddTorrentParams(BitTorrent::AddTorrentParams addTorrentParams);
|
||||||
std::optional<bool> addPaused() const;
|
|
||||||
void setAddPaused(std::optional<bool> addPaused);
|
|
||||||
std::optional<BitTorrent::TorrentContentLayout> torrentContentLayout() const;
|
|
||||||
void setTorrentContentLayout(std::optional<BitTorrent::TorrentContentLayout> contentLayout);
|
|
||||||
QString assignedCategory() const;
|
|
||||||
void setCategory(const QString &category);
|
|
||||||
|
|
||||||
bool matches(const QVariantHash &articleData) const;
|
bool matches(const QVariantHash &articleData) const;
|
||||||
bool accepts(const QVariantHash &articleData);
|
bool accepts(const QVariantHash &articleData);
|
||||||
|
|||||||
@@ -36,10 +36,8 @@
|
|||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonValue>
|
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
@@ -70,124 +68,12 @@ const QString CONF_FILE_NAME = u"watched_folders.json"_qs;
|
|||||||
const QString OPTION_ADDTORRENTPARAMS = u"add_torrent_params"_qs;
|
const QString OPTION_ADDTORRENTPARAMS = u"add_torrent_params"_qs;
|
||||||
const QString OPTION_RECURSIVE = u"recursive"_qs;
|
const QString OPTION_RECURSIVE = u"recursive"_qs;
|
||||||
|
|
||||||
const QString PARAM_CATEGORY = u"category"_qs;
|
|
||||||
const QString PARAM_TAGS = u"tags"_qs;
|
|
||||||
const QString PARAM_SAVEPATH = u"save_path"_qs;
|
|
||||||
const QString PARAM_USEDOWNLOADPATH = u"use_download_path"_qs;
|
|
||||||
const QString PARAM_DOWNLOADPATH = u"download_path"_qs;
|
|
||||||
const QString PARAM_OPERATINGMODE = u"operating_mode"_qs;
|
|
||||||
const QString PARAM_QUEUETOP = u"add_to_top_of_queue"_qs;
|
|
||||||
const QString PARAM_STOPPED = u"stopped"_qs;
|
|
||||||
const QString PARAM_SKIPCHECKING = u"skip_checking"_qs;
|
|
||||||
const QString PARAM_CONTENTLAYOUT = u"content_layout"_qs;
|
|
||||||
const QString PARAM_AUTOTMM = u"use_auto_tmm"_qs;
|
|
||||||
const QString PARAM_UPLOADLIMIT = u"upload_limit"_qs;
|
|
||||||
const QString PARAM_DOWNLOADLIMIT = u"download_limit"_qs;
|
|
||||||
const QString PARAM_SEEDINGTIMELIMIT = u"seeding_time_limit"_qs;
|
|
||||||
const QString PARAM_RATIOLIMIT = u"ratio_limit"_qs;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
TagSet parseTagSet(const QJsonArray &jsonArr)
|
|
||||||
{
|
|
||||||
TagSet tags;
|
|
||||||
for (const QJsonValue &jsonVal : jsonArr)
|
|
||||||
tags.insert(jsonVal.toString());
|
|
||||||
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray serializeTagSet(const TagSet &tags)
|
|
||||||
{
|
|
||||||
QJsonArray arr;
|
|
||||||
for (const QString &tag : tags)
|
|
||||||
arr.append(tag);
|
|
||||||
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<bool> getOptionalBool(const QJsonObject &jsonObj, const QString &key)
|
|
||||||
{
|
|
||||||
const QJsonValue jsonVal = jsonObj.value(key);
|
|
||||||
if (jsonVal.isUndefined() || jsonVal.isNull())
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
return jsonVal.toBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Enum>
|
|
||||||
std::optional<Enum> getOptionalEnum(const QJsonObject &jsonObj, const QString &key)
|
|
||||||
{
|
|
||||||
const QJsonValue jsonVal = jsonObj.value(key);
|
|
||||||
if (jsonVal.isUndefined() || jsonVal.isNull())
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
return Utils::String::toEnum<Enum>(jsonVal.toString(), {});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Enum>
|
|
||||||
Enum getEnum(const QJsonObject &jsonObj, const QString &key)
|
|
||||||
{
|
|
||||||
const QJsonValue jsonVal = jsonObj.value(key);
|
|
||||||
return Utils::String::toEnum<Enum>(jsonVal.toString(), {});
|
|
||||||
}
|
|
||||||
|
|
||||||
BitTorrent::AddTorrentParams parseAddTorrentParams(const QJsonObject &jsonObj)
|
|
||||||
{
|
|
||||||
BitTorrent::AddTorrentParams params;
|
|
||||||
params.category = jsonObj.value(PARAM_CATEGORY).toString();
|
|
||||||
params.tags = parseTagSet(jsonObj.value(PARAM_TAGS).toArray());
|
|
||||||
params.savePath = Path(jsonObj.value(PARAM_SAVEPATH).toString());
|
|
||||||
params.useDownloadPath = getOptionalBool(jsonObj, PARAM_USEDOWNLOADPATH);
|
|
||||||
params.downloadPath = Path(jsonObj.value(PARAM_DOWNLOADPATH).toString());
|
|
||||||
params.addForced = (getEnum<BitTorrent::TorrentOperatingMode>(jsonObj, PARAM_OPERATINGMODE) == BitTorrent::TorrentOperatingMode::Forced);
|
|
||||||
params.addToQueueTop = getOptionalBool(jsonObj, PARAM_QUEUETOP);
|
|
||||||
params.addPaused = getOptionalBool(jsonObj, PARAM_STOPPED);
|
|
||||||
params.skipChecking = jsonObj.value(PARAM_SKIPCHECKING).toBool();
|
|
||||||
params.contentLayout = getOptionalEnum<BitTorrent::TorrentContentLayout>(jsonObj, PARAM_CONTENTLAYOUT);
|
|
||||||
params.useAutoTMM = getOptionalBool(jsonObj, PARAM_AUTOTMM);
|
|
||||||
params.uploadLimit = jsonObj.value(PARAM_UPLOADLIMIT).toInt(-1);
|
|
||||||
params.downloadLimit = jsonObj.value(PARAM_DOWNLOADLIMIT).toInt(-1);
|
|
||||||
params.seedingTimeLimit = jsonObj.value(PARAM_SEEDINGTIMELIMIT).toInt(BitTorrent::Torrent::USE_GLOBAL_SEEDING_TIME);
|
|
||||||
params.ratioLimit = jsonObj.value(PARAM_RATIOLIMIT).toDouble(BitTorrent::Torrent::USE_GLOBAL_RATIO);
|
|
||||||
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject serializeAddTorrentParams(const BitTorrent::AddTorrentParams ¶ms)
|
|
||||||
{
|
|
||||||
QJsonObject jsonObj {
|
|
||||||
{PARAM_CATEGORY, params.category},
|
|
||||||
{PARAM_TAGS, serializeTagSet(params.tags)},
|
|
||||||
{PARAM_SAVEPATH, params.savePath.data()},
|
|
||||||
{PARAM_DOWNLOADPATH, params.downloadPath.data()},
|
|
||||||
{PARAM_OPERATINGMODE, Utils::String::fromEnum(params.addForced
|
|
||||||
? BitTorrent::TorrentOperatingMode::Forced : BitTorrent::TorrentOperatingMode::AutoManaged)},
|
|
||||||
{PARAM_SKIPCHECKING, params.skipChecking},
|
|
||||||
{PARAM_UPLOADLIMIT, params.uploadLimit},
|
|
||||||
{PARAM_DOWNLOADLIMIT, params.downloadLimit},
|
|
||||||
{PARAM_SEEDINGTIMELIMIT, params.seedingTimeLimit},
|
|
||||||
{PARAM_RATIOLIMIT, params.ratioLimit}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (params.addToQueueTop)
|
|
||||||
jsonObj[PARAM_QUEUETOP] = *params.addToQueueTop;
|
|
||||||
if (params.addPaused)
|
|
||||||
jsonObj[PARAM_STOPPED] = *params.addPaused;
|
|
||||||
if (params.contentLayout)
|
|
||||||
jsonObj[PARAM_CONTENTLAYOUT] = Utils::String::fromEnum(*params.contentLayout);
|
|
||||||
if (params.useAutoTMM)
|
|
||||||
jsonObj[PARAM_AUTOTMM] = *params.useAutoTMM;
|
|
||||||
if (params.useDownloadPath)
|
|
||||||
jsonObj[PARAM_USEDOWNLOADPATH] = *params.useDownloadPath;
|
|
||||||
|
|
||||||
return jsonObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
TorrentFilesWatcher::WatchedFolderOptions parseWatchedFolderOptions(const QJsonObject &jsonObj)
|
TorrentFilesWatcher::WatchedFolderOptions parseWatchedFolderOptions(const QJsonObject &jsonObj)
|
||||||
{
|
{
|
||||||
TorrentFilesWatcher::WatchedFolderOptions options;
|
TorrentFilesWatcher::WatchedFolderOptions options;
|
||||||
options.addTorrentParams = parseAddTorrentParams(jsonObj.value(OPTION_ADDTORRENTPARAMS).toObject());
|
options.addTorrentParams = BitTorrent::parseAddTorrentParams(jsonObj.value(OPTION_ADDTORRENTPARAMS).toObject());
|
||||||
options.recursive = jsonObj.value(OPTION_RECURSIVE).toBool();
|
options.recursive = jsonObj.value(OPTION_RECURSIVE).toBool();
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
@@ -195,10 +81,8 @@ namespace
|
|||||||
|
|
||||||
QJsonObject serializeWatchedFolderOptions(const TorrentFilesWatcher::WatchedFolderOptions &options)
|
QJsonObject serializeWatchedFolderOptions(const TorrentFilesWatcher::WatchedFolderOptions &options)
|
||||||
{
|
{
|
||||||
return {
|
return {{OPTION_ADDTORRENTPARAMS, BitTorrent::serializeAddTorrentParams(options.addTorrentParams)},
|
||||||
{OPTION_ADDTORRENTPARAMS, serializeAddTorrentParams(options.addTorrentParams)},
|
{OPTION_RECURSIVE, options.recursive}};
|
||||||
{OPTION_RECURSIVE, options.recursive}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ endif()
|
|||||||
qt_wrap_ui(UI_HEADERS
|
qt_wrap_ui(UI_HEADERS
|
||||||
aboutdialog.ui
|
aboutdialog.ui
|
||||||
addnewtorrentdialog.ui
|
addnewtorrentdialog.ui
|
||||||
|
addtorrentparamswidget.ui
|
||||||
autoexpandabledialog.ui
|
autoexpandabledialog.ui
|
||||||
banlistoptionsdialog.ui
|
banlistoptionsdialog.ui
|
||||||
cookiesdialog.ui
|
cookiesdialog.ui
|
||||||
@@ -46,6 +47,7 @@ add_library(qbt_gui STATIC
|
|||||||
# headers
|
# headers
|
||||||
aboutdialog.h
|
aboutdialog.h
|
||||||
addnewtorrentdialog.h
|
addnewtorrentdialog.h
|
||||||
|
addtorrentparamswidget.h
|
||||||
advancedsettings.h
|
advancedsettings.h
|
||||||
autoexpandabledialog.h
|
autoexpandabledialog.h
|
||||||
banlistoptionsdialog.h
|
banlistoptionsdialog.h
|
||||||
@@ -140,6 +142,7 @@ add_library(qbt_gui STATIC
|
|||||||
# sources
|
# sources
|
||||||
aboutdialog.cpp
|
aboutdialog.cpp
|
||||||
addnewtorrentdialog.cpp
|
addnewtorrentdialog.cpp
|
||||||
|
addtorrentparamswidget.cpp
|
||||||
advancedsettings.cpp
|
advancedsettings.cpp
|
||||||
autoexpandabledialog.cpp
|
autoexpandabledialog.cpp
|
||||||
banlistoptionsdialog.cpp
|
banlistoptionsdialog.cpp
|
||||||
|
|||||||
392
src/gui/addtorrentparamswidget.cpp
Normal file
392
src/gui/addtorrentparamswidget.cpp
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
|
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give permission to
|
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||||
|
* and distribute the linked executables. You must obey the GNU General Public
|
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||||
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
|
* exception statement from your version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "addtorrentparamswidget.h"
|
||||||
|
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
#include "base/bittorrent/session.h"
|
||||||
|
#include "base/bittorrent/torrent.h"
|
||||||
|
#include "base/utils/compare.h"
|
||||||
|
#include "flowlayout.h"
|
||||||
|
#include "fspathedit.h"
|
||||||
|
#include "torrenttagsdialog.h"
|
||||||
|
#include "ui_addtorrentparamswidget.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::optional<bool> toOptionalBool(const QVariant &data)
|
||||||
|
{
|
||||||
|
if (!data.isValid())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
Q_ASSERT(data.userType() == QMetaType::Bool);
|
||||||
|
return data.toBool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddTorrentParamsWidget::AddTorrentParamsWidget(BitTorrent::AddTorrentParams addTorrentParams, QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, m_ui {new Ui::AddTorrentParamsWidget}
|
||||||
|
, m_addTorrentParams {std::move(addTorrentParams)}
|
||||||
|
{
|
||||||
|
m_ui->setupUi(this);
|
||||||
|
|
||||||
|
m_ui->savePathEdit->setMode(FileSystemPathEdit::Mode::DirectorySave);
|
||||||
|
m_ui->savePathEdit->setDialogCaption(tr("Choose save path"));
|
||||||
|
|
||||||
|
m_ui->downloadPathEdit->setMode(FileSystemPathEdit::Mode::DirectorySave);
|
||||||
|
m_ui->downloadPathEdit->setDialogCaption(tr("Choose save path"));
|
||||||
|
|
||||||
|
m_ui->useDownloadPathComboBox->addItem(tr("Default"));
|
||||||
|
m_ui->useDownloadPathComboBox->addItem(tr("Yes"), true);
|
||||||
|
m_ui->useDownloadPathComboBox->addItem(tr("No"), false);
|
||||||
|
|
||||||
|
m_ui->comboTTM->addItem(tr("Default"));
|
||||||
|
m_ui->comboTTM->addItem(tr("Manual"), false);
|
||||||
|
m_ui->comboTTM->addItem(tr("Automatic"), true);
|
||||||
|
|
||||||
|
m_ui->contentLayoutComboBox->addItem(tr("Default"));
|
||||||
|
m_ui->contentLayoutComboBox->addItem(tr("Original"), QVariant::fromValue(BitTorrent::TorrentContentLayout::Original));
|
||||||
|
m_ui->contentLayoutComboBox->addItem(tr("Create subfolder"), QVariant::fromValue(BitTorrent::TorrentContentLayout::Subfolder));
|
||||||
|
m_ui->contentLayoutComboBox->addItem(tr("Don't create subfolder"), QVariant::fromValue(BitTorrent::TorrentContentLayout::NoSubfolder));
|
||||||
|
|
||||||
|
m_ui->stopConditionComboBox->addItem(tr("Default"));
|
||||||
|
m_ui->stopConditionComboBox->addItem(tr("None"), QVariant::fromValue(BitTorrent::Torrent::StopCondition::None));
|
||||||
|
m_ui->stopConditionComboBox->addItem(tr("Metadata received"), QVariant::fromValue(BitTorrent::Torrent::StopCondition::MetadataReceived));
|
||||||
|
m_ui->stopConditionComboBox->addItem(tr("Files checked"), QVariant::fromValue(BitTorrent::Torrent::StopCondition::FilesChecked));
|
||||||
|
|
||||||
|
m_ui->startTorrentComboBox->addItem(tr("Default"));
|
||||||
|
m_ui->startTorrentComboBox->addItem(tr("Yes"), true);
|
||||||
|
m_ui->startTorrentComboBox->addItem(tr("No"), false);
|
||||||
|
|
||||||
|
m_ui->addToQueueTopComboBox->addItem(tr("Default"));
|
||||||
|
m_ui->addToQueueTopComboBox->addItem(tr("Yes"), true);
|
||||||
|
m_ui->addToQueueTopComboBox->addItem(tr("No"), false);
|
||||||
|
|
||||||
|
connect(m_ui->tagsEditButton, &QAbstractButton::clicked, this, [this]
|
||||||
|
{
|
||||||
|
auto *dlg = new TorrentTagsDialog(m_addTorrentParams.tags, this);
|
||||||
|
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
connect(dlg, &TorrentTagsDialog::accepted, this, [this, dlg]
|
||||||
|
{
|
||||||
|
m_addTorrentParams.tags = dlg->tags();
|
||||||
|
m_ui->tagsLineEdit->setText(m_addTorrentParams.tags.join(u", "_qs));
|
||||||
|
});
|
||||||
|
dlg->open();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto *miscParamsLayout = new FlowLayout(m_ui->miscParamsWidget);
|
||||||
|
miscParamsLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
miscParamsLayout->addWidget(m_ui->contentLayoutWidget);
|
||||||
|
miscParamsLayout->addWidget(m_ui->skipCheckingCheckBox);
|
||||||
|
miscParamsLayout->setAlignment(m_ui->skipCheckingCheckBox, Qt::AlignVCenter);
|
||||||
|
miscParamsLayout->addWidget(m_ui->startTorrentWidget);
|
||||||
|
miscParamsLayout->addWidget(m_ui->stopConditionWidget);
|
||||||
|
miscParamsLayout->addWidget(m_ui->addToQueueTopWidget);
|
||||||
|
|
||||||
|
populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
AddTorrentParamsWidget::~AddTorrentParamsWidget()
|
||||||
|
{
|
||||||
|
delete m_ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTorrentParamsWidget::setAddTorrentParams(BitTorrent::AddTorrentParams addTorrentParams)
|
||||||
|
{
|
||||||
|
m_addTorrentParams = std::move(addTorrentParams);
|
||||||
|
populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
BitTorrent::AddTorrentParams AddTorrentParamsWidget::addTorrentParams() const
|
||||||
|
{
|
||||||
|
return m_addTorrentParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTorrentParamsWidget::populate()
|
||||||
|
{
|
||||||
|
m_ui->comboTTM->disconnect(this);
|
||||||
|
m_ui->comboTTM->setCurrentIndex(m_addTorrentParams.useAutoTMM
|
||||||
|
? m_ui->comboTTM->findData(*m_addTorrentParams.useAutoTMM) : 0);
|
||||||
|
connect(m_ui->comboTTM, &QComboBox::currentIndexChanged, this, [this]
|
||||||
|
{
|
||||||
|
m_addTorrentParams.useAutoTMM = toOptionalBool(m_ui->comboTTM->currentData());
|
||||||
|
|
||||||
|
populateSavePathOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_ui->categoryComboBox->disconnect(this);
|
||||||
|
m_ui->categoryComboBox->clear();
|
||||||
|
QStringList categories = BitTorrent::Session::instance()->categories();
|
||||||
|
std::sort(categories.begin(), categories.end(), Utils::Compare::NaturalLessThan<Qt::CaseInsensitive>());
|
||||||
|
if (!m_addTorrentParams.category.isEmpty())
|
||||||
|
m_ui->categoryComboBox->addItem(m_addTorrentParams.category);
|
||||||
|
m_ui->categoryComboBox->addItem(u""_qs);
|
||||||
|
for (const QString &category : asConst(categories))
|
||||||
|
{
|
||||||
|
if (category != m_addTorrentParams.category)
|
||||||
|
m_ui->categoryComboBox->addItem(category);
|
||||||
|
}
|
||||||
|
connect(m_ui->categoryComboBox, &QComboBox::currentIndexChanged, this, [this]
|
||||||
|
{
|
||||||
|
m_addTorrentParams.category = m_ui->categoryComboBox->currentText();
|
||||||
|
|
||||||
|
const auto *btSession = BitTorrent::Session::instance();
|
||||||
|
const bool useAutoTMM = m_addTorrentParams.useAutoTMM.value_or(!btSession->isAutoTMMDisabledByDefault());
|
||||||
|
if (useAutoTMM)
|
||||||
|
{
|
||||||
|
const auto downloadPathOption = btSession->categoryOptions(m_addTorrentParams.category).downloadPath;
|
||||||
|
m_ui->useDownloadPathComboBox->setCurrentIndex(downloadPathOption.has_value()
|
||||||
|
? m_ui->useDownloadPathComboBox->findData(downloadPathOption->enabled) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
populateDefaultPaths();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_ui->savePathEdit->disconnect(this);
|
||||||
|
m_ui->downloadPathEdit->disconnect(this);
|
||||||
|
m_ui->useDownloadPathComboBox->disconnect(this);
|
||||||
|
|
||||||
|
populateSavePathOptions();
|
||||||
|
|
||||||
|
connect(m_ui->savePathEdit, &FileSystemPathLineEdit::selectedPathChanged, this, [this]
|
||||||
|
{
|
||||||
|
m_addTorrentParams.savePath = m_ui->savePathEdit->selectedPath();
|
||||||
|
});
|
||||||
|
connect(m_ui->downloadPathEdit, &FileSystemPathLineEdit::selectedPathChanged, this, [this]
|
||||||
|
{
|
||||||
|
m_addTorrentParams.downloadPath = m_ui->downloadPathEdit->selectedPath();
|
||||||
|
});
|
||||||
|
connect(m_ui->useDownloadPathComboBox, &QComboBox::currentIndexChanged, this, [this]
|
||||||
|
{
|
||||||
|
m_addTorrentParams.useDownloadPath = toOptionalBool(m_ui->useDownloadPathComboBox->currentData());
|
||||||
|
|
||||||
|
loadCustomDownloadPath();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_ui->contentLayoutComboBox->disconnect(this);
|
||||||
|
m_ui->contentLayoutComboBox->setCurrentIndex(m_addTorrentParams.contentLayout
|
||||||
|
? m_ui->contentLayoutComboBox->findData(QVariant::fromValue(*m_addTorrentParams.contentLayout)) : 0);
|
||||||
|
connect(m_ui->contentLayoutComboBox, &QComboBox::currentIndexChanged, this, [this]
|
||||||
|
{
|
||||||
|
const QVariant data = m_ui->contentLayoutComboBox->currentData();
|
||||||
|
if (!data.isValid())
|
||||||
|
m_addTorrentParams.contentLayout = std::nullopt;
|
||||||
|
else
|
||||||
|
m_addTorrentParams.contentLayout = data.value<BitTorrent::TorrentContentLayout>();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_ui->stopConditionComboBox->disconnect(this);
|
||||||
|
m_ui->stopConditionComboBox->setCurrentIndex(m_addTorrentParams.stopCondition
|
||||||
|
? m_ui->stopConditionComboBox->findData(QVariant::fromValue(*m_addTorrentParams.stopCondition)) : 0);
|
||||||
|
connect(m_ui->stopConditionComboBox, &QComboBox::currentIndexChanged, this, [this]
|
||||||
|
{
|
||||||
|
const QVariant data = m_ui->stopConditionComboBox->currentData();
|
||||||
|
if (!data.isValid())
|
||||||
|
m_addTorrentParams.stopCondition = std::nullopt;
|
||||||
|
else
|
||||||
|
m_addTorrentParams.stopCondition = data.value<BitTorrent::Torrent::StopCondition>();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_ui->tagsLineEdit->setText(m_addTorrentParams.tags.join(u", "_qs));
|
||||||
|
|
||||||
|
m_ui->startTorrentComboBox->disconnect(this);
|
||||||
|
m_ui->startTorrentComboBox->setCurrentIndex(m_addTorrentParams.addPaused
|
||||||
|
? m_ui->startTorrentComboBox->findData(!*m_addTorrentParams.addPaused) : 0);
|
||||||
|
connect(m_ui->startTorrentComboBox, &QComboBox::currentIndexChanged, this, [this]
|
||||||
|
{
|
||||||
|
const QVariant data = m_ui->startTorrentComboBox->currentData();
|
||||||
|
if (!data.isValid())
|
||||||
|
m_addTorrentParams.addPaused = std::nullopt;
|
||||||
|
else
|
||||||
|
m_addTorrentParams.addPaused = !data.toBool();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_ui->skipCheckingCheckBox->disconnect(this);
|
||||||
|
m_ui->skipCheckingCheckBox->setChecked(m_addTorrentParams.skipChecking);
|
||||||
|
connect(m_ui->skipCheckingCheckBox, &QCheckBox::toggled, this, [this]
|
||||||
|
{
|
||||||
|
m_addTorrentParams.skipChecking = m_ui->skipCheckingCheckBox->isChecked();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_ui->addToQueueTopComboBox->disconnect(this);
|
||||||
|
m_ui->addToQueueTopComboBox->setCurrentIndex(m_addTorrentParams.addToQueueTop
|
||||||
|
? m_ui->addToQueueTopComboBox->findData(*m_addTorrentParams.addToQueueTop) : 0);
|
||||||
|
connect(m_ui->addToQueueTopComboBox, &QComboBox::currentIndexChanged, this, [this]
|
||||||
|
{
|
||||||
|
const QVariant data = m_ui->addToQueueTopComboBox->currentData();
|
||||||
|
if (!data.isValid())
|
||||||
|
m_addTorrentParams.addToQueueTop = std::nullopt;
|
||||||
|
else
|
||||||
|
m_addTorrentParams.addToQueueTop = data.toBool();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTorrentParamsWidget::loadCustomSavePathOptions()
|
||||||
|
{
|
||||||
|
[[maybe_unused]] const auto *btSession = BitTorrent::Session::instance();
|
||||||
|
Q_ASSERT(!m_addTorrentParams.useAutoTMM.value_or(!btSession->isAutoTMMDisabledByDefault()));
|
||||||
|
|
||||||
|
m_ui->savePathEdit->setSelectedPath(m_addTorrentParams.savePath);
|
||||||
|
|
||||||
|
m_ui->useDownloadPathComboBox->setCurrentIndex(m_addTorrentParams.useDownloadPath
|
||||||
|
? m_ui->useDownloadPathComboBox->findData(*m_addTorrentParams.useDownloadPath) : 0);
|
||||||
|
|
||||||
|
loadCustomDownloadPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTorrentParamsWidget::loadCustomDownloadPath()
|
||||||
|
{
|
||||||
|
populateDefaultDownloadPath();
|
||||||
|
|
||||||
|
if (!m_addTorrentParams.useDownloadPath.has_value())
|
||||||
|
{
|
||||||
|
// Default "Download path" settings
|
||||||
|
|
||||||
|
m_ui->downloadPathEdit->setEnabled(false);
|
||||||
|
m_ui->downloadPathEdit->blockSignals(true);
|
||||||
|
m_ui->downloadPathEdit->setSelectedPath(Path());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Overridden "Download path" settings
|
||||||
|
|
||||||
|
const bool useDownloadPath = m_addTorrentParams.useDownloadPath.value();
|
||||||
|
if (useDownloadPath)
|
||||||
|
{
|
||||||
|
m_ui->downloadPathEdit->setSelectedPath(m_addTorrentParams.downloadPath);
|
||||||
|
|
||||||
|
m_ui->downloadPathEdit->blockSignals(false);
|
||||||
|
m_ui->downloadPathEdit->setEnabled(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_ui->downloadPathEdit->setEnabled(false);
|
||||||
|
m_ui->downloadPathEdit->blockSignals(true);
|
||||||
|
|
||||||
|
m_ui->downloadPathEdit->setSelectedPath(Path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTorrentParamsWidget::loadCategorySavePathOptions()
|
||||||
|
{
|
||||||
|
const auto *btSession = BitTorrent::Session::instance();
|
||||||
|
Q_ASSERT(m_addTorrentParams.useAutoTMM.value_or(!btSession->isAutoTMMDisabledByDefault()));
|
||||||
|
|
||||||
|
const auto downloadPathOption = btSession->categoryOptions(m_addTorrentParams.category).downloadPath;
|
||||||
|
m_ui->useDownloadPathComboBox->setCurrentIndex(downloadPathOption.has_value()
|
||||||
|
? m_ui->useDownloadPathComboBox->findData(downloadPathOption->enabled) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTorrentParamsWidget::populateDefaultPaths()
|
||||||
|
{
|
||||||
|
const auto *btSession = BitTorrent::Session::instance();
|
||||||
|
|
||||||
|
const Path defaultSavePath = btSession->suggestedSavePath(
|
||||||
|
m_ui->categoryComboBox->currentText(), toOptionalBool(m_ui->comboTTM->currentData()));
|
||||||
|
m_ui->savePathEdit->setPlaceholder(defaultSavePath);
|
||||||
|
|
||||||
|
populateDefaultDownloadPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTorrentParamsWidget::populateDefaultDownloadPath()
|
||||||
|
{
|
||||||
|
const auto *btSession = BitTorrent::Session::instance();
|
||||||
|
|
||||||
|
const std::optional<bool> useDownloadPath = toOptionalBool(m_ui->useDownloadPathComboBox->currentData());
|
||||||
|
if (useDownloadPath.value_or(btSession->isDownloadPathEnabled()))
|
||||||
|
{
|
||||||
|
const Path defaultDownloadPath = btSession->suggestedDownloadPath(
|
||||||
|
m_ui->categoryComboBox->currentText(), toOptionalBool(m_ui->comboTTM->currentData()));
|
||||||
|
m_ui->downloadPathEdit->setPlaceholder(defaultDownloadPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_ui->downloadPathEdit->setPlaceholder(Path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTorrentParamsWidget::populateSavePathOptions()
|
||||||
|
{
|
||||||
|
if (!m_addTorrentParams.useAutoTMM.has_value())
|
||||||
|
{
|
||||||
|
// Default TMM settings
|
||||||
|
|
||||||
|
m_ui->groupBoxSavePath->setEnabled(false);
|
||||||
|
m_ui->defaultsNoteLabel->setVisible(true);
|
||||||
|
m_ui->savePathEdit->blockSignals(true);
|
||||||
|
m_ui->savePathEdit->setSelectedPath(Path());
|
||||||
|
m_ui->downloadPathEdit->blockSignals(true);
|
||||||
|
m_ui->useDownloadPathComboBox->blockSignals(true);
|
||||||
|
m_ui->downloadPathEdit->setSelectedPath(Path());
|
||||||
|
|
||||||
|
const auto *btSession = BitTorrent::Session::instance();
|
||||||
|
const bool useAutoTMM = !btSession->isAutoTMMDisabledByDefault();
|
||||||
|
|
||||||
|
if (useAutoTMM)
|
||||||
|
{
|
||||||
|
loadCategorySavePathOptions();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_ui->useDownloadPathComboBox->setCurrentIndex(
|
||||||
|
m_ui->useDownloadPathComboBox->findData(btSession->isDownloadPathEnabled()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Overridden TMM settings
|
||||||
|
|
||||||
|
const bool useAutoTMM = m_addTorrentParams.useAutoTMM.value();
|
||||||
|
if (useAutoTMM)
|
||||||
|
{
|
||||||
|
m_ui->groupBoxSavePath->setEnabled(false);
|
||||||
|
m_ui->defaultsNoteLabel->setVisible(true);
|
||||||
|
m_ui->savePathEdit->blockSignals(true);
|
||||||
|
m_ui->savePathEdit->setSelectedPath(Path());
|
||||||
|
m_ui->downloadPathEdit->blockSignals(true);
|
||||||
|
m_ui->useDownloadPathComboBox->blockSignals(true);
|
||||||
|
m_ui->downloadPathEdit->setSelectedPath(Path());
|
||||||
|
|
||||||
|
loadCategorySavePathOptions();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loadCustomSavePathOptions();
|
||||||
|
|
||||||
|
m_ui->groupBoxSavePath->setEnabled(true);
|
||||||
|
m_ui->defaultsNoteLabel->setVisible(false);
|
||||||
|
m_ui->savePathEdit->blockSignals(false);
|
||||||
|
m_ui->useDownloadPathComboBox->blockSignals(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
populateDefaultPaths();
|
||||||
|
}
|
||||||
64
src/gui/addtorrentparamswidget.h
Normal file
64
src/gui/addtorrentparamswidget.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
|
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give permission to
|
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||||
|
* and distribute the linked executables. You must obey the GNU General Public
|
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||||
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
|
* exception statement from your version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "base/bittorrent/addtorrentparams.h"
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class AddTorrentParamsWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddTorrentParamsWidget final : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY_MOVE(AddTorrentParamsWidget)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit AddTorrentParamsWidget(BitTorrent::AddTorrentParams addTorrentParams = {}, QWidget *parent = nullptr);
|
||||||
|
~AddTorrentParamsWidget() override;
|
||||||
|
|
||||||
|
void setAddTorrentParams(BitTorrent::AddTorrentParams addTorrentParams);
|
||||||
|
BitTorrent::AddTorrentParams addTorrentParams() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void populate();
|
||||||
|
void loadCustomSavePathOptions();
|
||||||
|
void loadCustomDownloadPath();
|
||||||
|
void loadCategorySavePathOptions();
|
||||||
|
void populateDefaultPaths();
|
||||||
|
void populateDefaultDownloadPath();
|
||||||
|
void populateSavePathOptions();
|
||||||
|
|
||||||
|
|
||||||
|
Ui::AddTorrentParamsWidget *m_ui;
|
||||||
|
BitTorrent::AddTorrentParams m_addTorrentParams;
|
||||||
|
};
|
||||||
363
src/gui/addtorrentparamswidget.ui
Normal file
363
src/gui/addtorrentparamswidget.ui
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>AddTorrentParamsWidget</class>
|
||||||
|
<widget class="QWidget" name="AddTorrentParamsWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>503</width>
|
||||||
|
<height>366</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="mainLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="managementLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labelTorrentManagementMode">
|
||||||
|
<property name="text">
|
||||||
|
<string>Torrent Management Mode:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboTTM">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Automatic mode means that various torrent properties(eg save path) will be decided by the associated category</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBoxSavePath">
|
||||||
|
<property name="title">
|
||||||
|
<string>Save at</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="defaultsNoteLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<italic>true</italic>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Note: the current defaults are displayed for reference.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="FileSystemPathLineEdit" name="savePathEdit" native="true"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="downloadPathLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="useDownloadPathLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use another path for incomplete torrents:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="useDownloadPathComboBox"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="downloadPathSpacer">
|
||||||
|
<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="FileSystemPathLineEdit" name="downloadPathEdit" native="true"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="categoryLayout" stretch="0,2,1">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labelCategory">
|
||||||
|
<property name="text">
|
||||||
|
<string>Category:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="categoryComboBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="insertPolicy">
|
||||||
|
<enum>QComboBox::InsertAtTop</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="categorySpacer">
|
||||||
|
<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="tagsLayout" stretch="0,0,0">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="tagsLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Tags:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="tagsLineEdit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Click [...] button to add/remove tags.</string>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="tagsEditButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Add/remove tags</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="miscParamsWidget" native="true">
|
||||||
|
<widget class="QWidget" name="startTorrentWidget" native="true">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>9</x>
|
||||||
|
<y>65</y>
|
||||||
|
<width>143</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="startTorrentLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Start torrent:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="startTorrentComboBox">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="contentLayoutWidget" native="true">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>9</x>
|
||||||
|
<y>9</y>
|
||||||
|
<width>159</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="contentLayoutLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="contentLayoutLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Content layout:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="contentLayoutComboBox">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="stopConditionWidget" native="true">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>9</x>
|
||||||
|
<y>93</y>
|
||||||
|
<width>158</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="stopConditionLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="stopConditionLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Stop condition:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="stopConditionComboBox">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="addToQueueTopWidget" native="true">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>9</x>
|
||||||
|
<y>121</y>
|
||||||
|
<width>187</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="addToQueueTopLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="addToQueueTopLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add to top of queue:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="addToQueueTopComboBox">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QCheckBox" name="skipCheckingCheckBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>83</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Skip hash check</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>FileSystemPathLineEdit</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>gui/fspathedit.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include "flowlayout.h"
|
#include "flowlayout.h"
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "base/global.h"
|
#include "base/global.h"
|
||||||
@@ -142,6 +143,7 @@ int FlowLayout::doLayout(const QRect &rect, const bool testOnly) const
|
|||||||
int y = effectiveRect.y();
|
int y = effectiveRect.y();
|
||||||
int lineHeight = 0;
|
int lineHeight = 0;
|
||||||
|
|
||||||
|
QHash<QLayoutItem *, QPoint> lineItems;
|
||||||
for (QLayoutItem *item : asConst(m_itemList))
|
for (QLayoutItem *item : asConst(m_itemList))
|
||||||
{
|
{
|
||||||
const QWidget *wid = item->widget();
|
const QWidget *wid = item->widget();
|
||||||
@@ -163,6 +165,12 @@ int FlowLayout::doLayout(const QRect &rect, const bool testOnly) const
|
|||||||
int nextX = x + item->sizeHint().width() + spaceX;
|
int nextX = x + item->sizeHint().width() + spaceX;
|
||||||
if (((nextX - spaceX) > effectiveRect.right()) && (lineHeight > 0))
|
if (((nextX - spaceX) > effectiveRect.right()) && (lineHeight > 0))
|
||||||
{
|
{
|
||||||
|
if (!testOnly)
|
||||||
|
{
|
||||||
|
applyItemsGeometry(lineItems, lineHeight);
|
||||||
|
lineItems.clear();
|
||||||
|
}
|
||||||
|
|
||||||
x = effectiveRect.x();
|
x = effectiveRect.x();
|
||||||
y = y + lineHeight + spaceY;
|
y = y + lineHeight + spaceY;
|
||||||
nextX = x + item->sizeHint().width() + spaceX;
|
nextX = x + item->sizeHint().width() + spaceX;
|
||||||
@@ -170,12 +178,15 @@ int FlowLayout::doLayout(const QRect &rect, const bool testOnly) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!testOnly)
|
if (!testOnly)
|
||||||
item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
|
lineItems[item] = QPoint(x, y);
|
||||||
|
|
||||||
x = nextX;
|
x = nextX;
|
||||||
lineHeight = std::max(lineHeight, item->sizeHint().height());
|
lineHeight = std::max(lineHeight, item->sizeHint().height());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!testOnly)
|
||||||
|
applyItemsGeometry(lineItems, lineHeight);
|
||||||
|
|
||||||
return y + lineHeight - rect.y() + bottom;
|
return y + lineHeight - rect.y() + bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,3 +204,20 @@ int FlowLayout::smartSpacing(const QStyle::PixelMetric pm) const
|
|||||||
|
|
||||||
return static_cast<QLayout *>(parent)->spacing();
|
return static_cast<QLayout *>(parent)->spacing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FlowLayout::applyItemsGeometry(const QHash<QLayoutItem *, QPoint> &items, const int lineHeight) const
|
||||||
|
{
|
||||||
|
for (auto it = items.cbegin(); it != items.cend(); ++it)
|
||||||
|
{
|
||||||
|
QLayoutItem *item = it.key();
|
||||||
|
QPoint point = it.value();
|
||||||
|
|
||||||
|
const auto alignment = item->alignment();
|
||||||
|
const int vSpace = lineHeight - item->sizeHint().height();
|
||||||
|
if (alignment & Qt::AlignVCenter)
|
||||||
|
point.ry() += vSpace / 2;
|
||||||
|
else if (alignment & Qt::AlignBottom)
|
||||||
|
point.ry() += vSpace;
|
||||||
|
item->setGeometry(QRect(point, item->sizeHint()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
int doLayout(const QRect &rect, bool testOnly) const;
|
int doLayout(const QRect &rect, bool testOnly) const;
|
||||||
int smartSpacing(QStyle::PixelMetric pm) const;
|
int smartSpacing(QStyle::PixelMetric pm) const;
|
||||||
|
void applyItemsGeometry(const QHash<QLayoutItem *, QPoint> &items, int lineHeight) const;
|
||||||
|
|
||||||
QList<QLayoutItem *> m_itemList;
|
QList<QLayoutItem *> m_itemList;
|
||||||
int m_hSpace;
|
int m_hSpace;
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ void FileSystemPathEdit::FileSystemPathEditPrivate::modeChanged()
|
|||||||
{
|
{
|
||||||
m_editor->completeDirectoriesOnly((m_mode == FileSystemPathEdit::Mode::DirectoryOpen) || (m_mode == FileSystemPathEdit::Mode::DirectorySave));
|
m_editor->completeDirectoriesOnly((m_mode == FileSystemPathEdit::Mode::DirectoryOpen) || (m_mode == FileSystemPathEdit::Mode::DirectorySave));
|
||||||
|
|
||||||
m_validator->setExistingOnly(m_mode != FileSystemPathEdit::Mode::FileSave);
|
m_validator->setExistingOnly((m_mode == FileSystemPathEdit::Mode::FileOpen) || (m_mode == FileSystemPathEdit::Mode::DirectoryOpen));
|
||||||
m_validator->setDirectoriesOnly((m_mode == FileSystemPathEdit::Mode::DirectoryOpen) || (m_mode == FileSystemPathEdit::Mode::DirectorySave));
|
m_validator->setDirectoriesOnly((m_mode == FileSystemPathEdit::Mode::DirectoryOpen) || (m_mode == FileSystemPathEdit::Mode::DirectorySave));
|
||||||
m_validator->setCheckReadPermission((m_mode == FileSystemPathEdit::Mode::FileOpen) || (m_mode == FileSystemPathEdit::Mode::DirectoryOpen));
|
m_validator->setCheckReadPermission((m_mode == FileSystemPathEdit::Mode::FileOpen) || (m_mode == FileSystemPathEdit::Mode::DirectoryOpen));
|
||||||
m_validator->setCheckWritePermission((m_mode == FileSystemPathEdit::Mode::FileSave) || (m_mode == FileSystemPathEdit::Mode::DirectorySave));
|
m_validator->setCheckWritePermission((m_mode == FileSystemPathEdit::Mode::FileSave) || (m_mode == FileSystemPathEdit::Mode::DirectorySave));
|
||||||
|
|||||||
@@ -102,8 +102,8 @@ Private::FileSystemPathValidator::testPath(const Path &path) const
|
|||||||
// `QFileInfo` will cache the query results and avoid exessive querying to filesystem
|
// `QFileInfo` will cache the query results and avoid exessive querying to filesystem
|
||||||
const QFileInfo info {path.data()};
|
const QFileInfo info {path.data()};
|
||||||
|
|
||||||
if (existingOnly() && !info.exists())
|
if (!info.exists())
|
||||||
return TestResult::DoesNotExist;
|
return existingOnly() ? TestResult::DoesNotExist : TestResult::OK;
|
||||||
|
|
||||||
if (directoriesOnly())
|
if (directoriesOnly())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ INCLUDEPATH += $$PWD
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/aboutdialog.h \
|
$$PWD/aboutdialog.h \
|
||||||
$$PWD/addnewtorrentdialog.h \
|
$$PWD/addnewtorrentdialog.h \
|
||||||
|
$$PWD/addtorrentparamswidget.h \
|
||||||
$$PWD/advancedsettings.h \
|
$$PWD/advancedsettings.h \
|
||||||
$$PWD/autoexpandabledialog.h \
|
$$PWD/autoexpandabledialog.h \
|
||||||
$$PWD/banlistoptionsdialog.h \
|
$$PWD/banlistoptionsdialog.h \
|
||||||
@@ -97,6 +98,7 @@ HEADERS += \
|
|||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/aboutdialog.cpp \
|
$$PWD/aboutdialog.cpp \
|
||||||
$$PWD/addnewtorrentdialog.cpp \
|
$$PWD/addnewtorrentdialog.cpp \
|
||||||
|
$$PWD/addtorrentparamswidget.cpp \
|
||||||
$$PWD/advancedsettings.cpp \
|
$$PWD/advancedsettings.cpp \
|
||||||
$$PWD/autoexpandabledialog.cpp \
|
$$PWD/autoexpandabledialog.cpp \
|
||||||
$$PWD/banlistoptionsdialog.cpp \
|
$$PWD/banlistoptionsdialog.cpp \
|
||||||
@@ -187,6 +189,7 @@ SOURCES += \
|
|||||||
FORMS += \
|
FORMS += \
|
||||||
$$PWD/aboutdialog.ui \
|
$$PWD/aboutdialog.ui \
|
||||||
$$PWD/addnewtorrentdialog.ui \
|
$$PWD/addnewtorrentdialog.ui \
|
||||||
|
$$PWD/addtorrentparamswidget.ui \
|
||||||
$$PWD/autoexpandabledialog.ui \
|
$$PWD/autoexpandabledialog.ui \
|
||||||
$$PWD/banlistoptionsdialog.ui \
|
$$PWD/banlistoptionsdialog.ui \
|
||||||
$$PWD/cookiesdialog.ui \
|
$$PWD/cookiesdialog.ui \
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2017, 2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
@@ -50,6 +50,7 @@
|
|||||||
#include "base/utils/compare.h"
|
#include "base/utils/compare.h"
|
||||||
#include "base/utils/io.h"
|
#include "base/utils/io.h"
|
||||||
#include "base/utils/string.h"
|
#include "base/utils/string.h"
|
||||||
|
#include "gui/addtorrentparamswidget.h"
|
||||||
#include "gui/autoexpandabledialog.h"
|
#include "gui/autoexpandabledialog.h"
|
||||||
#include "gui/torrentcategorydialog.h"
|
#include "gui/torrentcategorydialog.h"
|
||||||
#include "gui/uithememanager.h"
|
#include "gui/uithememanager.h"
|
||||||
@@ -61,37 +62,44 @@ const QString EXT_LEGACY = u".rssrules"_qs;
|
|||||||
|
|
||||||
AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent)
|
AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, m_formatFilterJSON(u"%1 (*%2)"_qs.arg(tr("Rules"), EXT_JSON))
|
, m_formatFilterJSON {u"%1 (*%2)"_qs.arg(tr("Rules"), EXT_JSON)}
|
||||||
, m_formatFilterLegacy(u"%1 (*%2)"_qs.arg(tr("Rules (legacy)"), EXT_LEGACY))
|
, m_formatFilterLegacy {u"%1 (*%2)"_qs.arg(tr("Rules (legacy)"), EXT_LEGACY)}
|
||||||
, m_ui(new Ui::AutomatedRssDownloader)
|
, m_ui {new Ui::AutomatedRssDownloader}
|
||||||
|
, m_addTorrentParamsWidget {new AddTorrentParamsWidget}
|
||||||
, m_storeDialogSize {u"RssFeedDownloader/geometrySize"_qs}
|
, m_storeDialogSize {u"RssFeedDownloader/geometrySize"_qs}
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||||
, m_storeHSplitterSize {u"GUI/Qt6/RSSFeedDownloader/HSplitterSizes"_qs}
|
, m_storeMainSplitterState {u"GUI/Qt6/RSSFeedDownloader/HSplitterSizes"_qs}
|
||||||
|
, m_storeRuleDefSplitterState {u"GUI/Qt6/RSSFeedDownloader/RuleDefSplitterState"_qs}
|
||||||
#else
|
#else
|
||||||
, m_storeHSplitterSize {u"RssFeedDownloader/qt5/hsplitterSizes"_qs}
|
, m_storeMainSplitterState {u"RssFeedDownloader/qt5/hsplitterSizes"_qs}
|
||||||
|
, m_storeRuleDefSplitterState {u"RssFeedDownloader/qt5/RuleDefSplitterState"_qs}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
|
m_ui->torrentParametersGroupBox->layout()->addWidget(m_addTorrentParamsWidget);
|
||||||
|
|
||||||
|
connect(m_ui->addRuleBtn, &QPushButton::clicked, this, &AutomatedRssDownloader::onAddRuleBtnClicked);
|
||||||
|
connect(m_ui->removeRuleBtn, &QPushButton::clicked, this, &AutomatedRssDownloader::onRemoveRuleBtnClicked);
|
||||||
|
connect(m_ui->exportBtn, &QPushButton::clicked, this, &AutomatedRssDownloader::onExportBtnClicked);
|
||||||
|
connect(m_ui->importBtn, &QPushButton::clicked, this, &AutomatedRssDownloader::onImportBtnClicked);
|
||||||
|
connect(m_ui->renameRuleBtn, &QPushButton::clicked, this, &AutomatedRssDownloader::onRenameRuleBtnClicked);
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
m_ui->renameRuleBtn->setIcon(UIThemeManager::instance()->getIcon(u"edit-rename"_qs));
|
m_ui->renameRuleBtn->setIcon(UIThemeManager::instance()->getIcon(u"edit-rename"_qs));
|
||||||
m_ui->removeRuleBtn->setIcon(UIThemeManager::instance()->getIcon(u"edit-clear"_qs, u"list-remove"_qs));
|
m_ui->removeRuleBtn->setIcon(UIThemeManager::instance()->getIcon(u"edit-clear"_qs, u"list-remove"_qs));
|
||||||
m_ui->addRuleBtn->setIcon(UIThemeManager::instance()->getIcon(u"list-add"_qs));
|
m_ui->addRuleBtn->setIcon(UIThemeManager::instance()->getIcon(u"list-add"_qs));
|
||||||
m_ui->addCategoryBtn->setIcon(UIThemeManager::instance()->getIcon(u"list-add"_qs));
|
|
||||||
|
|
||||||
// Ui Settings
|
// Ui Settings
|
||||||
m_ui->listRules->setSortingEnabled(true);
|
m_ui->ruleList->setSortingEnabled(true);
|
||||||
m_ui->listRules->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
m_ui->ruleList->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
m_ui->treeMatchingArticles->setSortingEnabled(true);
|
m_ui->matchingArticlesTree->setSortingEnabled(true);
|
||||||
m_ui->treeMatchingArticles->sortByColumn(0, Qt::AscendingOrder);
|
m_ui->matchingArticlesTree->sortByColumn(0, Qt::AscendingOrder);
|
||||||
m_ui->hsplitter->setCollapsible(0, false);
|
m_ui->mainSplitter->setCollapsible(0, false);
|
||||||
m_ui->hsplitter->setCollapsible(1, false);
|
m_ui->mainSplitter->setCollapsible(1, false);
|
||||||
m_ui->hsplitter->setCollapsible(2, true); // Only the preview list is collapsible
|
m_ui->mainSplitter->setCollapsible(2, true); // Only the preview list is collapsible
|
||||||
m_ui->lineSavePath->setDialogCaption(tr("Destination directory"));
|
|
||||||
m_ui->lineSavePath->setMode(FileSystemPathEdit::Mode::DirectorySave);
|
|
||||||
|
|
||||||
connect(m_ui->checkRegex, &QAbstractButton::toggled, this, &AutomatedRssDownloader::updateFieldsToolTips);
|
connect(m_ui->checkRegex, &QAbstractButton::toggled, this, &AutomatedRssDownloader::updateFieldsToolTips);
|
||||||
connect(m_ui->listRules, &QWidget::customContextMenuRequested, this, &AutomatedRssDownloader::displayRulesListMenu);
|
connect(m_ui->ruleList, &QWidget::customContextMenuRequested, this, &AutomatedRssDownloader::displayRulesListMenu);
|
||||||
|
|
||||||
m_episodeRegex = new QRegularExpression(u"^(^\\d{1,4}x(\\d{1,4}(-(\\d{1,4})?)?;){1,}){1,1}"_qs
|
m_episodeRegex = new QRegularExpression(u"^(^\\d{1,4}x(\\d{1,4}(-(\\d{1,4})?)?;){1,}){1,1}"_qs
|
||||||
, QRegularExpression::CaseInsensitiveOption);
|
, QRegularExpression::CaseInsensitiveOption);
|
||||||
@@ -106,7 +114,6 @@ AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent)
|
|||||||
+ u"<li>" + tr("Infinite range: <b>1x25-;</b> matches episodes 25 and upward of season one, and all episodes of later seasons") + u"</li>" + u"</ul></li></ul>";
|
+ u"<li>" + tr("Infinite range: <b>1x25-;</b> matches episodes 25 and upward of season one, and all episodes of later seasons") + u"</li>" + u"</ul></li></ul>";
|
||||||
m_ui->lineEFilter->setToolTip(tip);
|
m_ui->lineEFilter->setToolTip(tip);
|
||||||
|
|
||||||
initCategoryCombobox();
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
connect(RSS::AutoDownloader::instance(), &RSS::AutoDownloader::ruleAdded, this, &AutomatedRssDownloader::handleRuleAdded);
|
connect(RSS::AutoDownloader::instance(), &RSS::AutoDownloader::ruleAdded, this, &AutomatedRssDownloader::handleRuleAdded);
|
||||||
@@ -130,27 +137,28 @@ AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent)
|
|||||||
|
|
||||||
connect(m_ui->listFeeds, &QListWidget::itemChanged, this, &AutomatedRssDownloader::handleFeedCheckStateChange);
|
connect(m_ui->listFeeds, &QListWidget::itemChanged, this, &AutomatedRssDownloader::handleFeedCheckStateChange);
|
||||||
|
|
||||||
connect(m_ui->listRules, &QListWidget::itemSelectionChanged, this, &AutomatedRssDownloader::updateRuleDefinitionBox);
|
connect(m_ui->ruleList, &QListWidget::itemSelectionChanged, this, &AutomatedRssDownloader::updateRuleDefinitionBox);
|
||||||
connect(m_ui->listRules, &QListWidget::itemChanged, this, &AutomatedRssDownloader::handleRuleCheckStateChange);
|
connect(m_ui->ruleList, &QListWidget::itemChanged, this, &AutomatedRssDownloader::handleRuleCheckStateChange);
|
||||||
|
|
||||||
const auto *editHotkey = new QShortcut(Qt::Key_F2, m_ui->listRules, nullptr, nullptr, Qt::WidgetShortcut);
|
const auto *editHotkey = new QShortcut(Qt::Key_F2, m_ui->ruleList, nullptr, nullptr, Qt::WidgetShortcut);
|
||||||
connect(editHotkey, &QShortcut::activated, this, &AutomatedRssDownloader::renameSelectedRule);
|
connect(editHotkey, &QShortcut::activated, this, &AutomatedRssDownloader::renameSelectedRule);
|
||||||
const auto *deleteHotkey = new QShortcut(QKeySequence::Delete, m_ui->listRules, nullptr, nullptr, Qt::WidgetShortcut);
|
const auto *deleteHotkey = new QShortcut(QKeySequence::Delete, m_ui->ruleList, nullptr, nullptr, Qt::WidgetShortcut);
|
||||||
connect(deleteHotkey, &QShortcut::activated, this, &AutomatedRssDownloader::on_removeRuleBtn_clicked);
|
connect(deleteHotkey, &QShortcut::activated, this, &AutomatedRssDownloader::onRemoveRuleBtnClicked);
|
||||||
|
|
||||||
connect(m_ui->listRules, &QAbstractItemView::doubleClicked, this, &AutomatedRssDownloader::renameSelectedRule);
|
connect(m_ui->ruleList, &QAbstractItemView::doubleClicked, this, &AutomatedRssDownloader::renameSelectedRule);
|
||||||
|
|
||||||
loadFeedList();
|
loadFeedList();
|
||||||
|
|
||||||
m_ui->listRules->blockSignals(true);
|
m_ui->ruleList->blockSignals(true);
|
||||||
for (const RSS::AutoDownloadRule &rule : asConst(RSS::AutoDownloader::instance()->rules()))
|
for (const RSS::AutoDownloadRule &rule : asConst(RSS::AutoDownloader::instance()->rules()))
|
||||||
createRuleItem(rule);
|
createRuleItem(rule);
|
||||||
m_ui->listRules->blockSignals(false);
|
m_ui->ruleList->blockSignals(false);
|
||||||
|
|
||||||
updateRuleDefinitionBox();
|
updateRuleDefinitionBox();
|
||||||
|
|
||||||
if (RSS::AutoDownloader::instance()->isProcessingEnabled())
|
if (RSS::AutoDownloader::instance()->isProcessingEnabled())
|
||||||
m_ui->labelWarn->hide();
|
m_ui->labelWarn->hide();
|
||||||
|
|
||||||
connect(RSS::AutoDownloader::instance(), &RSS::AutoDownloader::processingStateChanged
|
connect(RSS::AutoDownloader::instance(), &RSS::AutoDownloader::processingStateChanged
|
||||||
, this, &AutomatedRssDownloader::handleProcessingStateChanged);
|
, this, &AutomatedRssDownloader::handleProcessingStateChanged);
|
||||||
}
|
}
|
||||||
@@ -170,19 +178,23 @@ void AutomatedRssDownloader::loadSettings()
|
|||||||
if (const QSize dialogSize = m_storeDialogSize; dialogSize.isValid())
|
if (const QSize dialogSize = m_storeDialogSize; dialogSize.isValid())
|
||||||
resize(dialogSize);
|
resize(dialogSize);
|
||||||
|
|
||||||
if (const QByteArray hSplitterSize = m_storeHSplitterSize; !hSplitterSize.isEmpty())
|
if (const QByteArray mainSplitterSize = m_storeMainSplitterState; !mainSplitterSize.isEmpty())
|
||||||
m_ui->hsplitter->restoreState(hSplitterSize);
|
m_ui->mainSplitter->restoreState(mainSplitterSize);
|
||||||
|
|
||||||
|
if (const QByteArray ruleDefSplitterSize = m_storeRuleDefSplitterState; !ruleDefSplitterSize.isEmpty())
|
||||||
|
m_ui->ruleDefSplitter->restoreState(ruleDefSplitterSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutomatedRssDownloader::saveSettings()
|
void AutomatedRssDownloader::saveSettings()
|
||||||
{
|
{
|
||||||
m_storeDialogSize = size();
|
m_storeDialogSize = size();
|
||||||
m_storeHSplitterSize = m_ui->hsplitter->saveState();
|
m_storeMainSplitterState = m_ui->mainSplitter->saveState();
|
||||||
|
m_storeRuleDefSplitterState = m_ui->ruleDefSplitter->saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutomatedRssDownloader::createRuleItem(const RSS::AutoDownloadRule &rule)
|
void AutomatedRssDownloader::createRuleItem(const RSS::AutoDownloadRule &rule)
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = new QListWidgetItem(rule.name(), m_ui->listRules);
|
QListWidgetItem *item = new QListWidgetItem(rule.name(), m_ui->ruleList);
|
||||||
m_itemsByRuleName.insert(rule.name(), item);
|
m_itemsByRuleName.insert(rule.name(), item);
|
||||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
item->setCheckState(rule.isEnabled() ? Qt::Checked : Qt::Unchecked);
|
item->setCheckState(rule.isEnabled() ? Qt::Checked : Qt::Unchecked);
|
||||||
@@ -211,7 +223,7 @@ void AutomatedRssDownloader::updateFeedList()
|
|||||||
if (m_currentRuleItem)
|
if (m_currentRuleItem)
|
||||||
selection << m_currentRuleItem;
|
selection << m_currentRuleItem;
|
||||||
else
|
else
|
||||||
selection = m_ui->listRules->selectedItems();
|
selection = m_ui->ruleList->selectedItems();
|
||||||
|
|
||||||
bool enable = !selection.isEmpty();
|
bool enable = !selection.isEmpty();
|
||||||
|
|
||||||
@@ -248,7 +260,7 @@ void AutomatedRssDownloader::updateFeedList()
|
|||||||
|
|
||||||
void AutomatedRssDownloader::updateRuleDefinitionBox()
|
void AutomatedRssDownloader::updateRuleDefinitionBox()
|
||||||
{
|
{
|
||||||
const QList<QListWidgetItem *> selection = m_ui->listRules->selectedItems();
|
const QList<QListWidgetItem *> selection = m_ui->ruleList->selectedItems();
|
||||||
QListWidgetItem *currentRuleItem = ((selection.count() == 1) ? selection.first() : nullptr);
|
QListWidgetItem *currentRuleItem = ((selection.count() == 1) ? selection.first() : nullptr);
|
||||||
|
|
||||||
// Enable the edit rule button but only if we have 1 rule selected
|
// Enable the edit rule button but only if we have 1 rule selected
|
||||||
@@ -261,7 +273,7 @@ void AutomatedRssDownloader::updateRuleDefinitionBox()
|
|||||||
{
|
{
|
||||||
saveEditedRule(); // Save previous rule first
|
saveEditedRule(); // Save previous rule first
|
||||||
m_currentRuleItem = currentRuleItem;
|
m_currentRuleItem = currentRuleItem;
|
||||||
//m_ui->listRules->setCurrentItem(m_currentRuleItem);
|
//m_ui->ruleList->setCurrentItem(m_currentRuleItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update rule definition box
|
// Update rule definition box
|
||||||
@@ -269,31 +281,20 @@ void AutomatedRssDownloader::updateRuleDefinitionBox()
|
|||||||
{
|
{
|
||||||
m_currentRule = RSS::AutoDownloader::instance()->ruleByName(m_currentRuleItem->text());
|
m_currentRule = RSS::AutoDownloader::instance()->ruleByName(m_currentRuleItem->text());
|
||||||
|
|
||||||
|
m_addTorrentParamsWidget->setAddTorrentParams(m_currentRule.addTorrentParams());
|
||||||
|
|
||||||
m_ui->lineContains->setText(m_currentRule.mustContain());
|
m_ui->lineContains->setText(m_currentRule.mustContain());
|
||||||
m_ui->lineNotContains->setText(m_currentRule.mustNotContain());
|
m_ui->lineNotContains->setText(m_currentRule.mustNotContain());
|
||||||
if (!m_currentRule.episodeFilter().isEmpty())
|
if (!m_currentRule.episodeFilter().isEmpty())
|
||||||
m_ui->lineEFilter->setText(m_currentRule.episodeFilter());
|
m_ui->lineEFilter->setText(m_currentRule.episodeFilter());
|
||||||
else
|
else
|
||||||
m_ui->lineEFilter->clear();
|
m_ui->lineEFilter->clear();
|
||||||
m_ui->checkBoxSaveDiffDir->setChecked(!m_currentRule.savePath().isEmpty());
|
|
||||||
m_ui->lineSavePath->setSelectedPath(m_currentRule.savePath());
|
|
||||||
m_ui->checkRegex->blockSignals(true);
|
m_ui->checkRegex->blockSignals(true);
|
||||||
m_ui->checkRegex->setChecked(m_currentRule.useRegex());
|
m_ui->checkRegex->setChecked(m_currentRule.useRegex());
|
||||||
m_ui->checkRegex->blockSignals(false);
|
m_ui->checkRegex->blockSignals(false);
|
||||||
m_ui->checkSmart->blockSignals(true);
|
m_ui->checkSmart->blockSignals(true);
|
||||||
m_ui->checkSmart->setChecked(m_currentRule.useSmartFilter());
|
m_ui->checkSmart->setChecked(m_currentRule.useSmartFilter());
|
||||||
m_ui->checkSmart->blockSignals(false);
|
m_ui->checkSmart->blockSignals(false);
|
||||||
m_ui->comboCategory->setCurrentIndex(m_ui->comboCategory->findText(m_currentRule.assignedCategory()));
|
|
||||||
if (m_currentRule.assignedCategory().isEmpty())
|
|
||||||
m_ui->comboCategory->clearEditText();
|
|
||||||
int index = 0;
|
|
||||||
if (m_currentRule.addPaused().has_value())
|
|
||||||
index = (*m_currentRule.addPaused() ? 1 : 2);
|
|
||||||
m_ui->comboAddPaused->setCurrentIndex(index);
|
|
||||||
index = 0;
|
|
||||||
if (m_currentRule.torrentContentLayout())
|
|
||||||
index = static_cast<int>(*m_currentRule.torrentContentLayout()) + 1;
|
|
||||||
m_ui->comboContentLayout->setCurrentIndex(index);
|
|
||||||
m_ui->spinIgnorePeriod->setValue(m_currentRule.ignoreDays());
|
m_ui->spinIgnorePeriod->setValue(m_currentRule.ignoreDays());
|
||||||
QDateTime dateTime = m_currentRule.lastMatch();
|
QDateTime dateTime = m_currentRule.lastMatch();
|
||||||
QString lMatch;
|
QString lMatch;
|
||||||
@@ -307,13 +308,13 @@ void AutomatedRssDownloader::updateRuleDefinitionBox()
|
|||||||
updateEpisodeFilterValidity();
|
updateEpisodeFilterValidity();
|
||||||
|
|
||||||
updateFieldsToolTips(m_ui->checkRegex->isChecked());
|
updateFieldsToolTips(m_ui->checkRegex->isChecked());
|
||||||
m_ui->ruleDefBox->setEnabled(true);
|
m_ui->ruleScrollArea->setEnabled(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_currentRule = RSS::AutoDownloadRule();
|
m_currentRule = RSS::AutoDownloadRule();
|
||||||
clearRuleDefinitionBox();
|
clearRuleDefinitionBox();
|
||||||
m_ui->ruleDefBox->setEnabled(false);
|
m_ui->ruleScrollArea->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFeedList();
|
updateFeedList();
|
||||||
@@ -322,38 +323,23 @@ void AutomatedRssDownloader::updateRuleDefinitionBox()
|
|||||||
|
|
||||||
void AutomatedRssDownloader::clearRuleDefinitionBox()
|
void AutomatedRssDownloader::clearRuleDefinitionBox()
|
||||||
{
|
{
|
||||||
|
m_addTorrentParamsWidget->setAddTorrentParams({});
|
||||||
m_ui->lineContains->clear();
|
m_ui->lineContains->clear();
|
||||||
m_ui->lineNotContains->clear();
|
m_ui->lineNotContains->clear();
|
||||||
m_ui->lineEFilter->clear();
|
m_ui->lineEFilter->clear();
|
||||||
m_ui->checkBoxSaveDiffDir->setChecked(false);
|
|
||||||
m_ui->lineSavePath->clear();
|
|
||||||
m_ui->comboCategory->clearEditText();
|
|
||||||
m_ui->comboCategory->setCurrentIndex(-1);
|
|
||||||
m_ui->checkRegex->setChecked(false);
|
m_ui->checkRegex->setChecked(false);
|
||||||
m_ui->checkSmart->setChecked(false);
|
m_ui->checkSmart->setChecked(false);
|
||||||
m_ui->spinIgnorePeriod->setValue(0);
|
m_ui->spinIgnorePeriod->setValue(0);
|
||||||
m_ui->comboAddPaused->clearEditText();
|
|
||||||
m_ui->comboAddPaused->setCurrentIndex(-1);
|
|
||||||
m_ui->comboContentLayout->clearEditText();
|
|
||||||
m_ui->comboContentLayout->setCurrentIndex(-1);
|
|
||||||
updateFieldsToolTips(m_ui->checkRegex->isChecked());
|
updateFieldsToolTips(m_ui->checkRegex->isChecked());
|
||||||
updateMustLineValidity();
|
updateMustLineValidity();
|
||||||
updateMustNotLineValidity();
|
updateMustNotLineValidity();
|
||||||
updateEpisodeFilterValidity();
|
updateEpisodeFilterValidity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutomatedRssDownloader::initCategoryCombobox()
|
|
||||||
{
|
|
||||||
// Load torrent categories
|
|
||||||
QStringList categories = BitTorrent::Session::instance()->categories();
|
|
||||||
std::sort(categories.begin(), categories.end(), Utils::Compare::NaturalLessThan<Qt::CaseInsensitive>());
|
|
||||||
m_ui->comboCategory->addItem(u""_qs);
|
|
||||||
m_ui->comboCategory->addItems(categories);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutomatedRssDownloader::updateEditedRule()
|
void AutomatedRssDownloader::updateEditedRule()
|
||||||
{
|
{
|
||||||
if (!m_currentRuleItem || !m_ui->ruleDefBox->isEnabled()) return;
|
if (!m_currentRuleItem || !m_ui->ruleScrollArea->isEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
m_currentRule.setEnabled(m_currentRuleItem->checkState() != Qt::Unchecked);
|
m_currentRule.setEnabled(m_currentRuleItem->checkState() != Qt::Unchecked);
|
||||||
m_currentRule.setUseRegex(m_ui->checkRegex->isChecked());
|
m_currentRule.setUseRegex(m_ui->checkRegex->isChecked());
|
||||||
@@ -361,32 +347,20 @@ void AutomatedRssDownloader::updateEditedRule()
|
|||||||
m_currentRule.setMustContain(m_ui->lineContains->text());
|
m_currentRule.setMustContain(m_ui->lineContains->text());
|
||||||
m_currentRule.setMustNotContain(m_ui->lineNotContains->text());
|
m_currentRule.setMustNotContain(m_ui->lineNotContains->text());
|
||||||
m_currentRule.setEpisodeFilter(m_ui->lineEFilter->text());
|
m_currentRule.setEpisodeFilter(m_ui->lineEFilter->text());
|
||||||
m_currentRule.setSavePath(m_ui->checkBoxSaveDiffDir->isChecked() ? m_ui->lineSavePath->selectedPath() : Path());
|
|
||||||
m_currentRule.setCategory(m_ui->comboCategory->currentText());
|
|
||||||
std::optional<bool> addPaused;
|
|
||||||
if (m_ui->comboAddPaused->currentIndex() == 1)
|
|
||||||
addPaused = true;
|
|
||||||
else if (m_ui->comboAddPaused->currentIndex() == 2)
|
|
||||||
addPaused = false;
|
|
||||||
m_currentRule.setAddPaused(addPaused);
|
|
||||||
|
|
||||||
std::optional<BitTorrent::TorrentContentLayout> contentLayout;
|
|
||||||
if (m_ui->comboContentLayout->currentIndex() > 0)
|
|
||||||
contentLayout = static_cast<BitTorrent::TorrentContentLayout>(m_ui->comboContentLayout->currentIndex() - 1);
|
|
||||||
m_currentRule.setTorrentContentLayout(contentLayout);
|
|
||||||
|
|
||||||
m_currentRule.setIgnoreDays(m_ui->spinIgnorePeriod->value());
|
m_currentRule.setIgnoreDays(m_ui->spinIgnorePeriod->value());
|
||||||
|
|
||||||
|
m_currentRule.setAddTorrentParams(m_addTorrentParamsWidget->addTorrentParams());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutomatedRssDownloader::saveEditedRule()
|
void AutomatedRssDownloader::saveEditedRule()
|
||||||
{
|
{
|
||||||
if (!m_currentRuleItem || !m_ui->ruleDefBox->isEnabled()) return;
|
if (!m_currentRuleItem || !m_ui->ruleScrollArea->isEnabled()) return;
|
||||||
|
|
||||||
updateEditedRule();
|
updateEditedRule();
|
||||||
RSS::AutoDownloader::instance()->insertRule(m_currentRule);
|
RSS::AutoDownloader::instance()->insertRule(m_currentRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutomatedRssDownloader::on_addRuleBtn_clicked()
|
void AutomatedRssDownloader::onAddRuleBtnClicked()
|
||||||
{
|
{
|
||||||
// saveEditedRule();
|
// saveEditedRule();
|
||||||
|
|
||||||
@@ -406,9 +380,9 @@ void AutomatedRssDownloader::on_addRuleBtn_clicked()
|
|||||||
RSS::AutoDownloader::instance()->insertRule(RSS::AutoDownloadRule(ruleName));
|
RSS::AutoDownloader::instance()->insertRule(RSS::AutoDownloadRule(ruleName));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutomatedRssDownloader::on_removeRuleBtn_clicked()
|
void AutomatedRssDownloader::onRemoveRuleBtnClicked()
|
||||||
{
|
{
|
||||||
const QList<QListWidgetItem *> selection = m_ui->listRules->selectedItems();
|
const QList<QListWidgetItem *> selection = m_ui->ruleList->selectedItems();
|
||||||
if (selection.isEmpty()) return;
|
if (selection.isEmpty()) return;
|
||||||
|
|
||||||
// Ask for confirmation
|
// Ask for confirmation
|
||||||
@@ -423,23 +397,12 @@ void AutomatedRssDownloader::on_removeRuleBtn_clicked()
|
|||||||
RSS::AutoDownloader::instance()->removeRule(item->text());
|
RSS::AutoDownloader::instance()->removeRule(item->text());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutomatedRssDownloader::on_addCategoryBtn_clicked()
|
void AutomatedRssDownloader::onRenameRuleBtnClicked()
|
||||||
{
|
|
||||||
const QString newCategoryName = TorrentCategoryDialog::createCategory(this);
|
|
||||||
|
|
||||||
if (!newCategoryName.isEmpty())
|
|
||||||
{
|
|
||||||
m_ui->comboCategory->addItem(newCategoryName);
|
|
||||||
m_ui->comboCategory->setCurrentText(newCategoryName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutomatedRssDownloader::on_renameRuleBtn_clicked()
|
|
||||||
{
|
{
|
||||||
renameSelectedRule();
|
renameSelectedRule();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutomatedRssDownloader::on_exportBtn_clicked()
|
void AutomatedRssDownloader::onExportBtnClicked()
|
||||||
{
|
{
|
||||||
if (RSS::AutoDownloader::instance()->rules().isEmpty())
|
if (RSS::AutoDownloader::instance()->rules().isEmpty())
|
||||||
{
|
{
|
||||||
@@ -482,7 +445,7 @@ void AutomatedRssDownloader::on_exportBtn_clicked()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutomatedRssDownloader::on_importBtn_clicked()
|
void AutomatedRssDownloader::onImportBtnClicked()
|
||||||
{
|
{
|
||||||
QString selectedFilter {m_formatFilterJSON};
|
QString selectedFilter {m_formatFilterJSON};
|
||||||
const Path path {QFileDialog::getOpenFileName(
|
const Path path {QFileDialog::getOpenFileName(
|
||||||
@@ -525,16 +488,16 @@ void AutomatedRssDownloader::displayRulesListMenu()
|
|||||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
menu->addAction(UIThemeManager::instance()->getIcon(u"list-add"_qs), tr("Add new rule...")
|
menu->addAction(UIThemeManager::instance()->getIcon(u"list-add"_qs), tr("Add new rule...")
|
||||||
, this, &AutomatedRssDownloader::on_addRuleBtn_clicked);
|
, this, &AutomatedRssDownloader::onAddRuleBtnClicked);
|
||||||
|
|
||||||
const QList<QListWidgetItem *> selection = m_ui->listRules->selectedItems();
|
const QList<QListWidgetItem *> selection = m_ui->ruleList->selectedItems();
|
||||||
|
|
||||||
if (!selection.isEmpty())
|
if (!selection.isEmpty())
|
||||||
{
|
{
|
||||||
if (selection.count() == 1)
|
if (selection.count() == 1)
|
||||||
{
|
{
|
||||||
menu->addAction(UIThemeManager::instance()->getIcon(u"edit-clear"_qs, u"list-remove"_qs), tr("Delete rule")
|
menu->addAction(UIThemeManager::instance()->getIcon(u"edit-clear"_qs, u"list-remove"_qs), tr("Delete rule")
|
||||||
, this, &AutomatedRssDownloader::on_removeRuleBtn_clicked);
|
, this, &AutomatedRssDownloader::onRemoveRuleBtnClicked);
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
menu->addAction(UIThemeManager::instance()->getIcon(u"edit-rename"_qs), tr("Rename rule...")
|
menu->addAction(UIThemeManager::instance()->getIcon(u"edit-rename"_qs), tr("Rename rule...")
|
||||||
, this, &AutomatedRssDownloader::renameSelectedRule);
|
, this, &AutomatedRssDownloader::renameSelectedRule);
|
||||||
@@ -542,7 +505,7 @@ void AutomatedRssDownloader::displayRulesListMenu()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
menu->addAction(UIThemeManager::instance()->getIcon(u"edit-clear"_qs, u"list-remove"_qs), tr("Delete selected rules")
|
menu->addAction(UIThemeManager::instance()->getIcon(u"edit-clear"_qs, u"list-remove"_qs), tr("Delete selected rules")
|
||||||
, this, &AutomatedRssDownloader::on_removeRuleBtn_clicked);
|
, this, &AutomatedRssDownloader::onRemoveRuleBtnClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
@@ -555,7 +518,7 @@ void AutomatedRssDownloader::displayRulesListMenu()
|
|||||||
|
|
||||||
void AutomatedRssDownloader::renameSelectedRule()
|
void AutomatedRssDownloader::renameSelectedRule()
|
||||||
{
|
{
|
||||||
const QList<QListWidgetItem *> selection = m_ui->listRules->selectedItems();
|
const QList<QListWidgetItem *> selection = m_ui->ruleList->selectedItems();
|
||||||
if (selection.isEmpty()) return;
|
if (selection.isEmpty()) return;
|
||||||
|
|
||||||
QListWidgetItem *item = selection.first();
|
QListWidgetItem *item = selection.first();
|
||||||
@@ -583,7 +546,7 @@ void AutomatedRssDownloader::renameSelectedRule()
|
|||||||
|
|
||||||
void AutomatedRssDownloader::handleRuleCheckStateChange(QListWidgetItem *ruleItem)
|
void AutomatedRssDownloader::handleRuleCheckStateChange(QListWidgetItem *ruleItem)
|
||||||
{
|
{
|
||||||
m_ui->listRules->setCurrentItem(ruleItem);
|
m_ui->ruleList->setCurrentItem(ruleItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutomatedRssDownloader::clearSelectedRuleDownloadedEpisodeList()
|
void AutomatedRssDownloader::clearSelectedRuleDownloadedEpisodeList()
|
||||||
@@ -604,7 +567,7 @@ void AutomatedRssDownloader::clearSelectedRuleDownloadedEpisodeList()
|
|||||||
void AutomatedRssDownloader::handleFeedCheckStateChange(QListWidgetItem *feedItem)
|
void AutomatedRssDownloader::handleFeedCheckStateChange(QListWidgetItem *feedItem)
|
||||||
{
|
{
|
||||||
const QString feedURL = feedItem->data(Qt::UserRole).toString();
|
const QString feedURL = feedItem->data(Qt::UserRole).toString();
|
||||||
for (QListWidgetItem *ruleItem : asConst(m_ui->listRules->selectedItems()))
|
for (QListWidgetItem *ruleItem : asConst(m_ui->ruleList->selectedItems()))
|
||||||
{
|
{
|
||||||
RSS::AutoDownloadRule rule = (ruleItem == m_currentRuleItem
|
RSS::AutoDownloadRule rule = (ruleItem == m_currentRuleItem
|
||||||
? m_currentRule
|
? m_currentRule
|
||||||
@@ -627,9 +590,9 @@ void AutomatedRssDownloader::handleFeedCheckStateChange(QListWidgetItem *feedIte
|
|||||||
|
|
||||||
void AutomatedRssDownloader::updateMatchingArticles()
|
void AutomatedRssDownloader::updateMatchingArticles()
|
||||||
{
|
{
|
||||||
m_ui->treeMatchingArticles->clear();
|
m_ui->matchingArticlesTree->clear();
|
||||||
|
|
||||||
for (const QListWidgetItem *ruleItem : asConst(m_ui->listRules->selectedItems()))
|
for (const QListWidgetItem *ruleItem : asConst(m_ui->ruleList->selectedItems()))
|
||||||
{
|
{
|
||||||
RSS::AutoDownloadRule rule = (ruleItem == m_currentRuleItem
|
RSS::AutoDownloadRule rule = (ruleItem == m_currentRuleItem
|
||||||
? m_currentRule
|
? m_currentRule
|
||||||
@@ -654,13 +617,13 @@ void AutomatedRssDownloader::updateMatchingArticles()
|
|||||||
void AutomatedRssDownloader::addFeedArticlesToTree(RSS::Feed *feed, const QStringList &articles)
|
void AutomatedRssDownloader::addFeedArticlesToTree(RSS::Feed *feed, const QStringList &articles)
|
||||||
{
|
{
|
||||||
// Turn off sorting while inserting
|
// Turn off sorting while inserting
|
||||||
m_ui->treeMatchingArticles->setSortingEnabled(false);
|
m_ui->matchingArticlesTree->setSortingEnabled(false);
|
||||||
|
|
||||||
// Check if this feed is already in the tree
|
// Check if this feed is already in the tree
|
||||||
QTreeWidgetItem *treeFeedItem = nullptr;
|
QTreeWidgetItem *treeFeedItem = nullptr;
|
||||||
for (int i = 0; i < m_ui->treeMatchingArticles->topLevelItemCount(); ++i)
|
for (int i = 0; i < m_ui->matchingArticlesTree->topLevelItemCount(); ++i)
|
||||||
{
|
{
|
||||||
QTreeWidgetItem *item = m_ui->treeMatchingArticles->topLevelItem(i);
|
QTreeWidgetItem *item = m_ui->matchingArticlesTree->topLevelItem(i);
|
||||||
if (item->data(0, Qt::UserRole).toString() == feed->url())
|
if (item->data(0, Qt::UserRole).toString() == feed->url())
|
||||||
{
|
{
|
||||||
treeFeedItem = item;
|
treeFeedItem = item;
|
||||||
@@ -678,7 +641,7 @@ void AutomatedRssDownloader::addFeedArticlesToTree(RSS::Feed *feed, const QStrin
|
|||||||
treeFeedItem->setFont(0, f);
|
treeFeedItem->setFont(0, f);
|
||||||
treeFeedItem->setData(0, Qt::DecorationRole, UIThemeManager::instance()->getIcon(u"directory"_qs));
|
treeFeedItem->setData(0, Qt::DecorationRole, UIThemeManager::instance()->getIcon(u"directory"_qs));
|
||||||
treeFeedItem->setData(0, Qt::UserRole, feed->url());
|
treeFeedItem->setData(0, Qt::UserRole, feed->url());
|
||||||
m_ui->treeMatchingArticles->addTopLevelItem(treeFeedItem);
|
m_ui->matchingArticlesTree->addTopLevelItem(treeFeedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the articles
|
// Insert the articles
|
||||||
@@ -695,9 +658,9 @@ void AutomatedRssDownloader::addFeedArticlesToTree(RSS::Feed *feed, const QStrin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ui->treeMatchingArticles->expandItem(treeFeedItem);
|
m_ui->matchingArticlesTree->expandItem(treeFeedItem);
|
||||||
m_ui->treeMatchingArticles->sortItems(0, Qt::AscendingOrder);
|
m_ui->matchingArticlesTree->sortItems(0, Qt::AscendingOrder);
|
||||||
m_ui->treeMatchingArticles->setSortingEnabled(true);
|
m_ui->matchingArticlesTree->setSortingEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutomatedRssDownloader::updateFieldsToolTips(bool regex)
|
void AutomatedRssDownloader::updateFieldsToolTips(bool regex)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2017, 2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
@@ -51,6 +51,8 @@ namespace Ui
|
|||||||
class AutomatedRssDownloader;
|
class AutomatedRssDownloader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddTorrentParamsWidget;
|
||||||
|
|
||||||
class AutomatedRssDownloader : public QDialog
|
class AutomatedRssDownloader : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -61,13 +63,11 @@ public:
|
|||||||
~AutomatedRssDownloader() override;
|
~AutomatedRssDownloader() override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_addRuleBtn_clicked();
|
void onAddRuleBtnClicked();
|
||||||
void on_removeRuleBtn_clicked();
|
void onRemoveRuleBtnClicked();
|
||||||
void on_addCategoryBtn_clicked();
|
void onExportBtnClicked();
|
||||||
void on_exportBtn_clicked();
|
void onImportBtnClicked();
|
||||||
void on_importBtn_clicked();
|
void onRenameRuleBtnClicked();
|
||||||
void on_renameRuleBtn_clicked();
|
|
||||||
|
|
||||||
void handleRuleCheckStateChange(QListWidgetItem *ruleItem);
|
void handleRuleCheckStateChange(QListWidgetItem *ruleItem);
|
||||||
void handleFeedCheckStateChange(QListWidgetItem *feedItem);
|
void handleFeedCheckStateChange(QListWidgetItem *feedItem);
|
||||||
void displayRulesListMenu();
|
void displayRulesListMenu();
|
||||||
@@ -90,7 +90,6 @@ private:
|
|||||||
void loadSettings();
|
void loadSettings();
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
void createRuleItem(const RSS::AutoDownloadRule &rule);
|
void createRuleItem(const RSS::AutoDownloadRule &rule);
|
||||||
void initCategoryCombobox();
|
|
||||||
void clearRuleDefinitionBox();
|
void clearRuleDefinitionBox();
|
||||||
void updateEditedRule();
|
void updateEditedRule();
|
||||||
void updateMatchingArticles();
|
void updateMatchingArticles();
|
||||||
@@ -103,6 +102,7 @@ private:
|
|||||||
const QString m_formatFilterLegacy;
|
const QString m_formatFilterLegacy;
|
||||||
|
|
||||||
Ui::AutomatedRssDownloader *m_ui = nullptr;
|
Ui::AutomatedRssDownloader *m_ui = nullptr;
|
||||||
|
AddTorrentParamsWidget *m_addTorrentParamsWidget = nullptr;
|
||||||
QListWidgetItem *m_currentRuleItem = nullptr;
|
QListWidgetItem *m_currentRuleItem = nullptr;
|
||||||
QSet<std::pair<QString, QString>> m_treeListEntries;
|
QSet<std::pair<QString, QString>> m_treeListEntries;
|
||||||
RSS::AutoDownloadRule m_currentRule;
|
RSS::AutoDownloadRule m_currentRule;
|
||||||
@@ -110,5 +110,6 @@ private:
|
|||||||
QRegularExpression *m_episodeRegex = nullptr;
|
QRegularExpression *m_episodeRegex = nullptr;
|
||||||
|
|
||||||
SettingValue<QSize> m_storeDialogSize;
|
SettingValue<QSize> m_storeDialogSize;
|
||||||
SettingValue<QByteArray> m_storeHSplitterSize;
|
SettingValue<QByteArray> m_storeMainSplitterState;
|
||||||
|
SettingValue<QByteArray> m_storeRuleDefSplitterState;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,13 +7,13 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>818</width>
|
<width>818</width>
|
||||||
<height>571</height>
|
<height>588</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>RSS Downloader</string>
|
<string>RSS Downloader</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="labelWarn">
|
<widget class="QLabel" name="labelWarn">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QSplitter" name="hsplitter">
|
<widget class="QSplitter" name="mainSplitter">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
@@ -43,15 +43,14 @@
|
|||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="layoutWidget">
|
<widget class="QWidget" name="ruleListLayoutWidget">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="ruleListLayout">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="ruleListHeaderLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="ruleListLabel">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
<bold>true</bold>
|
||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
@@ -99,7 +98,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QListWidget" name="listRules">
|
<widget class="QListWidget" name="ruleList">
|
||||||
<property name="contextMenuPolicy">
|
<property name="contextMenuPolicy">
|
||||||
<enum>Qt::CustomContextMenu</enum>
|
<enum>Qt::CustomContextMenu</enum>
|
||||||
</property>
|
</property>
|
||||||
@@ -107,313 +106,240 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="layoutWidget1">
|
<widget class="QSplitter" name="ruleDefSplitter">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
<property name="orientation">
|
||||||
<item>
|
<enum>Qt::Vertical</enum>
|
||||||
<widget class="QGroupBox" name="ruleDefBox">
|
</property>
|
||||||
<property name="title">
|
<widget class="QScrollArea" name="ruleScrollArea">
|
||||||
<string>Rule Definition</string>
|
<property name="sizePolicy">
|
||||||
</property>
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
<horstretch>0</horstretch>
|
||||||
<item>
|
<verstretch>0</verstretch>
|
||||||
<widget class="QCheckBox" name="checkRegex">
|
</sizepolicy>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>Use Regular Expressions</string>
|
<property name="verticalScrollBarPolicy">
|
||||||
</property>
|
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||||
</widget>
|
</property>
|
||||||
</item>
|
<property name="horizontalScrollBarPolicy">
|
||||||
<item>
|
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
</property>
|
||||||
<item row="0" column="0">
|
<property name="sizeAdjustPolicy">
|
||||||
<widget class="QLabel" name="label_4">
|
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>Must Contain:</string>
|
<property name="widgetResizable">
|
||||||
</property>
|
<bool>true</bool>
|
||||||
</widget>
|
</property>
|
||||||
</item>
|
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||||
<item row="1" column="0">
|
<property name="geometry">
|
||||||
<widget class="QLabel" name="label_5">
|
<rect>
|
||||||
<property name="text">
|
<x>0</x>
|
||||||
<string>Must Not Contain:</string>
|
<y>0</y>
|
||||||
</property>
|
<width>329</width>
|
||||||
</widget>
|
<height>243</height>
|
||||||
</item>
|
</rect>
|
||||||
<item row="2" column="0">
|
</property>
|
||||||
<widget class="QLabel" name="lblEFilter">
|
<layout class="QVBoxLayout" name="verticalLayout_8" stretch="0,0,0,0,0,0,1">
|
||||||
<property name="text">
|
|
||||||
<string>Episode Filter:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="2">
|
|
||||||
<widget class="QLabel" name="lblEFilterStat">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>18</width>
|
|
||||||
<height>18</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="2">
|
|
||||||
<widget class="QLabel" name="labelMustNotStat">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>18</width>
|
|
||||||
<height>18</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLineEdit" name="lineContains"/>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="2">
|
|
||||||
<widget class="QLabel" name="labelMustStat">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>18</width>
|
|
||||||
<height>18</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="2">
|
|
||||||
<widget class="QLabel" name="labelEpFilterStat">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>18</width>
|
|
||||||
<height>18</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLineEdit" name="lineNotContains"/>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QLineEdit" name="lineEFilter"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="checkSmart">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Smart Episode Filter will check the episode number to prevent downloading of duplicates.
|
|
||||||
Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also support - as a separator)</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Use Smart Episode Filter</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="Line" name="line">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_7">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Category:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="comboCategory">
|
|
||||||
<property name="editable">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="addCategoryBtn"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="checkBoxSaveDiffDir">
|
|
||||||
<property name="text">
|
|
||||||
<string>Save to a Different Directory</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_6">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Save to:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="FileSystemPathLineEdit" name="lineSavePath" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="lblIgnoreDays">
|
|
||||||
<property name="text">
|
|
||||||
<string extracomment="... X days">Ignore Subsequent Matches for (0 to Disable)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QSpinBox" name="spinIgnorePeriod">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="specialValueText">
|
|
||||||
<string>Disabled</string>
|
|
||||||
</property>
|
|
||||||
<property name="suffix">
|
|
||||||
<string> days</string>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<number>365</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="lblLastMatch">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="lblAddPaused">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Add Paused:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="comboAddPaused">
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Use global settings</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Always</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Never</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="lblContentLayout">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Torrent content layout:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="comboContentLayout">
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Use global settings</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Original</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Create subfolder</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Don't create subfolder</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="lblListFeeds">
|
<widget class="QCheckBox" name="checkRegex">
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<weight>50</weight>
|
|
||||||
<bold>false</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Apply Rule to Feeds:</string>
|
<string>Use Regular Expressions</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QListWidget" name="listFeeds"/>
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="labelMustContain">
|
||||||
|
<property name="text">
|
||||||
|
<string>Must Contain:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="labelMustNotContain">
|
||||||
|
<property name="text">
|
||||||
|
<string>Must Not Contain:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="lblEFilter">
|
||||||
|
<property name="text">
|
||||||
|
<string>Episode Filter:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QLabel" name="lblEFilterStat">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>18</width>
|
||||||
|
<height>18</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QLabel" name="labelMustNotStat">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>18</width>
|
||||||
|
<height>18</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineContains"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="labelMustStat">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>18</width>
|
||||||
|
<height>18</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QLabel" name="labelEpFilterStat">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>18</width>
|
||||||
|
<height>18</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineNotContains"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEFilter"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkSmart">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Smart Episode Filter will check the episode number to prevent downloading of duplicates.
|
||||||
|
Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also support - as a separator)</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use Smart Episode Filter</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="ignorePeriodLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblIgnoreDays">
|
||||||
|
<property name="text">
|
||||||
|
<string extracomment="... X days">Ignore Subsequent Matches for (0 to Disable)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinIgnorePeriod">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="specialValueText">
|
||||||
|
<string>Disabled</string>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string> days</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>365</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblLastMatch">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="torrentParametersGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Torrent parameters</string>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</widget>
|
||||||
</layout>
|
</widget>
|
||||||
|
<widget class="QWidget" name="layoutWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetDefaultConstraint</enum>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblListFeeds">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Apply Rule to Feeds:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="listFeeds"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="layoutWidget2">
|
<widget class="QWidget" name="matchingArticlesLayoutWidget">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="matchingArticlesLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="matchingArticlesLabel">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
<bold>true</bold>
|
||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
@@ -423,7 +349,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTreeWidget" name="treeMatchingArticles">
|
<widget class="QTreeWidget" name="matchingArticlesTree">
|
||||||
<attribute name="headerVisible">
|
<attribute name="headerVisible">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
@@ -439,7 +365,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
<layout class="QHBoxLayout" name="buttonsLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="importBtn">
|
<widget class="QPushButton" name="importBtn">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@@ -474,31 +400,17 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>FileSystemPathLineEdit</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>gui/fspathedit.h</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>renameRuleBtn</tabstop>
|
<tabstop>renameRuleBtn</tabstop>
|
||||||
<tabstop>removeRuleBtn</tabstop>
|
<tabstop>removeRuleBtn</tabstop>
|
||||||
<tabstop>addRuleBtn</tabstop>
|
<tabstop>addRuleBtn</tabstop>
|
||||||
<tabstop>listRules</tabstop>
|
<tabstop>ruleList</tabstop>
|
||||||
<tabstop>checkRegex</tabstop>
|
|
||||||
<tabstop>checkSmart</tabstop>
|
|
||||||
<tabstop>lineContains</tabstop>
|
<tabstop>lineContains</tabstop>
|
||||||
<tabstop>lineNotContains</tabstop>
|
<tabstop>lineNotContains</tabstop>
|
||||||
<tabstop>lineEFilter</tabstop>
|
<tabstop>lineEFilter</tabstop>
|
||||||
<tabstop>comboCategory</tabstop>
|
|
||||||
<tabstop>checkBoxSaveDiffDir</tabstop>
|
|
||||||
<tabstop>lineSavePath</tabstop>
|
|
||||||
<tabstop>spinIgnorePeriod</tabstop>
|
<tabstop>spinIgnorePeriod</tabstop>
|
||||||
<tabstop>comboAddPaused</tabstop>
|
|
||||||
<tabstop>comboContentLayout</tabstop>
|
|
||||||
<tabstop>listFeeds</tabstop>
|
<tabstop>listFeeds</tabstop>
|
||||||
<tabstop>treeMatchingArticles</tabstop>
|
<tabstop>matchingArticlesTree</tabstop>
|
||||||
<tabstop>importBtn</tabstop>
|
<tabstop>importBtn</tabstop>
|
||||||
<tabstop>exportBtn</tabstop>
|
<tabstop>exportBtn</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
@@ -536,37 +448,5 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
|
|||||||
</hint>
|
</hint>
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
<connection>
|
|
||||||
<sender>checkBoxSaveDiffDir</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>label_6</receiver>
|
|
||||||
<slot>setEnabled(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>304</x>
|
|
||||||
<y>171</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>377</x>
|
|
||||||
<y>205</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>checkBoxSaveDiffDir</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>lineSavePath</receiver>
|
|
||||||
<slot>setEnabled(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>474</x>
|
|
||||||
<y>174</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>476</x>
|
|
||||||
<y>204</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
</connections>
|
||||||
</ui>
|
</ui>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2021 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2021-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -28,14 +28,9 @@
|
|||||||
|
|
||||||
#include "watchedfolderoptionsdialog.h"
|
#include "watchedfolderoptionsdialog.h"
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QPushButton>
|
|
||||||
|
|
||||||
#include "base/bittorrent/session.h"
|
|
||||||
#include "base/global.h"
|
#include "base/global.h"
|
||||||
#include "base/utils/fs.h"
|
#include "addtorrentparamswidget.h"
|
||||||
#include "ui_watchedfolderoptionsdialog.h"
|
#include "ui_watchedfolderoptionsdialog.h"
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#define SETTINGS_KEY(name) u"WatchedFolderOptionsDialog/" name
|
#define SETTINGS_KEY(name) u"WatchedFolderOptionsDialog/" name
|
||||||
|
|
||||||
@@ -43,56 +38,13 @@ WatchedFolderOptionsDialog::WatchedFolderOptionsDialog(
|
|||||||
const TorrentFilesWatcher::WatchedFolderOptions &watchedFolderOptions, QWidget *parent)
|
const TorrentFilesWatcher::WatchedFolderOptions &watchedFolderOptions, QWidget *parent)
|
||||||
: QDialog {parent}
|
: QDialog {parent}
|
||||||
, m_ui {new Ui::WatchedFolderOptionsDialog}
|
, m_ui {new Ui::WatchedFolderOptionsDialog}
|
||||||
, m_savePath {watchedFolderOptions.addTorrentParams.savePath}
|
, m_addTorrentParamsWidget {new AddTorrentParamsWidget(watchedFolderOptions.addTorrentParams)}
|
||||||
, m_downloadPath {watchedFolderOptions.addTorrentParams.downloadPath}
|
|
||||||
, m_storeDialogSize {SETTINGS_KEY(u"DialogSize"_qs)}
|
, m_storeDialogSize {SETTINGS_KEY(u"DialogSize"_qs)}
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
|
m_ui->groupBoxParameters->layout()->addWidget(m_addTorrentParamsWidget);
|
||||||
m_ui->savePath->setMode(FileSystemPathEdit::Mode::DirectorySave);
|
|
||||||
m_ui->savePath->setDialogCaption(tr("Choose save path"));
|
|
||||||
|
|
||||||
m_ui->downloadPath->setMode(FileSystemPathEdit::Mode::DirectorySave);
|
|
||||||
m_ui->downloadPath->setDialogCaption(tr("Choose save path"));
|
|
||||||
|
|
||||||
const auto *session = BitTorrent::Session::instance();
|
|
||||||
m_useDownloadPath = watchedFolderOptions.addTorrentParams.useDownloadPath.value_or(session->isDownloadPathEnabled());
|
|
||||||
|
|
||||||
connect(m_ui->comboTTM, qOverload<int>(&QComboBox::currentIndexChanged), this, &WatchedFolderOptionsDialog::onTMMChanged);
|
|
||||||
connect(m_ui->categoryComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this, &WatchedFolderOptionsDialog::onCategoryChanged);
|
|
||||||
|
|
||||||
m_ui->checkBoxRecursive->setChecked(watchedFolderOptions.recursive);
|
|
||||||
populateSavePaths();
|
|
||||||
|
|
||||||
const BitTorrent::AddTorrentParams &torrentParams = watchedFolderOptions.addTorrentParams;
|
|
||||||
m_ui->addToQueueTopCheckBox->setChecked(torrentParams.addToQueueTop.value_or(session->isAddTorrentToQueueTop()));
|
|
||||||
m_ui->startTorrentCheckBox->setChecked(!torrentParams.addPaused.value_or(session->isAddTorrentPaused()));
|
|
||||||
m_ui->skipCheckingCheckBox->setChecked(torrentParams.skipChecking);
|
|
||||||
m_ui->comboTTM->setCurrentIndex(torrentParams.useAutoTMM.value_or(!session->isAutoTMMDisabledByDefault()));
|
|
||||||
m_ui->contentLayoutComboBox->setCurrentIndex(
|
|
||||||
static_cast<int>(torrentParams.contentLayout.value_or(session->torrentContentLayout())));
|
|
||||||
|
|
||||||
// Load categories
|
|
||||||
QStringList categories = session->categories();
|
|
||||||
std::sort(categories.begin(), categories.end(), Utils::Compare::NaturalLessThan<Qt::CaseInsensitive>());
|
|
||||||
|
|
||||||
if (!torrentParams.category.isEmpty())
|
|
||||||
m_ui->categoryComboBox->addItem(torrentParams.category);
|
|
||||||
m_ui->categoryComboBox->addItem(u""_qs);
|
|
||||||
|
|
||||||
for (const QString &category : asConst(categories))
|
|
||||||
{
|
|
||||||
if (category != torrentParams.category)
|
|
||||||
m_ui->categoryComboBox->addItem(category);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadState();
|
loadState();
|
||||||
|
|
||||||
// Default focus
|
|
||||||
if (m_ui->comboTTM->currentIndex() == 0) // 0 is Manual mode
|
|
||||||
m_ui->savePath->setFocus();
|
|
||||||
else
|
|
||||||
m_ui->categoryComboBox->setFocus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchedFolderOptionsDialog::~WatchedFolderOptionsDialog()
|
WatchedFolderOptionsDialog::~WatchedFolderOptionsDialog()
|
||||||
@@ -105,22 +57,7 @@ TorrentFilesWatcher::WatchedFolderOptions WatchedFolderOptionsDialog::watchedFol
|
|||||||
{
|
{
|
||||||
TorrentFilesWatcher::WatchedFolderOptions watchedFolderOptions;
|
TorrentFilesWatcher::WatchedFolderOptions watchedFolderOptions;
|
||||||
watchedFolderOptions.recursive = m_ui->checkBoxRecursive->isChecked();
|
watchedFolderOptions.recursive = m_ui->checkBoxRecursive->isChecked();
|
||||||
|
watchedFolderOptions.addTorrentParams = m_addTorrentParamsWidget->addTorrentParams();
|
||||||
BitTorrent::AddTorrentParams ¶ms = watchedFolderOptions.addTorrentParams;
|
|
||||||
const bool useAutoTMM = (m_ui->comboTTM->currentIndex() == 1);
|
|
||||||
if (!useAutoTMM)
|
|
||||||
{
|
|
||||||
params.savePath = m_ui->savePath->selectedPath();
|
|
||||||
params.useDownloadPath = m_ui->groupBoxDownloadPath->isChecked();
|
|
||||||
if (params.useDownloadPath)
|
|
||||||
params.downloadPath = m_ui->downloadPath->selectedPath();
|
|
||||||
}
|
|
||||||
params.useAutoTMM = useAutoTMM;
|
|
||||||
params.category = m_ui->categoryComboBox->currentText();
|
|
||||||
params.addToQueueTop = m_ui->addToQueueTopCheckBox->isChecked();
|
|
||||||
params.addPaused = !m_ui->startTorrentCheckBox->isChecked();
|
|
||||||
params.skipChecking = m_ui->skipCheckingCheckBox->isChecked();
|
|
||||||
params.contentLayout = static_cast<BitTorrent::TorrentContentLayout>(m_ui->contentLayoutComboBox->currentIndex());
|
|
||||||
|
|
||||||
return watchedFolderOptions;
|
return watchedFolderOptions;
|
||||||
}
|
}
|
||||||
@@ -135,65 +72,3 @@ void WatchedFolderOptionsDialog::saveState()
|
|||||||
{
|
{
|
||||||
m_storeDialogSize = size();
|
m_storeDialogSize = size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchedFolderOptionsDialog::onCategoryChanged(const int index)
|
|
||||||
{
|
|
||||||
Q_UNUSED(index);
|
|
||||||
|
|
||||||
if (m_ui->comboTTM->currentIndex() == 1)
|
|
||||||
{
|
|
||||||
const auto *btSession = BitTorrent::Session::instance();
|
|
||||||
const QString categoryName = m_ui->categoryComboBox->currentText();
|
|
||||||
|
|
||||||
const Path savePath = btSession->categorySavePath(categoryName);
|
|
||||||
m_ui->savePath->setSelectedPath(savePath);
|
|
||||||
|
|
||||||
const Path downloadPath = btSession->categoryDownloadPath(categoryName);
|
|
||||||
m_ui->downloadPath->setSelectedPath(downloadPath);
|
|
||||||
|
|
||||||
m_ui->groupBoxDownloadPath->setChecked(!downloadPath.isEmpty());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchedFolderOptionsDialog::populateSavePaths()
|
|
||||||
{
|
|
||||||
const auto *btSession = BitTorrent::Session::instance();
|
|
||||||
|
|
||||||
const Path defaultSavePath {btSession->savePath()};
|
|
||||||
m_ui->savePath->setSelectedPath(!m_savePath.isEmpty() ? m_savePath : defaultSavePath);
|
|
||||||
|
|
||||||
const Path defaultDownloadPath {btSession->downloadPath()};
|
|
||||||
m_ui->downloadPath->setSelectedPath(!m_downloadPath.isEmpty() ? m_downloadPath : defaultDownloadPath);
|
|
||||||
|
|
||||||
m_ui->groupBoxDownloadPath->setChecked(m_useDownloadPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchedFolderOptionsDialog::onTMMChanged(const int index)
|
|
||||||
{
|
|
||||||
if (index != 1)
|
|
||||||
{ // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.
|
|
||||||
populateSavePaths();
|
|
||||||
m_ui->groupBoxSavePath->setEnabled(true);
|
|
||||||
m_ui->savePath->blockSignals(false);
|
|
||||||
m_ui->downloadPath->blockSignals(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_ui->groupBoxSavePath->setEnabled(false);
|
|
||||||
|
|
||||||
const auto *btSession = BitTorrent::Session::instance();
|
|
||||||
|
|
||||||
m_ui->savePath->blockSignals(true);
|
|
||||||
m_savePath = m_ui->savePath->selectedPath();
|
|
||||||
const Path savePath = btSession->categorySavePath(m_ui->categoryComboBox->currentText());
|
|
||||||
m_ui->savePath->setSelectedPath(savePath);
|
|
||||||
|
|
||||||
m_ui->downloadPath->blockSignals(true);
|
|
||||||
m_downloadPath = m_ui->downloadPath->selectedPath();
|
|
||||||
const Path downloadPath = btSession->categoryDownloadPath(m_ui->categoryComboBox->currentText());
|
|
||||||
m_ui->downloadPath->setSelectedPath(downloadPath);
|
|
||||||
|
|
||||||
m_useDownloadPath = m_ui->groupBoxDownloadPath->isChecked();
|
|
||||||
m_ui->groupBoxDownloadPath->setChecked(!downloadPath.isEmpty());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2021 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2021-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
|
||||||
#include "base/path.h"
|
|
||||||
#include "base/settingvalue.h"
|
#include "base/settingvalue.h"
|
||||||
#include "base/torrentfileswatcher.h"
|
#include "base/torrentfileswatcher.h"
|
||||||
|
|
||||||
@@ -39,6 +38,8 @@ namespace Ui
|
|||||||
class WatchedFolderOptionsDialog;
|
class WatchedFolderOptionsDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddTorrentParamsWidget;
|
||||||
|
|
||||||
class WatchedFolderOptionsDialog final : public QDialog
|
class WatchedFolderOptionsDialog final : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -58,8 +59,6 @@ private:
|
|||||||
void onCategoryChanged(int index);
|
void onCategoryChanged(int index);
|
||||||
|
|
||||||
Ui::WatchedFolderOptionsDialog *m_ui = nullptr;
|
Ui::WatchedFolderOptionsDialog *m_ui = nullptr;
|
||||||
Path m_savePath;
|
AddTorrentParamsWidget *m_addTorrentParamsWidget = nullptr;
|
||||||
Path m_downloadPath;
|
|
||||||
bool m_useDownloadPath = false;
|
|
||||||
SettingValue<QSize> m_storeDialogSize;
|
SettingValue<QSize> m_storeDialogSize;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>462</width>
|
<width>462</width>
|
||||||
<height>364</height>
|
<height>392</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -42,267 +42,24 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QSplitter" name="splitter">
|
<widget class="QGroupBox" name="groupBoxParameters">
|
||||||
<property name="orientation">
|
<property name="title">
|
||||||
<enum>Qt::Horizontal</enum>
|
<string>Torrent parameters</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="childrenCollapsible">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<bool>false</bool>
|
<property name="leftMargin">
|
||||||
</property>
|
<number>0</number>
|
||||||
<widget class="QFrame" name="torrentoptionsFrame">
|
</property>
|
||||||
<layout class="QVBoxLayout" name="mainlayout_addui">
|
<property name="topMargin">
|
||||||
<property name="leftMargin">
|
<number>0</number>
|
||||||
<number>0</number>
|
</property>
|
||||||
</property>
|
<property name="rightMargin">
|
||||||
<property name="topMargin">
|
<number>0</number>
|
||||||
<number>0</number>
|
</property>
|
||||||
</property>
|
<property name="bottomMargin">
|
||||||
<property name="rightMargin">
|
<number>0</number>
|
||||||
<number>0</number>
|
</property>
|
||||||
</property>
|
</layout>
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBoxParameters">
|
|
||||||
<property name="title">
|
|
||||||
<string>Torrent parameters</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="managementLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="labelTorrentManagementMode">
|
|
||||||
<property name="text">
|
|
||||||
<string>Torrent Management Mode:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="comboTTM">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Automatic mode means that various torrent properties(eg save path) will be decided by the associated category</string>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Manual</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Automatic</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBoxSavePath">
|
|
||||||
<property name="title">
|
|
||||||
<string>Save at</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="FileSystemPathLineEdit" name="savePath" native="true"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBoxDownloadPath">
|
|
||||||
<property name="title">
|
|
||||||
<string>Use another path for incomplete torrents</string>
|
|
||||||
</property>
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
|
||||||
<item>
|
|
||||||
<widget class="FileSystemPathLineEdit" name="downloadPath" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="categoryLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="labelCategory">
|
|
||||||
<property name="text">
|
|
||||||
<string>Category:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="categoryComboBox">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="editable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="insertPolicy">
|
|
||||||
<enum>QComboBox::InsertAtTop</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_7">
|
|
||||||
<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_3">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="startTorrentCheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>Start torrent</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_3">
|
|
||||||
<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="addToQueueTopLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="addToQueueTopCheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>Add to top of queue</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="addToQueueTopSpacer">
|
|
||||||
<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="skipCheckingLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="skipCheckingCheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>Skip hash check</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="skipCheckingSpacer">
|
|
||||||
<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>
|
|
||||||
<widget class="QLabel" name="contentLayoutLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Content layout:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="contentLayoutComboBox">
|
|
||||||
<property name="currentIndex">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Original</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Create subfolder</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Don't create subfolder</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_4">
|
|
||||||
<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>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -331,20 +88,6 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>FileSystemPathLineEdit</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>gui/fspathedit.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>FileSystemPathLineEdit</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>gui/fspathedit.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
|
|||||||
Reference in New Issue
Block a user