[KLF Application][KLF Tools][KLF Backend][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 627 2011-04-12 12:36:22Z 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 
40 {
41 }
43 {
44  int k;
45  QList<KLFSearchBar*> bars = pTargetOf;
46  for (k = 0; k < bars.size(); ++k) {
47  bars[k]->pTarget = NULL;
48  }
49  QList<KLFSearchableProxy*> pl = pTargetOfProxy;
50  for (k = 0; k < pl.size(); ++k) {
51  pl[k]->pTarget = NULL;
52  }
53 }
54 
55 // -----
56 
58 {
59  if (pTarget != NULL)
60  pTarget->pTargetOfProxy.removeAll(this);
61 }
62 
64 {
65  if (pTarget != NULL)
66  pTarget->pTargetOfProxy.removeAll(this);
67 
68  pTarget = target;
69 
70  if (pTarget != NULL)
71  pTarget->pTargetOfProxy.append(this);
72 }
73 
74 bool KLFSearchableProxy::searchFind(const QString& queryString, bool forward)
75 {
76  KLF_ASSERT_NOT_NULL( pTarget, "Search target is NULL!", return false );
77  return pTarget->searchFind(queryString, forward);
78 }
80 {
81  KLF_ASSERT_NOT_NULL( pTarget, "Search target is NULL!", return false );
82  return pTarget->searchFindNext(forward);
83 }
85 {
86  KLF_ASSERT_NOT_NULL( pTarget, "Search target is NULL!", return );
87  return pTarget->searchAbort();
88 }
89 
90 
91 // ------------------------
92 
94  : QFrame(parent), pTarget(NULL)
95 {
97  klfDbg("parent: "<<parent) ;
98 
99  u = new Ui::KLFSearchBar;
100  u->setupUi(this);
101 
102  setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
103 
104  u->txtSearch->installEventFilter(this);
105  connect(u->btnSearchClear, SIGNAL(clicked()), this, SLOT(clear()));
106  connect(u->txtSearch, SIGNAL(textChanged(const QString&)),
107  this, SLOT(find(const QString&)));
108  connect(u->btnFindNext, SIGNAL(clicked()), this, SLOT(findNext()));
109  connect(u->btnFindPrev, SIGNAL(clicked()), this, SLOT(findPrev()));
110 
111  QPalette defaultpal = u->txtSearch->palette();
112  u->txtSearch->setProperty(palettePropName(Default).toAscii(), QVariant::fromValue<QPalette>(defaultpal));
113  QPalette pal0 = defaultpal;
114  pal0.setColor(QPalette::Text, QColor(180,180,180));
115  pal0.setColor(QPalette::WindowText, QColor(180,180,180));
116  pal0.setColor(u->txtSearch->foregroundRole(), QColor(180,180,180));
117  u->txtSearch->setProperty(palettePropName(FocusOut).toAscii(), QVariant::fromValue<QPalette>(pal0));
118  // default found/not-found colors
119  setColorFound(QColor(128,255,128));
120  setColorNotFound(QColor(255,128,128));
121 
122  connect(u->btnHide, SIGNAL(clicked()), this, SLOT(hide()));
123  setShowHideButton(false); // not shown by default
124 
125  pWaitLabel = new KLFWaitAnimationOverlay(u->txtSearch);
126  pWaitLabel->setWaitMovie(":/pics/wait_anim.mng");
127  /* // amusing test
128  pWaitLabel->setWaitMovie("/home/philippe/projects/klf/artwork/experimental/packman_anim.gif");
129  */
130 
131  pShowOverlayMode = false;
132  // default relative geometry: position at (50%, 95%) (centered, quasi-bottom)
133  // size of (90%, 0%) [remember: expanded to minimum size]
134  pShowOverlayRelativeGeometry = QRect(QPoint(50, 95), QSize(90, 0));
135 
136  pFocusOutText = " "+tr("Hit Ctrl-F, Ctrl-S or / to start searching");
137 
138  pSearchForward = true;
139 
140  setSearchTarget(NULL);
142 }
144 {
145  if (pTarget != NULL)
146  pTarget->pTargetOf.removeAll(this);
147 }
148 
150 {
151  return u->txtSearch->text();
152 }
153 
155 {
156  QPalette p = u->txtSearch->property(palettePropName(Found).toAscii()).value<QPalette>();
157  return p.color(QPalette::Base);
158 }
160 {
161  QPalette p = u->txtSearch->property(palettePropName(NotFound).toAscii()).value<QPalette>();
162  return p.color(QPalette::Base);
163 }
164 
166 {
167  return u->btnHide->isVisible();
168 }
169 
171 {
172  QPalette pal1 = u->txtSearch->property(palettePropName(Default).toAscii()).value<QPalette>();
173  pal1.setColor(QPalette::Base, color);
174  pal1.setColor(QPalette::Window, color);
175  pal1.setColor(u->txtSearch->backgroundRole(), color);
176  u->txtSearch->setProperty(palettePropName(Found).toAscii(), QVariant::fromValue<QPalette>(pal1));
177 }
179 {
180  QPalette pal2 = u->txtSearch->property(palettePropName(Default).toAscii()).value<QPalette>();
181  pal2.setColor(QPalette::Base, color);
182  pal2.setColor(QPalette::Window, color);
183  pal2.setColor(u->txtSearch->backgroundRole(), color);
184  u->txtSearch->setProperty(palettePropName(NotFound).toAscii(), QVariant::fromValue<QPalette>(pal2));
185 }
186 
187 void KLFSearchBar::setShowHideButton(bool showHideButton)
188 {
189  u->btnHide->setShown(showHideButton);
190 }
191 
193 #define DECLARE_SEARCH_SHORTCUT(shortcut, parent, slotmember) \
194  { QShortcut *s = new QShortcut(parent); s->setKey(QKeySequence(shortcut)); \
195  connect(s, SIGNAL(activated()), this, slotmember); }
196 
198 {
199  DECLARE_SEARCH_SHORTCUT(tr("Ctrl+F", "[[find]]"), parent, SLOT(focusOrNext()));
200  DECLARE_SEARCH_SHORTCUT(tr("Ctrl+S", "[[find]]"), parent, SLOT(focusOrNext()));
201  DECLARE_SEARCH_SHORTCUT(tr("/", "[[find]]"), parent, SLOT(clear()));
202  DECLARE_SEARCH_SHORTCUT(tr("F3", "[[find next]]"), parent, SLOT(findNext()));
203  DECLARE_SEARCH_SHORTCUT(tr("Shift+F3", "[[find prev]]"), parent, SLOT(findPrev()));
204  DECLARE_SEARCH_SHORTCUT(tr("Ctrl+R", "[[find rev]]"), parent, SLOT(focusOrPrev()));
205  // Esc will be captured through event filter so that it isn't too obstrusive...
206 }
207 
209 {
211  klfDbg("target="<<object) ;
212 
213  abortSearch();
214 
215  if (pTarget != NULL)
216  pTarget->pTargetOf.removeAll(this);
217 
218  pTarget = object;
219 
220  if (pTarget != NULL)
221  pTarget->pTargetOf.append(this);
222 
223  setEnabled(pTarget != NULL);
224 }
225 
227 {
228  u->lblSearch->setText(text);
229 }
230 
231 void KLFSearchBar::setFocusOutText(const QString& focusOutText)
232 {
233  pFocusOutText = focusOutText;
234 }
235 
236 
238 {
239  if (obj == u->txtSearch) {
240  if (ev->type() == QEvent::FocusIn) {
241  klfDbg("focus-in event...") ;
243  // don't eat event
244  } else if (ev->type() == QEvent::FocusOut) {
245  klfDbg("focus-out event...") ;
247  abortSearch();
248  // don't eat event
249  } else if (ev->type() == QEvent::KeyPress) {
250  QKeyEvent *ke = (QKeyEvent*)ev;
251  if (ke->key() == Qt::Key_Escape) {
252  abortSearch();
253  emit escapePressed();
254  return true;
255  }
256  }
257  }
258  return QFrame::eventFilter(obj, ev);
259 }
260 
262 {
263  return u->txtSearch;
264 }
265 
266 void KLFSearchBar::setShowOverlayMode(bool overlayMode)
267 {
268  klfDbg("setting show overlay mode to "<<overlayMode) ;
269  pShowOverlayMode = overlayMode;
270  if (pShowOverlayMode && !searchBarHasFocus())
271  hide();
272  setProperty("klfShowOverlayMode", QVariant::fromValue<bool>(pShowOverlayMode));
273  // cheat with klfTopLevelWidget property, set it always in show-overlay-mode
274  setProperty("klfTopLevelWidget", QVariant::fromValue<bool>(pShowOverlayMode));
275 
278 }
279 
280 void KLFSearchBar::setShowOverlayRelativeGeometry(const QRect& relativeGeometryPercent)
281 {
282  pShowOverlayRelativeGeometry = relativeGeometryPercent;
283 }
284 void KLFSearchBar::setShowOverlayRelativeGeometry(int widthPercent, int heightPercent,
285  int positionXPercent, int positionYPercent)
286 {
287  setShowOverlayRelativeGeometry(QRect(QPoint(positionXPercent, positionYPercent),
288  QSize(widthPercent, heightPercent)));
289 }
290 
291 
292 
294 {
295  klfDbgT("clear") ;
296  u->txtSearch->setText("");
297  focus();
298 }
299 
300 void KLFSearchBar::focusOrNext(bool forward)
301 {
302  pSearchForward = forward;
303 
304  if (QApplication::focusWidget() == u->txtSearch) {
305  klfDbgT("already have focus") ;
306  // already has focus
307  // -> either recall history (if empty search text)
308  // -> or find next
309  if (u->txtSearch->text().isEmpty()) {
310  u->txtSearch->setText(pLastSearchText);
311  } else {
312  if (pSearchText.isEmpty())
313  find(u->txtSearch->text(), forward);
314  else
315  findNext(forward);
316  }
317  } else {
318  klfDbgT("setting focus") ;
319  u->txtSearch->setText("");
320  focus();
321  }
322 }
323 
324 void KLFSearchBar::find(const QString& text, bool forward)
325 {
326  klfDbgT("text="<<text<<", forward="<<forward) ;
327  if (text.isEmpty()) {
328  abortSearch();
329  return;
330  }
331 
332  KLF_ASSERT_NOT_NULL( pTarget , "search target is NULL!", return ) ;
333 
334  pWaitLabel->startWait();
335  bool found = pTarget->searchFind(text, forward);
336  updateSearchFound(found);
337  pWaitLabel->stopWait();
338  pSearchText = text;
339  emitFoundSignals(found, pSearchText, forward);
340 }
341 
342 void KLFSearchBar::findNext(bool forward)
343 {
344  klfDbgT("forward="<<forward) ;
345 
346  // focus search bar if not yet focused.
347  if (!searchBarHasFocus())
348  focus();
349 
350  if (pSearchText.isEmpty()) {
351  klfDbg("called but not in search mode. recalling history="<<pLastSearchText) ;
352  // we're not in search mode
353  // recall history
354  showSearchBarText(pLastSearchText);
355 
356  // and initiate search mode
357  find(u->txtSearch->text(), forward);
358  return;
359  }
360 
361  KLF_ASSERT_NOT_NULL( pTarget , "Search target is NULL!" , return ) ;
362 
363  pWaitLabel->startWait();
364  bool found = pTarget->searchFindNext(forward);
365  updateSearchFound(found);
366  pWaitLabel->stopWait();
367  pLastSearchText = pSearchText;
368  emitFoundSignals(found, pSearchText, forward);
369 }
370 
372 {
374 
375  pSearchText = QString();
376  if ( ! u->txtSearch->text().isEmpty() ) {
377  showSearchBarText("");
378  }
379 
380  if (searchBarHasFocus())
382  else
384 
385  if (pTarget != NULL) {
386  klfDbg("telling target to abort search...") ;
387  pTarget->searchAbort();
388  klfDbg("...done") ;
389  }
390 
391  emit searchAborted();
392 }
393 
395 {
397 
398  if (pShowOverlayMode) {
399  QWidget *pw = parentWidget();
400  if (pw != NULL) {
401  // if we have a parent widget, adjust using our relative geometry
402  QSize pws = pw->size();
403 
404  QPoint relPos = pShowOverlayRelativeGeometry.topLeft();
405  QSize relSz = pShowOverlayRelativeGeometry.size();
406 
407  QSize sz = QSize(pws.width()*relSz.width()/100, pws.height()*relSz.height()/100);
408  sz = sz.expandedTo(minimumSizeHint()) ;
409  QRect gm = QRect( QPoint( (pws.width()-sz.width())*relPos.x()/100, (pws.height()-sz.height())*relPos.y()/100 ),
410  sz );
411  klfDbg("Geometry is "<<gm) ;
412  setGeometry(gm);
413  // setAutoFillBackground(true);
414  setStyleSheet(styleSheet());
415  raise();
416  } else {
417  // set some widget window flags if we're parent-less...
418  setWindowFlags(Qt::Tool);
419  // just for fun...
420  setWindowOpacity(0.95);
421  }
422  }
423  if (!isVisible()) {
424  // show the search bar. This works with in overlay mode as well as when the widget is hidden
425  // with the hide button.
426  show();
427  }
428  u->txtSearch->setFocus();
429 }
430 
432 {
433  klfDbgT("focus in") ;
435  showSearchBarText("");
436 }
437 
439 {
440  klfDbgT("focus out") ;
442  if (pShowOverlayMode)
443  hide();
444 }
445 
447 {
448  displayState(found ? Found : NotFound);
449 }
450 
451 // private
452 QString KLFSearchBar::palettePropName(SearchState state) const
453 {
454  switch (state) {
455  case Default: return QString("paletteDefault");
456  case FocusOut: return QString("paletteFocusOut");
457  case Found: return QString("paletteFound");
458  case NotFound: return QString("paletteNotFound");
459  case Aborted: return QString("paletteDefault");
460  default:
461  qWarning()<<KLF_FUNC_NAME<<": invalid state: "<<state;
462  }
463  return QString();
464 }
465 // private
466 QString KLFSearchBar::statePropValue(SearchState state) const
467 {
468  switch (state) {
469  case Default: return QLatin1String("default");
470  case FocusOut: return QLatin1String("focus-out");
471  case Found: return QLatin1String("found");
472  case NotFound: return QLatin1String("not-found");
473  case Aborted: return QLatin1String("aborted");
474  default: return QLatin1String("invalid");
475  }
476 }
477 
479 {
480  klfDbg("Setting state: "<<statePropValue(s));
481  u->txtSearch->setProperty("searchState", statePropValue(s));
482  QPalette pal = u->txtSearch->property(palettePropName(s).toAscii()).value<QPalette>();
483  u->txtSearch->setStyleSheet(u->txtSearch->styleSheet());
484  u->txtSearch->setPalette(pal);
485  u->txtSearch->update();
486 
487  if (s == FocusOut) {
488  showSearchBarText(pFocusOutText);
489  }
490 }
491 
492 void KLFSearchBar::emitFoundSignals(bool resultfound, const QString& searchstring, bool forward)
493 {
494  emit searchPerformed(resultfound);
495  if (resultfound) {
496  emit found();
497  emit found(searchstring, forward);
498  } else {
499  emit didNotFind();
500  emit didNotFind(searchstring, forward);
501  }
502 }
503 
505 {
506  u->txtSearch->blockSignals(true);
507  u->txtSearch->setText(text);
508  u->txtSearch->blockSignals(false);
509 }
511 {
512  return QApplication::focusWidget() == u->txtSearch;
513 }
514 
515 
517 {
518  if (event->type() == QEvent::Polish)
519  setMinimumSize(minimumSizeHint());
520 
521  return QFrame::event(event);
522 }
void setSearchTarget(KLFSearchable *target)
virtual bool searchFindNext(bool forward)
KLFSearchBar(QWidget *parent=NULL)
virtual ~KLFSearchable()
An interface for objects that can be I-searched with a KLFSearchBar.
Definition: klfsearchbar.h:62
setColor(ColorGroup group, ColorRole role, const QColor &color)
virtual bool searchFindNext(bool forward)=0
Find next or previous occurence of query string.
#define klfDbgT(streamableItems)
QString currentSearchText() const
void setFocusOutText(const QString &focusOutText)
virtual void slotSearchFocusIn()
color(ColorGroup group, ColorRole role)
virtual void searchAbort()=0
Abort I-Search.
#define klfDbg(streamableItems)
void showSearchBarText(const QString &text)
#define KLF_DEBUG_BLOCK(msg)
void setColorFound(const QColor &color)
void focusOrNext(bool forward=true)
void setColorNotFound(const QColor &color)
#define DECLARE_SEARCH_SHORTCUT(shortcut, parent, slotmember)
QColor colorNotFound() const
virtual void setSearchTarget(KLFSearchable *object)
#define KLF_ASSERT_NOT_NULL(ptr, msg, failaction)
void escapePressed()
void abortSearch()
virtual bool searchFind(const QString &queryString, bool forward)=0
Find the first occurence of a query string.
virtual ~KLFSearchBar()
virtual void searchAbort()
append(const T &value)
void didNotFind()
virtual void displayState(SearchState state)
void findNext(bool forward=true)
removeAll(const T &value)
void setShowOverlayRelativeGeometry(const QRect &relativeGeometryPercent)
virtual void setSearchText(const QString &text)
#define KLF_DEBUG_TIME_BLOCK(msg)
void setShowHideButton(bool showHideButton)
bool searchBarHasFocus()
void emitFoundSignals(bool found, const QString &searchstring, bool forward)
#define KLF_FUNC_NAME
void searchPerformed(bool found)
virtual void updateSearchFound(bool found)
QColor colorFound() const
An animation display.
Definition: klfguiutil.h:412
void searchAborted()
void findPrev()
Definition: klfsearchbar.h:237
expandedTo(const QSize &otherSize)
Ui::KLFSearchBar * u
Definition: klfsearchbar.h:246
void setShowOverlayMode(bool showOverlayMode)
virtual void setWaitMovie(QMovie *movie)
Set which animation to display while searching.
Definition: klfguiutil.cpp:371
void focusOrPrev()
Definition: klfsearchbar.h:233
virtual void slotSearchFocusOut()
virtual void stopWait()
Hide the animation.
Definition: klfguiutil.cpp:415
QString focusOutText() const
Definition: klfsearchbar.h:196
virtual ~KLFSearchableProxy()
QLineEdit * editor()
bool hideButtonShown() const
virtual bool eventFilter(QObject *obj, QEvent *ev)
virtual void registerShortcuts(QWidget *parent)
virtual bool event(QEvent *event)
virtual void startWait()
Display the animation.
Definition: klfguiutil.cpp:395
void find(const QString &string)
Definition: klfsearchbar.h:234
virtual bool searchFind(const QString &queryString, bool forward)

Generated by doxygen 1.8.8