[KLF Backend][KLF Tools][KLF Home]
KLatexFormula Project
klfsearchbar.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * file klfsearchbar.cpp
3  * This file is part of the KLatexFormula Project.
4  * Copyright (C) 2011 by Philippe Faist
5  * philippe.faist at bluewin.ch
6  * *
7  * This program is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program; if not, write to the *
19  * Free Software Foundation, Inc., *
20  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21  ***************************************************************************/
22 /* $Id: klfsearchbar.cpp 983 2016-12-31 21:03:44Z phfaist $ */
23 
24 #include <QDebug>
25 #include <QObject>
26 #include <QFrame>
27 #include <QLineEdit>
28 #include <QEvent>
29 #include <QKeyEvent>
30 #include <QShortcut>
31 #include <QKeySequence>
32 #include <QTime>
33 
34 #include <klfguiutil.h>
35 
36 #include <ui_klfsearchbar.h>
37 #include "klfsearchbar.h"
38 #include "klfsearchbar_p.h"
39 
40 
41 
135 {
136  QString s;
137  s.sprintf("%p", (const void*)(const KLFPosSearchable::Pos::PosData*)pos.posdata);
138  str << "Pos("<<qPrintable(s);
139  if (pos.posdata != NULL) {
140  QString desc;
141  if (!(desc = pos.posdata->toDebug()).isEmpty())
142  str << " " << qPrintable(desc);
143  }
144  return str <<")";
145 }
146 
147 // --
148 
150 {
151  klfDbg("start from: base implementation, will return invalid. forward="<<forward) ;
152  Q_UNUSED(forward) ;
153  return Pos();
154 }
155 
157 {
158  klfDbg("on="<<on) ;
159  pInterruptRequested = on;
160 }
161 
162 
163 // ------------------------------------------------
164 
165 
167 {
168 }
169 
171 {
172  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return Pos() );
173  return target()->searchStartFrom(forward);
174 }
175 
176 KLFPosSearchable::Pos KLFPosSearchableProxy::searchFind(const QString& queryString, const Pos& fromPos, bool forward)
177 {
178  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return Pos() );
179  return target()->searchFind(queryString, fromPos, forward);
180 }
181 
183 {
184  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
185  return target()->searchMoveToPos(pos);
186 }
187 
188 void KLFPosSearchableProxy::searchPerformed(const QString& queryString, bool found, const Pos& pos)
189 {
190  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
191  target()->searchPerformed(queryString, found, pos);
192 }
193 
195 {
196  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
197  target()->searchAborted();
198 }
199 
201 {
202  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
203  target()->searchReinitialized();
204 }
205 
207 {
208  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return QString(); );
209  return target()->searchQueryString();
210 }
211 
213 {
214  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
215  target()->setSearchQueryString(s);
216 }
217 
219 {
220  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return false; );
221  return target()->searchHasInterruptRequested();
222 }
223 
225 {
226  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
227  target()->setSearchInterruptRequested(on);
228 }
229 
230 
231 
232 // ---
233 
234 struct DummySearchPosData : public KLFPosSearchable::Pos::PosData
235 {
236  bool equals(PosData *) const { return true; }
237 };
238 
239 
241 {
242 }
244 {
245 }
246 
247 KLFPosSearchable::Pos KLFSearchable::searchFind(const QString& queryString, const Pos& fromPos, bool forward)
248 {
249  bool r;
250  // simulate first search, then 'find next', by detecting if we're required to search from a given pos
251  // (heuristic that will fail in special cases!!)
252  if (!fromPos.valid())
253  r = searchFind(queryString, forward);
254  else
255  r = searchFindNext(forward);
256  Pos p = Pos();
257  if (!r)
258  return p;
259  // return dummy valid pos
260  p.posdata = new DummySearchPosData;
261  return p;
262 }
263 
264 
265 // -----
266 
268 {
269 }
270 
272 {
273  KLFSearchable *s = dynamic_cast<KLFSearchable*>(target);
274  KLF_ASSERT_CONDITION( (s!=NULL) || (target==NULL),
275  "target is not a valid KLFSearchable object !",
276  return; ) ;
278 }
279 
280 bool KLFSearchableProxy::searchFind(const QString& queryString, bool forward)
281 {
282  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return false );
283  return target()->searchFind(queryString, forward);
284 }
286 {
287  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return false );
288  return target()->searchFindNext(forward);
289 }
291 {
292  KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return );
293  return target()->searchAbort();
294 }
295 
296 
297 // ------------------------
298 
300  : QFrame(parent)
301 {
303  klfDbg("parent: "<<parent) ;
304 
305  _isInQtDesigner = false;
306 
307  d = new KLFSearchBarPrivate;
308 
309  u = new Ui::KLFSearchBar;
310  u->setupUi(this);
311 
312  setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
313 
314  u->txtSearch->installEventFilter(this);
315  connect(u->btnSearchClear, SIGNAL(clicked()), this, SLOT(clear()));
316  connect(u->txtSearch, SIGNAL(textChanged(const QString&)),
317  this, SLOT(find(const QString&)));
318  connect(u->btnFindNext, SIGNAL(clicked()), this, SLOT(findNext()));
319  connect(u->btnFindPrev, SIGNAL(clicked()), this, SLOT(findPrev()));
320 
321  QPalette defaultpal = u->txtSearch->palette();
322  u->txtSearch->setProperty(palettePropName(Default).toLatin1(), QVariant::fromValue<QPalette>(defaultpal));
323  QPalette pal0 = defaultpal;
324  pal0.setColor(QPalette::Text, QColor(180,180,180));
325  pal0.setColor(QPalette::WindowText, QColor(180,180,180));
326  pal0.setColor(u->txtSearch->foregroundRole(), QColor(180,180,180));
327  u->txtSearch->setProperty(palettePropName(FocusOut).toLatin1(), QVariant::fromValue<QPalette>(pal0));
328  // default found/not-found colors
329  setColorFound(QColor(128,255,128));
330  setColorNotFound(QColor(255,128,128));
331 
332  connect(u->btnHide, SIGNAL(clicked()), this, SLOT(hide()));
333  setShowHideButton(false); // not shown by default
334 
335  d->pResetTimeout = 10000;
336  connect(&d->pFocusOutResetTimer, SIGNAL(timeout()), this, SLOT(slotSearchReset()));
337 
338  d->pWaitLabel = new KLFWaitAnimationOverlay(u->txtSearch);
339  d->pWaitLabel->setWaitMovie(":/pics/wait_anim.mng");
340  /* // amusing test
341  d->pWaitLabel->setWaitMovie("/home/philippe/projects/klf/artwork/experimental/packman_anim.gif");
342  */
343 
344  d->pAutoHide = false;
345 
346  d->pShowOverlayMode = false;
347  // default relative geometry: position at (50%, 95%) (centered, quasi-bottom)
348  // size of (90%, 0%) [remember: expanded to minimum size]
349  d->pShowOverlayRelativeGeometry = QRect(QPoint(50, 95), QSize(90, 0));
350 
351  d->pFocusOutText = " "+tr("Hit Ctrl-F, Ctrl-S or / to start searching");
352 
353  d->pSearchForward = true;
354  d->pSearchText = QString();
355  d->pIsSearching = false;
356  d->pCurPos = KLFPosSearchable::Pos();
357  d->pLastPos = KLFPosSearchable::Pos();
358  d->pState = FocusOut;
360 
361  d->pIsFinding = false;
362  d->pHasQueuedFind = false;
363  d->pQueuedFindString = QString();
364  d->pQueuedFindForward = true;
365 
366  klfDbg("pCurPos is "<<d->pCurPos<<"; pLastPos is "<<d->pLastPos) ;
367 
368  d->pUseEsbs = true;
369 }
371 {
372  delete d;
373 }
374 
376 {
377  if (d->pState == FocusOut)
378  return QString();
379  return u->txtSearch->text();
380 }
381 
383 {
384  QPalette p = u->txtSearch->property(palettePropName(Found).toLatin1()).value<QPalette>();
385  return p.color(QPalette::Base);
386 }
388 {
389  QPalette p = u->txtSearch->property(palettePropName(NotFound).toLatin1()).value<QPalette>();
390  return p.color(QPalette::Base);
391 }
392 
394 {
395  return u->btnHide->isVisible();
396 }
397 
399 {
400  return u->lblSearch->isVisible();
401 }
402 
404 {
405  return d->pUseEsbs;
406 }
407 
408 int KLFSearchBar::resetTimeout() const
409 {
410  return d->pResetTimeout;
411 }
412 
414 {
415  return d->pCurPos;
416 }
417 
419 {
420  return d->pState;
421 }
422 
423 
425 {
426  QPalette pal1 = u->txtSearch->property(palettePropName(Default).toLatin1()).value<QPalette>();
427  pal1.setColor(QPalette::Base, color);
428  pal1.setColor(QPalette::Window, color);
429  pal1.setColor(u->txtSearch->backgroundRole(), color);
430  u->txtSearch->setProperty(palettePropName(Found).toLatin1(), QVariant::fromValue<QPalette>(pal1));
431 }
432 
434 {
435  QPalette pal2 = u->txtSearch->property(palettePropName(Default).toLatin1()).value<QPalette>();
436  pal2.setColor(QPalette::Base, color);
437  pal2.setColor(QPalette::Window, color);
438  pal2.setColor(u->txtSearch->backgroundRole(), color);
439  u->txtSearch->setProperty(palettePropName(NotFound).toLatin1(), QVariant::fromValue<QPalette>(pal2));
440 }
441 
443 {
444  u->btnHide->setVisible(showHideButton);
445 }
446 
448 {
449  u->lblSearch->setVisible(on);
450 }
451 
453 {
454  if (d->pIsSearching)
455  abortSearch();
456  d->pUseEsbs = on;
457 }
458 
460 {
461  d->pResetTimeout = ms;
462 }
463 
464 
466 #define DECLARE_SEARCH_SHORTCUT(shortcut, parent, slotmember) \
467  { QShortcut *s = new QShortcut(parent); s->setKey(QKeySequence(shortcut)); \
468  connect(s, SIGNAL(activated()), this, slotmember); }
469 
470 void KLFSearchBar::registerShortcuts(QWidget *parent)
471 {
472  DECLARE_SEARCH_SHORTCUT(tr("Ctrl+F", "[[find]]"), parent, SLOT(focusOrNext()));
473  DECLARE_SEARCH_SHORTCUT(tr("Ctrl+S", "[[find]]"), parent, SLOT(focusOrNext()));
474  DECLARE_SEARCH_SHORTCUT(tr("Ctrl+G", "[[find]]"), parent, SLOT(focusOrNext()));
475  DECLARE_SEARCH_SHORTCUT(tr("/", "[[find]]"), parent, SLOT(clear()));
476  DECLARE_SEARCH_SHORTCUT(tr("F3", "[[find next]]"), parent, SLOT(findNext()));
477  DECLARE_SEARCH_SHORTCUT(tr("Shift+F3", "[[find prev]]"), parent, SLOT(findPrev()));
478  DECLARE_SEARCH_SHORTCUT(tr("Ctrl+R", "[[find rev]]"), parent, SLOT(focusOrPrev()));
479  // Esc will be captured through event filter so that it isn't too obstrusive...
480 }
481 
483 {
484  if (d->pIsSearching)
485  abortSearch();
486 
487  KLFPosSearchable *s = dynamic_cast<KLFPosSearchable*>(target);
488  KLF_ASSERT_CONDITION( (s!=NULL) || (target==NULL),
489  "target is not a valid KLFPosSearchable object !",
490  return; ) ;
492 }
493 
495 {
496  u->txtSearch->setText(text);
497 }
498 
499 bool KLFSearchBar::autoHide() const
500 {
501  return d->pAutoHide;
502 }
503 
505 {
506  return d->pShowOverlayMode;
507 }
509 {
510  return d->pShowOverlayRelativeGeometry;
511 }
513 {
514  return d->pFocusOutText;
515 }
516 
517 
519 {
520  d->pFocusOutText = focusOutText;
521  if (d->pState == FocusOut) {
522  // re-display focus-out state
524  }
525 }
526 
527 
528 static KLFSearchBarPrivate::HistBuffer::CurLastPosPair
529 /* */ esbs_get_last_pos(const QList<KLFSearchBarPrivate::HistBuffer>& hb, int offset = 0)
530 {
531  if (hb.size() <= offset) { // there is no preceeding histbuffer
532  return KLFSearchBarPrivate::HistBuffer::CurLastPosPair(KLFPosSearchable::Pos(),
534  }
535  const QList<KLFSearchBarPrivate::HistBuffer::CurLastPosPair>& poslist = hb[hb.size()-1 - offset].poslist;
536 
537  if (poslist.isEmpty()) {
538  return esbs_get_last_pos(hb, offset+1);
539  }
540  return poslist.last();
541 }
542 
544 {
546 
547  if (obj == u->txtSearch) {
548  if (ev->type() == QEvent::FocusIn) {
549  klfDbg("focus-in event...") ;
551  // don't eat event
552  } else if (ev->type() == QEvent::FocusOut) {
553  klfDbg("focus-out event...") ;
555  // don't eat event
556  } else if (ev->type() == QEvent::KeyPress) {
557  klfDbg("key press event!") ;
558  QKeyEvent *ke = (QKeyEvent*)ev;
559  if (ke->key() == Qt::Key_Escape) {
560  abortSearch();
561  emit escapePressed();
562  return true;
563  }
564  // Emacs-Style Backspace handling
565  if (d->pUseEsbs) {
566  // what kind of key press is this
567  if (ke->key() == Qt::Key_Backspace) {
568  // if searching, backspace interrupts the search.
569  if (d->pIsFinding) {
570  KLF_ASSERT_CONDITION_ELSE(target()!=NULL, "Search Target is NULL!", ; ) {
571  target()->setSearchInterruptRequested(true);
572  return true;
573  }
574  }
575  if ( ! d->esbs_histbuffer.size() ) {
576  // back to beginning of text buffer...
578  } else {
579  // there is a current history buffer
580  KLFSearchBarPrivate::HistBuffer& histbuf = d->esbs_histbuffer.last();
581  if (histbuf.poslist.size() > 1) {
582  // jump to previous match
583  histbuf.poslist.pop_back();
584  const KLFSearchBarPrivate::HistBuffer::CurLastPosPair& pos = histbuf.poslist.last();
585  // move to previous match
586  KLF_ASSERT_CONDITION_ELSE(target()!=NULL, "Search Target is NULL!", ; ) {
587  d->pCurPos = pos.cur;
588  d->pLastPos = pos.last;
589  // move to given pos, and present found result
590  target()->searchMoveToPos(d->pCurPos);
591  target()->searchPerformed(d->pSearchText, d->pCurPos.valid(), d->pCurPos);
592  updateSearchFound(d->pCurPos.valid());
593  emit hasMatch(d->pCurPos.valid());
594  }
595  } else {
596  d->esbs_histbuffer.pop_back();
597  // if there is left
598  if (!d->esbs_histbuffer.size()) {
599  // back to beginning of text buffer...
601  } else {
602  // remove last item in buffer
603  d->pSearchText = d->esbs_histbuffer.last().str;
604  // check if there actually is text left
605  u->txtSearch->blockSignals(true);
606  u->txtSearch->setText(d->pSearchText);
607  u->txtSearch->blockSignals(false);
609  = d->esbs_histbuffer.last().poslist;
610  KLF_ASSERT_CONDITION_ELSE(target()!=NULL, "Search Target is NULL!", ; ) {
611  // find the last position where we were
612  KLFSearchBarPrivate::HistBuffer::CurLastPosPair clpos = esbs_get_last_pos(d->esbs_histbuffer);
613  d->pCurPos = clpos.cur;
614  d->pLastPos = clpos.last;
615  // make sure query string is up-to-date
616  target()->setSearchQueryString(d->pSearchText);
617  if (poslist.isEmpty()) {
618  // can be the result of an interrupted find, search from the preceeding poslist
619  d->pCurPos = d->pLastPos;
620  findNext(clpos.reachedForward);
621  } else {
622  target()->searchMoveToPos(d->pCurPos);
623  target()->searchPerformed(d->pSearchText, d->pCurPos.valid(), d->pCurPos);
624  updateSearchFound(d->pCurPos.valid());
625  emitFoundSignals(d->pCurPos, d->pSearchText, clpos.reachedForward);
626  emit hasMatch(d->pCurPos.valid());
627  }
628  }
629  }
630  }
631  }
632  // in every case, eat the event
633  return true;
634  } else if (ke->key() == Qt::Key_Left || ke->key() == Qt::Key_Right) {
635  // no left/right navigation
636  return true;
637  } else if (ke->key() == Qt::Key_Home || ke->key() == Qt::Key_End) {
638  // don't allow text navigation
639  return true;
640  } else if (ke->text().size() && ke->text()[0].isPrint()) {
641  // pass on the event further to QLineEdit
642  // Also, it is in find() that will we will create a new HistBuffer for this exact
643  // new partial search string.
644  }
645  } // if (use e-s-b-s)
646  else {
647  klfDbg("key press, but not using e-s-b-s.");
648  return false;
649  }
650  } // if (is key-press)
651 
652  }
653  return QFrame::eventFilter(obj, ev);
654 }
655 
656 QLineEdit * KLFSearchBar::editor()
657 {
658  return u->txtSearch;
659 }
660 
661 void KLFSearchBar::setAutoHide(bool autohide)
662 {
663  klfDbg("autohide="<<autohide) ;
664  d->pAutoHide = autohide;
665  if (d->pAutoHide && !searchBarHasFocus() && !_isInQtDesigner)
666  hide();
667 }
668 
669 void KLFSearchBar::setShowOverlayMode(bool overlayMode)
670 {
671  klfDbg("setting show overlay mode to "<<overlayMode) ;
672  d->pShowOverlayMode = overlayMode;
673  setProperty("klfShowOverlayMode", QVariant::fromValue<bool>(d->pShowOverlayMode));
674  // cheat with klfTopLevelWidget property, set it always in show-overlay-mode
675  setProperty("klfTopLevelWidget", QVariant::fromValue<bool>(d->pShowOverlayMode));
676 
677  adjustOverlayGeometry();
680 }
681 
682 void KLFSearchBar::setShowOverlayRelativeGeometry(const QRect& relativeGeometryPercent)
683 {
684  d->pShowOverlayRelativeGeometry = relativeGeometryPercent;
685  adjustOverlayGeometry();
686 }
687 void KLFSearchBar::setShowOverlayRelativeGeometry(int widthPercent, int heightPercent,
688  int positionXPercent, int positionYPercent)
689 {
690  setShowOverlayRelativeGeometry(QRect(QPoint(positionXPercent, positionYPercent),
691  QSize(widthPercent, heightPercent)));
692  adjustOverlayGeometry();
693 }
694 
695 
696 
698 {
699  klfDbgT("clear") ;
700  setSearchText("");
701  focus();
702 }
703 
704 void KLFSearchBar::focusOrNext(bool forward)
705 {
706  d->pSearchForward = forward;
707 
708  if (d->pState != FocusOut) {
709  klfDbgT("already are in focus state") ;
710  // focus search bar if not yet focused.
711  if (!searchBarHasFocus())
712  focus();
713  // already has focus
714  // -> either recall history (if empty search text)
715  // -> or find next
716  if (u->txtSearch->text().isEmpty()) {
717  setSearchText(d->pLastSearchText);
718  } else {
719  if (!d->pIsSearching) {
720  find(u->txtSearch->text(), forward);
721  } else {
722  findNext(forward);
723  }
724  }
725  } else {
726  klfDbgT("setting focus") ;
727  setSearchText("");
728  focus();
729  }
730 }
731 
732 void KLFSearchBar::find(const QString& string)
733 {
734  find(string, d->pSearchForward);
735 }
736 
737 void KLFSearchBar::find(const QString& text, bool forward)
738 {
740  klfDbgT("text="<<text<<", forward="<<forward) ;
741 
742  if (target() == NULL && text.isEmpty())
743  return;
744 
745  KLF_ASSERT_NOT_NULL( target() , "search target is NULL!", return ) ;
746 
747  if (d->pIsFinding) {
748  klfDbg("find()ing already. queueing and requesting to stop previous find.");
749  target()->setSearchInterruptRequested(true);
750  d->pHasQueuedFind = true;
751  d->pQueuedFindString = text;
752  d->pQueuedFindForward = forward;
753  return;
754  }
755 
756  if ( text.isEmpty() ||
757  (d->pUseEsbs && text.mid(0, d->pSearchText.size()) != d->pSearchText) ) {
759  return;
760  }
761 
762  if (!d->pIsSearching) {
763  klfDbg("new search. find start from position.") ;
764  // first find() call, started new search, start from suggested position
765  d->pCurPos = target()->searchStartFrom(forward);
766  d->pLastPos = d->pCurPos;
767  klfDbg("Starting from d->pCurPos="<<d->pCurPos) ;
768  }
769 
770  d->pIsSearching = true;
771  d->pSearchText = text;
772  performFind(forward, false);
773 }
774 
775 
776 // private
777 void KLFSearchBar::performFind(bool forward, bool isfindnext)
778 {
780 
781  KLF_ASSERT_NOT_NULL( target() , "search target is NULL!", return ) ;
782 
783  if (!isfindnext) {
784  // prepare this esbs-hist-buffer
785  if (d->pUseEsbs) {
786  KLFSearchBarPrivate::HistBuffer buf;
787  buf.str = d->pSearchText;
788  d->esbs_histbuffer << buf;
789  }
790  }
791 
792  klfDbg("pSearchText="<<d->pSearchText<<"; pCurPos="<<d->pCurPos<<"; pLastPos="<<d->pLastPos) ;
793 
794  // reset the interrupt request flag
795  target()->setSearchInterruptRequested(false);
796 
797  d->pIsFinding = true;
798  d->pWaitLabel->startWait();
799  target()->setSearchQueryString(d->pSearchText);
800  klfDbg("pSearchText="<<d->pSearchText<<"; target()->searchQueryString()="<<target()->searchQueryString()) ;
801  KLFPosSearchable::Pos pos = target()->searchFind(d->pSearchText, d->pLastPos, forward);
802  d->pWaitLabel->stopWait();
803  d->pIsFinding = false;
804 
805  if (!d->pIsSearching) {
806  // search was aborted.
807  return;
808  }
809 
810  d->pCurPos = pos;
811 
812  if (target()->searchHasInterruptRequested()) {
813  // perform queued find
814  if (d->pHasQueuedFind) {
815  QString s = d->pQueuedFindString;
816  bool f = d->pQueuedFindForward;
817  d->pHasQueuedFind = false;
818  d->pQueuedFindString = QString();
819  d->pQueuedFindForward = true;
820  find(s, f);
821  }
822  return;
823  }
824 
825  target()->searchMoveToPos(d->pCurPos);
826  target()->searchPerformed(d->pSearchText, d->pCurPos.valid(), d->pCurPos);
827  updateSearchFound(d->pCurPos.valid());
828  emitFoundSignals(d->pCurPos, d->pSearchText, forward);
829  emit hasMatch(d->pCurPos.valid());
830 
831  klfDbg("Are now at position pCurPos="<<d->pCurPos) ;
832 
833  if (d->pUseEsbs) {
834  KLF_ASSERT_CONDITION_ELSE(d->esbs_histbuffer.size(), "HistBuffer is empty!!", ;) {
835  if (d->pCurPos.valid() ||
836  // append invalid item only if poslist is empty or if the last poslist item is valid
837  (d->esbs_histbuffer.last().poslist.isEmpty() ||
838  d->esbs_histbuffer.last().poslist.last().cur.valid())) {
839  d->esbs_histbuffer.last().poslist
840  << KLFSearchBarPrivate::HistBuffer::CurLastPosPair(d->pCurPos, d->pLastPos, forward);
841  }
842  }
843  }
844 }
845 
846 void KLFSearchBar::findNext(bool forward)
847 {
848  klfDbgT("forward="<<forward) ;
849 
850  if (d->pIsFinding) {
851  klfDbg("finding already. Must wait, ignoring request.");
852  return;
853  }
854 
855  // focus search bar if not yet focused.
856  if (!searchBarHasFocus())
857  focus();
858 
859  if (d->pSearchText.isEmpty()) {
860  klfDbg("called but not in search mode. recalling history="<<d->pLastSearchText) ;
861  // we're not in search mode
862  // recall history
863  showSearchBarText(d->pLastSearchText);
864 
865  // and initiate search mode
866  find(u->txtSearch->text(), forward);
867  return;
868  }
869 
870  KLF_ASSERT_NOT_NULL( pTarget , "Search target is NULL!" , return ) ;
871 
872  d->pLastPos = d->pCurPos; // precisely, find _next_
873  d->pLastSearchText = d->pSearchText;
874  performFind(forward, true);
875 }
876 
878 {
880  u->txtSearch->blockSignals(true);
881  u->txtSearch->setText("");
882  u->txtSearch->blockSignals(false);
883  d->pSearchText = QString();
884  d->pCurPos = KLFPosSearchable::Pos();
885  d->pLastPos = KLFPosSearchable::Pos();
886  if (target() != NULL) {
887  klfDbg("telling target to reinitialize search...") ;
888  if (d->pIsFinding)
889  target()->setSearchInterruptRequested(true);
890  target()->setSearchQueryString(QString());
891  target()->searchMoveToPos(d->pCurPos);
892  target()->searchReinitialized();
893  emit searchReinitialized();
894  emit hasMatch(d->pCurPos.valid());
895  }
896 }
897 
899 {
901 
904  d->pSearchText = QString();
905  d->pIsSearching = false;
906  d->pCurPos = KLFPosSearchable::Pos();
907  d->pLastPos = KLFPosSearchable::Pos();
908  klfDbg("pCurPos="<<d->pCurPos) ;
909 
910  if ( ! u->txtSearch->text().isEmpty() ) {
911  showSearchBarText("");
912  }
913  if (d->pUseEsbs)
914  d->esbs_histbuffer.clear();
915 
916  if (searchBarHasFocus()) {
918  } else {
920  }
921 
922  if (target() != NULL) {
923  klfDbg("telling target to abort search...") ;
924  if (d->pIsFinding)
925  target()->setSearchInterruptRequested(true);
926  target()->searchAborted();
927  target()->setSearchQueryString(QString());
928  klfDbg("...done") ;
929  }
930 
931  emit searchAborted();
932  emit hasMatch(false);
933 }
934 
935 void KLFSearchBar::adjustOverlayGeometry()
936 {
937  if (d->pShowOverlayMode) {
938  QWidget *pw = parentWidget();
939  if (pw != NULL) {
940  // if we have a parent widget, adjust using our relative geometry
941  QSize pws = pw->size();
942 
943  QPoint relPos = d->pShowOverlayRelativeGeometry.topLeft();
944  QSize relSz = d->pShowOverlayRelativeGeometry.size();
945 
946  QSize sz = QSize(pws.width()*relSz.width()/100, pws.height()*relSz.height()/100);
947  sz = sz.expandedTo(minimumSizeHint()) ;
948  QRect gm = QRect( QPoint( (pws.width()-sz.width())*relPos.x()/100, (pws.height()-sz.height())*relPos.y()/100 ),
949  sz );
950  klfDbg("Geometry is "<<gm) ;
951  setGeometry(gm);
952  // setAutoFillBackground(true);
953  setStyleSheet(styleSheet());
954  raise();
955  } else {
956  // set some widget window flags if we're parent-less...
957  setWindowFlags(Qt::Tool);
958  // just for fun...
959  setWindowOpacity(0.95);
960  }
961  }
962 }
963 
965 {
967 
968  if (d->pShowOverlayMode)
969  adjustOverlayGeometry();
970 
971  if (!isVisible()) {
972  // show the search bar. This works with in overlay mode as well as when the widget is hidden
973  // with the hide button.
974  show();
975  }
976  u->txtSearch->setFocus();
977 }
978 
980 {
981  klfDbgT("focus in") ;
982  if (d->pState != FocusOut) {
983  // don't have to reinitialize from focusout state.
984  if (d->pFocusOutResetTimer.isActive()) {
985  d->pFocusOutResetTimer.stop();
986  }
987  return;
988  }
990  showSearchBarText("");
991 }
992 
994 {
995  klfDbgT("focus out") ;
996 
997  if (d->pResetTimeout == 0) {
998  slotSearchReset();
999  return;
1000  }
1001  if (d->pResetTimeout > 0) {
1002  d->pFocusOutResetTimer.setInterval(d->pResetTimeout);
1003  d->pFocusOutResetTimer.setSingleShot(true);
1004  d->pFocusOutResetTimer.start();
1005  return;
1006  }
1007  // if d->pResetTimeout < 0, do not abort search.
1008 }
1009 
1011 {
1012  klfDbgT("search reset after focus out.");
1013 
1014  if (d->pAutoHide && !_isInQtDesigner)
1015  hide();
1016 
1017  abortSearch();
1018 }
1019 
1021 {
1022  setCurrentState(found ? Found : NotFound);
1023 }
1024 
1025 // private
1026 QString KLFSearchBar::palettePropName(SearchState state) const
1027 {
1028  switch (state) {
1029  case Default: return QString("paletteDefault");
1030  case FocusOut: return QString("paletteFocusOut");
1031  case Found: return QString("paletteFound");
1032  case NotFound: return QString("paletteNotFound");
1033  case Aborted: return QString("paletteDefault");
1034  default:
1035  qWarning()<<KLF_FUNC_NAME<<": invalid state: "<<state;
1036  }
1037  return QString();
1038 }
1039 // private
1040 QString KLFSearchBar::statePropValue(SearchState state) const
1041 {
1042  switch (state) {
1043  case Default: return QLatin1String("default");
1044  case FocusOut: return QLatin1String("focus-out");
1045  case Found: return QLatin1String("found");
1046  case NotFound: return QLatin1String("not-found");
1047  case Aborted: return QLatin1String("aborted");
1048  default: return QLatin1String("invalid");
1049  }
1050 }
1051 
1053 {
1054  klfDbg("state: "<<state) ;
1055 
1056  if (d->pState == state)
1057  return;
1058 
1059  d->pState = state;
1060  displayState(state);
1061  emit stateChanged(state);
1062 }
1063 
1065 {
1066  klfDbg("Setting state: "<<statePropValue(s));
1067  u->txtSearch->setProperty("searchState", statePropValue(s));
1068  QPalette pal = u->txtSearch->property(palettePropName(s).toLatin1()).value<QPalette>();
1070  u->txtSearch->setStyleSheet(u->txtSearch->styleSheet());
1071  u->txtSearch->setPalette(pal);
1072  u->txtSearch->update();
1073 
1074  if (s == FocusOut) {
1075  showSearchBarText(d->pFocusOutText);
1076  }
1077 }
1078 
1079 void KLFSearchBar::emitFoundSignals(const KLFPosSearchable::Pos& pos, const QString& searchstring, bool forward)
1080 {
1081  bool resultfound = pos.valid();
1082  emit searchPerformed(resultfound);
1083  emit searchPerformed(searchstring, resultfound);
1084  if (resultfound) {
1085  emit found();
1086  emit found(d->pSearchText, forward);
1087  emit found(d->pSearchText, forward, pos);
1088  } else {
1089  emit didNotFind();
1090  emit didNotFind(d->pSearchText, forward);
1091  }
1092 }
1093 
1095 {
1096  u->txtSearch->blockSignals(true);
1097  u->txtSearch->setText(text);
1098  if (d->pUseEsbs)
1099  d->esbs_histbuffer.clear();
1100  u->txtSearch->blockSignals(false);
1101 }
1103 {
1104  return QApplication::focusWidget() == u->txtSearch;
1105 }
1106 
1107 
1109 {
1110  if (event->type() == QEvent::Polish)
1111  setMinimumSize(minimumSizeHint());
1112 
1113  if (event->type() == QEvent::Show) {
1114  emit visibilityChanged(true);
1115  }
1116  if (event->type() == QEvent::Hide) {
1117  emit visibilityChanged(false);
1118  }
1119 
1120  return QFrame::event(event);
1121 }
virtual void slotSearchFocusIn()
virtual void displayState(SearchState state)
bool _isInQtDesigner
Definition: klfsearchbar.h:594
bool showOverlayMode() const
virtual bool event(QEvent *event)
void abortSearch()
virtual void setTarget(KLFTarget *target)
Definition: klfutil.cpp:667
virtual void setTarget(KLFTarget *target)
void setColorNotFound(const QColor &color)
Type type() const
int width() const
An object that can be searched with a KLFSearchBar.
Definition: klfsearchbar.h:73
virtual void setSearchInterruptRequested(bool on)
void setColor(ColorGroup group, ColorRole role, const QColor &color)
virtual Pos searchStartFrom(bool forward)
#define klfDbgT(streamableItems)
print debug stream items, with current time
void setShowOverlayRelativeGeometry(const QRect &relativeGeometryPercent)
void hasMatch(bool hasmatch)
Reflects whether the search is currently pointing on a valid result.
virtual void setSearchQueryString(const QString &s)
void promptEmptySearch()
const QColor & color(ColorGroup group, ColorRole role) const
int size() const
void find(const QString &string)
void emitFoundSignals(const KLFPosSearchable::Pos &pos, const QString &searchstring, bool forward)
#define klfDbg(streamableItems)
print debug stream items
void setShowOverlayMode(bool showOverlayMode)
virtual void setSearchInterruptRequested(bool on)
void setEmacsStyleBackspace(bool on)
#define KLF_DEBUG_BLOCK(msg)
Utility to debug the execution of a block.
KLFTarget * pTarget
Definition: klfutil.h:530
virtual void searchAbort()
virtual bool searchFind(const QString &queryString, bool forward)
virtual ~KLFPosSearchableProxy()
SearchState currentState() const
bool hideButtonShown() const
virtual ~KLFSearchable()
virtual void registerShortcuts(QWidget *parent)
int resetTimeout() const
KLFSearchBar(QWidget *parent=NULL)
#define DECLARE_SEARCH_SHORTCUT(shortcut, parent, slotmember)
QColor colorFound() const
virtual Pos searchFind(const QString &queryString, const Pos &fromPos, bool forward)
int x() const
int y() const
int size() const
#define KLF_ASSERT_NOT_NULL(ptr, msg, failaction)
Asserting Non-NULL pointers (NON-FATAL)
QString & sprintf(const char *cformat,...)
void focusOrNext(bool forward=true)
bool autoHide() const
void setAutoHide(bool autohide)
virtual Pos searchFind(const QString &queryString, const Pos &fromPos, bool forward)=0
virtual void searchPerformed(const QString &queryString, bool found, const Pos &pos)
virtual bool eventFilter(QObject *obj, QEvent *ev)
bool searchBarHasFocus()
virtual void searchAborted()=0
virtual void searchPerformed(const QString &queryString, bool found, const Pos &pos)
Definition: klfsearchbar.h:262
virtual bool searchHasInterruptRequested()
bool showSearchLabel() const
void visibilityChanged(bool isShown)
bool isEmpty() const
bool isEmpty() const
virtual QString searchQueryString() const
virtual void setSearchText(const QString &text)
QString text() const
void setShowHideButton(bool showHideButton)
virtual ~KLFSearchBar()
An animation display.
Definition: klfguiutil.h:412
void setResetTimeout(int ms)
virtual bool searchFindNext(bool forward)
void findPrev()
Definition: klfsearchbar.h:577
QDebug & operator<<(QDebug &str, const KLFPosSearchable::Pos &pos)
void setColorFound(const QColor &color)
virtual bool searchFind(const QString &queryString, bool forward)=0
Find the first occurence of a query string.
QString focusOutText() const
void searchReinitialized()
void searchAborted()
#define KLF_DEBUG_TIME_BLOCK(msg)
Utility to time the execution of a block.
KLFRefPtr< PosData > posdata
Stores the actual position data, see PosData.
Definition: klfsearchbar.h:196
virtual void searchReinitialized()
Definition: klfsearchbar.h:272
int key() const
#define KLF_FUNC_NAME
virtual void slotSearchFocusOut()
An abstract position in a searchable object.
Definition: klfsearchbar.h:97
QString currentSearchText() const
void searchPerformed(bool found)
virtual ~KLFSearchableProxy()
virtual void setTarget(KLFTarget *target)
void setShowSearchLabel(bool show)
virtual void updateSearchFound(bool found)
void didNotFind()
void setFocusOutText(const QString &focusOutText)
QString mid(int position, int n) const
virtual void slotSearchReset()
QColor colorNotFound() const
QSize expandedTo(const QSize &otherSize) const
Ui::KLFSearchBar * u
Definition: klfsearchbar.h:586
T & last()
void escapePressed()
void showSearchBarText(const QString &text)
virtual void setSearchQueryString(const QString &s)
Definition: klfsearchbar.h:284
int height() const
virtual void searchMoveToPos(const Pos &pos)
Definition: klfsearchbar.h:256
void setCurrentState(SearchState state)
KLFPosSearchable::Pos currentSearchPos() const
virtual void searchAborted()
virtual void searchMoveToPos(const Pos &pos)
virtual Pos searchStartFrom(bool forward)
void focusOrPrev()
Definition: klfsearchbar.h:573
#define KLF_ASSERT_CONDITION_ELSE(expr, msg, failaction)
Asserting Conditions previous to block (NON-FATAL)
void stateChanged(SearchState state)
bool showHideButton
Definition: klfsearchbar.h:475
A Base class for storing abstract position data.
Definition: klfsearchbar.h:124
QLineEdit * editor()
#define KLF_ASSERT_CONDITION(expr, msg, failaction)
Asserting Conditions (NON-FATAL)
QRect showOverlayRelativeGeometry() const
An interface for objects that can be I-searched with a KLFSearchBar (OBSOLETE)
Definition: klfsearchbar.h:346
virtual void searchReinitialized()
void findNext(bool forward=true)
bool emacsStyleBackspace() const

Generated by doxygen 1.8.13