• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kdeui

klistviewsearchline.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (c) 2003 Scott Wheeler <wheeler@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #include "klistviewsearchline.h"
00020 
00021 #include <klistview.h>
00022 #include <kiconloader.h>
00023 #include <ktoolbar.h>
00024 #include <ktoolbarbutton.h>
00025 #include <kdebug.h>
00026 #include <klocale.h>
00027 
00028 #include <qapplication.h>
00029 #include <qtimer.h>
00030 #include <qpopupmenu.h>
00031 #include <qlabel.h>
00032 #include <qheader.h>
00033 
00034 #define KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID 2004
00035 
00036 class KListViewSearchLine::KListViewSearchLinePrivate
00037 {
00038 public:
00039     KListViewSearchLinePrivate() :
00040         listView(0),
00041         caseSensitive(false),
00042         activeSearch(false),
00043         keepParentsVisible(true),
00044         queuedSearches(0) {}
00045 
00046     KListView *listView;
00047     bool caseSensitive;
00048     bool activeSearch;
00049     bool keepParentsVisible;
00050     QString search;
00051     int queuedSearches;
00052     QValueList<int> searchColumns;
00053 };
00054 
00056 // public methods
00058 
00059 KListViewSearchLine::KListViewSearchLine(QWidget *parent, KListView *listView, const char *name) :
00060     KLineEdit(parent, name)
00061 {
00062     d = new KListViewSearchLinePrivate;
00063 
00064     d->listView = listView;
00065 
00066     connect(this, SIGNAL(textChanged(const QString &)),
00067             this, SLOT(queueSearch(const QString &)));
00068 
00069     if(listView) {
00070         connect(listView, SIGNAL(destroyed()),
00071                 this, SLOT(listViewDeleted()));
00072 
00073         connect(listView, SIGNAL(itemAdded(QListViewItem *)),
00074                 this, SLOT(itemAdded(QListViewItem *)));
00075     }
00076     else
00077         setEnabled(false);
00078 }
00079 
00080 KListViewSearchLine::KListViewSearchLine(QWidget *parent, const char *name) :
00081     KLineEdit(parent, name)
00082 {
00083     d = new KListViewSearchLinePrivate;
00084 
00085     d->listView = 0;
00086 
00087     connect(this, SIGNAL(textChanged(const QString &)),
00088             this, SLOT(queueSearch(const QString &)));
00089 
00090     setEnabled(false);
00091 }
00092 
00093 KListViewSearchLine::~KListViewSearchLine()
00094 {
00095     delete d;
00096 }
00097 
00098 bool KListViewSearchLine::caseSensitive() const
00099 {
00100     return d->caseSensitive;
00101 }
00102 
00103 QValueList<int> KListViewSearchLine::searchColumns() const
00104 {
00105     return d->searchColumns;
00106 }
00107 
00108 bool KListViewSearchLine::keepParentsVisible() const
00109 {
00110     return d->keepParentsVisible;
00111 }
00112 
00113 KListView *KListViewSearchLine::listView() const
00114 {
00115     return d->listView;
00116 }
00117 
00119 // public slots
00121 
00122 void KListViewSearchLine::updateSearch(const QString &s)
00123 {
00124     if(!d->listView)
00125         return;
00126 
00127     d->search = s.isNull() ? text() : s;
00128 
00129     // If there's a selected item that is visible, make sure that it's visible
00130     // when the search changes too (assuming that it still matches).
00131 
00132     QListViewItem *currentItem = 0;
00133 
00134     switch(d->listView->selectionMode())
00135     {
00136     case KListView::NoSelection:
00137         break;
00138     case KListView::Single:
00139         currentItem = d->listView->selectedItem();
00140         break;
00141     default:
00142     {
00143         int flags = QListViewItemIterator::Selected | QListViewItemIterator::Visible;
00144         for(QListViewItemIterator it(d->listView, flags);
00145             it.current() && !currentItem;
00146             ++it)
00147         {
00148             if(d->listView->itemRect(it.current()).isValid())
00149                 currentItem = it.current();
00150         }
00151     }
00152     }
00153 
00154     if(d->keepParentsVisible)
00155         checkItemParentsVisible(d->listView->firstChild());
00156     else
00157         checkItemParentsNotVisible();
00158 
00159     if(currentItem)
00160         d->listView->ensureItemVisible(currentItem);
00161 }
00162 
00163 void KListViewSearchLine::setCaseSensitive(bool cs)
00164 {
00165     d->caseSensitive = cs;
00166 }
00167 
00168 void KListViewSearchLine::setKeepParentsVisible(bool v)
00169 {
00170     d->keepParentsVisible = v;
00171 }
00172 
00173 void KListViewSearchLine::setSearchColumns(const QValueList<int> &columns)
00174 {
00175     d->searchColumns = columns;
00176 }
00177 
00178 void KListViewSearchLine::setListView(KListView *lv)
00179 {
00180     if(d->listView) {
00181         disconnect(d->listView, SIGNAL(destroyed()),
00182                    this, SLOT(listViewDeleted()));
00183 
00184         disconnect(d->listView, SIGNAL(itemAdded(QListViewItem *)),
00185                    this, SLOT(itemAdded(QListViewItem *)));
00186     }
00187 
00188     d->listView = lv;
00189 
00190     if(lv) {
00191         connect(d->listView, SIGNAL(destroyed()),
00192                 this, SLOT(listViewDeleted()));
00193 
00194         connect(d->listView, SIGNAL(itemAdded(QListViewItem *)),
00195                 this, SLOT(itemAdded(QListViewItem *)));
00196     }
00197 
00198     setEnabled(bool(lv));
00199 }
00200 
00202 // protected members
00204 
00205 bool KListViewSearchLine::itemMatches(const QListViewItem *item, const QString &s) const
00206 {
00207     if(s.isEmpty())
00208         return true;
00209 
00210     // If the search column list is populated, search just the columns
00211     // specifified.  If it is empty default to searching all of the columns.
00212 
00213     if(!d->searchColumns.isEmpty()) {
00214         QValueList<int>::ConstIterator it = d->searchColumns.begin();
00215         for(; it != d->searchColumns.end(); ++it) {
00216             if(*it < item->listView()->columns() &&
00217                item->text(*it).find(s, 0, d->caseSensitive) >= 0)
00218                 return true;
00219         }
00220     }
00221     else {
00222         for(int i = 0; i < item->listView()->columns(); i++) {
00223             if(item->listView()->columnWidth(i) > 0 &&
00224                item->text(i).find(s, 0, d->caseSensitive) >= 0)
00225             {
00226                 return true;
00227             }
00228         }
00229     }
00230 
00231     return false;
00232 }
00233 
00234 QPopupMenu *KListViewSearchLine::createPopupMenu()
00235 {
00236     QPopupMenu *popup = KLineEdit::createPopupMenu();
00237 
00238     if (d->listView->columns()>1) {
00239         QPopupMenu *subMenu = new QPopupMenu(popup);
00240         connect(subMenu, SIGNAL(activated(int)), this, SLOT(searchColumnsMenuActivated(int)));
00241 
00242         popup->insertSeparator();
00243         popup->insertItem(i18n("Search Columns"), subMenu);
00244     
00245         subMenu->insertItem(i18n("All Visible Columns"), KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID);
00246         subMenu->insertSeparator();
00247     
00248         bool allColumnsAreSearchColumns = true;
00249     // TODO Make the entry order match the actual column order
00250     QHeader* const header = d->listView->header();
00251     int visibleColumns = 0;
00252     for(int i = 0; i < d->listView->columns(); i++) {
00253         if(d->listView->columnWidth(i)>0) {
00254             QString columnText = d->listView->columnText(i);
00255             if(columnText.isEmpty()) {
00256             int visiblePosition=1;
00257             for(int j = 0; j < header->mapToIndex(i); j++)
00258                 if(d->listView->columnWidth(header->mapToSection(j))>0)
00259                     visiblePosition++;
00260             columnText = i18n("Column number %1","Column No. %1").arg(visiblePosition);
00261             }
00262                 subMenu->insertItem(columnText, visibleColumns);
00263             if(d->searchColumns.isEmpty() || d->searchColumns.find(i) != d->searchColumns.end())
00264             subMenu->setItemChecked(visibleColumns, true);
00265                 else
00266                     allColumnsAreSearchColumns = false;
00267             visibleColumns++;
00268         }
00269         }
00270         subMenu->setItemChecked(KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID, allColumnsAreSearchColumns);
00271     
00272         // searchColumnsMenuActivated() relies on one possible "all" representation
00273         if(allColumnsAreSearchColumns && !d->searchColumns.isEmpty())
00274             d->searchColumns.clear();
00275     }
00276     
00277     return popup;   
00278 }    
00279 
00281 // protected slots
00283 
00284 void KListViewSearchLine::queueSearch(const QString &search)
00285 {
00286     d->queuedSearches++;
00287     d->search = search;
00288     QTimer::singleShot(200, this, SLOT(activateSearch()));
00289 }
00290 
00291 void KListViewSearchLine::activateSearch()
00292 {
00293     --(d->queuedSearches);
00294 
00295     if(d->queuedSearches == 0)
00296         updateSearch(d->search);
00297 }
00298 
00300 // private slots
00302 
00303 void KListViewSearchLine::itemAdded(QListViewItem *item) const
00304 {
00305     item->setVisible(itemMatches(item, text()));
00306 }
00307 
00308 void KListViewSearchLine::listViewDeleted()
00309 {
00310     d->listView = 0;
00311     setEnabled(false);
00312 }
00313 
00314 void KListViewSearchLine::searchColumnsMenuActivated(int id)
00315 {
00316     if(id == KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID) {
00317         if(d->searchColumns.isEmpty())
00318             d->searchColumns.append(0);
00319         else
00320             d->searchColumns.clear();
00321     }
00322     else {
00323         if(d->searchColumns.find(id) != d->searchColumns.end())
00324             d->searchColumns.remove(id);
00325         else {
00326             if(d->searchColumns.isEmpty()) {
00327                 for(int i = 0; i < d->listView->columns(); i++) {
00328                     if(i != id)
00329                         d->searchColumns.append(i);
00330                 }
00331             }
00332             else
00333                 d->searchColumns.append(id);
00334         }
00335     }
00336     updateSearch();
00337 }
00338 
00340 // private methods
00342 
00343 void KListViewSearchLine::checkItemParentsNotVisible()
00344 {
00345     QListViewItemIterator it(d->listView);
00346     for(; it.current(); ++it)
00347     {
00348         QListViewItem *item = it.current();
00349         if(itemMatches(item, d->search))
00350             item->setVisible(true);
00351         else
00352             item->setVisible(false);
00353     }
00354 }
00355 
00356 #include <kdebug.h>
00357 
00367 bool KListViewSearchLine::checkItemParentsVisible(QListViewItem *item, QListViewItem *highestHiddenParent)
00368 {
00369     bool visible = false;
00370     QListViewItem * first = item;
00371     for(; item; item = item->nextSibling())
00372     {
00373         //What we pass to our children as highestHiddenParent:
00374         QListViewItem * hhp = highestHiddenParent ? highestHiddenParent : item->isVisible() ? 0L : item;
00375         bool childMatch = false;
00376         if(item->firstChild() && checkItemParentsVisible(item->firstChild(), hhp))
00377             childMatch = true;
00378         // Should this item be shown? It should if any children should be, or if it matches.
00379         if(childMatch || itemMatches(item, d->search))
00380         {
00381             visible = true;
00382             if (highestHiddenParent)
00383             {
00384                 highestHiddenParent->setVisible(true);
00385                 // Calling setVisible on our ancestor will unhide all its descendents. Hide the ones
00386                 // before us that should not be shown.
00387                 for(QListViewItem *hide = first; hide != item; hide = hide->nextSibling())
00388                     hide->setVisible(false);
00389                 highestHiddenParent = 0;
00390                 // If we matched, than none of our children matched, yet the setVisible() call on our
00391                 // ancestor unhid them, undo the damage:
00392                 if(!childMatch)
00393                     for(QListViewItem *hide = item->firstChild(); hide; hide = hide->nextSibling())
00394                         hide->setVisible(false);
00395             }
00396             else
00397                 item->setVisible(true);
00398         }
00399         else
00400             item->setVisible(false);
00401     }
00402     return visible;
00403 }
00404 
00406 // KListViewSearchLineWidget
00408 
00409 class KListViewSearchLineWidget::KListViewSearchLineWidgetPrivate
00410 {
00411 public:
00412     KListViewSearchLineWidgetPrivate() : listView(0), searchLine(0), clearButton(0) {}
00413     KListView *listView;
00414     KListViewSearchLine *searchLine;
00415     QToolButton *clearButton;
00416 };
00417 
00418 KListViewSearchLineWidget::KListViewSearchLineWidget(KListView *listView,
00419                                                      QWidget *parent,
00420                                                      const char *name) :
00421     QHBox(parent, name)
00422 {
00423     d = new KListViewSearchLineWidgetPrivate;
00424     d->listView = listView;
00425 
00426     setSpacing(5);
00427 
00428     QTimer::singleShot(0, this, SLOT(createWidgets()));
00429 }
00430 
00431 KListViewSearchLineWidget::~KListViewSearchLineWidget()
00432 {
00433     delete d;
00434 }
00435 
00436 KListViewSearchLine *KListViewSearchLineWidget::createSearchLine(KListView *listView)
00437 {
00438     if(!d->searchLine)
00439         d->searchLine = new KListViewSearchLine(this, listView);
00440     return d->searchLine;
00441 }
00442 
00443 void KListViewSearchLineWidget::createWidgets()
00444 {
00445     positionInToolBar();
00446 
00447     if(!d->clearButton) {
00448         d->clearButton = new QToolButton(this);
00449         QIconSet icon = SmallIconSet(QApplication::reverseLayout() ? "clear_left" : "locationbar_erase");
00450         d->clearButton->setIconSet(icon);
00451     }
00452 
00453     d->clearButton->show();
00454 
00455     QLabel *label = new QLabel(i18n("S&earch:"), this, "kde toolbar widget");
00456 
00457     d->searchLine = createSearchLine(d->listView);
00458     d->searchLine->show();
00459 
00460     label->setBuddy(d->searchLine);
00461     label->show();
00462 
00463     connect(d->clearButton, SIGNAL(clicked()), d->searchLine, SLOT(clear()));
00464 }
00465 
00466 KListViewSearchLine *KListViewSearchLineWidget::searchLine() const
00467 {
00468     return d->searchLine;
00469 }
00470 
00471 void KListViewSearchLineWidget::positionInToolBar()
00472 {
00473     KToolBar *toolBar = dynamic_cast<KToolBar *>(parent());
00474 
00475     if(toolBar) {
00476 
00477         // Here we have The Big Ugly.  Figure out how many widgets are in the
00478         // and do a hack-ish iteration over them to find this widget so that we
00479         // can insert the clear button before it.
00480 
00481         int widgetCount = toolBar->count();
00482 
00483         for(int index = 0; index < widgetCount; index++) {
00484             int id = toolBar->idAt(index);
00485             if(toolBar->getWidget(id) == this) {
00486                 toolBar->setItemAutoSized(id);
00487                 if(!d->clearButton) {
00488                     QString icon = QApplication::reverseLayout() ? "clear_left" : "locationbar_erase";
00489                     d->clearButton = new KToolBarButton(icon, 2005, toolBar);
00490                 }
00491                 toolBar->insertWidget(2005, d->clearButton->width(), d->clearButton, index);
00492                 break;
00493             }
00494         }
00495     }
00496 
00497     if(d->searchLine)
00498         d->searchLine->show();
00499 }
00500 
00501 #include "klistviewsearchline.moc"

kdeui

Skip menu "kdeui"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal