Implement Advanced Saving Management subsystem

Closes #4696
This commit is contained in:
Vladimir Golovnev (Glassez)
2016-02-09 11:56:48 +03:00
parent d05d5a85a5
commit dd34663224
59 changed files with 1796 additions and 1280 deletions

View File

@@ -35,7 +35,7 @@
#include <QMenu>
#include <QFileDialog>
#include "base/preferences.h"
#include "base/settingsstorage.h"
#include "base/net/downloadmanager.h"
#include "base/net/downloadhandler.h"
#include "base/bittorrent/session.h"
@@ -44,16 +44,34 @@
#include "base/bittorrent/torrenthandle.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/utils/string.h"
#include "base/unicodestrings.h"
#include "guiiconprovider.h"
#include "autoexpandabledialog.h"
#include "messageboxraised.h"
#include "ui_addnewtorrentdialog.h"
#include "proplistdelegate.h"
#include "torrentcontentmodel.h"
#include "torrentcontentfiltermodel.h"
#include "ui_addnewtorrentdialog.h"
#include "addnewtorrentdialog.h"
#define SETTINGS_KEY(name) "AddNewTorrentDialog/" name
const QString KEY_ENABLED = SETTINGS_KEY("Enabled");
const QString KEY_DEFAULTSAVEPATH = SETTINGS_KEY("DefaultSavePath");
const QString KEY_DEFAULTCATEGORY = SETTINGS_KEY("DefaultCategory");
const QString KEY_TREEHEADERSTATE = SETTINGS_KEY("TreeHeaderState");
const QString KEY_WIDTH = SETTINGS_KEY("Width");
const QString KEY_EXPANDED = SETTINGS_KEY("Expanded");
const QString KEY_POSITION = SETTINGS_KEY("Position");
const QString KEY_TOPLEVEL = SETTINGS_KEY("TopLevel");
const QString KEY_SAVEPATHHISTORY = SETTINGS_KEY("SavePathHistory");
namespace
{
//just a shortcut
inline SettingsStorage *settings() { return SettingsStorage::instance(); }
}
AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::AddNewTorrentDialog)
@@ -67,34 +85,36 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
ui->lblMetaLoading->setVisible(false);
ui->progMetaLoading->setVisible(false);
Preferences* const pref = Preferences::instance();
ui->start_torrent_cb->setChecked(!pref->addTorrentsInPause());
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(pref->getSavePath()), pref->getSavePath());
loadSavePathHistory();
auto session = BitTorrent::Session::instance();
ui->startTorrentCheckBox->setChecked(!session->isAddTorrentPaused());
(session->isASMDisabledByDefault() ? ui->simpleModeRadioButton : ui->advancedModeRadioButton)->setChecked(true);
populateSavePathComboBox();
connect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), SLOT(onSavePathChanged(int)));
connect(ui->browse_button, SIGNAL(clicked()), SLOT(browseButton_clicked()));
ui->default_save_path_cb->setVisible(false); // Default path is selected by default
connect(ui->browseButton, SIGNAL(clicked()), SLOT(browseButton_clicked()));
ui->defaultSavePathCheckBox->setVisible(false); // Default path is selected by default
// Load labels
const QStringList customLabels = pref->getTorrentLabels();
const QString defaultLabel = pref->getDefaultLabel();
// Load categories
QStringList categories = session->categories();
std::sort(categories.begin(), categories.end(), Utils::String::NaturalCompare());
QString defaultCategory = settings()->loadValue(KEY_DEFAULTCATEGORY).toString();
if (!defaultLabel.isEmpty())
ui->label_combo->addItem(defaultLabel);
ui->label_combo->addItem("");
if (!defaultCategory.isEmpty())
ui->categoryComboBox->addItem(defaultCategory);
ui->categoryComboBox->addItem("");
foreach (const QString& label, customLabels)
if (label != defaultLabel)
ui->label_combo->addItem(label);
foreach (const QString &category, categories)
if (category != defaultCategory)
ui->categoryComboBox->addItem(category);
ui->label_combo->model()->sort(0);
ui->content_tree->header()->setSortIndicator(0, Qt::AscendingOrder);
ui->categoryComboBox->model()->sort(0);
ui->contentTreeView->header()->setSortIndicator(0, Qt::AscendingOrder);
loadState();
// Signal / slots
connect(ui->adv_button, SIGNAL(clicked(bool)), SLOT(showAdvancedSettings(bool)));
editHotkey = new QShortcut(QKeySequence("F2"), ui->content_tree, 0, 0, Qt::WidgetShortcut);
editHotkey = new QShortcut(QKeySequence("F2"), ui->contentTreeView, 0, 0, Qt::WidgetShortcut);
connect(editHotkey, SIGNAL(activated()), SLOT(renameSelectedFile()));
connect(ui->content_tree, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedFile()));
connect(ui->contentTreeView, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedFile()));
ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
}
@@ -108,27 +128,45 @@ AddNewTorrentDialog::~AddNewTorrentDialog()
delete editHotkey;
}
bool AddNewTorrentDialog::isEnabled()
{
return SettingsStorage::instance()->loadValue(KEY_ENABLED, true).toBool();
}
void AddNewTorrentDialog::setEnabled(bool value)
{
SettingsStorage::instance()->storeValue(KEY_ENABLED, value);
}
bool AddNewTorrentDialog::isTopLevel()
{
return SettingsStorage::instance()->loadValue(KEY_TOPLEVEL, true).toBool();
}
void AddNewTorrentDialog::setTopLevel(bool value)
{
SettingsStorage::instance()->storeValue(KEY_TOPLEVEL, value);
}
void AddNewTorrentDialog::loadState()
{
const Preferences* const pref = Preferences::instance();
m_headerState = pref->getAddNewTorrentDialogState();
int width = pref->getAddNewTorrentDialogWidth();
m_headerState = settings()->loadValue(KEY_TREEHEADERSTATE).toByteArray();
int width = settings()->loadValue(KEY_WIDTH, -1).toInt();
if (width >= 0) {
QRect geo = geometry();
geo.setWidth(width);
setGeometry(geo);
}
ui->adv_button->setChecked(pref->getAddNewTorrentDialogExpanded());
ui->adv_button->setChecked(settings()->loadValue(KEY_EXPANDED).toBool());
}
void AddNewTorrentDialog::saveState()
{
Preferences* const pref = Preferences::instance();
if (m_contentModel)
pref->setAddNewTorrentDialogState(ui->content_tree->header()->saveState());
pref->setAddNewTorrentDialogPos(pos().y());
pref->setAddNewTorrentDialogWidth(width());
pref->setAddNewTorrentDialogExpanded(ui->adv_button->isChecked());
settings()->storeValue(KEY_TREEHEADERSTATE, ui->contentTreeView->header()->saveState());
settings()->storeValue(KEY_POSITION, pos().y());
settings()->storeValue(KEY_WIDTH, width());
settings()->storeValue(KEY_EXPANDED, ui->adv_button->isChecked());
}
void AddNewTorrentDialog::show(QString source, QWidget *parent)
@@ -256,9 +294,8 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri)
void AddNewTorrentDialog::showEvent(QShowEvent *event)
{
QDialog::showEvent(event);
Preferences* const pref = Preferences::instance();
if (!pref->additionDialogFront())
return;
if (!isTopLevel()) return;
activateWindow();
raise();
}
@@ -272,7 +309,7 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
ui->adv_button->setText(QString::fromUtf8(C_UP));
ui->settings_group->setVisible(true);
ui->infoGroup->setVisible(true);
ui->content_tree->setVisible(m_hasMetadata);
ui->contentTreeView->setVisible(m_hasMetadata);
static_cast<QVBoxLayout*>(layout())->insertWidget(layout()->indexOf(ui->never_show_cb) + 1, ui->adv_button);
}
else {
@@ -287,21 +324,20 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
void AddNewTorrentDialog::saveSavePathHistory() const
{
QDir selected_save_path(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString());
Preferences* const pref = Preferences::instance();
QDir selectedSavePath(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString());
// Get current history
QStringList history = pref->getAddNewTorrentDialogPathHistory();
QList<QDir> history_dirs;
QStringList history = settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList();
QList<QDir> historyDirs;
foreach(const QString dir, history)
history_dirs << QDir(dir);
if (!history_dirs.contains(selected_save_path)) {
historyDirs << QDir(dir);
if (!historyDirs.contains(selectedSavePath)) {
// Add save path to history
history.push_front(selected_save_path.absolutePath());
history.push_front(selectedSavePath.absolutePath());
// Limit list size
if (history.size() > 8)
history.pop_back();
// Save history
pref->setAddNewTorrentDialogPathHistory(history);
settings()->storeValue(KEY_SAVEPATHHISTORY, history);
}
}
@@ -345,8 +381,10 @@ void AddNewTorrentDialog::updateDiskSpaceLabel()
void AddNewTorrentDialog::onSavePathChanged(int index)
{
// Toggle default save path setting checkbox visibility
ui->default_save_path_cb->setChecked(false);
ui->default_save_path_cb->setVisible(QDir(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString()) != QDir(Preferences::instance()->getSavePath()));
ui->defaultSavePathCheckBox->setChecked(false);
ui->defaultSavePathCheckBox->setVisible(
QDir(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString())
!= QDir(defaultSavePath()));
// Remember index
m_oldIndex = index;
@@ -354,6 +392,17 @@ void AddNewTorrentDialog::onSavePathChanged(int index)
updateDiskSpaceLabel();
}
void AddNewTorrentDialog::categoryChanged(int index)
{
Q_UNUSED(index);
if (ui->advancedModeRadioButton->isChecked()) {
QString savePath = BitTorrent::Session::instance()->categorySavePath(ui->categoryComboBox->currentText());
ui->savePathComboBox->setItemText(0, Utils::Fs::toNativePath(savePath));
ui->savePathComboBox->setItemData(0, savePath);
}
}
void AddNewTorrentDialog::browseButton_clicked()
{
disconnect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onSavePathChanged(int)));
@@ -390,7 +439,7 @@ void AddNewTorrentDialog::browseButton_clicked()
void AddNewTorrentDialog::renameSelectedFile()
{
const QModelIndexList selectedIndexes = ui->content_tree->selectionModel()->selectedRows(0);
const QModelIndexList selectedIndexes = ui->contentTreeView->selectionModel()->selectedRows(0);
if (selectedIndexes.size() != 1)
return;
const QModelIndex &index = selectedIndexes.first();
@@ -490,7 +539,7 @@ void AddNewTorrentDialog::setdialogPosition()
qApp->processEvents();
QPoint center(Utils::Misc::screenCenter(this));
// Adjust y
int y = Preferences::instance()->getAddNewTorrentDialogPos();
int y = settings()->loadValue(KEY_POSITION, -1).toInt();
if (y >= 0) {
center.setY(y);
}
@@ -502,20 +551,23 @@ void AddNewTorrentDialog::setdialogPosition()
move(center);
}
void AddNewTorrentDialog::loadSavePathHistory()
void AddNewTorrentDialog::populateSavePathComboBox()
{
QDir default_save_path(Preferences::instance()->getSavePath());
QString defSavePath = defaultSavePath();
ui->savePathComboBox->clear();
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(defSavePath), defSavePath);
QDir defaultSaveDir(defSavePath);
// Load save path history
QStringList raw_path_history = Preferences::instance()->getAddNewTorrentDialogPathHistory();
foreach (const QString &sp, raw_path_history)
if (QDir(sp) != default_save_path)
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(sp), sp);
foreach (const QString &savePath, settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList())
if (QDir(savePath) != defaultSaveDir)
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(savePath), savePath);
}
void AddNewTorrentDialog::displayContentTreeMenu(const QPoint&)
{
QMenu myFilesLlistMenu;
const QModelIndexList selectedRows = ui->content_tree->selectionModel()->selectedRows(0);
const QModelIndexList selectedRows = ui->contentTreeView->selectionModel()->selectedRows(0);
QAction *actRename = 0;
if (selectedRows.size() == 1) {
actRename = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
@@ -557,39 +609,34 @@ void AddNewTorrentDialog::accept()
if (!m_hasMetadata)
disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo &)));
Preferences *const pref = Preferences::instance();
BitTorrent::AddTorrentParams params;
if (ui->skip_check_cb->isChecked())
// TODO: Check if destination actually exists
params.skipChecking = true;
// Label
params.label = ui->label_combo->currentText();
// Category
params.category = ui->categoryComboBox->currentText();
if (ui->defaultLabel->isChecked())
pref->setDefaultLabel(params.label);
if (ui->defaultCategoryCheckbox->isChecked())
settings()->storeValue(KEY_DEFAULTCATEGORY, params.category);
// Save file priorities
if (m_contentModel)
params.filePriorities = m_contentModel->model()->getFilePriorities();
params.addPaused = !ui->start_torrent_cb->isChecked();
saveSavePathHistory();
pref->useAdditionDialog(!ui->never_show_cb->isChecked());
params.addPaused = !ui->startTorrentCheckBox->isChecked();
QString savePath = ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString();
if (ui->default_save_path_cb->isChecked()) {
pref->setSavePath(savePath);
pref->apply();
}
else {
// if we don't use default save path...
if (QDir(savePath) != QDir(pref->getSavePath()))
params.savePath = savePath;
if (ui->simpleModeRadioButton->isChecked()) {
params.savePath = savePath;
saveSavePathHistory();
if (ui->defaultSavePathCheckBox->isChecked())
settings()->storeValue(KEY_DEFAULTSAVEPATH, savePath);
}
setEnabled(!ui->never_show_cb->isChecked());
// Add torrent
if (!m_hasMetadata)
BitTorrent::Session::instance()->addTorrent(m_hash, params);
@@ -656,28 +703,35 @@ void AddNewTorrentDialog::setupTreeview()
// Prepare content tree
m_contentModel = new TorrentContentFilterModel(this);
connect(m_contentModel->model(), SIGNAL(filteredFilesChanged()), SLOT(updateDiskSpaceLabel()));
ui->content_tree->setModel(m_contentModel);
ui->content_tree->hideColumn(PROGRESS);
ui->contentTreeView->setModel(m_contentModel);
ui->contentTreeView->hideColumn(PROGRESS);
m_contentDelegate = new PropListDelegate();
ui->content_tree->setItemDelegate(m_contentDelegate);
connect(ui->content_tree, SIGNAL(clicked(const QModelIndex &)), ui->content_tree, SLOT(edit(const QModelIndex &)));
connect(ui->content_tree, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(displayContentTreeMenu(const QPoint &)));
ui->contentTreeView->setItemDelegate(m_contentDelegate);
connect(ui->contentTreeView, SIGNAL(clicked(const QModelIndex &)), ui->contentTreeView, SLOT(edit(const QModelIndex &)));
connect(ui->contentTreeView, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(displayContentTreeMenu(const QPoint &)));
// List files in torrent
m_contentModel->model()->setupModelData(m_torrentInfo);
if (!m_headerState.isEmpty())
ui->content_tree->header()->restoreState(m_headerState);
ui->contentTreeView->header()->restoreState(m_headerState);
// Expand root folder
ui->content_tree->setExpanded(m_contentModel->index(0, 0), true);
ui->contentTreeView->setExpanded(m_contentModel->index(0, 0), true);
}
updateDiskSpaceLabel();
showAdvancedSettings(Preferences::instance()->getAddNewTorrentDialogExpanded());
showAdvancedSettings(settings()->loadValue(KEY_EXPANDED, false).toBool());
// Set dialog position
setdialogPosition();
}
QString AddNewTorrentDialog::defaultSavePath() const
{
return Utils::Fs::fromNativePath(
settings()->loadValue(KEY_DEFAULTSAVEPATH,
BitTorrent::Session::instance()->defaultSavePath()).toString());
}
void AddNewTorrentDialog::handleDownloadFailed(const QString &url, const QString &reason)
{
MessageBoxRaised::critical(0, tr("Download Error"), QString("Cannot download '%1': %2").arg(url).arg(reason));
@@ -701,3 +755,25 @@ void AddNewTorrentDialog::handleDownloadFinished(const QString &url, const QStri
else
this->deleteLater();
}
void AddNewTorrentDialog::savingModeChanged(bool enabled)
{
if (!enabled) return;
if (ui->simpleModeRadioButton->isChecked()) {
populateSavePathComboBox();
ui->savePathComboBox->setEnabled(true);
ui->browseButton->setEnabled(true);
ui->savePathComboBox->blockSignals(false);
ui->savePathComboBox->setCurrentIndex(m_oldIndex < ui->savePathComboBox->count() ? m_oldIndex : ui->savePathComboBox->count() - 1);
}
else {
ui->savePathComboBox->blockSignals(true);
ui->savePathComboBox->clear();
QString savePath = BitTorrent::Session::instance()->categorySavePath(ui->categoryComboBox->currentText());
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(savePath), savePath);
ui->savePathComboBox->setEnabled(false);
ui->browseButton->setEnabled(false);
ui->defaultSavePathCheckBox->setVisible(false);
}
}

View File

@@ -58,10 +58,12 @@ class AddNewTorrentDialog: public QDialog
public:
~AddNewTorrentDialog();
static void show(QString source, QWidget *parent = 0);
static bool isEnabled();
static void setEnabled(bool value);
static bool isTopLevel();
static void setTopLevel(bool value);
protected:
void showEvent(QShowEvent *event);
static void show(QString source, QWidget *parent = 0);
private slots:
void showAdvancedSettings(bool show);
@@ -75,24 +77,27 @@ private slots:
void handleDownloadFailed(const QString &url, const QString &reason);
void handleRedirectedToMagnet(const QString &url, const QString &magnetUri);
void handleDownloadFinished(const QString &url, const QString &filePath);
void savingModeChanged(bool enabled);
void categoryChanged(int index);
protected slots:
virtual void accept();
virtual void reject();
void accept() override;
void reject() override;
private:
explicit AddNewTorrentDialog(QWidget *parent = 0);
bool loadTorrent(const QString &torrentPath);
bool loadMagnet(const BitTorrent::MagnetUri &magnetUri);
void loadSavePathHistory();
void populateSavePathComboBox();
void saveSavePathHistory() const;
int indexOfSavePath(const QString& save_path);
void loadState();
void saveState();
void setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText = QString());
void setupTreeview();
QString defaultSavePath() const;
void showEvent(QShowEvent *event) override;
private:
Ui::AddNewTorrentDialog *ui;
TorrentContentFilterModel *m_contentModel;
PropListDelegate *m_contentDelegate;

View File

@@ -17,6 +17,50 @@
<string>Save at</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>20</number>
</property>
<item>
<widget class="QLabel" name="savingModeLabel">
<property name="text">
<string>Saving Management:</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="simpleModeRadioButton">
<property name="text">
<string>Simple</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="advancedModeRadioButton">
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
@@ -33,7 +77,7 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="browse_button">
<widget class="QPushButton" name="browseButton">
<property name="text">
<string>Browse...</string>
</property>
@@ -42,7 +86,7 @@
</layout>
</item>
<item>
<widget class="QCheckBox" name="default_save_path_cb">
<widget class="QCheckBox" name="defaultSavePathCheckBox">
<property name="text">
<string>Set as default save path</string>
</property>
@@ -75,14 +119,14 @@
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="2">
<widget class="QCheckBox" name="defaultLabel">
<widget class="QCheckBox" name="defaultCategoryCheckbox">
<property name="text">
<string>Set as default label</string>
<string>Set as default category</string>
</property>
</widget>
</item>
<item row="0" column="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_1">
<item>
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
@@ -92,12 +136,12 @@
</sizepolicy>
</property>
<property name="text">
<string>Set label:</string>
<string>Category:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="label_combo">
<widget class="QComboBox" name="categoryComboBox">
<property name="minimumSize">
<size>
<width>140</width>
@@ -115,7 +159,7 @@
</layout>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="start_torrent_cb">
<widget class="QCheckBox" name="startTorrentCheckBox">
<property name="text">
<string>Start torrent</string>
</property>
@@ -231,7 +275,7 @@
</layout>
</item>
<item>
<widget class="TorrentContentTreeView" name="content_tree">
<widget class="TorrentContentTreeView" name="contentTreeView">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
@@ -311,6 +355,20 @@
<header>torrentcontenttreeview.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>savePathComboBox</tabstop>
<tabstop>browseButton</tabstop>
<tabstop>simpleModeRadioButton</tabstop>
<tabstop>advancedModeRadioButton</tabstop>
<tabstop>defaultSavePathCheckBox</tabstop>
<tabstop>never_show_cb</tabstop>
<tabstop>adv_button</tabstop>
<tabstop>startTorrentCheckBox</tabstop>
<tabstop>categoryComboBox</tabstop>
<tabstop>defaultCategoryCheckbox</tabstop>
<tabstop>skip_check_cb</tabstop>
<tabstop>contentTreeView</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
@@ -320,8 +378,8 @@
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
<x>403</x>
<y>579</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
@@ -336,8 +394,8 @@
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
<x>403</x>
<y>579</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
@@ -345,5 +403,57 @@
</hint>
</hints>
</connection>
<connection>
<sender>simpleModeRadioButton</sender>
<signal>toggled(bool)</signal>
<receiver>AddNewTorrentDialog</receiver>
<slot>savingModeChanged(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>154</x>
<y>39</y>
</hint>
<hint type="destinationlabel">
<x>122</x>
<y>6</y>
</hint>
</hints>
</connection>
<connection>
<sender>advancedModeRadioButton</sender>
<signal>toggled(bool)</signal>
<receiver>AddNewTorrentDialog</receiver>
<slot>savingModeChanged(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>218</x>
<y>44</y>
</hint>
<hint type="destinationlabel">
<x>209</x>
<y>7</y>
</hint>
</hints>
</connection>
<connection>
<sender>categoryComboBox</sender>
<signal>currentIndexChanged(int)</signal>
<receiver>AddNewTorrentDialog</receiver>
<slot>categoryChanged(int)</slot>
<hints>
<hint type="sourcelabel">
<x>337</x>
<y>205</y>
</hint>
<hint type="destinationlabel">
<x>403</x>
<y>160</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>savingModeChanged(bool)</slot>
<slot>categoryChanged(int)</slot>
</slots>
</ui>

View File

@@ -1004,7 +1004,7 @@ void MainWindow::dropEvent(QDropEvent *event)
}
// Add file to download list
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
const bool useTorrentAdditionDialog = AddNewTorrentDialog::isEnabled();
foreach (QString file, files) {
qDebug("Dropped file %s on download list", qPrintable(file));
if (useTorrentAdditionDialog)
@@ -1039,7 +1039,7 @@ void MainWindow::on_actionOpen_triggered()
const QStringList pathsList =
QFileDialog::getOpenFileNames(0, tr("Open Torrent Files"), pref->getMainLastDir(),
tr("Torrent Files") + QString::fromUtf8(" (*.torrent)"));
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
const bool useTorrentAdditionDialog = AddNewTorrentDialog::isEnabled();
if (!pathsList.isEmpty()) {
foreach (QString file, pathsList) {
qDebug("Dropped file %s on download list", qPrintable(file));
@@ -1249,7 +1249,7 @@ void MainWindow::showNotificationBaloon(QString title, QString msg) const
void MainWindow::downloadFromURLList(const QStringList& url_list)
{
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
const bool useTorrentAdditionDialog = AddNewTorrentDialog::isEnabled();
foreach (QString url, url_list) {
if ((url.size() == 40 && !url.contains(QRegExp("[^0-9A-Fa-f]")))
|| (url.size() == 32 && !url.contains(QRegExp("[^2-7A-Za-z]"))))

View File

@@ -546,8 +546,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>487</width>
<height>1040</height>
<width>454</width>
<height>1212</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@@ -599,7 +599,7 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="fileSystemBox">
<widget class="QGroupBox" name="groupSavingManagement">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
@@ -607,13 +607,57 @@
</sizepolicy>
</property>
<property name="title">
<string>Hard Disk</string>
<string>Saving Management</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_25">
<item>
<widget class="QGroupBox" name="groupBox_3">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Default Saving Mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioBtnSimpleMode">
<property name="text">
<string>Simple</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioBtnAdvancedMode">
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_16">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupDefaultSavePath">
<property name="title">
<string>Save files to location:</string>
<string>Default Save Path</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_26">
<property name="bottomMargin">
@@ -658,10 +702,134 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkAppendLabel">
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="labelEnableSubcategories">
<property name="text">
<string>Enable Subcategories:</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioBtnEnableSubcategories">
<property name="text">
<string>Yes</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioBtnDisableSubcategories">
<property name="text">
<string>No</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_17">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupCategoryChanged">
<property name="title">
<string>When Torrent Category changed</string>
</property>
<layout class="QFormLayout" name="formLayout_6">
<item row="0" column="0">
<widget class="QRadioButton" name="radioBtnRelocateOnCategoryChanged">
<property name="text">
<string>Append the label of the torrent to the save path</string>
<string>Relocate torrent</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="radioBtnDisableASMOnCategoryChanged">
<property name="text">
<string>Switch torrent to Simple Mode</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupDefaultSavePathChanged">
<property name="title">
<string>When Default Save Path changed</string>
</property>
<layout class="QFormLayout" name="formLayout_7">
<item row="0" column="0">
<widget class="QRadioButton" name="radioBtnRelocateOnDefaultSavePathChanged">
<property name="text">
<string>Relocate affected torrents</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="radioBtnDisableASMOnDefaultSavePathChanged">
<property name="text">
<string>Switch affected torrents to Simple Mode</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupCategorySavePathChanged">
<property name="title">
<string>When Category changed</string>
</property>
<layout class="QFormLayout" name="formLayout_8">
<item row="0" column="0">
<widget class="QRadioButton" name="radioBtnRelocateOnCategorySavePathChanged">
<property name="text">
<string>Relocate affected torrents</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="radioBtnDisableASMOnCategorySavePathChanged">
<property name="text">
<string>Switch affected torrents to Simple Mode</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
@@ -728,93 +896,6 @@
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Automatically add torrents from:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_38">
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_16">
<item>
<widget class="QTreeView" name="scanFoldersView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>250</width>
<height>150</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::AllEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="textElideMode">
<enum>Qt::ElideNone</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<attribute name="headerDefaultSectionSize">
<number>80</number>
</attribute>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_37">
<item>
<widget class="QPushButton" name="addScanFolderButton">
<property name="text">
<string>Add folder...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeScanFolderButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Remove folder</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="checkExportDir">
<property name="sizePolicy">
@@ -926,6 +1007,93 @@
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Automatically add torrents from:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_38">
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_16">
<item>
<widget class="QTreeView" name="scanFoldersView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>250</width>
<height>150</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::AllEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="textElideMode">
<enum>Qt::ElideNone</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<attribute name="headerDefaultSectionSize">
<number>80</number>
</attribute>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_37">
<item>
<widget class="QPushButton" name="addScanFolderButton">
<property name="text">
<string>Add folder...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeScanFolderButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Remove folder</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupMailNotification">
<property name="title">
@@ -1062,8 +1230,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>658</height>
<width>361</width>
<height>586</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_20">
@@ -1592,8 +1760,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>376</width>
<height>444</height>
<width>275</width>
<height>401</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
@@ -1979,8 +2147,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>555</width>
<height>527</height>
<width>440</width>
<height>481</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
@@ -2376,8 +2544,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>419</width>
<height>537</height>
<width>332</width>
<height>480</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_23">
@@ -2950,4 +3118,7 @@
</hints>
</connection>
</connections>
<buttongroups>
<buttongroup name="buttonGroup"/>
</buttongroups>
</ui>

View File

@@ -51,6 +51,7 @@
#include "advancedsettings.h"
#include "guiiconprovider.h"
#include "scanfoldersdelegate.h"
#include "addnewtorrentdialog.h"
#include "options_imp.h"
#ifndef QT_NO_OPENSSL
@@ -168,8 +169,12 @@ options_imp::options_imp(QWidget *parent)
#endif
// Downloads tab
connect(textSavePath, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
connect(radioBtnEnableSubcategories, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(radioBtnAdvancedMode, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(radioBtnRelocateOnCategoryChanged, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(radioBtnRelocateOnCategorySavePathChanged, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(radioBtnRelocateOnDefaultSavePathChanged, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(textTempPath, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
connect(checkAppendLabel, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(checkAppendqB, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(checkPreallocateAll, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(checkAdditionDialog, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
@@ -197,7 +202,7 @@ options_imp::options_imp(QWidget *parent)
autoRun_param->setText(QString::fromUtf8("%1\n %2\n %3\n %4\n %5\n %6\n %7\n %8\n %9\n %10")
.arg(tr("Supported parameters (case sensitive):"))
.arg(tr("%N: Torrent name"))
.arg(tr("%L: Label"))
.arg(tr("%L: Category"))
.arg(tr("%F: Content path (same as root path for multifile torrent)"))
.arg(tr("%R: Root path (first torrent subdirectory path)"))
.arg(tr("%D: Save path"))
@@ -429,16 +434,22 @@ void options_imp::saveOptions()
#endif
// End General preferences
auto session = BitTorrent::Session::instance();
// Downloads preferences
pref->setSavePath(getSavePath());
pref->setTempPathEnabled(isTempPathEnabled());
pref->setTempPath(getTempPath());
pref->setAppendTorrentLabel(checkAppendLabel->isChecked());
session->setDefaultSavePath(Utils::Fs::expandPathAbs(textSavePath->text()));
session->setSubcategoriesEnabled(radioBtnEnableSubcategories->isChecked());
session->setASMDisabledByDefault(radioBtnSimpleMode->isChecked());
session->setDisableASMWhenCategoryChanged(radioBtnDisableASMOnCategoryChanged->isChecked());
session->setDisableASMWhenCategorySavePathChanged(radioBtnDisableASMOnCategorySavePathChanged->isChecked());
session->setDisableASMWhenDefaultSavePathChanged(radioBtnDisableASMOnDefaultSavePathChanged->isChecked());
session->setTempPathEnabled(checkTempFolder->isChecked());
session->setTempPath(Utils::Fs::expandPathAbs(textTempPath->text()));
pref->useIncompleteFilesExtension(checkAppendqB->isChecked());
pref->preAllocateAllFiles(preAllocateAllFiles());
pref->useAdditionDialog(useAdditionDialog());
pref->additionDialogFront(checkAdditionDialogFront->isChecked());
pref->addTorrentsInPause(addTorrentsInPause());
AddNewTorrentDialog::setEnabled(useAdditionDialog());
AddNewTorrentDialog::setTopLevel(checkAdditionDialogFront->isChecked());
session->setAddTorrentPaused(addTorrentsInPause());
ScanFoldersModel::instance()->removeFromFSWatcher(removedScanDirs);
ScanFoldersModel::instance()->addToFSWatcher(addedScanDirs);
ScanFoldersModel::instance()->makePersistent();
@@ -500,7 +511,7 @@ void options_imp::saveOptions()
pref->setAddTrackersEnabled(checkEnableAddTrackers->isChecked());
pref->setTrackersList(textTrackers->toPlainText());
pref->setGlobalMaxRatio(getMaxRatio());
pref->setMaxRatioAction(static_cast<MaxRatioAction>(comboRatioLimitAct->currentIndex()));
session->setMaxRatioAction(static_cast<MaxRatioAction>(comboRatioLimitAct->currentIndex()));
// End Bittorrent preferences
// Misc preferences
// * IPFilter
@@ -610,18 +621,21 @@ void options_imp::loadOptions()
#endif
// End General preferences
// Downloads preferences
checkAdditionDialog->setChecked(pref->useAdditionDialog());
checkAdditionDialogFront->setChecked(pref->additionDialogFront());
checkStartPaused->setChecked(pref->addTorrentsInPause());
auto session = BitTorrent::Session::instance();
textSavePath->setText(Utils::Fs::toNativePath(pref->getSavePath()));
if (pref->isTempPathEnabled())
checkTempFolder->setChecked(true);
else
checkTempFolder->setChecked(false);
textTempPath->setText(Utils::Fs::toNativePath(pref->getTempPath()));
checkAppendLabel->setChecked(pref->appendTorrentLabel());
// Downloads preferences
checkAdditionDialog->setChecked(AddNewTorrentDialog::isEnabled());
checkAdditionDialogFront->setChecked(AddNewTorrentDialog::isTopLevel());
checkStartPaused->setChecked(session->isAddTorrentPaused());
textSavePath->setText(Utils::Fs::toNativePath(session->defaultSavePath()));
(session->isSubcategoriesEnabled() ? radioBtnEnableSubcategories : radioBtnDisableSubcategories)->setChecked(true);
(session->isASMDisabledByDefault() ? radioBtnSimpleMode : radioBtnAdvancedMode)->setChecked(true);
(session->isDisableASMWhenCategoryChanged() ? radioBtnDisableASMOnCategoryChanged : radioBtnRelocateOnCategoryChanged)->setChecked(true);
(session->isDisableASMWhenCategorySavePathChanged() ? radioBtnDisableASMOnCategorySavePathChanged : radioBtnRelocateOnCategorySavePathChanged)->setChecked(true);
(session->isDisableASMWhenDefaultSavePathChanged() ? radioBtnDisableASMOnDefaultSavePathChanged : radioBtnRelocateOnDefaultSavePathChanged)->setChecked(true);
checkTempFolder->setChecked(session->isTempPathEnabled());
textTempPath->setText(Utils::Fs::toNativePath(session->tempPath()));
checkAppendqB->setChecked(pref->useIncompleteFilesExtension());
checkPreallocateAll->setChecked(pref->preAllocateAllFiles());
@@ -844,7 +858,7 @@ void options_imp::loadOptions()
spinMaxRatio->setEnabled(false);
comboRatioLimitAct->setEnabled(false);
}
comboRatioLimitAct->setCurrentIndex(static_cast<int>(pref->getMaxRatioAction()));
comboRatioLimitAct->setCurrentIndex(session->maxRatioAction());
// End Bittorrent preferences
// Web UI preferences
@@ -974,26 +988,6 @@ qreal options_imp::getMaxRatio() const
return -1;
}
// Return Save Path
QString options_imp::getSavePath() const
{
if (textSavePath->text().trimmed().isEmpty()) {
QString save_path = Preferences::instance()->getSavePath();
textSavePath->setText(Utils::Fs::toNativePath(save_path));
}
return Utils::Fs::expandPathAbs(textSavePath->text());
}
QString options_imp::getTempPath() const
{
return Utils::Fs::expandPathAbs(textTempPath->text());
}
bool options_imp::isTempPathEnabled() const
{
return checkTempFolder->isChecked();
}
// Return max connections number
int options_imp::getMaxConnecs() const
{

View File

@@ -114,9 +114,6 @@ private:
bool WinStartup() const;
#endif
// Downloads
QString getSavePath() const;
bool isTempPathEnabled() const;
QString getTempPath() const;
bool preAllocateAllFiles() const;
bool useAdditionDialog() const;
bool addTorrentsInPause() const;

View File

@@ -34,17 +34,18 @@
#include <QMenu>
#include <QCursor>
#include "automatedrssdownloader.h"
#include "ui_automatedrssdownloader.h"
#include "base/rss/rssdownloadrulelist.h"
#include "base/preferences.h"
#include "base/bittorrent/session.h"
#include "base/rss/rssdownloadrulelist.h"
#include "base/rss/rssmanager.h"
#include "base/rss/rssfolder.h"
#include "base/rss/rssfeed.h"
#include "guiiconprovider.h"
#include "autoexpandabledialog.h"
#include "base/utils/fs.h"
#include "base/utils/string.h"
#include "guiiconprovider.h"
#include "autoexpandabledialog.h"
#include "ui_automatedrssdownloader.h"
#include "automatedrssdownloader.h"
AutomatedRssDownloader::AutomatedRssDownloader(const QWeakPointer<Rss::Manager>& manager, QWidget *parent) :
QDialog(parent),
@@ -85,7 +86,7 @@ AutomatedRssDownloader::AutomatedRssDownloader(const QWeakPointer<Rss::Manager>&
"<li>" + tr("Normal range: <b>1x25-40;</b> matches episodes 25 through 40 of season one") + "</li>" +
"<li>" + tr("Infinite range: <b>1x25-;</b> matches episodes 25 and upward of season one") + "</li>" + "</ul></li></ul>";
ui->lineEFilter->setToolTip(tip);
initLabelCombobox();
initCategoryCombobox();
loadFeedList();
loadSettings();
ok = connect(ui->listRules, SIGNAL(itemSelectionChanged()), SLOT(updateRuleDefinitionBox()));
@@ -253,11 +254,11 @@ void AutomatedRssDownloader::updateRuleDefinitionBox()
ui->checkRegex->blockSignals(true);
ui->checkRegex->setChecked(rule->useRegex());
ui->checkRegex->blockSignals(false);
if (rule->label().isEmpty()) {
ui->comboLabel->setCurrentIndex(-1);
ui->comboLabel->clearEditText();
if (rule->category().isEmpty()) {
ui->comboCategory->setCurrentIndex(-1);
ui->comboCategory->clearEditText();
} else {
ui->comboLabel->setCurrentIndex(ui->comboLabel->findText(rule->label()));
ui->comboCategory->setCurrentIndex(ui->comboCategory->findText(rule->category()));
}
ui->comboAddPaused->setCurrentIndex(rule->addPaused());
ui->spinIgnorePeriod->setValue(rule->ignoreDays());
@@ -293,7 +294,7 @@ void AutomatedRssDownloader::clearRuleDefinitionBox()
ui->lineNotContains->clear();
ui->saveDiffDir_check->setChecked(false);
ui->lineSavePath->clear();
ui->comboLabel->clearEditText();
ui->comboCategory->clearEditText();
ui->checkRegex->setChecked(false);
ui->spinIgnorePeriod->setValue(0);
updateFieldsToolTips(ui->checkRegex->isChecked());
@@ -309,13 +310,12 @@ Rss::DownloadRulePtr AutomatedRssDownloader::getCurrentRule() const
return Rss::DownloadRulePtr();
}
void AutomatedRssDownloader::initLabelCombobox()
void AutomatedRssDownloader::initCategoryCombobox()
{
// Load custom labels
QStringList customLabels = Preferences::instance()->getTorrentLabels();
std::sort(customLabels.begin(), customLabels.end(), Utils::String::NaturalCompare());
foreach (const QString& l, customLabels)
ui->comboLabel->addItem(l);
// Load torrent categories
QStringList categories = BitTorrent::Session::instance()->categories();
std::sort(categories.begin(), categories.end(), Utils::String::NaturalCompare());
ui->comboCategory->addItems(categories);
}
void AutomatedRssDownloader::saveEditedRule()
@@ -344,11 +344,9 @@ void AutomatedRssDownloader::saveEditedRule()
rule->setSavePath(ui->lineSavePath->text());
else
rule->setSavePath("");
rule->setLabel(ui->comboLabel->currentText());
rule->setCategory(ui->comboCategory->currentText());
rule->setAddPaused(Rss::DownloadRule::AddPausedState(ui->comboAddPaused->currentIndex()));
// Save new label
if (!rule->label().isEmpty())
Preferences::instance()->addTorrentLabelExternal(rule->label());
rule->setIgnoreDays(ui->spinIgnorePeriod->value());
//rule->setRssFeeds(getSelectedFeeds());
// Save it

View File

@@ -90,7 +90,7 @@ private slots:
private:
Rss::DownloadRulePtr getCurrentRule() const;
void initLabelCombobox();
void initCategoryCombobox();
void addFeedArticlesToTree(const Rss::FeedPtr& feed, const QStringList& articles);
private:

View File

@@ -177,14 +177,14 @@
</sizepolicy>
</property>
<property name="text">
<string>Assign Label:</string>
<string>Assign Category:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboLabel">
<widget class="QComboBox" name="comboCategory">
<property name="editable">
<bool>true</bool>
<bool>false</bool>
</property>
</widget>
</item>

View File

@@ -352,7 +352,7 @@ void RSSImp::downloadSelectedTorrents()
if (article->torrentUrl().isEmpty())
continue;
if (Preferences::instance()->useAdditionDialog())
if (AddNewTorrentDialog::isEnabled())
AddNewTorrentDialog::show(article->torrentUrl());
else
BitTorrent::Session::instance()->addTorrent(article->torrentUrl());

View File

@@ -36,7 +36,7 @@
#include <QItemSelectionModel>
#include "base/scanfoldersmodel.h"
#include "base/preferences.h"
#include "base/bittorrent/session.h"
#include "scanfoldersdelegate.h"
@@ -102,7 +102,7 @@ void ScanFoldersDelegate::setModelData(QWidget *editor, QAbstractItemModel *mode
0, tr("Choose save path"),
index.data(Qt::UserRole).toInt() == ScanFoldersModel::CUSTOM_LOCATION ?
index.data().toString() :
Preferences::instance()->getSavePath()),
BitTorrent::Session::instance()->defaultSavePath()),
Qt::DisplayRole);
break;

View File

@@ -259,7 +259,7 @@ void SearchWidget::saveResultsColumnsWidth()
void SearchWidget::downloadTorrent(QString url)
{
if (Preferences::instance()->useAdditionDialog())
if (AddNewTorrentDialog::isEnabled())
AddNewTorrentDialog::show(url, this);
else
BitTorrent::Session::instance()->addTorrent(url);

View File

@@ -104,7 +104,7 @@ QVariant TorrentModel::headerData(int section, Qt::Orientation orientation, int
case TR_UPSPEED: return tr("Up Speed", "i.e: Upload speed");
case TR_RATIO: return tr("Ratio", "Share ratio");
case TR_ETA: return tr("ETA", "i.e: Estimated Time of Arrival / Time left");
case TR_LABEL: return tr("Label");
case TR_CATEGORY: return tr("Category");
case TR_ADD_DATE: return tr("Added On", "Torrent was added to transfer list on 01/01/2010 08:00");
case TR_SEED_DATE: return tr("Completed On", "Torrent was completed on 01/01/2010 08:00");
case TR_TRACKER: return tr("Tracker");
@@ -196,8 +196,8 @@ QVariant TorrentModel::data(const QModelIndex &index, int role) const
return torrent->eta();
case TR_RATIO:
return torrent->realRatio();
case TR_LABEL:
return torrent->label();
case TR_CATEGORY:
return torrent->category();
case TR_ADD_DATE:
return torrent->addedTime();
case TR_SEED_DATE:
@@ -250,13 +250,13 @@ bool TorrentModel::setData(const QModelIndex &index, const QVariant &value, int
BitTorrent::TorrentHandle *const torrent = m_torrents.value(index.row());
if (!torrent) return false;
// Label, seed date and Name columns can be edited
// Category, seed date and Name columns can be edited
switch(index.column()) {
case TR_NAME:
torrent->setName(value.toString());
break;
case TR_LABEL:
torrent->setLabel(value.toString());
case TR_CATEGORY:
torrent->setCategory(value.toString());
break;
default:
return false;

View File

@@ -61,7 +61,7 @@ public:
TR_UPSPEED,
TR_ETA,
TR_RATIO,
TR_LABEL,
TR_CATEGORY,
TR_ADD_DATE,
TR_SEED_DATE,
TR_TRACKER,

View File

@@ -177,162 +177,156 @@ void StatusFiltersWidget::handleNewTorrent(BitTorrent::TorrentHandle *const) {}
void StatusFiltersWidget::torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const) {}
LabelFiltersList::LabelFiltersList(QWidget *parent, TransferListWidget *transferList)
CategoryFiltersList::CategoryFiltersList(QWidget *parent, TransferListWidget *transferList)
: FiltersBase(parent, transferList)
, m_totalTorrents(0)
, m_totalLabeled(0)
{
connect(BitTorrent::Session::instance(), SIGNAL(torrentLabelChanged(BitTorrent::TorrentHandle *const, QString)), SLOT(torrentChangedLabel(BitTorrent::TorrentHandle *const, QString)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString)), SLOT(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString)));
connect(BitTorrent::Session::instance(), SIGNAL(categoryAdded(QString)), SLOT(addItem(QString)));
connect(BitTorrent::Session::instance(), SIGNAL(categoryRemoved(QString)), SLOT(categoryRemoved(QString)));
connect(BitTorrent::Session::instance(), SIGNAL(subcategoriesSupportChanged()), SLOT(subcategoriesSupportChanged()));
// Add Label filters
QListWidgetItem *allLabels = new QListWidgetItem(this);
allLabels->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the label filter")));
allLabels->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
QListWidgetItem *noLabel = new QListWidgetItem(this);
noLabel->setData(Qt::DisplayRole, QVariant(tr("Unlabeled (0)")));
noLabel->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
refresh();
toggleFilter(Preferences::instance()->getCategoryFilterState());
}
const Preferences* const pref = Preferences::instance();
QStringList labelList = pref->getTorrentLabels();
for (int i=0; i < labelList.size(); ++i)
addItem(labelList[i], false);
void CategoryFiltersList::refresh()
{
clear();
m_categories.clear();
m_totalTorrents = 0;
m_totalCategorized = 0;
QListWidgetItem *allCategories = new QListWidgetItem(this);
allCategories->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the category filter")));
allCategories->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
QListWidgetItem *noCategory = new QListWidgetItem(this);
noCategory->setData(Qt::DisplayRole, QVariant(tr("Uncategorized (0)")));
noCategory->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
foreach (const QString &category, BitTorrent::Session::instance()->categories())
addItem(category, false);
foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents())
handleNewTorrent(torrent);
setCurrentRow(0, QItemSelectionModel::SelectCurrent);
toggleFilter(pref->getLabelFilterState());
}
LabelFiltersList::~LabelFiltersList()
void CategoryFiltersList::addItem(const QString &category, bool hasTorrent)
{
Preferences::instance()->setTorrentLabels(m_labels.keys());
}
if (category.isEmpty()) return;
void LabelFiltersList::addItem(QString &label, bool hasTorrent)
{
int labelCount = 0;
QListWidgetItem *labelItem = 0;
label = Utils::Fs::toValidFileSystemName(label.trimmed());
item(0)->setText(tr("All (%1)", "this is for the label filter").arg(m_totalTorrents));
int torrentsInCategory = 0;
QListWidgetItem *categoryItem = 0;
if (label.isEmpty()) {
item(1)->setText(tr("Unlabeled (%1)").arg(m_totalTorrents - m_totalLabeled));
return;
}
bool exists = m_labels.contains(label);
bool exists = m_categories.contains(category);
if (exists) {
labelCount = m_labels.value(label);
labelItem = item(rowFromLabel(label));
torrentsInCategory = m_categories.value(category);
categoryItem = item(rowFromCategory(category));
}
else {
labelItem = new QListWidgetItem();
labelItem->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
categoryItem = new QListWidgetItem();
categoryItem->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
}
if (hasTorrent) {
++m_totalLabeled;
++labelCount;
}
item(1)->setText(tr("Unlabeled (%1)").arg(m_totalTorrents - m_totalLabeled));
if (hasTorrent)
++torrentsInCategory;
Preferences::instance()->addTorrentLabel(label);
m_labels.insert(label, labelCount);
labelItem->setText(tr("%1 (%2)", "label_name (10)").arg(label).arg(labelCount));
if (exists)
return;
m_categories.insert(category, torrentsInCategory);
categoryItem->setText(tr("%1 (%2)", "category_name (10)").arg(category).arg(torrentsInCategory));
if (exists) return;
Q_ASSERT(count() >= 2);
for (int i = 2; i<count(); ++i) {
for (int i = 2; i < count(); ++i) {
bool less = false;
if (!(Utils::String::naturalSort(label, item(i)->text(), less)))
less = (label.localeAwareCompare(item(i)->text()) < 0);
if (!(Utils::String::naturalSort(category, item(i)->text(), less)))
less = (category.localeAwareCompare(item(i)->text()) < 0);
if (less) {
insertItem(i, labelItem);
insertItem(i, categoryItem);
updateGeometry();
return;
}
}
QListWidget::addItem(labelItem);
QListWidget::addItem(categoryItem);
updateGeometry();
}
void LabelFiltersList::removeItem(const QString &label)
void CategoryFiltersList::removeItem(const QString &category)
{
item(0)->setText(tr("All (%1)", "this is for the label filter").arg(m_totalTorrents));
if (label.isEmpty()) {
// In case we here from torrentAboutToBeDeleted()
item(1)->setText(tr("Unlabeled (%1)").arg(m_totalTorrents - m_totalLabeled));
return;
}
if (category.isEmpty()) return;
--m_totalLabeled;
item(1)->setText(tr("Unlabeled (%1)").arg(m_totalTorrents - m_totalLabeled));
int torrentsInCategory = m_categories.value(category) - 1;
int row = rowFromCategory(category);
if (row < 2) return;
int labelCount = m_labels.value(label) - 1;
int row = rowFromLabel(label);
if (row < 2)
return;
QListWidgetItem *labelItem = item(row);
labelItem->setText(tr("%1 (%2)", "label_name (10)").arg(label).arg(labelCount));
m_labels.insert(label, labelCount);
QListWidgetItem *categoryItem = item(row);
categoryItem->setText(tr("%1 (%2)", "category_name (10)").arg(category).arg(torrentsInCategory));
m_categories.insert(category, torrentsInCategory);
}
void LabelFiltersList::removeSelectedLabel()
void CategoryFiltersList::removeSelectedCategory()
{
QList<QListWidgetItem*> items = selectedItems();
if (items.size() == 0) return;
const int labelRow = row(items.first());
if (labelRow < 2) return;
const int categoryRow = row(items.first());
if (categoryRow < 2) return;
const QString &label = labelFromRow(labelRow);
Q_ASSERT(m_labels.contains(label));
m_labels.remove(label);
// Select first label
setCurrentRow(0, QItemSelectionModel::SelectCurrent);
// Un display filter
delete takeItem(labelRow);
transferList->removeLabelFromRows(label);
// Save custom labels to remember it was deleted
Preferences::instance()->removeTorrentLabel(label);
BitTorrent::Session::instance()->removeCategory(categoryFromRow(categoryRow));
updateGeometry();
}
void LabelFiltersList::removeUnusedLabels()
void CategoryFiltersList::removeUnusedCategories()
{
QStringList unusedLabels;
QHash<QString, int>::const_iterator i;
for (i = m_labels.begin(); i != m_labels.end(); ++i) {
if (i.value() == 0)
unusedLabels << i.key();
}
foreach (const QString &label, unusedLabels) {
m_labels.remove(label);
delete takeItem(rowFromLabel(label));
Preferences::instance()->removeTorrentLabel(label);
}
if (!unusedLabels.isEmpty())
updateGeometry();
foreach (const QString &category, m_categories.keys())
if (m_categories[category] == 0)
BitTorrent::Session::instance()->removeCategory(category);
updateGeometry();
}
void LabelFiltersList::torrentChangedLabel(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel)
void CategoryFiltersList::torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory)
{
qDebug("Torrent label changed from %s to %s", qPrintable(oldLabel), qPrintable(torrent->label()));
removeItem(oldLabel);
QString newLabel = torrent->label();
addItem(newLabel, true);
qDebug() << "Torrent category changed from" << oldCategory << "to" << torrent->category();
if (torrent->category().isEmpty() && !oldCategory.isEmpty())
--m_totalCategorized;
else if (!torrent->category().isEmpty() && oldCategory.isEmpty())
++m_totalCategorized;
item(1)->setText(tr("Uncategorized (%1)").arg(m_totalTorrents - m_totalCategorized));
if (BitTorrent::Session::instance()->isSubcategoriesEnabled()) {
foreach (const QString &subcategory, BitTorrent::Session::expandCategory(oldCategory))
removeItem(subcategory);
foreach (const QString &subcategory, BitTorrent::Session::expandCategory(torrent->category()))
addItem(subcategory, true);
}
else {
removeItem(oldCategory);
addItem(torrent->category(), true);
}
}
void LabelFiltersList::showMenu(QPoint)
void CategoryFiltersList::categoryRemoved(const QString &category)
{
m_categories.remove(category);
delete takeItem(rowFromCategory(category));
}
void CategoryFiltersList::subcategoriesSupportChanged()
{
refresh();
}
void CategoryFiltersList::showMenu(QPoint)
{
QMenu menu(this);
QAction *addAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("Add label..."));
QAction *addAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("Add category..."));
QAction *removeAct = 0;
QAction *removeUnusedAct = 0;
if (!selectedItems().empty() && row(selectedItems().first()) > 1)
removeAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove label"));
removeUnusedAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove unused labels"));
removeAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove category"));
removeUnusedAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove unused categories"));
menu.addSeparator();
QAction *startAct = menu.addAction(GuiIconProvider::instance()->getIcon("media-playback-start"), tr("Resume torrents"));
QAction *pauseAct = menu.addAction(GuiIconProvider::instance()->getIcon("media-playback-pause"), tr("Pause torrents"));
@@ -343,10 +337,10 @@ void LabelFiltersList::showMenu(QPoint)
return;
if (act == removeAct) {
removeSelectedLabel();
removeSelectedCategory();
}
else if (act == removeUnusedAct) {
removeUnusedLabels();
removeUnusedCategories();
}
else if (act == deleteTorrentsAct) {
transferList->deleteVisibleTorrents();
@@ -359,64 +353,90 @@ void LabelFiltersList::showMenu(QPoint)
}
else if (act == addAct) {
bool ok;
QString label = "";
QString category = "";
bool invalid;
do {
invalid = false;
label = AutoExpandableDialog::getText(this, tr("New Label"), tr("Label:"), QLineEdit::Normal, label, &ok);
if (ok && !label.isEmpty()) {
if (Utils::Fs::isValidFileSystemName(label)) {
addItem(label, false);
category = AutoExpandableDialog::getText(this, tr("New Category"), tr("Category:"), QLineEdit::Normal, category, &ok);
if (ok && !category.isEmpty()) {
if (!BitTorrent::Session::isValidCategoryName(category)) {
QMessageBox::warning(this, tr("Invalid category name"),
tr("Category name must not contain '\\'.\n"
"Category name must not start/end with '/'.\n"
"Category name must not contain '//' sequence."));
invalid = true;
}
else {
QMessageBox::warning(this, tr("Invalid label name"), tr("Please don't use any special characters in the label name."));
invalid = true;
BitTorrent::Session::instance()->addCategory(category);
}
}
} while (invalid);
}
}
void LabelFiltersList::applyFilter(int row)
void CategoryFiltersList::applyFilter(int row)
{
transferList->applyLabelFilter(labelFromRow(row));
if (row >= 0)
transferList->applyCategoryFilter(categoryFromRow(row));
}
void LabelFiltersList::handleNewTorrent(BitTorrent::TorrentHandle *const torrent)
void CategoryFiltersList::handleNewTorrent(BitTorrent::TorrentHandle *const torrent)
{
Q_ASSERT(torrent);
++m_totalTorrents;
QString label = torrent->label();
addItem(label, true);
// FIXME: Drop this confusion.
// labelFilters->addItem() may have changed the label, update the model accordingly.
torrent->setLabel(label);
if (!torrent->category().isEmpty())
++m_totalCategorized;
item(0)->setText(tr("All (%1)", "this is for the category filter").arg(m_totalTorrents));
item(1)->setText(tr("Uncategorized (%1)").arg(m_totalTorrents - m_totalCategorized));
if (BitTorrent::Session::instance()->isSubcategoriesEnabled()) {
foreach (const QString &subcategory, BitTorrent::Session::expandCategory(torrent->category()))
addItem(subcategory, true);
}
else {
addItem(torrent->category(), true);
}
}
void LabelFiltersList::torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent)
void CategoryFiltersList::torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent)
{
Q_ASSERT(torrent);
--m_totalTorrents;
removeItem(torrent->label());
if (!torrent->category().isEmpty())
--m_totalCategorized;
item(0)->setText(tr("All (%1)", "this is for the category filter").arg(m_totalTorrents));
item(1)->setText(tr("Uncategorized (%1)").arg(m_totalTorrents - m_totalCategorized));
if (BitTorrent::Session::instance()->isSubcategoriesEnabled()) {
foreach (const QString &subcategory, BitTorrent::Session::expandCategory(torrent->category()))
removeItem(subcategory);
}
else {
removeItem(torrent->category());
}
}
QString LabelFiltersList::labelFromRow(int row) const
QString CategoryFiltersList::categoryFromRow(int row) const
{
if (row == 0) return QString(); // All
if (row == 1) return QLatin1String(""); // Unlabeled
if (row == 1) return QLatin1String(""); // Uncategorized
const QString &label = item(row)->text();
QStringList parts = label.split(" ");
const QString &category = item(row)->text();
QStringList parts = category.split(" ");
Q_ASSERT(parts.size() >= 2);
parts.removeLast(); // Remove trailing number
return parts.join(" ");
}
int LabelFiltersList::rowFromLabel(const QString &label) const
int CategoryFiltersList::rowFromCategory(const QString &category) const
{
Q_ASSERT(!label.isEmpty());
Q_ASSERT(!category.isEmpty());
for (int i = 2; i<count(); ++i)
if (label == labelFromRow(i)) return i;
if (category == categoryFromRow(i)) return i;
return -1;
}
@@ -425,7 +445,7 @@ TrackerFiltersList::TrackerFiltersList(QWidget *parent, TransferListWidget *tran
, m_totalTorrents(0)
{
QListWidgetItem *allTrackers = new QListWidgetItem(this);
allTrackers->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the label filter")));
allTrackers->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the tracker filter")));
allTrackers->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("network-server"));
QListWidgetItem *noTracker = new QListWidgetItem(this);
noTracker->setData(Qt::DisplayRole, QVariant(tr("Trackerless (0)")));
@@ -799,13 +819,13 @@ TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferLi
StatusFiltersWidget *statusFilters = new StatusFiltersWidget(this, transferList);
frameLayout->addWidget(statusFilters);
QCheckBox *labelLabel = new QCheckBox(tr("Labels"), this);
labelLabel->setChecked(pref->getLabelFilterState());
labelLabel->setFont(font);
frameLayout->addWidget(labelLabel);
QCheckBox *categoryLabel = new QCheckBox(tr("Categories"), this);
categoryLabel->setChecked(pref->getCategoryFilterState());
categoryLabel->setFont(font);
frameLayout->addWidget(categoryLabel);
LabelFiltersList *labelFilters = new LabelFiltersList(this, transferList);
frameLayout->addWidget(labelFilters);
CategoryFiltersList *categoryFilters = new CategoryFiltersList(this, transferList);
frameLayout->addWidget(categoryFilters);
QCheckBox *trackerLabel = new QCheckBox(tr("Trackers"), this);
trackerLabel->setChecked(pref->getTrackerFilterState());
@@ -817,9 +837,8 @@ TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferLi
connect(statusLabel, SIGNAL(toggled(bool)), statusFilters, SLOT(toggleFilter(bool)));
connect(statusLabel, SIGNAL(toggled(bool)), pref, SLOT(setStatusFilterState(const bool)));
connect(labelLabel, SIGNAL(toggled(bool)), labelFilters, SLOT(toggleFilter(bool)));
connect(labelLabel, SIGNAL(toggled(bool)), pref, SLOT(setLabelFilterState(const bool)));
connect(pref, SIGNAL(externalLabelAdded(QString&)), labelFilters, SLOT(addItem(QString&)));
connect(categoryLabel, SIGNAL(toggled(bool)), categoryFilters, SLOT(toggleFilter(bool)));
connect(categoryLabel, SIGNAL(toggled(bool)), pref, SLOT(setCategoryFilterState(const bool)));
connect(trackerLabel, SIGNAL(toggled(bool)), trackerFilters, SLOT(toggleFilter(bool)));
connect(trackerLabel, SIGNAL(toggled(bool)), pref, SLOT(setTrackerFilterState(const bool)));
connect(this, SIGNAL(trackerSuccess(const QString &, const QString &)), trackerFilters, SLOT(trackerSuccess(const QString &, const QString &)));

View File

@@ -90,22 +90,22 @@ private:
virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const);
};
class LabelFiltersList: public FiltersBase
class CategoryFiltersList: public FiltersBase
{
Q_OBJECT
public:
LabelFiltersList(QWidget *parent, TransferListWidget *transferList);
~LabelFiltersList();
CategoryFiltersList(QWidget *parent, TransferListWidget *transferList);
private slots:
// Redefine addItem() to make sure the list stays sorted
void addItem(QString &label, bool hasTorrent = false);
void removeItem(const QString &label);
void removeSelectedLabel();
void removeUnusedLabels();
void torrentChangedLabel(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel);
void addItem(const QString &category, bool hasTorrent = false);
void removeItem(const QString &category);
void removeSelectedCategory();
void removeUnusedCategories();
void torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory);
void categoryRemoved(const QString &category);
void subcategoriesSupportChanged();
private:
// These 4 methods are virtual slots in the base class.
@@ -114,13 +114,14 @@ private:
virtual void applyFilter(int row);
virtual void handleNewTorrent(BitTorrent::TorrentHandle *const torrent);
virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent);
QString labelFromRow(int row) const;
int rowFromLabel(const QString &label) const;
QString categoryFromRow(int row) const;
int rowFromCategory(const QString &category) const;
void refresh();
private:
QHash<QString, int> m_labels;
QHash<QString, int> m_categories;
int m_totalTorrents;
int m_totalLabeled;
int m_totalCategorized;
};
class TrackerFiltersList: public FiltersBase

View File

@@ -47,15 +47,15 @@ void TransferListSortModel::setStatusFilter(TorrentFilter::Type filter)
invalidateFilter();
}
void TransferListSortModel::setLabelFilter(const QString &label)
void TransferListSortModel::setCategoryFilter(const QString &category)
{
if (m_filter.setLabel(label))
if (m_filter.setCategory(category))
invalidateFilter();
}
void TransferListSortModel::disableLabelFilter()
void TransferListSortModel::disableCategoryFilter()
{
if (m_filter.setLabel(TorrentFilter::AnyLabel))
if (m_filter.setCategory(TorrentFilter::AnyCategory))
invalidateFilter();
}

View File

@@ -44,8 +44,8 @@ public:
TransferListSortModel(QObject *parent = 0);
void setStatusFilter(TorrentFilter::Type filter);
void setLabelFilter(const QString &label);
void disableLabelFilter();
void setCategoryFilter(const QString &category);
void disableCategoryFilter();
void setTrackerFilter(const QStringList &hashes);
void disableTrackerFilter();

View File

@@ -60,6 +60,7 @@
#include "propertieswidget.h"
#include "guiiconprovider.h"
#include "base/utils/fs.h"
#include "base/utils/string.h"
#include "autoexpandabledialog.h"
#include "transferlistsortmodel.h"
@@ -565,21 +566,30 @@ void TransferListWidget::toggleSelectedFirstLastPiecePrio() const
torrent->toggleFirstLastPiecePriority();
}
void TransferListWidget::askNewLabelForSelection()
void TransferListWidget::setSelectedASMEnabled(bool enabled) const
{
// Ask for label
foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents())
torrent->setASMEnabled(enabled);
}
void TransferListWidget::askNewCategoryForSelection()
{
// Ask for category
bool ok;
bool invalid;
do {
invalid = false;
const QString label = AutoExpandableDialog::getText(this, tr("New Label"), tr("Label:"), QLineEdit::Normal, "", &ok).trimmed();
if (ok && !label.isEmpty()) {
if (Utils::Fs::isValidFileSystemName(label)) {
setSelectionLabel(label);
const QString category = AutoExpandableDialog::getText(this, tr("New Category"), tr("Category:"), QLineEdit::Normal, "", &ok).trimmed();
if (ok && !category.isEmpty()) {
if (!BitTorrent::Session::isValidCategoryName(category)) {
QMessageBox::warning(this, tr("Invalid category name"),
tr("Category name must not contain '\\'.\n"
"Category name must not start/end with '/'.\n"
"Category name must not contain '//' sequence."));
invalid = true;
}
else {
QMessageBox::warning(this, tr("Invalid label name"), tr("Please don't use any special characters in the label name."));
invalid = true;
setSelectionCategory(category);
}
}
} while(invalid);
@@ -605,19 +615,10 @@ void TransferListWidget::renameSelectedTorrent()
}
}
void TransferListWidget::setSelectionLabel(QString label)
void TransferListWidget::setSelectionCategory(QString category)
{
foreach (const QModelIndex &index, selectionModel()->selectedRows())
listModel->setData(listModel->index(mapToSource(index).row(), TorrentModel::TR_LABEL), label, Qt::DisplayRole);
}
void TransferListWidget::removeLabelFromRows(QString label)
{
for (int i = 0; i < listModel->rowCount(); ++i) {
if (listModel->data(listModel->index(i, TorrentModel::TR_LABEL)) == label) {
listModel->setData(listModel->index(i, TorrentModel::TR_LABEL), "", Qt::DisplayRole);
}
}
listModel->setData(listModel->index(mapToSource(index).row(), TorrentModel::TR_CATEGORY), category, Qt::DisplayRole);
}
void TransferListWidget::displayListMenu(const QPoint&)
@@ -671,6 +672,9 @@ void TransferListWidget::displayListMenu(const QPoint&)
QAction actionFirstLastPiece_prio(tr("Download first and last pieces first"), 0);
actionFirstLastPiece_prio.setCheckable(true);
connect(&actionFirstLastPiece_prio, SIGNAL(triggered()), this, SLOT(toggleSelectedFirstLastPiecePrio()));
QAction actionEnableASM(tr("Enable Advanced Saving Management"), 0);
actionEnableASM.setCheckable(true);
connect(&actionEnableASM, SIGNAL(triggered(bool)), this, SLOT(setSelectedASMEnabled(bool)));
// End of actions
// Enable/disable pause/start action given the DL state
@@ -680,8 +684,10 @@ void TransferListWidget::displayListMenu(const QPoint&)
bool all_same_sequential_download_mode = true, all_same_prio_firstlast = true;
bool sequential_download_mode = false, prioritize_first_last = false;
bool one_has_metadata = false, one_not_seed = false;
bool all_same_label = true;
QString first_label;
bool allSameCategory = true;
bool allSameASM = true;
bool firstASM = false;
QString firstCategory;
bool first = true;
BitTorrent::TorrentHandle *torrent;
@@ -692,10 +698,15 @@ void TransferListWidget::displayListMenu(const QPoint&)
torrent = listModel->torrentHandle(mapToSource(index));
if (!torrent) continue;
if (first_label.isEmpty() && first)
first_label = torrent->label();
if (firstCategory.isEmpty() && first)
firstCategory = torrent->category();
if (firstCategory != torrent->category())
allSameCategory = false;
all_same_label = (first_label == torrent->label());
if (first)
firstASM = torrent->isASMEnabled();
if (firstASM != torrent->isASMEnabled())
allSameASM = false;
if (torrent->hasMetadata())
one_has_metadata = true;
@@ -738,8 +749,8 @@ void TransferListWidget::displayListMenu(const QPoint&)
first = false;
if (one_has_metadata && one_not_seed && !all_same_sequential_download_mode
&& !all_same_prio_firstlast && !all_same_super_seeding && !all_same_label
&& needs_start && needs_force && needs_pause && needs_preview) {
&& !all_same_prio_firstlast && !all_same_super_seeding && !allSameCategory
&& needs_start && needs_force && needs_pause && needs_preview && !allSameASM) {
break;
}
}
@@ -756,24 +767,30 @@ void TransferListWidget::displayListMenu(const QPoint&)
listMenu.addAction(&actionSetTorrentPath);
if (selectedIndexes.size() == 1)
listMenu.addAction(&actionRename);
// Label Menu
QStringList customLabels = Preferences::instance()->getTorrentLabels();
customLabels.sort();
QList<QAction*> labelActions;
QMenu *labelMenu = listMenu.addMenu(GuiIconProvider::instance()->getIcon("view-categories"), tr("Label"));
labelActions << labelMenu->addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("New...", "New label..."));
labelActions << labelMenu->addAction(GuiIconProvider::instance()->getIcon("edit-clear"), tr("Reset", "Reset label"));
labelMenu->addSeparator();
foreach (QString label, customLabels) {
label.replace('&', "&&"); // avoid '&' becomes accelerator key
QAction *lb = new QAction(GuiIconProvider::instance()->getIcon("inode-directory"), label, labelMenu);
if (all_same_label && (label == first_label)) {
lb->setCheckable(true);
lb->setChecked(true);
// Category Menu
QStringList categories = BitTorrent::Session::instance()->categories();
std::sort(categories.begin(), categories.end(), Utils::String::NaturalCompare());
QList<QAction*> categoryActions;
QMenu *categoryMenu = listMenu.addMenu(GuiIconProvider::instance()->getIcon("view-categories"), tr("Category"));
categoryActions << categoryMenu->addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("New...", "New category..."));
categoryActions << categoryMenu->addAction(GuiIconProvider::instance()->getIcon("edit-clear"), tr("Reset", "Reset category"));
categoryMenu->addSeparator();
foreach (QString category, categories) {
category.replace('&', "&&"); // avoid '&' becomes accelerator key
QAction *cat = new QAction(GuiIconProvider::instance()->getIcon("inode-directory"), category, categoryMenu);
if (allSameCategory && (category == firstCategory)) {
cat->setCheckable(true);
cat->setChecked(true);
}
labelMenu->addAction(lb);
labelActions << lb;
categoryMenu->addAction(cat);
categoryActions << cat;
}
if (allSameASM) {
actionEnableASM.setChecked(firstASM);
listMenu.addAction(&actionEnableASM);
}
listMenu.addSeparator();
if (one_not_seed)
listMenu.addAction(&actionSet_download_limit);
@@ -801,6 +818,7 @@ void TransferListWidget::displayListMenu(const QPoint&)
added_preview_action = true;
}
}
if (added_preview_action)
listMenu.addSeparator();
if (one_has_metadata) {
@@ -823,20 +841,20 @@ void TransferListWidget::displayListMenu(const QPoint&)
QAction *act = 0;
act = listMenu.exec(QCursor::pos());
if (act) {
// Parse label actions only (others have slots assigned)
int i = labelActions.indexOf(act);
// Parse category actions only (others have slots assigned)
int i = categoryActions.indexOf(act);
if (i >= 0) {
// Label action
// Category action
if (i == 0) {
// New Label
askNewLabelForSelection();
// New Category
askNewCategoryForSelection();
}
else {
QString label = "";
QString category = "";
if (i > 1)
label = customLabels.at(i - 2);
// Update Label
setSelectionLabel(label);
category = categories.at(i - 2);
// Update Category
setSelectionCategory(category);
}
}
}
@@ -854,12 +872,12 @@ void TransferListWidget::currentChanged(const QModelIndex& current, const QModel
emit currentTorrentChanged(torrent);
}
void TransferListWidget::applyLabelFilter(QString label)
void TransferListWidget::applyCategoryFilter(QString category)
{
if (label.isNull())
nameFilterModel->disableLabelFilter();
if (category.isNull())
nameFilterModel->disableCategoryFilter();
else
nameFilterModel->setLabelFilter(label);
nameFilterModel->setCategoryFilter(category);
}
void TransferListWidget::applyTrackerFilterAll()

View File

@@ -59,7 +59,7 @@ public:
TorrentModel* getSourceModel() const;
public slots:
void setSelectionLabel(QString label);
void setSelectionCategory(QString category);
void setSelectedTorrentsLocation();
void pauseAllTorrents();
void resumeAllTorrents();
@@ -86,11 +86,10 @@ public slots:
void displayDLHoSMenu(const QPoint&);
void applyNameFilter(const QString& name);
void applyStatusFilter(int f);
void applyLabelFilter(QString label);
void applyCategoryFilter(QString category);
void applyTrackerFilterAll();
void applyTrackerFilter(const QStringList &hashes);
void previewFile(QString filePath);
void removeLabelFromRows(QString label);
void renameSelectedTorrent();
protected:
@@ -106,7 +105,8 @@ protected slots:
void toggleSelectedTorrentsSuperSeeding() const;
void toggleSelectedTorrentsSequentialDownload() const;
void toggleSelectedFirstLastPiecePrio() const;
void askNewLabelForSelection();
void setSelectedASMEnabled(bool enabled) const;
void askNewCategoryForSelection();
void saveSettings();
signals: