aboutsummaryrefslogtreecommitdiffstats
path: root/src/finddialog.cpp
blob: fe56b384f4381faa0863c1303bf57de5d617fde6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "finddialog.h"
#include "./ui_finddialog.h"

#include <QTimer>
#include <QDebug>

FindDialog::FindDialog(QWidget* parent)
    : QDialog(parent, Qt::Tool), ui(new Ui::FindDialog)
{
    ui->setupUi(this);
}

FindDialog::~FindDialog() {
    delete last_search;
    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, bool search_immediately) {
    ui->textInputSearch->setText(text);
    if (search_immediately) init_search();
    else on_textInputSearch_textEdited(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."));
}