00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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
00130
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
00204
00205 bool KListViewSearchLine::itemMatches(const QListViewItem *item, const QString &s) const
00206 {
00207 if(s.isEmpty())
00208 return true;
00209
00210
00211
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
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
00273 if(allColumnsAreSearchColumns && !d->searchColumns.isEmpty())
00274 d->searchColumns.clear();
00275 }
00276
00277 return popup;
00278 }
00279
00281
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
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
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
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
00379 if(childMatch || itemMatches(item, d->search))
00380 {
00381 visible = true;
00382 if (highestHiddenParent)
00383 {
00384 highestHiddenParent->setVisible(true);
00385
00386
00387 for(QListViewItem *hide = first; hide != item; hide = hide->nextSibling())
00388 hide->setVisible(false);
00389 highestHiddenParent = 0;
00390
00391
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
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
00478
00479
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"