00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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);
00124
00125 pWaitLabel = new KLFWaitAnimationOverlay(u->txtSearch);
00126 pWaitLabel->setWaitMovie(":/pics/wait_anim.mng");
00127
00128
00129
00130
00131 pShowOverlayMode = false;
00132
00133
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
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
00244 } else if (ev->type() == QEvent::FocusOut) {
00245 klfDbg("focus-out event...") ;
00246 slotSearchFocusOut();
00247 abortSearch();
00248
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
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
00307
00308
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
00347 if (!searchBarHasFocus())
00348 focus();
00349
00350 if (pSearchText.isEmpty()) {
00351 klfDbg("called but not in search mode. recalling history="<<pLastSearchText) ;
00352
00353
00354 showSearchBarText(pLastSearchText);
00355
00356
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
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
00414 setStyleSheet(styleSheet());
00415 raise();
00416 } else {
00417
00418 setWindowFlags(Qt::Tool);
00419
00420 setWindowOpacity(0.95);
00421 }
00422 }
00423 if (!isVisible()) {
00424
00425
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
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
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 }