kdeui Library API Documentation

klistviewsearchline.cpp

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., 59 Temple Place - Suite 330,
00016    Boston, MA 02111-1307, 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 bool KListViewSearchLine::checkItemParentsVisible(QListViewItem *item)
00357 {
00358     bool visible = false;
00359     for(; item; item = item->nextSibling()) {
00360         if((item->firstChild() && checkItemParentsVisible(item->firstChild())) ||
00361            itemMatches(item, d->search))
00362         {
00363             item->setVisible( true );
00364             visible = true;
00365         }
00366         else
00367             item->setVisible(false);
00368     }
00369     return visible;
00370 }
00371 
00373 // KListViewSearchLineWidget
00375 
00376 class KListViewSearchLineWidget::KListViewSearchLineWidgetPrivate
00377 {
00378 public:
00379     KListViewSearchLineWidgetPrivate() : listView(0), searchLine(0), clearButton(0) {}
00380     KListView *listView;
00381     KListViewSearchLine *searchLine;
00382     QToolButton *clearButton;
00383 };
00384 
00385 KListViewSearchLineWidget::KListViewSearchLineWidget(KListView *listView,
00386                                                      QWidget *parent,
00387                                                      const char *name) :
00388     QHBox(parent, name)
00389 {
00390     d = new KListViewSearchLineWidgetPrivate;
00391     d->listView = listView;
00392 
00393     setSpacing(5);
00394 
00395     QTimer::singleShot(0, this, SLOT(createWidgets()));
00396 }
00397 
00398 KListViewSearchLineWidget::~KListViewSearchLineWidget()
00399 {
00400     delete d;
00401 }
00402 
00403 KListViewSearchLine *KListViewSearchLineWidget::createSearchLine(KListView *listView)
00404 {
00405     if(!d->searchLine)
00406         d->searchLine = new KListViewSearchLine(this, listView);
00407     return d->searchLine;
00408 }
00409 
00410 void KListViewSearchLineWidget::createWidgets()
00411 {
00412     positionInToolBar();
00413 
00414     if(!d->clearButton) {
00415         d->clearButton = new QToolButton(this);
00416         QIconSet icon = SmallIconSet(QApplication::reverseLayout() ? "clear_left" : "locationbar_erase");
00417         d->clearButton->setIconSet(icon);
00418     }
00419 
00420     d->clearButton->show();
00421 
00422     QLabel *label = new QLabel(i18n("S&earch:"), this, "kde toolbar widget");
00423 
00424     d->searchLine = createSearchLine(d->listView);
00425     d->searchLine->show();
00426 
00427     label->setBuddy(d->searchLine);
00428     label->show();
00429 
00430     connect(d->clearButton, SIGNAL(clicked()), d->searchLine, SLOT(clear()));
00431 }
00432 
00433 KListViewSearchLine *KListViewSearchLineWidget::searchLine() const
00434 {
00435     return d->searchLine;
00436 }
00437 
00438 void KListViewSearchLineWidget::positionInToolBar()
00439 {
00440     KToolBar *toolBar = dynamic_cast<KToolBar *>(parent());
00441 
00442     if(toolBar) {
00443 
00444         // Here we have The Big Ugly.  Figure out how many widgets are in the
00445         // and do a hack-ish iteration over them to find this widget so that we
00446         // can insert the clear button before it.
00447 
00448         int widgetCount = toolBar->count();
00449 
00450         for(int index = 0; index < widgetCount; index++) {
00451             int id = toolBar->idAt(index);
00452             if(toolBar->getWidget(id) == this) {
00453                 toolBar->setItemAutoSized(id);
00454                 if(!d->clearButton) {
00455                     QString icon = QApplication::reverseLayout() ? "clear_left" : "locationbar_erase";
00456                     d->clearButton = new KToolBarButton(icon, 2005, toolBar);
00457                 }
00458                 toolBar->insertWidget(2005, d->clearButton->width(), d->clearButton, index);
00459                 break;
00460             }
00461         }
00462     }
00463 
00464     if(d->searchLine)
00465         d->searchLine->show();
00466 }
00467 
00468 #include "klistviewsearchline.moc"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Jun 12 11:31:04 2006 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003