diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index 11de498dc..a869561ee 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -55,6 +55,7 @@ #include "base/utils/fs.h" #include "base/utils/misc.h" #include "autoexpandabledialog.h" +#include "lineedit.h" #include "properties/proplistdelegate.h" #include "raisedmessagebox.h" #include "torrentcontentfiltermodel.h" @@ -169,6 +170,7 @@ const int AddNewTorrentDialog::maxPathHistoryLength; AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inParams, QWidget *parent) : QDialog(parent) , m_ui(new Ui::AddNewTorrentDialog) + , m_filterLine(new LineEdit(this)) , m_torrentParams(inParams) , m_storeDialogSize(SETTINGS_KEY(u"DialogSize"_qs)) , m_storeDefaultCategory(SETTINGS_KEY(u"DefaultCategory"_qs)) @@ -242,6 +244,12 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP connect(m_ui->contentTreeView->header(), &QWidget::customContextMenuRequested, this, &AddNewTorrentDialog::displayColumnHeaderMenu); + // Torrent content filtering + m_filterLine->setPlaceholderText(tr("Filter files...")); + m_filterLine->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + connect(m_filterLine, &LineEdit::textChanged, this, &AddNewTorrentDialog::handleFilterTextChanged); + m_ui->contentFilterLayout->insertWidget(3, m_filterLine); + loadState(); // Signal / slots connect(m_ui->doNotDeleteTorrentCheckBox, &QCheckBox::clicked, this, &AddNewTorrentDialog::doNotDeleteTorrentClicked); @@ -912,6 +920,8 @@ void AddNewTorrentDialog::setupTreeview() { m_ui->labelCommentData->setText(tr("Not Available", "This comment is unavailable")); m_ui->labelDateData->setText(tr("Not Available", "This date is unavailable")); + // Prevent crash if something is typed in the filter. m_contentModel is not initialized at this point + m_filterLine->blockSignals(true); } else { @@ -949,6 +959,8 @@ void AddNewTorrentDialog::setupTreeview() if (const QByteArray state = m_storeTreeHeaderState; !state.isEmpty()) m_ui->contentTreeView->header()->restoreState(state); + m_filterLine->blockSignals(false); + // Hide useless columns after loading the header state m_ui->contentTreeView->hideColumn(PROGRESS); m_ui->contentTreeView->hideColumn(REMAINING); @@ -1045,3 +1057,18 @@ void AddNewTorrentDialog::renameSelectedFile() m_ui->contentTreeView->renameSelectedFile(fileStorageAdaptor); } } + +void AddNewTorrentDialog::handleFilterTextChanged(const QString &filter) +{ + const QString pattern = Utils::String::wildcardToRegexPattern(filter); + m_contentModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption)); + if (filter.isEmpty()) + { + m_ui->contentTreeView->collapseAll(); + m_ui->contentTreeView->expand(m_contentModel->index(0, 0)); + } + else + { + m_ui->contentTreeView->expandAll(); + } +} diff --git a/src/gui/addnewtorrentdialog.h b/src/gui/addnewtorrentdialog.h index a7bd28807..747844f1b 100644 --- a/src/gui/addnewtorrentdialog.h +++ b/src/gui/addnewtorrentdialog.h @@ -53,6 +53,7 @@ namespace Ui class AddNewTorrentDialog; } +class LineEdit; class PropListDelegate; class TorrentContentFilterModel; class TorrentFileGuard; @@ -92,6 +93,7 @@ private slots: void contentLayoutChanged(); void doNotDeleteTorrentClicked(bool checked); void renameSelectedFile(); + void handleFilterTextChanged(const QString &filter); void accept() override; void reject() override; @@ -123,6 +125,7 @@ private: int m_savePathIndex = -1; int m_downloadPathIndex = -1; bool m_useDownloadPath = false; + LineEdit *m_filterLine = nullptr; std::unique_ptr m_torrentGuard; BitTorrent::AddTorrentParams m_torrentParams; diff --git a/src/gui/addnewtorrentdialog.ui b/src/gui/addnewtorrentdialog.ui index 1089c6970..845dad783 100644 --- a/src/gui/addnewtorrentdialog.ui +++ b/src/gui/addnewtorrentdialog.ui @@ -415,9 +415,12 @@ Qt::Horizontal + + QSizePolicy::Maximum + - 168 + 165 20