23 #include <QtCore/QList>
24 #include <QtCore/QTimer>
25 #include <QtGui/QApplication>
26 #include <QtGui/QContextMenuEvent>
27 #include <QtGui/QHBoxLayout>
28 #include <QtGui/QHeaderView>
29 #include <QtGui/QLabel>
30 #include <QtGui/QMenu>
31 #include <QtGui/QToolButton>
32 #include <QtGui/QTreeWidget>
37 class KTreeWidgetSearchLine::Private
42 caseSensitive( Qt::CaseInsensitive ),
44 canChooseColumns( true ),
51 Qt::CaseSensitivity caseSensitive;
53 bool canChooseColumns;
58 void _k_rowsInserted(
const QModelIndex & parent,
int start,
int end)
const;
60 void _k_slotColumnActivated(
QAction* action);
61 void _k_slotAllVisibleColumns();
62 void _k_queueSearch(
const QString&);
63 void _k_activateSearch();
67 bool checkItemParentsVisible(QTreeWidgetItem* item);
78 QTreeWidgetItem *itemFromIndex(
const QModelIndex &index )
const
80 return QTreeWidget::itemFromIndex( index );
84 void KTreeWidgetSearchLine::Private::_k_rowsInserted(
const QModelIndex & parentIndex,
int start,
int end )
const
92 if ( tree->model() == model ) {
100 QTreeWidgetWorkaround* widgetW =
static_cast<QTreeWidgetWorkaround *
>(widget);
101 for (
int i = start; i <=
end; ++i) {
102 if (QTreeWidgetItem *item = widgetW->itemFromIndex(model->index(i, 0, parentIndex))) {
103 bool newHidden = !q->itemMatches(item, q->text());
104 if (item->isHidden() != newHidden) {
105 item->setHidden(newHidden);
106 emit q->hiddenChanged(item, newHidden);
112 void KTreeWidgetSearchLine::Private::_k_treeWidgetDeleted(
QObject *
object )
114 treeWidgets.removeAll( static_cast<QTreeWidget *>(
object ) );
115 q->setEnabled( treeWidgets.isEmpty() );
118 void KTreeWidgetSearchLine::Private::_k_slotColumnActivated(
QAction *action )
124 int column = action->data().toInt( &ok );
129 if ( action->isChecked() ) {
130 if ( !searchColumns.isEmpty() ) {
131 if ( !searchColumns.contains( column ) )
132 searchColumns.append( column );
134 if ( searchColumns.count() == treeWidgets.first()->header()->count() - treeWidgets.first()->header()->hiddenSectionCount() )
135 searchColumns.clear();
138 searchColumns.append( column );
141 if ( searchColumns.isEmpty() ) {
142 QHeaderView*
const header = treeWidgets.first()->header();
144 for (
int i = 0; i < header->count(); i++ ) {
145 if ( i != column && !header->isSectionHidden( i ) )
146 searchColumns.append( i );
149 }
else if ( searchColumns.contains( column ) ) {
150 searchColumns.removeAll( column );
157 void KTreeWidgetSearchLine::Private::_k_slotAllVisibleColumns()
159 if ( searchColumns.isEmpty() )
160 searchColumns.append( 0 );
162 searchColumns.clear();
172 void KTreeWidgetSearchLine::Private::checkColumns()
174 canChooseColumns = q->canChooseColumnsCheck();
177 void KTreeWidgetSearchLine::Private::checkItemParentsNotVisible(
QTreeWidget *treeWidget)
179 for (QTreeWidgetItemIterator it(treeWidget); *it; ++it) {
180 QTreeWidgetItem *item = *it;
181 bool newHidden = !q->itemMatches(item, search);
182 if (item->isHidden() != newHidden) {
183 item->setHidden(newHidden);
184 emit q->hiddenChanged(item, newHidden);
196 bool KTreeWidgetSearchLine::Private::checkItemParentsVisible(QTreeWidgetItem *item)
198 bool childMatch =
false;
199 for (
int i = 0; i < item->childCount(); ++i) {
200 childMatch |= checkItemParentsVisible(item->child(i));
204 bool newHidden = !childMatch && !q->itemMatches(item, search);
205 if (item->isHidden() != newHidden) {
206 item->setHidden(newHidden);
207 emit q->hiddenChanged(item, newHidden);
219 :
KLineEdit( q ), d( new Private( this ) )
221 connect(
this, SIGNAL(textChanged(
QString)),
222 this, SLOT(_k_queueSearch(
QString)) );
233 const QList<QTreeWidget *> &treeWidgets )
234 :
KLineEdit( q ), d( new Private( this ) )
236 connect(
this, SIGNAL(textChanged(
QString)),
237 this, SLOT(_k_queueSearch(
QString)) );
250 return d->caseSensitive;
255 if ( d->canChooseColumns )
256 return d->searchColumns;
263 return d->keepParentsVisible;
268 if ( d->treeWidgets.count() == 1 )
269 return d->treeWidgets.first();
276 return d->treeWidgets;
289 d->treeWidgets.append( treeWidget );
290 setEnabled( !d->treeWidgets.isEmpty() );
299 int index = d->treeWidgets.indexOf( treeWidget );
302 d->treeWidgets.removeAt( index );
307 setEnabled( !d->treeWidgets.isEmpty() );
314 d->search = pattern.isNull() ? text() : pattern;
316 foreach (
QTreeWidget* treeWidget, d->treeWidgets )
322 if ( !treeWidget || !treeWidget->topLevelItemCount() )
329 QTreeWidgetItem *currentItem = treeWidget->currentItem();
331 if ( d->keepParentsVisible )
332 for (
int i = 0; i < treeWidget->topLevelItemCount(); ++i )
333 d->checkItemParentsVisible( treeWidget->topLevelItem( i ) );
335 d->checkItemParentsNotVisible( treeWidget );
338 treeWidget->scrollToItem( currentItem );
343 if ( d->caseSensitive != caseSensitive ) {
344 d->caseSensitive = caseSensitive;
351 if ( d->keepParentsVisible != visible ) {
352 d->keepParentsVisible = visible;
359 if ( d->canChooseColumns )
360 d->searchColumns = columns;
371 foreach (
QTreeWidget* treeWidget, d->treeWidgets )
376 foreach (
QTreeWidget* treeWidget, d->treeWidgets )
381 setEnabled( !d->treeWidgets.isEmpty() );
390 if ( pattern.isEmpty() )
396 if ( !d->searchColumns.isEmpty() ) {
397 QList<int>::ConstIterator it = d->searchColumns.constBegin();
398 for ( ; it != d->searchColumns.constEnd(); ++it ) {
399 if ( *it < item->
treeWidget()->columnCount() &&
400 item->text( *it ).indexOf( pattern, 0, d->caseSensitive ) >= 0 )
404 for (
int i = 0; i < item->treeWidget()->columnCount(); i++) {
405 if ( item->treeWidget()->columnWidth(i) > 0 &&
406 item->text( i ).indexOf( pattern, 0, d->caseSensitive ) >= 0 )
418 if ( d->canChooseColumns ) {
419 popup->addSeparator();
420 QMenu *subMenu = popup->addMenu(
i18n(
"Search Columns") );
422 QAction* allVisibleColumnsAction = subMenu->addAction(
i18n(
"All Visible Columns"),
423 this, SLOT(_k_slotAllVisibleColumns()) );
424 allVisibleColumnsAction->setCheckable(
true );
425 allVisibleColumnsAction->setChecked( !d->searchColumns.count() );
426 subMenu->addSeparator();
428 bool allColumnsAreSearchColumns =
true;
430 QActionGroup*
group =
new QActionGroup( popup );
431 group->setExclusive(
false );
432 connect( group, SIGNAL(triggered(
QAction*)), SLOT(_k_slotColumnActivated(
QAction*)) );
434 QHeaderView*
const header = d->treeWidgets.first()->header();
435 for (
int j = 0; j < header->count(); j++ ) {
436 int i = header->logicalIndex( j );
438 if ( header->isSectionHidden( i ) )
441 QString columnText = d->treeWidgets.first()->headerItem()->text( i );
442 QAction* columnAction = subMenu->addAction( d->treeWidgets.first()->headerItem()->icon( i ), columnText );
443 columnAction->setCheckable(
true );
444 columnAction->setChecked( d->searchColumns.isEmpty() || d->searchColumns.contains( i ) );
445 columnAction->setData( i );
446 columnAction->setActionGroup( group );
448 if ( d->searchColumns.isEmpty() || d->searchColumns.indexOf( i ) != -1 )
449 columnAction->setChecked(
true );
451 allColumnsAreSearchColumns =
false;
454 allVisibleColumnsAction->setChecked( allColumnsAreSearchColumns );
457 if ( allColumnsAreSearchColumns && !d->searchColumns.isEmpty() )
458 d->searchColumns.clear();
461 popup->exec( event->globalPos() );
467 connect( treeWidget, SIGNAL(destroyed(
QObject*)),
468 this, SLOT(_k_treeWidgetDeleted(
QObject*)) );
470 connect( treeWidget->model(), SIGNAL(rowsInserted(QModelIndex,
int,
int)),
471 this, SLOT(_k_rowsInserted(QModelIndex,
int,
int)) );
476 disconnect( treeWidget, SIGNAL(destroyed(
QObject*)),
477 this, SLOT(_k_treeWidgetDeleted(
QObject*)) );
479 disconnect( treeWidget->model(), SIGNAL(rowsInserted(QModelIndex,
int,
int)),
480 this, SLOT(_k_rowsInserted(QModelIndex,
int,
int)) );
488 if ( d->treeWidgets.isEmpty() )
493 const unsigned int numcols = first->columnCount();
499 for (
unsigned int i = 0; i < numcols; ++i )
500 headers.append( first->headerItem()->text( i ) );
502 QList<QTreeWidget *>::ConstIterator it = d->treeWidgets.constBegin();
503 for ( ++it ; it != d->treeWidgets.constEnd(); ++it ) {
505 if ( (
unsigned int) (*it)->columnCount() != numcols )
509 QStringList::ConstIterator jt;
511 for ( i = 0, jt = headers.constBegin(); i < numcols; ++i, ++jt ) {
512 Q_ASSERT( jt != headers.constEnd() );
514 if ( (*it)->headerItem()->text( i ) != *jt )
524 if (event->type() == QEvent::KeyPress) {
525 QKeyEvent *keyEvent =
static_cast<QKeyEvent *
>(
event);
526 if(keyEvent->matches(QKeySequence::MoveToNextLine) || keyEvent->matches(QKeySequence::SelectNextLine) ||
527 keyEvent->matches(QKeySequence::MoveToPreviousLine) || keyEvent->matches(QKeySequence::SelectPreviousLine) ||
528 keyEvent->matches(QKeySequence::MoveToNextPage) || keyEvent->matches(QKeySequence::SelectNextPage) ||
529 keyEvent->matches(QKeySequence::MoveToPreviousPage) || keyEvent->matches(QKeySequence::SelectPreviousPage) ||
530 keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)
534 QApplication::sendEvent(first, event);
546 void KTreeWidgetSearchLine::Private::_k_queueSearch(
const QString &_search )
551 QTimer::singleShot( 200, q, SLOT(_k_activateSearch()) );
554 void KTreeWidgetSearchLine::Private::_k_activateSearch()
558 if ( queuedSearches == 0 )
559 q->updateSearch( search );
566 class KTreeWidgetSearchLineWidget::Private
580 :
QWidget( parent ), d( new Private )
582 d->treeWidget = treeWidget;
586 QMetaObject::invokeMethod(
this,
"createWidgets", Qt::QueuedConnection);
605 label->setBuddy( d->searchLine );
608 QHBoxLayout* layout =
new QHBoxLayout(
this );
609 layout->setMargin( 0 );
610 layout->addWidget( label );
611 layout->addWidget( d->searchLine );
617 if ( !d->searchLine )
620 return d->searchLine;
623 #include "ktreewidgetsearchline.moc"