mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-11 15:56:17 -07:00
Improve "Watched folders" feature
Make "file system watcher" an application core component and separate it from its presentation model.
This commit is contained in:
parent
9565b695ef
commit
2993fdb169
29 changed files with 1636 additions and 1016 deletions
|
@ -43,6 +43,7 @@
|
|||
#include <QTranslator>
|
||||
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/exceptions.h"
|
||||
#include "base/global.h"
|
||||
#include "base/net/dnsupdater.h"
|
||||
#include "base/net/portforwarder.h"
|
||||
|
@ -50,8 +51,8 @@
|
|||
#include "base/preferences.h"
|
||||
#include "base/rss/rss_autodownloader.h"
|
||||
#include "base/rss/rss_session.h"
|
||||
#include "base/scanfoldersmodel.h"
|
||||
#include "base/torrentfileguard.h"
|
||||
#include "base/torrentfileswatcher.h"
|
||||
#include "base/unicodestrings.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/net.h"
|
||||
|
@ -63,10 +64,11 @@
|
|||
#include "banlistoptionsdialog.h"
|
||||
#include "ipsubnetwhitelistoptionsdialog.h"
|
||||
#include "rss/automatedrssdownloader.h"
|
||||
#include "scanfoldersdelegate.h"
|
||||
#include "ui_optionsdialog.h"
|
||||
#include "uithememanager.h"
|
||||
#include "utils.h"
|
||||
#include "watchedfolderoptionsdialog.h"
|
||||
#include "watchedfoldersmodel.h"
|
||||
|
||||
#define SETTINGS_KEY(name) "OptionsDialog/" name
|
||||
|
||||
|
@ -236,11 +238,12 @@ OptionsDialog::OptionsDialog(QWidget *parent)
|
|||
m_applyButton = m_ui->buttonBox->button(QDialogButtonBox::Apply);
|
||||
connect(m_applyButton, &QPushButton::clicked, this, &OptionsDialog::applySettings);
|
||||
|
||||
auto watchedFoldersModel = new WatchedFoldersModel(TorrentFilesWatcher::instance(), this);
|
||||
connect(watchedFoldersModel, &QAbstractListModel::dataChanged, this, &ThisType::enableApplyButton);
|
||||
m_ui->scanFoldersView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
m_ui->scanFoldersView->setModel(ScanFoldersModel::instance());
|
||||
m_ui->scanFoldersView->setItemDelegate(new ScanFoldersDelegate(this, m_ui->scanFoldersView));
|
||||
connect(ScanFoldersModel::instance(), &QAbstractListModel::dataChanged, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->scanFoldersView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ThisType::handleScanFolderViewSelectionChanged);
|
||||
m_ui->scanFoldersView->setModel(watchedFoldersModel);
|
||||
connect(m_ui->scanFoldersView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ThisType::handleWatchedFolderViewSelectionChanged);
|
||||
connect(m_ui->scanFoldersView, &QTreeView::doubleClicked, this, &ThisType::editWatchedFolderOptions);
|
||||
|
||||
// Languages supported
|
||||
initializeLanguageCombo();
|
||||
|
@ -368,8 +371,8 @@ OptionsDialog::OptionsDialog(QWidget *parent)
|
|||
connect(m_ui->actionTorrentFnOnDblClBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->checkTempFolder, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->checkTempFolder, &QAbstractButton::toggled, m_ui->textTempPath, &QWidget::setEnabled);
|
||||
connect(m_ui->addScanFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->removeScanFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->addWatchedFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->removeWatchedFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->groupMailNotification, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->senderEmailTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->lineEditDestEmail, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
|
||||
|
@ -609,9 +612,6 @@ OptionsDialog::~OptionsDialog()
|
|||
hSplitterSizes.append(QString::number(size));
|
||||
m_storeHSplitterSize = hSplitterSizes;
|
||||
|
||||
for (const QString &path : asConst(m_addedScanDirs))
|
||||
ScanFoldersModel::instance()->removePath(path);
|
||||
ScanFoldersModel::instance()->configure(); // reloads "removed" paths
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
@ -736,11 +736,8 @@ void OptionsDialog::saveOptions()
|
|||
AddNewTorrentDialog::setTopLevel(m_ui->checkAdditionDialogFront->isChecked());
|
||||
session->setAddTorrentPaused(addTorrentsInPause());
|
||||
session->setTorrentContentLayout(static_cast<BitTorrent::TorrentContentLayout>(m_ui->contentLayoutComboBox->currentIndex()));
|
||||
ScanFoldersModel::instance()->removeFromFSWatcher(m_removedScanDirs);
|
||||
ScanFoldersModel::instance()->addToFSWatcher(m_addedScanDirs);
|
||||
ScanFoldersModel::instance()->makePersistent();
|
||||
m_removedScanDirs.clear();
|
||||
m_addedScanDirs.clear();
|
||||
auto watchedFoldersModel = static_cast<WatchedFoldersModel *>(m_ui->scanFoldersView->model());
|
||||
watchedFoldersModel->apply();
|
||||
session->setTorrentExportDirectory(getTorrentExportDir());
|
||||
session->setFinishedTorrentExportDirectory(getFinishedTorrentExportDir());
|
||||
pref->setMailNotificationEnabled(m_ui->groupMailNotification->isChecked());
|
||||
|
@ -1648,57 +1645,85 @@ int OptionsDialog::getActionOnDblClOnTorrentFn() const
|
|||
return m_ui->actionTorrentFnOnDblClBox->currentIndex();
|
||||
}
|
||||
|
||||
void OptionsDialog::on_addScanFolderButton_clicked()
|
||||
void OptionsDialog::on_addWatchedFolderButton_clicked()
|
||||
{
|
||||
Preferences *const pref = Preferences::instance();
|
||||
const QString dir = QFileDialog::getExistingDirectory(this, tr("Select folder to monitor"),
|
||||
Utils::Fs::toNativePath(Utils::Fs::folderName(pref->getScanDirsLastPath())));
|
||||
if (!dir.isEmpty())
|
||||
Utils::Fs::toNativePath(Utils::Fs::folderName(pref->getScanDirsLastPath())));
|
||||
if (dir.isEmpty())
|
||||
return;
|
||||
|
||||
auto dialog = new WatchedFolderOptionsDialog({}, this);
|
||||
dialog->setModal(true);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
connect(dialog, &QDialog::accepted, this, [this, dialog, dir, pref]()
|
||||
{
|
||||
const ScanFoldersModel::PathStatus status = ScanFoldersModel::instance()->addPath(dir, ScanFoldersModel::DEFAULT_LOCATION, QString(), false);
|
||||
QString error;
|
||||
switch (status)
|
||||
try
|
||||
{
|
||||
case ScanFoldersModel::AlreadyInList:
|
||||
error = tr("Folder is already being monitored:");
|
||||
break;
|
||||
case ScanFoldersModel::DoesNotExist:
|
||||
error = tr("Folder does not exist:");
|
||||
break;
|
||||
case ScanFoldersModel::CannotRead:
|
||||
error = tr("Folder is not readable:");
|
||||
break;
|
||||
default:
|
||||
auto watchedFoldersModel = static_cast<WatchedFoldersModel *>(m_ui->scanFoldersView->model());
|
||||
watchedFoldersModel->addFolder(dir, dialog->watchedFolderOptions());
|
||||
|
||||
pref->setScanDirsLastPath(dir);
|
||||
m_addedScanDirs << dir;
|
||||
for (int i = 0; i < ScanFoldersModel::instance()->columnCount(); ++i)
|
||||
|
||||
for (int i = 0; i < watchedFoldersModel->columnCount(); ++i)
|
||||
m_ui->scanFoldersView->resizeColumnToContents(i);
|
||||
|
||||
enableApplyButton();
|
||||
}
|
||||
catch (const RuntimeError &err)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Adding entry failed"), err.message());
|
||||
}
|
||||
});
|
||||
|
||||
if (!error.isEmpty())
|
||||
QMessageBox::critical(this, tr("Adding entry failed"), QString::fromLatin1("%1\n%2").arg(error, dir));
|
||||
}
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
void OptionsDialog::on_removeScanFolderButton_clicked()
|
||||
void OptionsDialog::on_editWatchedFolderButton_clicked()
|
||||
{
|
||||
const QModelIndex selected
|
||||
= m_ui->scanFoldersView->selectionModel()->selectedIndexes().at(0);
|
||||
|
||||
editWatchedFolderOptions(selected);
|
||||
}
|
||||
|
||||
void OptionsDialog::on_removeWatchedFolderButton_clicked()
|
||||
{
|
||||
const QModelIndexList selected
|
||||
= m_ui->scanFoldersView->selectionModel()->selectedIndexes();
|
||||
if (selected.isEmpty())
|
||||
return;
|
||||
Q_ASSERT(selected.count() == ScanFoldersModel::instance()->columnCount());
|
||||
|
||||
for (const QModelIndex &index : selected)
|
||||
{
|
||||
if (index.column() == ScanFoldersModel::WATCH)
|
||||
m_removedScanDirs << index.data().toString();
|
||||
}
|
||||
ScanFoldersModel::instance()->removePath(selected.first().row(), false);
|
||||
m_ui->scanFoldersView->model()->removeRow(index.row());
|
||||
}
|
||||
|
||||
void OptionsDialog::handleScanFolderViewSelectionChanged()
|
||||
void OptionsDialog::handleWatchedFolderViewSelectionChanged()
|
||||
{
|
||||
m_ui->removeScanFolderButton->setEnabled(!m_ui->scanFoldersView->selectionModel()->selectedIndexes().isEmpty());
|
||||
const QModelIndexList selectedIndexes = m_ui->scanFoldersView->selectionModel()->selectedIndexes();
|
||||
m_ui->removeWatchedFolderButton->setEnabled(!selectedIndexes.isEmpty());
|
||||
m_ui->editWatchedFolderButton->setEnabled(selectedIndexes.count() == 1);
|
||||
}
|
||||
|
||||
void OptionsDialog::editWatchedFolderOptions(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
auto watchedFoldersModel = static_cast<WatchedFoldersModel *>(m_ui->scanFoldersView->model());
|
||||
auto dialog = new WatchedFolderOptionsDialog(watchedFoldersModel->folderOptions(index.row()), this);
|
||||
dialog->setModal(true);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
connect(dialog, &QDialog::accepted, this, [this, dialog, index, watchedFoldersModel]()
|
||||
{
|
||||
if (index.isValid())
|
||||
{
|
||||
// The index could be invalidated while the dialog was displayed,
|
||||
// for example, if you deleted the folder using the Web API.
|
||||
watchedFoldersModel->setFolderOptions(index.row(), dialog->watchedFolderOptions());
|
||||
enableApplyButton();
|
||||
}
|
||||
});
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
QString OptionsDialog::askForExportDir(const QString ¤tExportPath)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue