[KLF Application][KLF Tools][KLF Backend][KLF Home]
KLatexFormula Project

src/klftools/klfsearchbar.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   file klfsearchbar.cpp
00003  *   This file is part of the KLatexFormula Project.
00004  *   Copyright (C) 2010 by Philippe Faist
00005  *   philippe.faist at bluewin.ch
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************/
00022 /* $Id: klfsearchbar.cpp 516 2010-09-26 23:24:33Z philippe $ */
00023 
00024 #include <QDebug>
00025 #include <QObject>
00026 #include <QFrame>
00027 #include <QLineEdit>
00028 #include <QEvent>
00029 #include <QKeyEvent>
00030 #include <QShortcut>
00031 #include <QKeySequence>
00032 #include <QTime>
00033 
00034 #include <klfguiutil.h>
00035 
00036 #include <ui_klfsearchbar.h>
00037 #include "klfsearchbar.h"
00038 
00039 KLFSearchable::KLFSearchable()
00040 {
00041 }
00042 KLFSearchable::~KLFSearchable()
00043 {
00044   int k;
00045   QList<KLFSearchBar*> bars = pTargetOf;
00046   for (k = 0; k < bars.size(); ++k) {
00047     bars[k]->pTarget = NULL;
00048   }
00049   QList<KLFSearchableProxy*> pl = pTargetOfProxy;
00050   for (k = 0; k < pl.size(); ++k) {
00051     pl[k]->pTarget = NULL;
00052   }
00053 }
00054 
00055 // -----
00056 
00057 KLFSearchableProxy::~KLFSearchableProxy()
00058 {
00059   if (pTarget != NULL)
00060     pTarget->pTargetOfProxy.removeAll(this);
00061 }
00062 
00063 void KLFSearchableProxy::setSearchTarget(KLFSearchable *target)
00064 {
00065   if (pTarget != NULL)
00066     pTarget->pTargetOfProxy.removeAll(this);
00067 
00068   pTarget = target;
00069 
00070   if (pTarget != NULL)
00071     pTarget->pTargetOfProxy.append(this);
00072 }
00073 
00074 bool KLFSearchableProxy::searchFind(const QString& queryString, bool forward)
00075 {
00076   KLF_ASSERT_NOT_NULL( pTarget, "Search target is NULL!", return false );
00077   return pTarget->searchFind(queryString, forward);
00078 }
00079 bool KLFSearchableProxy::searchFindNext(bool forward)
00080 {
00081   KLF_ASSERT_NOT_NULL( pTarget, "Search target is NULL!", return false );
00082   return pTarget->searchFindNext(forward);
00083 }
00084 void KLFSearchableProxy::searchAbort()
00085 {
00086   KLF_ASSERT_NOT_NULL( pTarget, "Search target is NULL!", return );
00087   return pTarget->searchAbort();
00088 }
00089 
00090 
00091 // ------------------------
00092 
00093 KLFSearchBar::KLFSearchBar(QWidget *parent)
00094   : QFrame(parent), pTarget(NULL)
00095 {
00096   KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00097   klfDbg("parent: "<<parent) ;
00098 
00099   u = new Ui::KLFSearchBar;
00100   u->setupUi(this);
00101 
00102   setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
00103 
00104   u->txtSearch->installEventFilter(this);
00105   connect(u->btnSearchClear, SIGNAL(clicked()), this, SLOT(clear()));
00106   connect(u->txtSearch, SIGNAL(textChanged(const QString&)),
00107           this, SLOT(find(const QString&)));
00108   connect(u->btnFindNext, SIGNAL(clicked()), this, SLOT(findNext()));
00109   connect(u->btnFindPrev, SIGNAL(clicked()), this, SLOT(findPrev()));
00110 
00111   QPalette defaultpal = u->txtSearch->palette();
00112   u->txtSearch->setProperty(palettePropName(Default).toAscii(), QVariant::fromValue<QPalette>(defaultpal));
00113   QPalette pal0 = defaultpal;
00114   pal0.setColor(QPalette::Text, QColor(180,180,180));
00115   pal0.setColor(QPalette::WindowText, QColor(180,180,180));
00116   pal0.setColor(u->txtSearch->foregroundRole(), QColor(180,180,180));
00117   u->txtSearch->setProperty(palettePropName(FocusOut).toAscii(), QVariant::fromValue<QPalette>(pal0));
00118   // default found/not-found colors
00119   setColorFound(QColor(128,255,128));
00120   setColorNotFound(QColor(255,128,128));
00121 
00122   connect(u->btnHide, SIGNAL(clicked()), this, SLOT(hide()));
00123   setShowHideButton(false); // not shown by default
00124 
00125   pWaitLabel = new KLFWaitAnimationOverlay(u->txtSearch);
00126   pWaitLabel->setWaitMovie(":/pics/wait_anim.mng");
00127   /* // amusing test
00128      pWaitLabel->setWaitMovie("/home/philippe/projects/klf/artwork/experimental/packman_anim.gif");
00129   */
00130 
00131   pShowOverlayMode = false;
00132   // default relative geometry: position at (50%, 95%) (centered, quasi-bottom)
00133   //                            size     of (90%, 0%)   [remember: expanded to minimum size]
00134   pShowOverlayRelativeGeometry = QRect(QPoint(50, 95), QSize(90, 0));
00135 
00136   pFocusOutText = "  "+tr("Hit Ctrl-F, Ctrl-S or / to start searching");
00137 
00138   pSearchForward = true;
00139 
00140   setSearchTarget(NULL);
00141   slotSearchFocusOut();
00142 }
00143 KLFSearchBar::~KLFSearchBar()
00144 {
00145   if (pTarget != NULL)
00146     pTarget->pTargetOf.removeAll(this);
00147 }
00148 
00149 QString KLFSearchBar::currentSearchText() const
00150 {
00151   return u->txtSearch->text();
00152 }
00153 
00154 QColor KLFSearchBar::colorFound() const
00155 {
00156   QPalette p = u->txtSearch->property(palettePropName(Found).toAscii()).value<QPalette>();
00157   return p.color(QPalette::Base);
00158 }
00159 QColor KLFSearchBar::colorNotFound() const
00160 {
00161   QPalette p = u->txtSearch->property(palettePropName(NotFound).toAscii()).value<QPalette>();
00162   return p.color(QPalette::Base);
00163 }
00164 
00165 bool KLFSearchBar::hideButtonShown() const
00166 {
00167   return u->btnHide->isVisible();
00168 }
00169 
00170 void KLFSearchBar::setColorFound(const QColor& color)
00171 {
00172   QPalette pal1 = u->txtSearch->property(palettePropName(Default).toAscii()).value<QPalette>();
00173   pal1.setColor(QPalette::Base, color);
00174   pal1.setColor(QPalette::Window, color);
00175   pal1.setColor(u->txtSearch->backgroundRole(), color);
00176   u->txtSearch->setProperty(palettePropName(Found).toAscii(), QVariant::fromValue<QPalette>(pal1));
00177 }
00178 void KLFSearchBar::setColorNotFound(const QColor& color)
00179 {
00180   QPalette pal2 = u->txtSearch->property(palettePropName(Default).toAscii()).value<QPalette>();
00181   pal2.setColor(QPalette::Base, color);
00182   pal2.setColor(QPalette::Window, color);
00183   pal2.setColor(u->txtSearch->backgroundRole(), color);
00184   u->txtSearch->setProperty(palettePropName(NotFound).toAscii(), QVariant::fromValue<QPalette>(pal2));
00185 }
00186 
00187 void KLFSearchBar::setShowHideButton(bool showHideButton)
00188 {
00189   u->btnHide->setShown(showHideButton);
00190 }
00191 
00193 #define DECLARE_SEARCH_SHORTCUT(shortcut, parent, slotmember)           \
00194   { QShortcut *s = new QShortcut(parent); s->setKey(QKeySequence(shortcut)); \
00195     connect(s, SIGNAL(activated()), this, slotmember); }
00196 
00197 void KLFSearchBar::registerShortcuts(QWidget *parent)
00198 {
00199   DECLARE_SEARCH_SHORTCUT(tr("Ctrl+F", "[[find]]"), parent, SLOT(focusOrNext()));
00200   DECLARE_SEARCH_SHORTCUT(tr("Ctrl+S", "[[find]]"), parent, SLOT(focusOrNext()));
00201   DECLARE_SEARCH_SHORTCUT(tr("/", "[[find]]"), parent, SLOT(clear()));
00202   DECLARE_SEARCH_SHORTCUT(tr("F3", "[[find next]]"), parent, SLOT(findNext()));
00203   DECLARE_SEARCH_SHORTCUT(tr("Shift+F3", "[[find prev]]"), parent, SLOT(findPrev()));
00204   DECLARE_SEARCH_SHORTCUT(tr("Ctrl+R", "[[find rev]]"), parent, SLOT(focusOrPrev()));
00205   // Esc will be captured through event filter so that it isn't too obstrusive...
00206 }
00207 
00208 void KLFSearchBar::setSearchTarget(KLFSearchable * object)
00209 {
00210   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00211   klfDbg("target="<<object) ;
00212 
00213   abortSearch();
00214 
00215   if (pTarget != NULL)
00216     pTarget->pTargetOf.removeAll(this);
00217 
00218   pTarget = object;
00219 
00220   if (pTarget != NULL)
00221     pTarget->pTargetOf.append(this);
00222 
00223   setEnabled(pTarget != NULL);
00224 }
00225 
00226 void KLFSearchBar::setSearchText(const QString& text)
00227 {
00228   u->lblSearch->setText(text);
00229 }
00230 
00231 void KLFSearchBar::setFocusOutText(const QString& focusOutText)
00232 {
00233   pFocusOutText = focusOutText;
00234 }
00235 
00236 
00237 bool KLFSearchBar::eventFilter(QObject *obj, QEvent *ev)
00238 {
00239   if (obj == u->txtSearch) {
00240     if (ev->type() == QEvent::FocusIn) {
00241       klfDbg("focus-in event...") ;
00242       slotSearchFocusIn();
00243       // don't eat event
00244     } else if (ev->type() == QEvent::FocusOut) {
00245       klfDbg("focus-out event...") ;
00246       slotSearchFocusOut();
00247       abortSearch();
00248       // don't eat event
00249     } else if (ev->type() == QEvent::KeyPress) {
00250       QKeyEvent *ke = (QKeyEvent*)ev;
00251       if (ke->key() == Qt::Key_Escape) {
00252         abortSearch();
00253         emit escapePressed();
00254         return true;
00255       }
00256     }
00257   }
00258   return QFrame::eventFilter(obj, ev);
00259 }
00260 
00261 QLineEdit * KLFSearchBar::editor()
00262 {
00263   return u->txtSearch;
00264 }
00265 
00266 void KLFSearchBar::setShowOverlayMode(bool overlayMode)
00267 {
00268   klfDbg("setting show overlay mode to "<<overlayMode) ;
00269   pShowOverlayMode = overlayMode;
00270   if (pShowOverlayMode && !searchBarHasFocus())
00271     hide();
00272   setProperty("klfShowOverlayMode", QVariant::fromValue<bool>(pShowOverlayMode));
00273   // cheat with klfTopLevelWidget property, set it always in show-overlay-mode
00274   setProperty("klfTopLevelWidget", QVariant::fromValue<bool>(pShowOverlayMode));
00275 
00278 }
00279 
00280 void KLFSearchBar::setShowOverlayRelativeGeometry(const QRect& relativeGeometryPercent)
00281 {
00282   pShowOverlayRelativeGeometry = relativeGeometryPercent;
00283 }
00284 void KLFSearchBar::setShowOverlayRelativeGeometry(int widthPercent, int heightPercent,
00285                                                   int positionXPercent, int positionYPercent)
00286 {
00287   setShowOverlayRelativeGeometry(QRect(QPoint(positionXPercent, positionYPercent),
00288                                        QSize(widthPercent, heightPercent)));
00289 }
00290 
00291 
00292 
00293 void KLFSearchBar::clear()
00294 {
00295   klfDbgT("clear") ;
00296   u->txtSearch->setText("");
00297   focus();
00298 }
00299 
00300 void KLFSearchBar::focusOrNext(bool forward)
00301 {
00302   pSearchForward = forward;
00303 
00304   if (QApplication::focusWidget() == u->txtSearch) {
00305     klfDbgT("already have focus") ;
00306     // already has focus
00307     // -> either recall history (if empty search text)
00308     // -> or find next
00309     if (u->txtSearch->text().isEmpty()) {
00310       u->txtSearch->setText(pLastSearchText);
00311     } else {
00312       if (pSearchText.isEmpty())
00313         find(u->txtSearch->text(), forward);
00314       else
00315         findNext(forward);
00316     }
00317   } else {
00318     klfDbgT("setting focus") ;
00319     u->txtSearch->setText("");
00320     focus();
00321   }
00322 }
00323 
00324 void KLFSearchBar::find(const QString& text, bool forward)
00325 {
00326   klfDbgT("text="<<text<<", forward="<<forward) ;
00327   if (text.isEmpty()) {
00328     abortSearch();
00329     return;
00330   }
00331 
00332   KLF_ASSERT_NOT_NULL( pTarget , "search target is NULL!", return ) ;
00333 
00334   pWaitLabel->startWait();
00335   bool found = pTarget->searchFind(text, forward);
00336   updateSearchFound(found);
00337   pWaitLabel->stopWait();
00338   pSearchText = text;
00339   emitFoundSignals(found, pSearchText, forward);
00340 }
00341 
00342 void KLFSearchBar::findNext(bool forward)
00343 {
00344   klfDbgT("forward="<<forward) ;
00345 
00346   // focus search bar if not yet focused.
00347   if (!searchBarHasFocus())
00348     focus();
00349 
00350   if (pSearchText.isEmpty()) {
00351     klfDbg("called but not in search mode. recalling history="<<pLastSearchText) ;
00352     // we're not in search mode
00353     // recall history
00354     showSearchBarText(pLastSearchText);
00355 
00356     // and initiate search mode
00357     find(u->txtSearch->text(), forward);
00358     return;
00359   }
00360 
00361   KLF_ASSERT_NOT_NULL( pTarget , "Search target is NULL!" , return ) ;
00362 
00363   pWaitLabel->startWait();
00364   bool found = pTarget->searchFindNext(forward);
00365   updateSearchFound(found);
00366   pWaitLabel->stopWait();
00367   pLastSearchText = pSearchText;
00368   emitFoundSignals(found, pSearchText, forward);
00369 }
00370 
00371 void KLFSearchBar::abortSearch()
00372 {
00373   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00374 
00375   pSearchText = QString();
00376   if ( ! u->txtSearch->text().isEmpty() ) {
00377     showSearchBarText("");
00378   }
00379 
00380   if (searchBarHasFocus())
00381     displayState(Aborted);
00382   else
00383     displayState(FocusOut);
00384 
00385   if (pTarget != NULL) {
00386     klfDbg("telling target to abort search...") ;
00387     pTarget->searchAbort();
00388     klfDbg("...done") ;
00389   }
00390 
00391   emit searchAborted();
00392 }
00393 
00394 void KLFSearchBar::focus()
00395 {
00396   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00397 
00398   if (pShowOverlayMode) {
00399     QWidget *pw = parentWidget();
00400     if (pw != NULL) {
00401       // if we have a parent widget, adjust using our relative geometry
00402       QSize pws = pw->size();
00403       
00404       QPoint relPos = pShowOverlayRelativeGeometry.topLeft();
00405       QSize relSz = pShowOverlayRelativeGeometry.size();
00406       
00407       QSize sz = QSize(pws.width()*relSz.width()/100, pws.height()*relSz.height()/100);
00408       sz = sz.expandedTo(minimumSizeHint()) ;
00409       QRect gm = QRect( QPoint( (pws.width()-sz.width())*relPos.x()/100, (pws.height()-sz.height())*relPos.y()/100 ),
00410                         sz );
00411       klfDbg("Geometry is "<<gm) ;
00412       setGeometry(gm);
00413       //      setAutoFillBackground(true);
00414       setStyleSheet(styleSheet());
00415       raise();
00416     } else {
00417       // set some widget window flags if we're parent-less...
00418       setWindowFlags(Qt::Tool);
00419       // just for fun...
00420       setWindowOpacity(0.95);
00421     }
00422   }
00423   if (!isVisible()) {
00424     // show the search bar. This works with in overlay mode as well as when the widget is hidden
00425     // with the hide button.
00426     show();
00427   }
00428   u->txtSearch->setFocus();
00429 }
00430 
00431 void KLFSearchBar::slotSearchFocusIn()
00432 {
00433   klfDbgT("focus in") ;
00434   displayState(Default);
00435   showSearchBarText("");
00436 }
00437 
00438 void KLFSearchBar::slotSearchFocusOut()
00439 {
00440   klfDbgT("focus out") ;
00441   displayState(FocusOut);
00442   if (pShowOverlayMode)
00443     hide();
00444 }
00445 
00446 void KLFSearchBar::updateSearchFound(bool found)
00447 {
00448   displayState(found ? Found : NotFound);
00449 }
00450 
00451 // private
00452 QString KLFSearchBar::palettePropName(SearchState state) const
00453 {
00454   switch (state) {
00455   case Default:  return QString("paletteDefault");
00456   case FocusOut: return QString("paletteFocusOut");
00457   case Found:    return QString("paletteFound");
00458   case NotFound: return QString("paletteNotFound");
00459   case Aborted:  return QString("paletteDefault");
00460   default:
00461     qWarning()<<KLF_FUNC_NAME<<": invalid state: "<<state;
00462   }
00463   return QString();
00464 }
00465 // private
00466 QString KLFSearchBar::statePropValue(SearchState state) const
00467 {
00468   switch (state) {
00469   case Default:  return QLatin1String("default");
00470   case FocusOut: return QLatin1String("focus-out");
00471   case Found:    return QLatin1String("found");
00472   case NotFound: return QLatin1String("not-found");
00473   case Aborted:  return QLatin1String("aborted");
00474   default:       return QLatin1String("invalid");
00475   }
00476 }
00477 
00478 void KLFSearchBar::displayState(SearchState s)
00479 {
00480   klfDbg("Setting state: "<<statePropValue(s));
00481   u->txtSearch->setProperty("searchState", statePropValue(s));
00482   QPalette pal = u->txtSearch->property(palettePropName(s).toAscii()).value<QPalette>();
00483   u->txtSearch->setStyleSheet(u->txtSearch->styleSheet());
00484   u->txtSearch->setPalette(pal);
00485   u->txtSearch->update();
00486 
00487   if (s == FocusOut) {
00488     showSearchBarText(pFocusOutText);
00489   }
00490 }
00491 
00492 void KLFSearchBar::emitFoundSignals(bool resultfound, const QString& searchstring, bool forward)
00493 {
00494   emit searchPerformed(resultfound);
00495   if (resultfound) {
00496     emit found();
00497     emit found(pSearchText, forward);
00498   } else {
00499     emit didNotFind();
00500     emit didNotFind(pSearchText, forward);
00501   }
00502 }
00503 
00504 void KLFSearchBar::showSearchBarText(const QString& text)
00505 {
00506   u->txtSearch->blockSignals(true);
00507   u->txtSearch->setText(text);
00508   u->txtSearch->blockSignals(false);
00509 }
00510 bool KLFSearchBar::searchBarHasFocus()
00511 {
00512   return  QApplication::focusWidget() == u->txtSearch;
00513 }
00514 
00515 
00516 bool KLFSearchBar::event(QEvent *event)
00517 {
00518   if (event->type() == QEvent::Polish)
00519     setMinimumSize(minimumSizeHint());
00520 
00521   return QFrame::event(event);
00522 }

Generated by doxygen 1.7.3