@@ -46,10 +46,10 @@ QuickFindWidget::QuickFindWidget(QWidget *parent) :
4646 connect (ui->lineEdit , &QLineEdit::returnPressed, this , &QuickFindWidget::returnPressed);
4747
4848 // Any changes need to trigger a new search
49- connect (ui->lineEdit , &QLineEdit::textChanged, this , &QuickFindWidget::highlightAndNavigateToNextMatch );
50- connect (ui->buttonMatchCase , &QToolButton::toggled, this , &QuickFindWidget::highlightAndNavigateToNextMatch );
51- connect (ui->buttonWholeWord , &QToolButton::toggled, this , &QuickFindWidget::highlightAndNavigateToNextMatch );
52- connect (ui->buttonRegexp , &QToolButton::toggled, this , &QuickFindWidget::highlightAndNavigateToNextMatch );
49+ connect (ui->lineEdit , &QLineEdit::textChanged, this , &QuickFindWidget::performNewSearch );
50+ connect (ui->buttonMatchCase , &QToolButton::toggled, this , &QuickFindWidget::performNewSearch );
51+ connect (ui->buttonWholeWord , &QToolButton::toggled, this , &QuickFindWidget::performNewSearch );
52+ connect (ui->buttonRegexp , &QToolButton::toggled, this , &QuickFindWidget::performNewSearch );
5353}
5454
5555QuickFindWidget::~QuickFindWidget ()
@@ -92,6 +92,7 @@ bool QuickFindWidget::eventFilter(QObject *obj, QEvent *event)
9292 // Use escape key to close the quick find widget
9393 if (keyEvent->key () == Qt::Key_Escape) {
9494 clearHighlights ();
95+ clearCachedMatches ();
9596 hide ();
9697 editor->grabFocus ();
9798 }
@@ -100,94 +101,141 @@ bool QuickFindWidget::eventFilter(QObject *obj, QEvent *event)
100101 return QObject::eventFilter (obj, event);
101102}
102103
103- void QuickFindWidget::highlightMatches ()
104+ void QuickFindWidget::setSearchContextColorBad ()
104105{
105- qInfo (Q_FUNC_INFO);
106+ setSearchContextColor (QStringLiteral (" red" ));
107+ }
106108
109+ void QuickFindWidget::setSearchContextColorGood ()
110+ {
111+ setSearchContextColor (QStringLiteral (" blue" ));
112+ }
113+
114+ void QuickFindWidget::performNewSearch ()
115+ {
107116 clearHighlights ();
117+ clearCachedMatches ();
118+ ui->lblInfo ->hide ();
108119
120+ // Early out
109121 if (searchText ().isEmpty ()) {
110- setSearchContextColor ( " blue " );
122+ setSearchContextColorGood ( );
111123 return ;
112124 }
113125
114126 prepareSearch ();
115- editor->setIndicatorCurrent (indicator);
116-
117- bool foundOne = false ;
118127 finder->forEachMatch ([&](int start, int end) {
119- foundOne = true ;
120-
121- const int length = end - start;
122-
123- // Don't highlight 0 length matches
124- if (length > 0 )
125- editor->indicatorFillRange (start, length);
126-
127- // Advance at least 1 character to prevent infinite loop
128+ matches.append (qMakePair (start, end));
128129 return qMax (start + 1 , end);
129130 });
130131
131- if (foundOne == false ) {
132- setSearchContextColor ( " red " );
132+ if (matches. empty () ) {
133+ setSearchContextColorBad ( );
133134 }
134135 else {
135- setSearchContextColor (" blue" );
136+ setSearchContextColorGood ();
137+ }
138+
139+ highlightMatches ();
140+ navigateToNextMatch (false );
141+ }
142+
143+ void QuickFindWidget::highlightMatches ()
144+ {
145+ qInfo (Q_FUNC_INFO);
146+
147+ editor->setIndicatorCurrent (indicator);
148+ for (const auto &range : matches) {
149+ editor->indicatorFillRange (range.first , range.second - range.first );
136150 }
137151}
138152
153+ void QuickFindWidget::showWrapIndicator ()
154+ {
155+ FadingIndicator::showPixmap (editor, QStringLiteral (" :/icons/wrapindicator.png" ));
156+ }
157+
139158void QuickFindWidget::navigateToNextMatch (bool skipCurrent)
140159{
141160 qInfo (Q_FUNC_INFO);
142161
143- if (searchText ().isEmpty ()) {
162+ // Early out if there are no matches
163+ if (matches.length () == 0 ) {
164+ ui->lblInfo ->hide ();
144165 return ;
145166 }
146167
147- int startPos = INVALID_POSITION;
148- if (skipCurrent) {
149- startPos = editor->selectionEnd ();
168+ if (currentMatchIndex != -1 ) {
169+ currentMatchIndex++;
170+ if (currentMatchIndex >= matches.length ()) {
171+ currentMatchIndex = 0 ;
172+ }
150173 }
151174 else {
152- startPos = editor->selectionStart ();
153- }
154-
155- prepareSearch ();
175+ int startPos = INVALID_POSITION;
176+ if (skipCurrent) {
177+ startPos = editor->selectionEnd ();
178+ }
179+ else {
180+ startPos = editor->selectionStart ();
181+ }
156182
157- auto range = finder-> findNext ( startPos);
158- if (range. cpMin == INVALID_POSITION)
159- return ;
183+ auto it = std::lower_bound (matches. begin (), matches. end (), startPos, []( const QPair< int , int >& pair, int value) {
184+ return pair. first < value;
185+ }) ;
160186
161- editor->setSel (range.cpMin , range.cpMax );
162- editor->verticalCentreCaret ();
187+ if (it != matches.end ()) {
188+ currentMatchIndex = std::distance (matches.begin (), it);
189+ } else {
190+ // Wrap back around
191+ currentMatchIndex = 0 ;
192+ }
193+ }
163194
164- if (finder->didLatestSearchWrapAround ()) {
165- FadingIndicator::showPixmap (editor, QStringLiteral (" :/icons/wrapindicator.png" ));
195+ // Search wrapped around
196+ if (currentMatchIndex == 0 ) {
197+ showWrapIndicator ();
166198 }
199+
200+ goToCurrentMatch ();
167201}
168202
169203void QuickFindWidget::navigateToPrevMatch ()
170204{
171205 qInfo (Q_FUNC_INFO);
172206
173- if (searchText ().isEmpty ()) {
207+ // Early out if there are no matches
208+ if (matches.length () == 0 ) {
209+ ui->lblInfo ->hide ();
174210 return ;
175211 }
176212
177- prepareSearch ();
178-
179- auto range = finder->findPrev ();
180- if (range.cpMin == INVALID_POSITION)
213+ if (currentMatchIndex != -1 ) {
214+ currentMatchIndex--;
215+ if (currentMatchIndex < 0 ) {
216+ currentMatchIndex = matches.length () - 1 ;
217+ }
218+ }
219+ else {
220+ qWarning (" navigateToPrevMatch() with no valid index yet" );
181221 return ;
222+ }
182223
183- editor->setSel (range.cpMin , range.cpMax );
184- editor->verticalCentreCaret ();
224+ // Search wrapped around
225+ if (currentMatchIndex == matches.length () - 1 ) {
226+ showWrapIndicator ();
227+ }
228+
229+ goToCurrentMatch ();
185230}
186231
187- void QuickFindWidget::highlightAndNavigateToNextMatch ()
232+ void QuickFindWidget::goToCurrentMatch ()
188233{
189- highlightMatches ();
190- navigateToNextMatch (false );
234+ editor->setSel (matches[currentMatchIndex].first , matches[currentMatchIndex].second );
235+ editor->verticalCentreCaret ();
236+
237+ ui->lblInfo ->show ();
238+ ui->lblInfo ->setText (tr (" %L1/%L2" ).arg (currentMatchIndex + 1 ).arg (matches.length ()));
191239}
192240
193241int QuickFindWidget::computeSearchFlags () const
@@ -209,7 +257,7 @@ int QuickFindWidget::computeSearchFlags() const
209257 return searchFlags;
210258}
211259
212- void QuickFindWidget::setSearchContextColor (QString color)
260+ void QuickFindWidget::setSearchContextColor (const QString & color)
213261{
214262 ui->lineEdit ->setStyleSheet (QStringLiteral (" border: 1px solid %1; padding: 2px;" ).arg (color));
215263}
@@ -253,12 +301,14 @@ void QuickFindWidget::prepareSearch()
253301void QuickFindWidget::focusIn ()
254302{
255303 ui->lineEdit ->selectAll ();
256- highlightAndNavigateToNextMatch ();
304+ ui->lblInfo ->hide ();
305+ performNewSearch ();
257306}
258307
259308void QuickFindWidget::focusOut ()
260309{
261310 clearHighlights ();
311+ clearCachedMatches ();
262312 hide ();
263313}
264314
@@ -277,3 +327,9 @@ void QuickFindWidget::clearHighlights()
277327 editor->setIndicatorCurrent (indicator);
278328 editor->indicatorClearRange (0 , editor->length ());
279329}
330+
331+ void QuickFindWidget::clearCachedMatches ()
332+ {
333+ matches.clear ();
334+ currentMatchIndex = -1 ;
335+ }
0 commit comments