00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "k3listviewsearchline.h"
00021
00022 #include <k3listview.h>
00023 #include <kiconloader.h>
00024 #include <ktoolbar.h>
00025 #include <kdebug.h>
00026 #include <klocale.h>
00027
00028 #include <QApplication>
00029 #include <QTimer>
00030 #include <QMenu>
00031 #include <QLabel>
00032 #include <QContextMenuEvent>
00033 #include <QList>
00034 #include <Q3Header>
00035 #include <QToolButton>
00036
00037 class K3ListViewSearchLine::K3ListViewSearchLinePrivate
00038 {
00039 public:
00040 K3ListViewSearchLinePrivate() :
00041 caseSensitive(Qt::CaseInsensitive),
00042 activeSearch(false),
00043 keepParentsVisible(true),
00044 canChooseColumns(true),
00045 queuedSearches(0),
00046 allVisibleColumnsAction(0)
00047 {}
00048
00049 QList<K3ListView *> listViews;
00050 Qt::CaseSensitivity caseSensitive;
00051 bool activeSearch;
00052 bool keepParentsVisible;
00053 bool canChooseColumns;
00054 QString search;
00055 int queuedSearches;
00056 QList<int> searchColumns;
00057 QAction *allVisibleColumnsAction;
00058 };
00059
00061
00063
00064 K3ListViewSearchLine::K3ListViewSearchLine(QWidget *parent, K3ListView *listView) :
00065 KLineEdit(parent)
00066 {
00067 d = new K3ListViewSearchLinePrivate;
00068 setClearButtonShown( true );
00069
00070 connect(this, SIGNAL(textChanged(const QString &)),
00071 this, SLOT(queueSearch(const QString &)));
00072
00073 setListView( listView );
00074 if( !listView)
00075 setEnabled(false);
00076 }
00077
00078 K3ListViewSearchLine::K3ListViewSearchLine(QWidget *parent,
00079 const QList<K3ListView *> &listViews) :
00080 KLineEdit(parent)
00081 {
00082 d = new K3ListViewSearchLinePrivate;
00083 setClearButtonShown( true );
00084
00085 connect(this, SIGNAL(textChanged(const QString &)),
00086 this, SLOT(queueSearch(const QString &)));
00087
00088 setListViews( listViews );
00089 }
00090
00091
00092 K3ListViewSearchLine::~K3ListViewSearchLine()
00093 {
00094 delete d;
00095 }
00096
00097 bool K3ListViewSearchLine::caseSensitive() const
00098 {
00099 return (d->caseSensitive ==Qt::CaseSensitive);
00100 }
00101
00102 QList<int> K3ListViewSearchLine::searchColumns() const
00103 {
00104 if (d->canChooseColumns)
00105 return d->searchColumns;
00106 else
00107 return QList<int>();
00108 }
00109
00110 bool K3ListViewSearchLine::keepParentsVisible() const
00111 {
00112 return d->keepParentsVisible;
00113 }
00114
00115 K3ListView *K3ListViewSearchLine::listView() const
00116 {
00117 if ( d->listViews.count() == 1 )
00118 return d->listViews.first();
00119 else
00120 return 0;
00121 }
00122
00123 const QList<K3ListView *> &K3ListViewSearchLine::listViews() const
00124 {
00125 return d->listViews;
00126 }
00127
00128
00130
00132
00133 void K3ListViewSearchLine::addListView(K3ListView *lv)
00134 {
00135 if (lv) {
00136 connectListView(lv);
00137
00138 d->listViews.append(lv);
00139 setEnabled(!d->listViews.isEmpty());
00140
00141 checkColumns();
00142 }
00143 }
00144
00145 void K3ListViewSearchLine::removeListView(K3ListView *lv)
00146 {
00147 if (lv) {
00148 int idx = d->listViews.indexOf(lv);
00149
00150 if ( idx != -1 ) {
00151 d->listViews.removeAt( idx );
00152 checkColumns();
00153
00154 disconnectListView(lv);
00155
00156 setEnabled(!d->listViews.isEmpty());
00157 }
00158 }
00159 }
00160
00161 void K3ListViewSearchLine::updateSearch(const QString &s)
00162 {
00163 d->search = s.isNull() ? text() : s;
00164
00165 for (QList<K3ListView *>::Iterator it = d->listViews.begin();
00166 it != d->listViews.end(); ++it)
00167 updateSearch( *it );
00168 }
00169
00170 void K3ListViewSearchLine::updateSearch(K3ListView *listView)
00171 {
00172 if(!listView)
00173 return;
00174
00175
00176
00177
00178
00179 Q3ListViewItem *currentItem = 0;
00180
00181 switch(listView->selectionMode())
00182 {
00183 case K3ListView::NoSelection:
00184 break;
00185 case K3ListView::Single:
00186 currentItem = listView->selectedItem();
00187 break;
00188 default:
00189 {
00190 int flags = Q3ListViewItemIterator::Selected | Q3ListViewItemIterator::Visible;
00191 for(Q3ListViewItemIterator it(listView, flags);
00192 it.current() && !currentItem;
00193 ++it)
00194 {
00195 if(listView->itemRect(it.current()).isValid())
00196 currentItem = it.current();
00197 }
00198 }
00199 }
00200
00201 if(d->keepParentsVisible)
00202 checkItemParentsVisible(listView->firstChild());
00203 else
00204 checkItemParentsNotVisible(listView);
00205
00206 if(currentItem)
00207 listView->ensureItemVisible(currentItem);
00208 }
00209
00210 void K3ListViewSearchLine::setCaseSensitive(bool cs)
00211 {
00212 d->caseSensitive = cs?Qt::CaseSensitive:Qt::CaseInsensitive;
00213 }
00214
00215 void K3ListViewSearchLine::setKeepParentsVisible(bool v)
00216 {
00217 d->keepParentsVisible = v;
00218 }
00219
00220 void K3ListViewSearchLine::setSearchColumns(const QList<int> &columns)
00221 {
00222 if (d->canChooseColumns)
00223 d->searchColumns = columns;
00224 }
00225
00226 void K3ListViewSearchLine::setListView(K3ListView *lv)
00227 {
00228 setListViews(QList<K3ListView *>());
00229 addListView(lv);
00230 }
00231
00232 void K3ListViewSearchLine::setListViews(const QList<K3ListView *> &lv)
00233 {
00234 for (QList<K3ListView *>::Iterator it = d->listViews.begin();
00235 it != d->listViews.end(); ++it)
00236 disconnectListView(*it);
00237
00238 d->listViews = lv;
00239
00240 for (QList<K3ListView *>::Iterator it = d->listViews.begin();
00241 it != d->listViews.end(); ++it)
00242 connectListView(*it);
00243
00244 checkColumns();
00245 setEnabled(!d->listViews.isEmpty());
00246 }
00247
00249
00251
00252 bool K3ListViewSearchLine::itemMatches(const Q3ListViewItem *item, const QString &s) const
00253 {
00254 if(s.isEmpty())
00255 return true;
00256
00257
00258
00259
00260 if(!d->searchColumns.isEmpty()) {
00261 QList<int>::ConstIterator it = d->searchColumns.constBegin();
00262 for(; it != d->searchColumns.constEnd(); ++it) {
00263 if(*it < item->listView()->columns() &&
00264 item->text(*it).indexOf(s, 0, d->caseSensitive) >= 0)
00265 return true;
00266 }
00267 }
00268 else {
00269 for(int i = 0; i < item->listView()->columns(); i++) {
00270 if(item->listView()->columnWidth(i) > 0 &&
00271 item->text(i).indexOf(s, 0, d->caseSensitive) >= 0)
00272 {
00273 return true;
00274 }
00275 }
00276 }
00277
00278 return false;
00279 }
00280
00281 void K3ListViewSearchLine::contextMenuEvent( QContextMenuEvent*e )
00282 {
00283 QMenu *popup = KLineEdit::createStandardContextMenu();
00284
00285 if (d->canChooseColumns) {
00286 popup->addSeparator();
00287 QMenu *subMenu = popup->addMenu(i18n("Search Columns"));
00288 connect(subMenu, SIGNAL(triggered(QAction*)), this, SLOT(searchColumnsMenuActivated(QAction*)));
00289
00290 d->allVisibleColumnsAction = subMenu->addAction(i18n("All Visible Columns"));
00291 d->allVisibleColumnsAction->setCheckable( true );
00292 subMenu->addSeparator();
00293
00294 bool allColumnsAreSearchColumns = true;
00295
00296 Q3Header* const header = d->listViews.first()->header();
00297 int visibleColumns = 0;
00298 for(int i = 0; i < d->listViews.first()->columns(); i++) {
00299 if(d->listViews.first()->columnWidth(i)>0) {
00300 QString columnText = d->listViews.first()->columnText(i);
00301 if(columnText.isEmpty()) {
00302 int visiblePosition=1;
00303 for(int j = 0; j < header->mapToIndex(i); j++)
00304 if(d->listViews.first()->columnWidth(header->mapToSection(j))>0)
00305 visiblePosition++;
00306
00307 columnText = i18nc("Column number %1","Column No. %1", visiblePosition);
00308 }
00309 QAction *action = subMenu->addAction(columnText);
00310 action->setData( visibleColumns );
00311 action->setCheckable( true );
00312
00313 if(d->searchColumns.isEmpty() || d->searchColumns.indexOf(i) != -1)
00314 action->setChecked(true);
00315 else
00316 allColumnsAreSearchColumns = false;
00317
00318 visibleColumns++;
00319 }
00320 }
00321 d->allVisibleColumnsAction->setChecked( allColumnsAreSearchColumns );
00322
00323
00324 if(allColumnsAreSearchColumns && !d->searchColumns.isEmpty())
00325 d->searchColumns.clear();
00326 }
00327
00328 popup->exec( e->globalPos() );
00329
00330 delete popup;
00331 }
00332
00333 void K3ListViewSearchLine::connectListView(K3ListView *lv)
00334 {
00335 connect(lv, SIGNAL(destroyed( QObject * )),
00336 this, SLOT(listViewDeleted( QObject *)));
00337 connect(lv, SIGNAL(itemAdded(Q3ListViewItem *)),
00338 this, SLOT(itemAdded(Q3ListViewItem *)));
00339 }
00340
00341 void K3ListViewSearchLine::disconnectListView(K3ListView *lv)
00342 {
00343 disconnect(lv, SIGNAL(destroyed( QObject * )),
00344 this, SLOT(listViewDeleted( QObject *)));
00345 disconnect(lv, SIGNAL(itemAdded(Q3ListViewItem *)),
00346 this, SLOT(itemAdded(Q3ListViewItem *)));
00347 }
00348
00349 bool K3ListViewSearchLine::canChooseColumnsCheck()
00350 {
00351
00352
00353
00354 if (d->listViews.isEmpty())
00355 return false;
00356
00357 const K3ListView *first = d->listViews.first();
00358
00359 const unsigned int numcols = first->columns();
00360
00361 if (numcols < 2)
00362 return false;
00363
00364 QStringList headers;
00365 for (unsigned int i = 0; i < numcols; ++i)
00366 headers.append(first->columnText(i));
00367
00368 QList<K3ListView *>::ConstIterator it = d->listViews.constBegin();
00369 for (++it ; it !=d->listViews.constEnd(); ++it) {
00370
00371 if ((unsigned int) (*it)->columns() != numcols)
00372 return false;
00373
00374
00375 QStringList::ConstIterator jt;
00376 unsigned int i;
00377 for (i = 0, jt = headers.constBegin(); i < numcols; ++i, ++jt) {
00378 Q_ASSERT(jt != headers.constEnd());
00379 if ((*it)->columnText(i) != *jt)
00380 return false;
00381 }
00382 }
00383
00384 return true;
00385 }
00386
00388
00390
00391 void K3ListViewSearchLine::queueSearch(const QString &search)
00392 {
00393 d->queuedSearches++;
00394 d->search = search;
00395 QTimer::singleShot(200, this, SLOT(activateSearch()));
00396 }
00397
00398 void K3ListViewSearchLine::activateSearch()
00399 {
00400 --(d->queuedSearches);
00401
00402 if(d->queuedSearches == 0)
00403 updateSearch(d->search);
00404 }
00405
00407
00409
00410 void K3ListViewSearchLine::itemAdded(Q3ListViewItem *item) const
00411 {
00412 item->setVisible(itemMatches(item, text()));
00413 }
00414
00415 void K3ListViewSearchLine::listViewDeleted(QObject *o)
00416 {
00417 d->listViews.removeAll(static_cast<K3ListView *>(o));
00418 setEnabled(d->listViews.isEmpty());
00419 }
00420
00421 void K3ListViewSearchLine::searchColumnsMenuActivated(QAction *action)
00422 {
00423 int id = action->data().toInt();
00424
00425 if(action == d->allVisibleColumnsAction) {
00426 if(d->searchColumns.isEmpty())
00427 d->searchColumns.append(0);
00428 else
00429 d->searchColumns.clear();
00430 }
00431 else {
00432 if(d->searchColumns.indexOf(id) != -1)
00433 d->searchColumns.removeAll(id);
00434 else {
00435 if(d->searchColumns.isEmpty()) {
00436 for(int i = 0; i < d->listViews.first()->columns(); i++) {
00437 if(i != id)
00438 d->searchColumns.append(i);
00439 }
00440 }
00441 else
00442 d->searchColumns.append(id);
00443 }
00444 }
00445 updateSearch();
00446 }
00447
00449
00451
00452 void K3ListViewSearchLine::checkColumns()
00453 {
00454 d->canChooseColumns = canChooseColumnsCheck();
00455 }
00456
00457 void K3ListViewSearchLine::checkItemParentsNotVisible(K3ListView *listView)
00458 {
00459 Q3ListViewItemIterator it(listView);
00460 for(; it.current(); ++it)
00461 {
00462 Q3ListViewItem *item = it.current();
00463 if(itemMatches(item, d->search))
00464 item->setVisible(true);
00465 else
00466 item->setVisible(false);
00467 }
00468 }
00469
00470 #include <kvbox.h>
00471
00481 bool K3ListViewSearchLine::checkItemParentsVisible(Q3ListViewItem *item, Q3ListViewItem *highestHiddenParent)
00482 {
00483 bool visible = false;
00484 Q3ListViewItem * first = item;
00485 for(; item; item = item->nextSibling())
00486 {
00487
00488 Q3ListViewItem * hhp = highestHiddenParent ? highestHiddenParent : item->isVisible() ? 0L : item;
00489 bool childMatch = false;
00490 if(item->firstChild() && checkItemParentsVisible(item->firstChild(), hhp))
00491 childMatch = true;
00492
00493 if(childMatch || itemMatches(item, d->search))
00494 {
00495 visible = true;
00496 if (highestHiddenParent)
00497 {
00498 highestHiddenParent->setVisible(true);
00499
00500
00501 for(Q3ListViewItem *hide = first; hide != item; hide = hide->nextSibling())
00502 hide->setVisible(false);
00503 highestHiddenParent = 0;
00504
00505
00506 if(!childMatch)
00507 for(Q3ListViewItem *hide = item->firstChild(); hide; hide = hide->nextSibling())
00508 hide->setVisible(false);
00509 }
00510 else
00511 item->setVisible(true);
00512 }
00513 else
00514 item->setVisible(false);
00515 }
00516 return visible;
00517 }
00518
00520
00522
00523 class K3ListViewSearchLineWidget::K3ListViewSearchLineWidgetPrivate
00524 {
00525 public:
00526 K3ListViewSearchLineWidgetPrivate() : listView(0), searchLine(0) {}
00527 K3ListView *listView;
00528 K3ListViewSearchLine *searchLine;
00529 };
00530
00531 K3ListViewSearchLineWidget::K3ListViewSearchLineWidget(K3ListView *listView,
00532 QWidget *parent) :
00533 KHBox(parent)
00534 {
00535 d = new K3ListViewSearchLineWidgetPrivate;
00536 d->listView = listView;
00537
00538 setSpacing(5);
00539
00540 QTimer::singleShot(0, this, SLOT(createWidgets()));
00541 }
00542
00543 K3ListViewSearchLineWidget::~K3ListViewSearchLineWidget()
00544 {
00545 delete d;
00546 }
00547
00548 K3ListViewSearchLine *K3ListViewSearchLineWidget::createSearchLine(K3ListView *listView)
00549 {
00550 if(!d->searchLine)
00551 d->searchLine = new K3ListViewSearchLine(this, listView);
00552 return d->searchLine;
00553 }
00554
00555 void K3ListViewSearchLineWidget::createWidgets()
00556 {
00557 QLabel *label = new QLabel(i18n("S&earch:"), this);
00558 label->setObjectName(QLatin1String("kde toolbar widget"));
00559
00560 d->searchLine = createSearchLine(d->listView);
00561 d->searchLine->show();
00562
00563 label->setBuddy(d->searchLine);
00564 label->show();
00565 }
00566
00567 K3ListViewSearchLine *K3ListViewSearchLineWidget::searchLine() const
00568 {
00569 return d->searchLine;
00570 }
00571
00572 #include "k3listviewsearchline.moc"