From 42434314d65cdc29402c7adcb08c2fa5113f7ca2 Mon Sep 17 00:00:00 2001 From: ConfuSomu Date: Wed, 2 Aug 2023 01:56:58 +0200 Subject: Implement find dialog This dialog consolidates options for searching through textual elements in lists which simplifies the logic present in the MainWindow class. --- src/finddialog.cpp | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 src/finddialog.cpp (limited to 'src/finddialog.cpp') diff --git a/src/finddialog.cpp b/src/finddialog.cpp new file mode 100644 index 0000000..4de17d0 --- /dev/null +++ b/src/finddialog.cpp @@ -0,0 +1,134 @@ +#include "finddialog.h" +#include "./ui_finddialog.h" + +#include +#include +#include +#include +#include + +FindDialog::FindDialog(QWidget* parent) + : QDialog(parent, Qt::Tool), ui(new Ui::FindDialog) +{ + ui->setupUi(this); +} + +FindDialog::~FindDialog() { + delete ui; +} + +void FindDialog::on_buttonSearchPrev_clicked() { + if (--selected_match < 0) { + selected_match = total_matches - 1; + ui->statusLabel->setText(tr("Reached top, continued from bottom.")); + } else update_status(); + select_match(); +} + +void FindDialog::on_buttonSearchNext_clicked() { + if (++selected_match >= total_matches) { + selected_match = 0; + ui->statusLabel->setText(tr("Reached bottom, continued from top.")); + } else update_status(); + select_match(); +} + +// Update the textbox in the main window and search after 400 ms of no typing +void FindDialog::on_textInputSearch_textEdited(const QString &text) { + emit search_text_changed(text); + static QTimer* differed_search = new QTimer(this); + if (static bool timer_init_done = false; not timer_init_done) { + differed_search->setTimerType(Qt::CoarseTimer); + differed_search->setSingleShot(true); + differed_search->setInterval(400); + connect(differed_search, &QTimer::timeout, this, &FindDialog::run_search); + timer_init_done = true; + } + differed_search->start(); +} + +void FindDialog::set_search_text(const QString &text) { + ui->textInputSearch->setText(text); +} + +inline void FindDialog::run_search() { + init_search(); +} + +void FindDialog::on_hSlider_valueChanged(int value) { + selected_match = value; + update_status(); + select_match(); +} + +void FindDialog::on_spinBox_valueChanged(int value) { + // Avoids repeatedly changing the selected_match as the valueChanged signal is a notifier for the spin box's value + if (not value_changed_processed) { + selected_match = value - 1; + update_status(); + select_match(); + } + value_changed_processed = false; +} + +void FindDialog::set_qlist_widget(QListWidget* widget) { + list_widget = widget; +} + +// Start a new search only if the search text input has changed +void FindDialog::init_search() { + QString current_search = ui->textInputSearch->text(); + if (*last_search == current_search or not list_widget) return; + + matches = list_widget->findItems(current_search, Qt::MatchContains); + + *last_search = current_search; + selected_match = 0; + total_matches = matches.size(); + + if (total_matches > 0) { + ui->hSlider->setEnabled(true); + ui->spinBox->setEnabled(true); + ui->buttonSearchPrev->setEnabled(true); + ui->buttonSearchNext->setEnabled(true); + } else { + ui->spinBox->setEnabled(false); + ui->hSlider->setEnabled(false); + ui->buttonSearchPrev->setEnabled(false); + ui->buttonSearchNext->setEnabled(false); + } + + // Set the minimum as when there are no matches, the widget would return out of range index values to having an out of range minimum. + ui->hSlider->setMinimum(0); + ui->spinBox->setMinimum(1); + ui->hSlider->setMaximum(total_matches - 1); + ui->spinBox->setMaximum(total_matches); + + select_match(); + update_status(); +} + +// Activate the match requested by the user +void FindDialog::select_match() { + if (list_widget and total_matches != 0 and selected_match >= 0) { + list_widget->scrollToItem(matches[selected_match], QAbstractItemView::EnsureVisible); + list_widget->setCurrentItem(matches[selected_match]); + emit item_selected(matches[selected_match]); + } + + // Best place to update these sliders as select_match is always called by each input + ui->hSlider->setValue(selected_match); + ui->spinBox->setValue(selected_match + 1); + value_changed_processed = true; +} + +// Update the status line with current search information +void FindDialog::update_status() { + if (total_matches > 0) { + ui->statusLabel->setText(tr("Search result %1 out of %2.") + .arg(selected_match+1) + .arg(total_matches)); + } else ui->statusLabel->setText(tr("No search results.")); +} + + -- cgit v1.2.3-54-g00ecf