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.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 12 22:56:28 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003