diff --git a/src/gui/search/searchjobwidget.cpp b/src/gui/search/searchjobwidget.cpp index c71ec7b2f..a77561b69 100644 --- a/src/gui/search/searchjobwidget.cpp +++ b/src/gui/search/searchjobwidget.cpp @@ -85,6 +85,8 @@ namespace } } +using Utils::Misc::SizeUnit; + SearchJobWidget::SearchJobWidget(const QString &id, IGUIApplication *app, QWidget *parent) : GUIApplicationComponent(app, parent) , m_nameFilteringMode {u"Search/FilteringMode"_s} @@ -99,6 +101,8 @@ SearchJobWidget::SearchJobWidget(const QString &id, IGUIApplication *app, QWidge header()->setStretchLastSection(false); header()->setTextElideMode(Qt::ElideRight); + fillFilterComboBoxes(); + // Set Search results list model m_searchListModel = new QStandardItemModel(0, SearchSortModel::NB_SEARCH_COLUMNS, this); m_searchListModel->setHeaderData(SearchSortModel::NAME, Qt::Horizontal, tr("Name", "i.e: file name")); @@ -116,6 +120,13 @@ SearchJobWidget::SearchJobWidget(const QString &id, IGUIApplication *app, QWidge m_proxyModel = new SearchSortModel(this); m_proxyModel->setDynamicSortFilter(true); m_proxyModel->setSourceModel(m_searchListModel); + m_proxyModel->enableNameFilter(m_nameFilteringMode.get(NameFilteringMode::OnlyNames) == NameFilteringMode::OnlyNames); + m_proxyModel->setSeedsFilter(m_ui->minSeeds->value(), m_ui->maxSeeds->value()); + m_proxyModel->setSizeFilter(sizeInBytes(m_ui->minSize->value(), static_cast(m_ui->minSizeUnit->currentIndex())) + , sizeInBytes(m_ui->maxSize->value(), static_cast(m_ui->maxSizeUnit->currentIndex()))); + + updateResultsCount(); + m_ui->resultsBrowser->setModel(m_proxyModel); m_ui->resultsBrowser->hideColumn(SearchSortModel::DL_LINK); // Hide url column @@ -154,8 +165,6 @@ SearchJobWidget::SearchJobWidget(const QString &id, IGUIApplication *app, QWidge connect(header(), &QHeaderView::sectionMoved, this, &SearchJobWidget::saveSettings); connect(header(), &QHeaderView::sortIndicatorChanged, this, &SearchJobWidget::saveSettings); - fillFilterComboBoxes(); - m_lineEditSearchResultsFilter = new LineEdit(this); m_lineEditSearchResultsFilter->setPlaceholderText(tr("Filter search results...")); m_lineEditSearchResultsFilter->setContextMenuPolicy(Qt::CustomContextMenu); @@ -163,24 +172,17 @@ SearchJobWidget::SearchJobWidget(const QString &id, IGUIApplication *app, QWidge connect(m_lineEditSearchResultsFilter, &LineEdit::textChanged, this, &SearchJobWidget::filterSearchResults); m_ui->horizontalLayout->insertWidget(0, m_lineEditSearchResultsFilter); - connect(m_ui->filterMode, qOverload(&QComboBox::currentIndexChanged) - , this, &SearchJobWidget::updateFilter); - connect(m_ui->minSeeds, &QAbstractSpinBox::editingFinished, this, &SearchJobWidget::updateFilter); - connect(m_ui->minSeeds, qOverload(&QSpinBox::valueChanged) - , this, &SearchJobWidget::updateFilter); - connect(m_ui->maxSeeds, &QAbstractSpinBox::editingFinished, this, &SearchJobWidget::updateFilter); - connect(m_ui->maxSeeds, qOverload(&QSpinBox::valueChanged) - , this, &SearchJobWidget::updateFilter); - connect(m_ui->minSize, &QAbstractSpinBox::editingFinished, this, &SearchJobWidget::updateFilter); - connect(m_ui->minSize, qOverload(&QDoubleSpinBox::valueChanged) - , this, &SearchJobWidget::updateFilter); - connect(m_ui->maxSize, &QAbstractSpinBox::editingFinished, this, &SearchJobWidget::updateFilter); - connect(m_ui->maxSize, qOverload(&QDoubleSpinBox::valueChanged) - , this, &SearchJobWidget::updateFilter); - connect(m_ui->minSizeUnit, qOverload(&QComboBox::currentIndexChanged) - , this, &SearchJobWidget::updateFilter); - connect(m_ui->maxSizeUnit, qOverload(&QComboBox::currentIndexChanged) - , this, &SearchJobWidget::updateFilter); + connect(m_ui->filterMode, qOverload(&QComboBox::currentIndexChanged), this, &SearchJobWidget::updateNameFilter); + connect(m_ui->minSeeds, &QAbstractSpinBox::editingFinished, this, &SearchJobWidget::updateSeedsFilter); + connect(m_ui->minSeeds, qOverload(&QSpinBox::valueChanged), this, &SearchJobWidget::updateSeedsFilter); + connect(m_ui->maxSeeds, &QAbstractSpinBox::editingFinished, this, &SearchJobWidget::updateSeedsFilter); + connect(m_ui->maxSeeds, qOverload(&QSpinBox::valueChanged), this, &SearchJobWidget::updateSeedsFilter); + connect(m_ui->minSize, &QAbstractSpinBox::editingFinished, this, &SearchJobWidget::updateSizeFilter); + connect(m_ui->minSize, qOverload(&QDoubleSpinBox::valueChanged), this, &SearchJobWidget::updateSizeFilter); + connect(m_ui->maxSize, &QAbstractSpinBox::editingFinished, this, &SearchJobWidget::updateSizeFilter); + connect(m_ui->maxSize, qOverload(&QDoubleSpinBox::valueChanged), this, &SearchJobWidget::updateSizeFilter); + connect(m_ui->minSizeUnit, qOverload(&QComboBox::currentIndexChanged), this, &SearchJobWidget::updateSizeFilter); + connect(m_ui->maxSizeUnit, qOverload(&QComboBox::currentIndexChanged), this, &SearchJobWidget::updateSizeFilter); connect(m_ui->resultsBrowser, &QAbstractItemView::doubleClicked, this, &SearchJobWidget::onItemDoubleClicked); @@ -193,7 +195,6 @@ SearchJobWidget::SearchJobWidget(const QString &id, const QString &searchPattern { m_searchPattern = searchPattern; m_proxyModel->setNameFilter(m_searchPattern); - updateFilter(); appendSearchResults(searchResults); } @@ -301,8 +302,8 @@ void SearchJobWidget::assignSearchHandler(SearchHandler *searchHandler) m_searchPattern = m_searchHandler->pattern(); m_proxyModel->setNameFilter(m_searchPattern); - updateFilter(); + updateResultsCount(); setStatus(Status::Ongoing); } @@ -454,26 +455,34 @@ void SearchJobWidget::updateResultsCount() emit resultsCountUpdated(); } -void SearchJobWidget::updateFilter() +void SearchJobWidget::updateNameFilter() { - using Utils::Misc::SizeUnit; + const auto filteringMode = static_cast(m_ui->filterMode->itemData(m_ui->filterMode->currentIndex()).toInt()); + m_proxyModel->enableNameFilter(filteringMode == NameFilteringMode::OnlyNames); + m_nameFilteringMode = filteringMode; - m_proxyModel->enableNameFilter(filteringMode() == NameFilteringMode::OnlyNames); + updateResultsCount(); +} + +void SearchJobWidget::updateSeedsFilter() +{ // we update size and seeds filter parameters in the model even if they are disabled m_proxyModel->setSeedsFilter(m_ui->minSeeds->value(), m_ui->maxSeeds->value()); - m_proxyModel->setSizeFilter( - sizeInBytes(m_ui->minSize->value(), static_cast(m_ui->minSizeUnit->currentIndex())), - sizeInBytes(m_ui->maxSize->value(), static_cast(m_ui->maxSizeUnit->currentIndex()))); - m_nameFilteringMode = filteringMode(); + updateResultsCount(); +} + +void SearchJobWidget::updateSizeFilter() +{ + // we update size and seeds filter parameters in the model even if they are disabled + m_proxyModel->setSizeFilter(sizeInBytes(m_ui->minSize->value(), static_cast(m_ui->minSizeUnit->currentIndex())) + , sizeInBytes(m_ui->maxSize->value(), static_cast(m_ui->maxSizeUnit->currentIndex()))); - m_proxyModel->invalidate(); updateResultsCount(); } void SearchJobWidget::fillFilterComboBoxes() { - using Utils::Misc::SizeUnit; using Utils::Misc::unitString; QStringList unitStrings; @@ -500,16 +509,15 @@ void SearchJobWidget::fillFilterComboBoxes() m_ui->filterMode->addItem(tr("Torrent names only"), static_cast(NameFilteringMode::OnlyNames)); m_ui->filterMode->addItem(tr("Everywhere"), static_cast(NameFilteringMode::Everywhere)); - - const QVariant selectedMode = static_cast(m_nameFilteringMode.get(NameFilteringMode::OnlyNames)); - const int index = m_ui->filterMode->findData(selectedMode); + const auto selectedFilteringMode = static_cast(m_nameFilteringMode.get(NameFilteringMode::OnlyNames)); + const int index = m_ui->filterMode->findData(selectedFilteringMode); m_ui->filterMode->setCurrentIndex((index == -1) ? 0 : index); } void SearchJobWidget::filterSearchResults(const QString &name) { const QString pattern = (Preferences::instance()->getRegexAsFilteringPatternForSearchJob() - ? name : Utils::String::wildcardToRegexPattern(name)); + ? name : Utils::String::wildcardToRegexPattern(name)); m_proxyModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption)); updateResultsCount(); } @@ -557,11 +565,6 @@ void SearchJobWidget::contextMenuEvent(QContextMenuEvent *event) menu->popup(event->globalPos()); } -SearchJobWidget::NameFilteringMode SearchJobWidget::filteringMode() const -{ - return static_cast(m_ui->filterMode->itemData(m_ui->filterMode->currentIndex()).toInt()); -} - void SearchJobWidget::loadSettings() { header()->restoreState(Preferences::instance()->getSearchTabHeaderState()); diff --git a/src/gui/search/searchjobwidget.h b/src/gui/search/searchjobwidget.h index f2842f470..00ad9cca7 100644 --- a/src/gui/search/searchjobwidget.h +++ b/src/gui/search/searchjobwidget.h @@ -106,7 +106,9 @@ private: void loadSettings(); void saveSettings() const; - void updateFilter(); + void updateNameFilter(); + void updateSeedsFilter(); + void updateSizeFilter(); void filterSearchResults(const QString &name); void showFilterContextMenu(); void contextMenuEvent(QContextMenuEvent *event) override; @@ -119,7 +121,6 @@ private: void downloadTorrent(const QModelIndex &rowIndex, AddTorrentOption option = AddTorrentOption::Default); void addTorrentToSession(const QString &source, AddTorrentOption option = AddTorrentOption::Default); void fillFilterComboBoxes(); - NameFilteringMode filteringMode() const; QHeaderView *header() const; int visibleColumnsCount() const; void setRowColor(int row, const QColor &color); diff --git a/src/gui/search/searchsortmodel.cpp b/src/gui/search/searchsortmodel.cpp index 5b0f815a4..77293436c 100644 --- a/src/gui/search/searchsortmodel.cpp +++ b/src/gui/search/searchsortmodel.cpp @@ -1,5 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2025 Vladimir Golovnev * Copyright (C) 2013 sledgehammer999 * * This program is free software; you can redistribute it and/or @@ -39,34 +40,103 @@ SearchSortModel::SearchSortModel(QObject *parent) void SearchSortModel::enableNameFilter(const bool enabled) { + if (m_isNameFilterEnabled == enabled) + return; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); m_isNameFilterEnabled = enabled; + endFilterChange(Direction::Rows); +#else + m_isNameFilterEnabled = enabled; + invalidateRowsFilter(); +#endif } void SearchSortModel::setNameFilter(const QString &searchTerm) { + if (m_searchTerm == searchTerm) + return; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); + m_searchTerm = searchTerm; if ((searchTerm.length() > 2) && searchTerm.startsWith(u'"') && searchTerm.endsWith(u'"')) m_searchTermWords = QStringList(m_searchTerm.sliced(1, (m_searchTerm.length() - 2))); else m_searchTermWords = searchTerm.split(u' ', Qt::SkipEmptyParts); + + endFilterChange(Direction::Rows); +#else + m_searchTerm = searchTerm; + if ((searchTerm.length() > 2) && searchTerm.startsWith(u'"') && searchTerm.endsWith(u'"')) + m_searchTermWords = QStringList(m_searchTerm.sliced(1, (m_searchTerm.length() - 2))); + else + m_searchTermWords = searchTerm.split(u' ', Qt::SkipEmptyParts); + + invalidateRowsFilter(); +#endif } -void SearchSortModel::setSizeFilter(const qint64 minSize, const qint64 maxSize) +void SearchSortModel::setSizeFilter(qint64 minSize, qint64 maxSize) { - m_minSize = std::max(static_cast(0), minSize); - m_maxSize = std::max(static_cast(-1), maxSize); + minSize = std::max(0, minSize); + maxSize = std::max(-1, maxSize); + + if ((m_minSize == minSize) && (m_maxSize == maxSize)) + return; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); + m_minSize = minSize; + m_maxSize = maxSize; + endFilterChange(Direction::Rows); +#else + m_minSize = minSize; + m_maxSize = maxSize; + invalidateRowsFilter(); +#endif } -void SearchSortModel::setSeedsFilter(const int minSeeds, const int maxSeeds) +void SearchSortModel::setSeedsFilter(int minSeeds, int maxSeeds) { - m_minSeeds = std::max(0, minSeeds); - m_maxSeeds = std::max(-1, maxSeeds); + minSeeds = std::max(0, minSeeds); + maxSeeds = std::max(-1, maxSeeds); + + if ((m_minSeeds == minSeeds) && (m_maxSeeds == maxSeeds)) + return; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); + m_minSeeds = minSeeds; + m_maxSeeds = maxSeeds; + endFilterChange(Direction::Rows); +#else + m_minSeeds = minSeeds; + m_maxSeeds = maxSeeds; + invalidateRowsFilter(); +#endif } -void SearchSortModel::setLeechesFilter(const int minLeeches, const int maxLeeches) +void SearchSortModel::setLeechesFilter(int minLeeches, int maxLeeches) { - m_minLeeches = std::max(0, minLeeches); - m_maxLeeches = std::max(-1, maxLeeches); + minLeeches = std::max(0, minLeeches); + maxLeeches = std::max(-1, maxLeeches); + + if ((m_minLeeches == minLeeches) && (m_maxLeeches == maxLeeches)) + return; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); + m_minLeeches = minLeeches; + m_maxLeeches = maxLeeches; + endFilterChange(Direction::Rows); +#else + m_minLeeches = minLeeches; + m_maxLeeches = maxLeeches; + invalidateRowsFilter(); +#endif } bool SearchSortModel::isNameFilterEnabled() const diff --git a/src/gui/search/searchsortmodel.h b/src/gui/search/searchsortmodel.h index f250cded5..3f3229c2f 100644 --- a/src/gui/search/searchsortmodel.h +++ b/src/gui/search/searchsortmodel.h @@ -1,5 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2025 Vladimir Golovnev * Copyright (C) 2013 sledgehammer999 * * This program is free software; you can redistribute it and/or