[KLF Backend][KLF Tools][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) 2011 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$ */
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 #include "klfsearchbar_p.h"
00039 
00040 
00041 
00134 QDebug& operator<<(QDebug& str, const KLFPosSearchable::Pos& pos)
00135 {
00136   QString s;
00137   s.sprintf("%p", (const void*)(const KLFPosSearchable::Pos::PosData*)pos.posdata);
00138   str << "Pos("<<qPrintable(s);
00139   if (pos.posdata != NULL) {
00140     QString desc;
00141     if (!(desc = pos.posdata->toDebug()).isEmpty())
00142       str << " " << qPrintable(desc);
00143   }
00144   return str <<")";
00145 }
00146 
00147 // --
00148 
00149 KLFPosSearchable::Pos KLFPosSearchable::searchStartFrom(bool forward)
00150 {
00151   klfDbg("start from: base implementation, will return invalid. forward="<<forward) ;
00152   Q_UNUSED(forward) ;
00153   return Pos();
00154 }
00155 
00156 void KLFPosSearchable::setSearchInterruptRequested(bool on)
00157 {
00158   klfDbg("on="<<on) ;
00159   pInterruptRequested = on;
00160 }
00161 
00162 
00163 // ------------------------------------------------
00164 
00165 
00166 KLFPosSearchableProxy::~KLFPosSearchableProxy()
00167 {
00168 }
00169 
00170 KLFPosSearchable::Pos KLFPosSearchableProxy::searchStartFrom(bool forward)
00171 {
00172   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return Pos() );
00173   return target()->searchStartFrom(forward);
00174 }
00175 
00176 KLFPosSearchable::Pos KLFPosSearchableProxy::searchFind(const QString& queryString, const Pos& fromPos, bool forward)
00177 {
00178   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return Pos() );
00179   return target()->searchFind(queryString, fromPos, forward);
00180 }
00181 
00182 void KLFPosSearchableProxy::searchMoveToPos(const Pos& pos)
00183 {
00184   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
00185   return target()->searchMoveToPos(pos);
00186 }
00187 
00188 void KLFPosSearchableProxy::searchPerformed(const QString& queryString, bool found, const Pos& pos)
00189 {
00190   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
00191   target()->searchPerformed(queryString, found, pos);
00192 }
00193 
00194 void KLFPosSearchableProxy::searchAborted()
00195 {
00196   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
00197   target()->searchAborted();
00198 }
00199 
00200 void KLFPosSearchableProxy::searchReinitialized()
00201 {
00202   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
00203   target()->searchReinitialized();
00204 }
00205 
00206 QString KLFPosSearchableProxy::searchQueryString() const
00207 {
00208   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return QString(); );
00209   return target()->searchQueryString();
00210 }
00211 
00212 void KLFPosSearchableProxy::setSearchQueryString(const QString& s)
00213 {
00214   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
00215   target()->setSearchQueryString(s);
00216 }
00217 
00218 bool KLFPosSearchableProxy::searchHasInterruptRequested()
00219 {
00220   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return false; );
00221   return target()->searchHasInterruptRequested();
00222 }
00223 
00224 void KLFPosSearchableProxy::setSearchInterruptRequested(bool on)
00225 {
00226   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return ; );
00227   target()->setSearchInterruptRequested(on);
00228 }
00229 
00230 
00231 
00232 // ---
00233 
00234 struct DummySearchPosData : public KLFPosSearchable::Pos::PosData
00235 {
00236   bool equals(PosData *) const { return true; }
00237 };
00238 
00239 
00240 KLFSearchable::KLFSearchable()
00241 {
00242 }
00243 KLFSearchable::~KLFSearchable()
00244 {
00245 }
00246 
00247 KLFPosSearchable::Pos KLFSearchable::searchFind(const QString& queryString, const Pos& fromPos, bool forward)
00248 {
00249   bool r;
00250   // simulate first search, then 'find next', by detecting if we're required to search from a given pos
00251   // (heuristic that will fail in special cases!!)
00252   if (!fromPos.valid())
00253     r = searchFind(queryString, forward);
00254   else
00255     r = searchFindNext(forward);
00256   Pos p = Pos();
00257   if (!r)
00258     return p;
00259   // return dummy valid pos
00260   p.posdata = new DummySearchPosData;
00261   return p;
00262 }
00263 
00264 
00265 // -----
00266 
00267 KLFSearchableProxy::~KLFSearchableProxy()
00268 {
00269 }
00270 
00271 void KLFSearchableProxy::setTarget(KLFTarget *target)
00272 {
00273   KLFSearchable *s = dynamic_cast<KLFSearchable*>(target);
00274   KLF_ASSERT_CONDITION( (s!=NULL) || (target==NULL),
00275                         "target is not a valid KLFSearchable object !",
00276                         return; ) ;
00277   KLFTargeter::setTarget(s);
00278 }
00279 
00280 bool KLFSearchableProxy::searchFind(const QString& queryString, bool forward)
00281 {
00282   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return false );
00283   return target()->searchFind(queryString, forward);
00284 }
00285 bool KLFSearchableProxy::searchFindNext(bool forward)
00286 {
00287   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return false );
00288   return target()->searchFindNext(forward);
00289 }
00290 void KLFSearchableProxy::searchAbort()
00291 {
00292   KLF_ASSERT_NOT_NULL( target(), "Search target is NULL!", return );
00293   return target()->searchAbort();
00294 }
00295 
00296 
00297 // ------------------------
00298 
00299 KLFSearchBar::KLFSearchBar(QWidget *parent)
00300   : QFrame(parent)
00301 {
00302   KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00303   klfDbg("parent: "<<parent) ;
00304 
00305   _isInQtDesigner = false;
00306 
00307   d = new KLFSearchBarPrivate;
00308 
00309   u = new Ui::KLFSearchBar;
00310   u->setupUi(this);
00311 
00312   setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
00313 
00314   u->txtSearch->installEventFilter(this);
00315   connect(u->btnSearchClear, SIGNAL(clicked()), this, SLOT(clear()));
00316   connect(u->txtSearch, SIGNAL(textChanged(const QString&)),
00317           this, SLOT(find(const QString&)));
00318   connect(u->btnFindNext, SIGNAL(clicked()), this, SLOT(findNext()));
00319   connect(u->btnFindPrev, SIGNAL(clicked()), this, SLOT(findPrev()));
00320 
00321   QPalette defaultpal = u->txtSearch->palette();
00322   u->txtSearch->setProperty(palettePropName(Default).toLatin1(), QVariant::fromValue<QPalette>(defaultpal));
00323   QPalette pal0 = defaultpal;
00324   pal0.setColor(QPalette::Text, QColor(180,180,180));
00325   pal0.setColor(QPalette::WindowText, QColor(180,180,180));
00326   pal0.setColor(u->txtSearch->foregroundRole(), QColor(180,180,180));
00327   u->txtSearch->setProperty(palettePropName(FocusOut).toLatin1(), QVariant::fromValue<QPalette>(pal0));
00328   // default found/not-found colors
00329   setColorFound(QColor(128,255,128));
00330   setColorNotFound(QColor(255,128,128));
00331 
00332   connect(u->btnHide, SIGNAL(clicked()), this, SLOT(hide()));
00333   setShowHideButton(false); // not shown by default
00334 
00335   d->pResetTimeout = 10000;
00336   connect(&d->pFocusOutResetTimer, SIGNAL(timeout()), this, SLOT(slotSearchReset()));
00337 
00338   d->pWaitLabel = new KLFWaitAnimationOverlay(u->txtSearch);
00339   d->pWaitLabel->setWaitMovie(":/pics/wait_anim.mng");
00340   /* // amusing test
00341      d->pWaitLabel->setWaitMovie("/home/philippe/projects/klf/artwork/experimental/packman_anim.gif");
00342   */
00343 
00344   d->pAutoHide = false;
00345 
00346   d->pShowOverlayMode = false;
00347   // default relative geometry: position at (50%, 95%) (centered, quasi-bottom)
00348   //                            size     of (90%, 0%)   [remember: expanded to minimum size]
00349   d->pShowOverlayRelativeGeometry = QRect(QPoint(50, 95), QSize(90, 0));
00350 
00351   d->pFocusOutText = "  "+tr("Hit Ctrl-F, Ctrl-S or / to start searching");
00352 
00353   d->pSearchForward = true;
00354   d->pSearchText = QString();
00355   d->pIsSearching = false;
00356   d->pCurPos = KLFPosSearchable::Pos();
00357   d->pLastPos = KLFPosSearchable::Pos();
00358   d->pState = FocusOut;
00359   displayState(FocusOut);
00360 
00361   d->pIsFinding = false;
00362   d->pHasQueuedFind = false;
00363   d->pQueuedFindString = QString();
00364   d->pQueuedFindForward = true;
00365 
00366   klfDbg("pCurPos is "<<d->pCurPos<<"; pLastPos is "<<d->pLastPos) ;
00367 
00368   d->pUseEsbs = true;
00369 }
00370 KLFSearchBar::~KLFSearchBar()
00371 {
00372   delete d;
00373 }
00374 
00375 QString KLFSearchBar::currentSearchText() const
00376 {
00377   if (d->pState == FocusOut)
00378     return QString();
00379   return u->txtSearch->text();
00380 }
00381 
00382 QColor KLFSearchBar::colorFound() const
00383 {
00384   QPalette p = u->txtSearch->property(palettePropName(Found).toLatin1()).value<QPalette>();
00385   return p.color(QPalette::Base);
00386 }
00387 QColor KLFSearchBar::colorNotFound() const
00388 {
00389   QPalette p = u->txtSearch->property(palettePropName(NotFound).toLatin1()).value<QPalette>();
00390   return p.color(QPalette::Base);
00391 }
00392 
00393 bool KLFSearchBar::hideButtonShown() const
00394 {
00395   return u->btnHide->isVisible();
00396 }
00397 
00398 bool KLFSearchBar::showSearchLabel() const
00399 {
00400   return u->lblSearch->isVisible();
00401 }
00402 
00403 bool KLFSearchBar::emacsStyleBackspace() const
00404 {
00405   return d->pUseEsbs;
00406 }
00407 
00408 int KLFSearchBar::resetTimeout() const
00409 {
00410   return d->pResetTimeout;
00411 }
00412 
00413 KLFPosSearchable::Pos KLFSearchBar::currentSearchPos() const
00414 {
00415   return d->pCurPos;
00416 }
00417 
00418 KLFSearchBar::SearchState KLFSearchBar::currentState() const
00419 {
00420   return d->pState;
00421 }
00422 
00423 
00424 void KLFSearchBar::setColorFound(const QColor& color)
00425 {
00426   QPalette pal1 = u->txtSearch->property(palettePropName(Default).toLatin1()).value<QPalette>();
00427   pal1.setColor(QPalette::Base, color);
00428   pal1.setColor(QPalette::Window, color);
00429   pal1.setColor(u->txtSearch->backgroundRole(), color);
00430   u->txtSearch->setProperty(palettePropName(Found).toLatin1(), QVariant::fromValue<QPalette>(pal1));
00431 }
00432 
00433 void KLFSearchBar::setColorNotFound(const QColor& color)
00434 {
00435   QPalette pal2 = u->txtSearch->property(palettePropName(Default).toLatin1()).value<QPalette>();
00436   pal2.setColor(QPalette::Base, color);
00437   pal2.setColor(QPalette::Window, color);
00438   pal2.setColor(u->txtSearch->backgroundRole(), color);
00439   u->txtSearch->setProperty(palettePropName(NotFound).toLatin1(), QVariant::fromValue<QPalette>(pal2));
00440 }
00441 
00442 void KLFSearchBar::setShowHideButton(bool showHideButton)
00443 {
00444   u->btnHide->setVisible(showHideButton);
00445 }
00446 
00447 void KLFSearchBar::setShowSearchLabel(bool on)
00448 {
00449   u->lblSearch->setVisible(on);
00450 }
00451 
00452 void KLFSearchBar::setEmacsStyleBackspace(bool on)
00453 {
00454   if (d->pIsSearching)
00455     abortSearch();
00456   d->pUseEsbs = on;
00457 }
00458 
00459 void KLFSearchBar::setResetTimeout(int ms)
00460 {
00461   d->pResetTimeout = ms;
00462 }
00463 
00464 
00466 #define DECLARE_SEARCH_SHORTCUT(shortcut, parent, slotmember)           \
00467   { QShortcut *s = new QShortcut(parent); s->setKey(QKeySequence(shortcut)); \
00468     connect(s, SIGNAL(activated()), this, slotmember); }
00469 
00470 void KLFSearchBar::registerShortcuts(QWidget *parent)
00471 {
00472   DECLARE_SEARCH_SHORTCUT(tr("Ctrl+F", "[[find]]"), parent, SLOT(focusOrNext()));
00473   DECLARE_SEARCH_SHORTCUT(tr("Ctrl+S", "[[find]]"), parent, SLOT(focusOrNext()));
00474   DECLARE_SEARCH_SHORTCUT(tr("Ctrl+G", "[[find]]"), parent, SLOT(focusOrNext()));
00475   DECLARE_SEARCH_SHORTCUT(tr("/", "[[find]]"), parent, SLOT(clear()));
00476   DECLARE_SEARCH_SHORTCUT(tr("F3", "[[find next]]"), parent, SLOT(findNext()));
00477   DECLARE_SEARCH_SHORTCUT(tr("Shift+F3", "[[find prev]]"), parent, SLOT(findPrev()));
00478   DECLARE_SEARCH_SHORTCUT(tr("Ctrl+R", "[[find rev]]"), parent, SLOT(focusOrPrev()));
00479   // Esc will be captured through event filter so that it isn't too obstrusive...
00480 }
00481 
00482 void KLFSearchBar::setTarget(KLFTarget * target)
00483 {
00484   if (d->pIsSearching)
00485     abortSearch();
00486 
00487   KLFPosSearchable *s = dynamic_cast<KLFPosSearchable*>(target);
00488   KLF_ASSERT_CONDITION( (s!=NULL) || (target==NULL),
00489                         "target is not a valid KLFPosSearchable object !",
00490                         return; ) ;
00491   KLFTargeter::setTarget(s);
00492 }
00493 
00494 void KLFSearchBar::setSearchText(const QString& text)
00495 {
00496   u->txtSearch->setText(text);
00497 }
00498 
00499 bool KLFSearchBar::autoHide() const
00500 {
00501   return d->pAutoHide;
00502 }
00503 
00504 bool KLFSearchBar::showOverlayMode() const
00505 {
00506   return d->pShowOverlayMode;
00507 }
00508 QRect KLFSearchBar::showOverlayRelativeGeometry() const
00509 {
00510   return d->pShowOverlayRelativeGeometry;
00511 }
00512 QString KLFSearchBar::focusOutText() const
00513 {
00514   return d->pFocusOutText;
00515 }
00516 
00517 
00518 void KLFSearchBar::setFocusOutText(const QString& focusOutText)
00519 {
00520   d->pFocusOutText = focusOutText;
00521   if (d->pState == FocusOut) {
00522     // re-display focus-out state
00523     displayState(FocusOut);
00524   }
00525 }
00526 
00527 
00528 static KLFSearchBarPrivate::HistBuffer::CurLastPosPair
00529 /* */ esbs_get_last_pos(const QList<KLFSearchBarPrivate::HistBuffer>& hb, int offset = 0)
00530 {
00531   if (hb.size() <= offset) { // there is no preceeding histbuffer
00532     return KLFSearchBarPrivate::HistBuffer::CurLastPosPair(KLFPosSearchable::Pos(),
00533                                                            KLFPosSearchable::Pos());
00534   }
00535   const QList<KLFSearchBarPrivate::HistBuffer::CurLastPosPair>& poslist = hb[hb.size()-1 - offset].poslist;
00536 
00537   if (poslist.isEmpty()) {
00538     return esbs_get_last_pos(hb, offset+1);
00539   }
00540   return poslist.last();
00541 }
00542 
00543 bool KLFSearchBar::eventFilter(QObject *obj, QEvent *ev)
00544 {
00545   KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00546 
00547   if (obj == u->txtSearch) {
00548     if (ev->type() == QEvent::FocusIn) {
00549       klfDbg("focus-in event...") ;
00550       slotSearchFocusIn();
00551       // don't eat event
00552     } else if (ev->type() == QEvent::FocusOut) {
00553       klfDbg("focus-out event...") ;
00554       slotSearchFocusOut();
00555       // don't eat event
00556     } else if (ev->type() == QEvent::KeyPress) {
00557       klfDbg("key press event!") ;
00558       QKeyEvent *ke = (QKeyEvent*)ev;
00559       if (ke->key() == Qt::Key_Escape) {
00560         abortSearch();
00561         emit escapePressed();
00562         return true;
00563       }
00564       // Emacs-Style Backspace handling
00565       if (d->pUseEsbs) {
00566         // what kind of key press is this
00567         if (ke->key() == Qt::Key_Backspace) {
00568           // if searching, backspace interrupts the search.
00569           if (d->pIsFinding) {
00570             KLF_ASSERT_CONDITION_ELSE(target()!=NULL, "Search Target is NULL!", ; )  {
00571               target()->setSearchInterruptRequested(true);
00572               return true;
00573             }
00574           }
00575           if ( ! d->esbs_histbuffer.size() ) {
00576             // back to beginning of text buffer...
00577             promptEmptySearch();
00578           } else {
00579             // there is a current history buffer
00580             KLFSearchBarPrivate::HistBuffer& histbuf = d->esbs_histbuffer.last();
00581             if (histbuf.poslist.size() > 1) {
00582               // jump to previous match
00583               histbuf.poslist.pop_back();
00584               const KLFSearchBarPrivate::HistBuffer::CurLastPosPair& pos = histbuf.poslist.last();
00585               // move to previous match
00586               KLF_ASSERT_CONDITION_ELSE(target()!=NULL, "Search Target is NULL!", ; )  {
00587                 d->pCurPos = pos.cur;
00588                 d->pLastPos = pos.last;
00589                 // move to given pos, and present found result
00590                 target()->searchMoveToPos(d->pCurPos);
00591                 target()->searchPerformed(d->pSearchText, d->pCurPos.valid(), d->pCurPos);
00592                 updateSearchFound(d->pCurPos.valid());
00593                 emit hasMatch(d->pCurPos.valid());
00594               }
00595             } else {
00596               d->esbs_histbuffer.pop_back();
00597               // if there is left 
00598               if (!d->esbs_histbuffer.size()) {
00599                 // back to beginning of text buffer...
00600                 promptEmptySearch();
00601               } else {
00602                 // remove last item in buffer
00603                 d->pSearchText = d->esbs_histbuffer.last().str;
00604                 // check if there actually is text left
00605                 u->txtSearch->blockSignals(true);
00606                 u->txtSearch->setText(d->pSearchText);
00607                 u->txtSearch->blockSignals(false);
00608                 const QList<KLFSearchBarPrivate::HistBuffer::CurLastPosPair> poslist
00609                   = d->esbs_histbuffer.last().poslist;
00610                 KLF_ASSERT_CONDITION_ELSE(target()!=NULL, "Search Target is NULL!", ; ) {
00611                   // find the last position where we were
00612                   KLFSearchBarPrivate::HistBuffer::CurLastPosPair clpos = esbs_get_last_pos(d->esbs_histbuffer);
00613                   d->pCurPos = clpos.cur;
00614                   d->pLastPos = clpos.last;
00615                   // make sure query string is up-to-date
00616                   target()->setSearchQueryString(d->pSearchText);
00617                   if (poslist.isEmpty()) {
00618                     // can be the result of an interrupted find, search from the preceeding poslist
00619                     d->pCurPos = d->pLastPos;
00620                     findNext(clpos.reachedForward);
00621                   } else {
00622                     target()->searchMoveToPos(d->pCurPos);
00623                     target()->searchPerformed(d->pSearchText, d->pCurPos.valid(), d->pCurPos);
00624                     updateSearchFound(d->pCurPos.valid());
00625                     emitFoundSignals(d->pCurPos, d->pSearchText, clpos.reachedForward);
00626                     emit hasMatch(d->pCurPos.valid());
00627                   }
00628                 }
00629               }
00630             }
00631           }
00632           // in every case, eat the event
00633           return true;
00634         } else if (ke->key() == Qt::Key_Left || ke->key() == Qt::Key_Right) {
00635           // no left/right navigation
00636           return true;
00637         } else if (ke->key() == Qt::Key_Home || ke->key() == Qt::Key_End) {
00638           // don't allow text navigation
00639           return true;
00640         } else if (ke->text().size() && ke->text()[0].isPrint()) {
00641           // pass on the event further to QLineEdit
00642           // Also, it is in find() that will we will create a new HistBuffer for this exact
00643           // new partial search string.
00644         }
00645       } // if (use e-s-b-s)
00646       else {
00647         klfDbg("key press, but not using e-s-b-s.");
00648         return false;
00649       }
00650     } // if (is key-press)
00651 
00652   }
00653   return QFrame::eventFilter(obj, ev);
00654 }
00655 
00656 QLineEdit * KLFSearchBar::editor()
00657 {
00658   return u->txtSearch;
00659 }
00660 
00661 void KLFSearchBar::setAutoHide(bool autohide)
00662 {
00663   klfDbg("autohide="<<autohide) ;
00664   d->pAutoHide = autohide;
00665   if (d->pAutoHide && !searchBarHasFocus() && !_isInQtDesigner)
00666     hide();
00667 }
00668 
00669 void KLFSearchBar::setShowOverlayMode(bool overlayMode)
00670 {
00671   klfDbg("setting show overlay mode to "<<overlayMode) ;
00672   d->pShowOverlayMode = overlayMode;
00673   setProperty("klfShowOverlayMode", QVariant::fromValue<bool>(d->pShowOverlayMode));
00674   // cheat with klfTopLevelWidget property, set it always in show-overlay-mode
00675   setProperty("klfTopLevelWidget", QVariant::fromValue<bool>(d->pShowOverlayMode));
00676 
00677   adjustOverlayGeometry();
00680 }
00681 
00682 void KLFSearchBar::setShowOverlayRelativeGeometry(const QRect& relativeGeometryPercent)
00683 {
00684   d->pShowOverlayRelativeGeometry = relativeGeometryPercent;
00685   adjustOverlayGeometry();
00686 }
00687 void KLFSearchBar::setShowOverlayRelativeGeometry(int widthPercent, int heightPercent,
00688                                                   int positionXPercent, int positionYPercent)
00689 {
00690   setShowOverlayRelativeGeometry(QRect(QPoint(positionXPercent, positionYPercent),
00691                                        QSize(widthPercent, heightPercent)));
00692   adjustOverlayGeometry();
00693 }
00694 
00695 
00696 
00697 void KLFSearchBar::clear()
00698 {
00699   klfDbgT("clear") ;
00700   setSearchText("");
00701   focus();
00702 }
00703 
00704 void KLFSearchBar::focusOrNext(bool forward)
00705 {
00706   d->pSearchForward = forward;
00707 
00708   if (d->pState != FocusOut) {
00709     klfDbgT("already are in focus state") ;
00710     // focus search bar if not yet focused.
00711     if (!searchBarHasFocus())
00712       focus();
00713     // already has focus
00714     // -> either recall history (if empty search text)
00715     // -> or find next
00716     if (u->txtSearch->text().isEmpty()) {
00717       setSearchText(d->pLastSearchText);
00718     } else {
00719       if (!d->pIsSearching) {
00720         find(u->txtSearch->text(), forward);
00721       } else {
00722         findNext(forward);
00723       }
00724     }
00725   } else {
00726     klfDbgT("setting focus") ;
00727     setSearchText("");
00728     focus();
00729   }
00730 }
00731 
00732 void KLFSearchBar::find(const QString& string)
00733 {
00734   find(string, d->pSearchForward);
00735 }
00736 
00737 void KLFSearchBar::find(const QString& text, bool forward)
00738 {
00739   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00740   klfDbgT("text="<<text<<", forward="<<forward) ;
00741 
00742   if (target() == NULL && text.isEmpty())
00743     return;
00744 
00745   KLF_ASSERT_NOT_NULL( target() , "search target is NULL!", return ) ;
00746 
00747   if (d->pIsFinding) {
00748     klfDbg("find()ing already. queueing and requesting to stop previous find.");
00749     target()->setSearchInterruptRequested(true);
00750     d->pHasQueuedFind = true;
00751     d->pQueuedFindString = text;
00752     d->pQueuedFindForward = forward;
00753     return;
00754   }
00755 
00756   if ( text.isEmpty() ||
00757        (d->pUseEsbs && text.mid(0, d->pSearchText.size()) != d->pSearchText) ) {
00758     promptEmptySearch();
00759     return;
00760   }
00761 
00762   if (!d->pIsSearching) {
00763     klfDbg("new search. find start from position.") ;
00764     // first find() call, started new search, start from suggested position
00765     d->pCurPos = target()->searchStartFrom(forward);
00766     d->pLastPos = d->pCurPos;
00767     klfDbg("Starting from d->pCurPos="<<d->pCurPos) ;
00768   }
00769 
00770   d->pIsSearching = true;
00771   d->pSearchText = text;
00772   performFind(forward, false);
00773 }
00774 
00775 
00776 // private
00777 void KLFSearchBar::performFind(bool forward, bool isfindnext)
00778 {
00779   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00780 
00781   KLF_ASSERT_NOT_NULL( target() , "search target is NULL!", return ) ;
00782 
00783   if (!isfindnext) {
00784     // prepare this esbs-hist-buffer
00785     if (d->pUseEsbs) {
00786       KLFSearchBarPrivate::HistBuffer buf;
00787       buf.str = d->pSearchText;
00788       d->esbs_histbuffer << buf;
00789     }
00790   }
00791 
00792   klfDbg("pSearchText="<<d->pSearchText<<"; pCurPos="<<d->pCurPos<<"; pLastPos="<<d->pLastPos) ;
00793 
00794   // reset the interrupt request flag
00795   target()->setSearchInterruptRequested(false);
00796 
00797   d->pIsFinding = true;
00798   d->pWaitLabel->startWait();
00799   target()->setSearchQueryString(d->pSearchText);
00800   klfDbg("pSearchText="<<d->pSearchText<<"; target()->searchQueryString()="<<target()->searchQueryString()) ;
00801   KLFPosSearchable::Pos pos = target()->searchFind(d->pSearchText, d->pLastPos, forward);
00802   d->pWaitLabel->stopWait();
00803   d->pIsFinding = false;
00804 
00805   if (!d->pIsSearching) {
00806     // search was aborted.
00807     return;
00808   }
00809 
00810   d->pCurPos = pos;
00811 
00812   if (target()->searchHasInterruptRequested()) {
00813     // perform queued find
00814     if (d->pHasQueuedFind) {
00815       QString s = d->pQueuedFindString;
00816       bool f = d->pQueuedFindForward;
00817       d->pHasQueuedFind = false;
00818       d->pQueuedFindString = QString();
00819       d->pQueuedFindForward = true;
00820       find(s, f);
00821     }
00822     return;
00823   }
00824 
00825   target()->searchMoveToPos(d->pCurPos);
00826   target()->searchPerformed(d->pSearchText, d->pCurPos.valid(), d->pCurPos);
00827   updateSearchFound(d->pCurPos.valid());
00828   emitFoundSignals(d->pCurPos, d->pSearchText, forward);
00829   emit hasMatch(d->pCurPos.valid());
00830 
00831   klfDbg("Are now at position pCurPos="<<d->pCurPos) ;
00832 
00833   if (d->pUseEsbs) {
00834     KLF_ASSERT_CONDITION_ELSE(d->esbs_histbuffer.size(), "HistBuffer is empty!!", ;)  {
00835       if (d->pCurPos.valid() ||
00836         // append invalid item only if poslist is empty or if the last poslist item is valid
00837           (d->esbs_histbuffer.last().poslist.isEmpty() ||
00838            d->esbs_histbuffer.last().poslist.last().cur.valid())) {
00839         d->esbs_histbuffer.last().poslist
00840           << KLFSearchBarPrivate::HistBuffer::CurLastPosPair(d->pCurPos, d->pLastPos, forward);
00841       }
00842     }
00843   }
00844 }
00845 
00846 void KLFSearchBar::findNext(bool forward)
00847 {
00848   klfDbgT("forward="<<forward) ;
00849 
00850   if (d->pIsFinding) {
00851     klfDbg("finding already. Must wait, ignoring request.");
00852     return;
00853   }
00854 
00855   // focus search bar if not yet focused.
00856   if (!searchBarHasFocus())
00857     focus();
00858 
00859   if (d->pSearchText.isEmpty()) {
00860     klfDbg("called but not in search mode. recalling history="<<d->pLastSearchText) ;
00861     // we're not in search mode
00862     // recall history
00863     showSearchBarText(d->pLastSearchText);
00864 
00865     // and initiate search mode
00866     find(u->txtSearch->text(), forward);
00867     return;
00868   }
00869 
00870   KLF_ASSERT_NOT_NULL( pTarget , "Search target is NULL!" , return ) ;
00871 
00872   d->pLastPos = d->pCurPos; // precisely, find _next_
00873   d->pLastSearchText = d->pSearchText;
00874   performFind(forward, true);
00875 }
00876 
00877 void KLFSearchBar::promptEmptySearch()
00878 {
00879   setCurrentState(Default);
00880   u->txtSearch->blockSignals(true);
00881   u->txtSearch->setText("");
00882   u->txtSearch->blockSignals(false);
00883   d->pSearchText = QString();
00884   d->pCurPos = KLFPosSearchable::Pos();
00885   d->pLastPos = KLFPosSearchable::Pos();
00886   if (target() != NULL) {
00887     klfDbg("telling target to reinitialize search...") ;
00888     if (d->pIsFinding)
00889       target()->setSearchInterruptRequested(true);
00890     target()->setSearchQueryString(QString());
00891     target()->searchMoveToPos(d->pCurPos);
00892     target()->searchReinitialized();
00893     emit searchReinitialized();
00894     emit hasMatch(d->pCurPos.valid());
00895   }
00896 }
00897 
00898 void KLFSearchBar::abortSearch()
00899 {
00900   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00901 
00904   d->pSearchText = QString();
00905   d->pIsSearching = false;
00906   d->pCurPos = KLFPosSearchable::Pos();
00907   d->pLastPos = KLFPosSearchable::Pos();
00908   klfDbg("pCurPos="<<d->pCurPos) ;
00909 
00910   if ( ! u->txtSearch->text().isEmpty() ) {
00911     showSearchBarText("");
00912   }
00913   if (d->pUseEsbs)
00914     d->esbs_histbuffer.clear();
00915 
00916   if (searchBarHasFocus()) {
00917     setCurrentState(Aborted);
00918   } else {
00919     setCurrentState(FocusOut);
00920   }
00921 
00922   if (target() != NULL) {
00923     klfDbg("telling target to abort search...") ;
00924     if (d->pIsFinding)
00925       target()->setSearchInterruptRequested(true);
00926     target()->searchAborted();
00927     target()->setSearchQueryString(QString());
00928     klfDbg("...done") ;
00929   }
00930 
00931   emit searchAborted();
00932   emit hasMatch(false);
00933 }
00934 
00935 void KLFSearchBar::adjustOverlayGeometry()
00936 {
00937   if (d->pShowOverlayMode) {
00938     QWidget *pw = parentWidget();
00939     if (pw != NULL) {
00940       // if we have a parent widget, adjust using our relative geometry
00941       QSize pws = pw->size();
00942       
00943       QPoint relPos = d->pShowOverlayRelativeGeometry.topLeft();
00944       QSize relSz = d->pShowOverlayRelativeGeometry.size();
00945       
00946       QSize sz = QSize(pws.width()*relSz.width()/100, pws.height()*relSz.height()/100);
00947       sz = sz.expandedTo(minimumSizeHint()) ;
00948       QRect gm = QRect( QPoint( (pws.width()-sz.width())*relPos.x()/100, (pws.height()-sz.height())*relPos.y()/100 ),
00949                         sz );
00950       klfDbg("Geometry is "<<gm) ;
00951       setGeometry(gm);
00952       //      setAutoFillBackground(true);
00953       setStyleSheet(styleSheet());
00954       raise();
00955     } else {
00956       // set some widget window flags if we're parent-less...
00957       setWindowFlags(Qt::Tool);
00958       // just for fun...
00959       setWindowOpacity(0.95);
00960     }
00961   }
00962 }
00963 
00964 void KLFSearchBar::focus()
00965 {
00966   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00967 
00968   if (d->pShowOverlayMode)
00969     adjustOverlayGeometry();
00970 
00971   if (!isVisible()) {
00972     // show the search bar. This works with in overlay mode as well as when the widget is hidden
00973     // with the hide button.
00974     show();
00975   }
00976   u->txtSearch->setFocus();
00977 }
00978 
00979 void KLFSearchBar::slotSearchFocusIn()
00980 {
00981   klfDbgT("focus in") ;
00982   if (d->pState != FocusOut) {
00983     // don't have to reinitialize from focusout state.
00984     if (d->pFocusOutResetTimer.isActive()) {
00985       d->pFocusOutResetTimer.stop();
00986     }
00987     return;
00988   }
00989   setCurrentState(Default);
00990   showSearchBarText("");
00991 }
00992 
00993 void KLFSearchBar::slotSearchFocusOut()
00994 {
00995   klfDbgT("focus out") ;
00996 
00997   if (d->pResetTimeout == 0) {
00998     slotSearchReset();
00999     return;
01000   }
01001   if (d->pResetTimeout > 0) {
01002     d->pFocusOutResetTimer.setInterval(d->pResetTimeout);
01003     d->pFocusOutResetTimer.setSingleShot(true);
01004     d->pFocusOutResetTimer.start();
01005     return;
01006   }
01007   // if d->pResetTimeout < 0, do not abort search.
01008 }
01009 
01010 void KLFSearchBar::slotSearchReset()
01011 {
01012   klfDbgT("search reset after focus out.");
01013 
01014   if (d->pAutoHide && !_isInQtDesigner)
01015     hide();
01016 
01017   abortSearch();
01018 }
01019 
01020 void KLFSearchBar::updateSearchFound(bool found)
01021 {
01022   setCurrentState(found ? Found : NotFound);
01023 }
01024 
01025 // private
01026 QString KLFSearchBar::palettePropName(SearchState state) const
01027 {
01028   switch (state) {
01029   case Default:  return QString("paletteDefault");
01030   case FocusOut: return QString("paletteFocusOut");
01031   case Found:    return QString("paletteFound");
01032   case NotFound: return QString("paletteNotFound");
01033   case Aborted:  return QString("paletteDefault");
01034   default:
01035     qWarning()<<KLF_FUNC_NAME<<": invalid state: "<<state;
01036   }
01037   return QString();
01038 }
01039 // private
01040 QString KLFSearchBar::statePropValue(SearchState state) const
01041 {
01042   switch (state) {
01043   case Default:  return QLatin1String("default");
01044   case FocusOut: return QLatin1String("focus-out");
01045   case Found:    return QLatin1String("found");
01046   case NotFound: return QLatin1String("not-found");
01047   case Aborted:  return QLatin1String("aborted");
01048   default:       return QLatin1String("invalid");
01049   }
01050 }
01051 
01052 void KLFSearchBar::setCurrentState(SearchState state)
01053 {
01054   klfDbg("state: "<<state) ;
01055 
01056   if (d->pState == state)
01057     return;
01058 
01059   d->pState = state;
01060   displayState(state);
01061   emit stateChanged(state);
01062 }
01063 
01064 void KLFSearchBar::displayState(SearchState s)
01065 {
01066   klfDbg("Setting state: "<<statePropValue(s));
01067   u->txtSearch->setProperty("searchState", statePropValue(s));
01068   QPalette pal = u->txtSearch->property(palettePropName(s).toLatin1()).value<QPalette>();
01070   u->txtSearch->setStyleSheet(u->txtSearch->styleSheet());
01071   u->txtSearch->setPalette(pal);
01072   u->txtSearch->update();
01073 
01074   if (s == FocusOut) {
01075     showSearchBarText(d->pFocusOutText);
01076   }
01077 }
01078 
01079 void KLFSearchBar::emitFoundSignals(const KLFPosSearchable::Pos& pos, const QString& searchstring, bool forward)
01080 {
01081   bool resultfound = pos.valid();
01082   emit searchPerformed(resultfound);
01083   emit searchPerformed(searchstring, resultfound);
01084   if (resultfound) {
01085     emit found();
01086     emit found(d->pSearchText, forward);
01087     emit found(d->pSearchText, forward, pos);
01088   } else {
01089     emit didNotFind();
01090     emit didNotFind(d->pSearchText, forward);
01091   }
01092 }
01093 
01094 void KLFSearchBar::showSearchBarText(const QString& text)
01095 {
01096   u->txtSearch->blockSignals(true);
01097   u->txtSearch->setText(text);
01098   if (d->pUseEsbs)
01099     d->esbs_histbuffer.clear();
01100   u->txtSearch->blockSignals(false);
01101 }
01102 bool KLFSearchBar::searchBarHasFocus()
01103 {
01104   return  QApplication::focusWidget() == u->txtSearch;
01105 }
01106 
01107 
01108 bool KLFSearchBar::event(QEvent *event)
01109 {
01110   if (event->type() == QEvent::Polish)
01111     setMinimumSize(minimumSizeHint());
01112 
01113   if (event->type() == QEvent::Show) {
01114     emit visibilityChanged(true);
01115   }
01116   if (event->type() == QEvent::Hide) {
01117     emit visibilityChanged(false);
01118   }
01119 
01120   return QFrame::event(event);
01121 }

Generated by doxygen 1.7.6.1. The KLatexFormula website is hosted on sourceforge.net