• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Plasma

ktreeviewsearchline.cpp

Go to the documentation of this file.
00001 /*
00002    Copyright (c) 2003 Scott Wheeler <wheeler@kde.org>
00003    Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net>
00004    Copyright (c) 2006 Hamish Rodda <rodda@kde.org>
00005    Copyright 2007 Pino Toscano <pino@kde.org>
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License version 2 as published by the Free Software Foundation.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019    Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "ktreeviewsearchline.h"
00023 
00024 #include <QtCore/QList>
00025 #include <QtCore/QTimer>
00026 #include <QtGui/QApplication>
00027 #include <QtGui/QContextMenuEvent>
00028 #include <QtGui/QHBoxLayout>
00029 #include <QtGui/QHeaderView>
00030 #include <QtGui/QLabel>
00031 #include <QtGui/QMenu>
00032 #include <QtGui/QToolButton>
00033 #include <QtGui/QTreeView>
00034 
00035 #include <kdebug.h>
00036 #include <kiconloader.h>
00037 #include <klocale.h>
00038 #include <ktoolbar.h>
00039 
00040 class KTreeViewSearchLine::Private
00041 {
00042   public:
00043     Private( KTreeViewSearchLine *_parent )
00044       : parent( _parent ),
00045         caseSensitive( Qt::CaseInsensitive ),
00046         activeSearch( false ),
00047         keepParentsVisible( true ),
00048         canChooseColumns( true ),
00049         queuedSearches( 0 )
00050     {
00051     }
00052 
00053     KTreeViewSearchLine *parent;
00054     QList<QTreeView *> treeViews;
00055     Qt::CaseSensitivity caseSensitive;
00056     bool activeSearch;
00057     bool keepParentsVisible;
00058     bool canChooseColumns;
00059     QString search;
00060     int queuedSearches;
00061     QList<int> searchColumns;
00062 
00063     void rowsInserted(const QModelIndex & parent, int start, int end) const;
00064     void treeViewDeleted( QObject *treeView );
00065     void slotColumnActivated(QAction* action);
00066     void slotAllVisibleColumns();
00067 
00068     void checkColumns();
00069     void checkItemParentsNotVisible(QTreeView *treeView);
00070     bool checkItemParentsVisible(QTreeView *treeView, const QModelIndex &index);
00071 };
00072 
00074 // private slots
00076 
00077 void KTreeViewSearchLine::Private::rowsInserted( const QModelIndex & parentIndex, int start, int end ) const
00078 {
00079   QAbstractItemModel* model = qobject_cast<QAbstractItemModel*>( parent->sender() );
00080   if ( !model )
00081     return;
00082 
00083   QTreeView* widget = 0L;
00084   foreach ( QTreeView* tree, treeViews )
00085     if ( tree->model() == model ) {
00086       widget = tree;
00087       break;
00088     }
00089 
00090   if ( !widget )
00091     return;
00092 
00093   for ( int i = start; i <= end; ++i ) {
00094      widget->setRowHidden( i, parentIndex, !parent->itemMatches( parentIndex, i, parent->text() ) );
00095   }
00096 }
00097 
00098 void KTreeViewSearchLine::Private::treeViewDeleted( QObject *object )
00099 {
00100   treeViews.removeAll( static_cast<QTreeView *>( object ) );
00101   parent->setEnabled( treeViews.isEmpty() );
00102 }
00103 
00104 void KTreeViewSearchLine::Private::slotColumnActivated( QAction *action )
00105 {
00106   if ( !action )
00107     return;
00108 
00109   bool ok;
00110   int column = action->data().toInt( &ok );
00111 
00112   if ( !ok )
00113     return;
00114 
00115   if ( action->isChecked() ) {
00116     if ( !searchColumns.isEmpty() ) {
00117       if ( !searchColumns.contains( column ) )
00118         searchColumns.append( column );
00119 
00120       if ( searchColumns.count() == treeViews.first()->header()->count() - treeViews.first()->header()->hiddenSectionCount() )
00121         searchColumns.clear();
00122 
00123     } else {
00124       searchColumns.append( column );
00125     }
00126   } else {
00127     if ( searchColumns.isEmpty() ) {
00128       QHeaderView* const header = treeViews.first()->header();
00129 
00130       for ( int i = 0; i < header->count(); i++ ) {
00131         if ( i != column && !header->isSectionHidden( i ) )
00132           searchColumns.append( i );
00133       }
00134 
00135     } else if ( searchColumns.contains( column ) ) {
00136       searchColumns.removeAll( column );
00137     }
00138   }
00139 
00140   parent->updateSearch();
00141 }
00142 
00143 void KTreeViewSearchLine::Private::slotAllVisibleColumns()
00144 {
00145   if ( searchColumns.isEmpty() )
00146     searchColumns.append( 0 );
00147   else
00148     searchColumns.clear();
00149 
00150   parent->updateSearch();
00151 }
00152 
00154 // private methods
00156 
00157 
00158 void KTreeViewSearchLine::Private::checkColumns()
00159 {
00160   canChooseColumns = parent->canChooseColumnsCheck();
00161 }
00162 
00163 void KTreeViewSearchLine::Private::checkItemParentsNotVisible( QTreeView *treeView )
00164 {
00165     Q_UNUSED(treeView)
00166 
00167 // TODO: PORT ME
00168 #if 0
00169   QTreeWidgetItemIterator it( treeWidget );
00170 
00171   for ( ; *it; ++it ) {
00172     QTreeWidgetItem *item = *it;
00173     item->treeWidget()->setItemHidden( item, !parent->itemMatches( item, search ) );
00174   }
00175 #endif
00176 }
00177 
00178 #include <kvbox.h>
00179 
00187 bool KTreeViewSearchLine::Private::checkItemParentsVisible( QTreeView *treeView, const QModelIndex &index )
00188 {
00189   bool childMatch = false;
00190   const int rowcount = treeView->model()->rowCount( index );
00191   for ( int i = 0; i < rowcount; ++i )
00192     childMatch |= checkItemParentsVisible( treeView, treeView->model()->index( i, 0, index ) );
00193 
00194   // Should this item be shown? It should if any children should be, or if it matches.
00195   const QModelIndex parentindex = index.parent();
00196   if ( childMatch || parent->itemMatches( parentindex, index.row(), search ) ) {
00197     treeView->setRowHidden( index.row(), parentindex, false );
00198     return true;
00199   }
00200 
00201   treeView->setRowHidden( index.row(), parentindex, true );
00202 
00203   return false;
00204 }
00205 
00206 
00208 // public methods
00210 
00211 KTreeViewSearchLine::KTreeViewSearchLine( QWidget *parent, QTreeView *treeView )
00212   : KLineEdit( parent ), d( new Private( this ) )
00213 {
00214   connect( this, SIGNAL( textChanged( const QString& ) ),
00215            this, SLOT( queueSearch( const QString& ) ) );
00216 
00217   setClearButtonShown( true );
00218   setTreeView( treeView );
00219 
00220   if ( !treeView ) {
00221       setEnabled( false );
00222   }
00223 }
00224 
00225 KTreeViewSearchLine::KTreeViewSearchLine( QWidget *parent,
00226                                               const QList<QTreeView *> &treeViews )
00227   : KLineEdit( parent ), d( new Private( this ) )
00228 {
00229   connect( this, SIGNAL( textChanged( const QString& ) ),
00230            this, SLOT( queueSearch( const QString& ) ) );
00231 
00232   setClearButtonShown( true );
00233   setTreeViews( treeViews );
00234 }
00235 
00236 KTreeViewSearchLine::~KTreeViewSearchLine()
00237 {
00238   delete d;
00239 }
00240 
00241 Qt::CaseSensitivity KTreeViewSearchLine::caseSensitivity() const
00242 {
00243   return d->caseSensitive;
00244 }
00245 
00246 QList<int> KTreeViewSearchLine::searchColumns() const
00247 {
00248   if ( d->canChooseColumns )
00249     return d->searchColumns;
00250   else
00251     return QList<int>();
00252 }
00253 
00254 bool KTreeViewSearchLine::keepParentsVisible() const
00255 {
00256   return d->keepParentsVisible;
00257 }
00258 
00259 QTreeView *KTreeViewSearchLine::treeView() const
00260 {
00261   if ( d->treeViews.count() == 1 )
00262     return d->treeViews.first();
00263   else
00264     return 0;
00265 }
00266 
00267 QList<QTreeView *> KTreeViewSearchLine::treeViews() const
00268 {
00269   return d->treeViews;
00270 }
00271 
00272 
00274 // public slots
00276 
00277 void KTreeViewSearchLine::addTreeView( QTreeView *treeView )
00278 {
00279   if ( treeView ) {
00280     connectTreeView( treeView );
00281 
00282     d->treeViews.append( treeView );
00283     setEnabled( !d->treeViews.isEmpty() );
00284 
00285     d->checkColumns();
00286   }
00287 }
00288 
00289 void KTreeViewSearchLine::removeTreeView( QTreeView *treeView )
00290 {
00291   if ( treeView ) {
00292     int index = d->treeViews.indexOf( treeView );
00293 
00294     if ( index != -1 ) {
00295       d->treeViews.removeAt( index );
00296       d->checkColumns();
00297 
00298       disconnectTreeView( treeView );
00299 
00300       setEnabled( !d->treeViews.isEmpty() );
00301     }
00302   }
00303 }
00304 
00305 void KTreeViewSearchLine::updateSearch( const QString &pattern )
00306 {
00307   d->search = pattern.isNull() ? text() : pattern;
00308 
00309   foreach ( QTreeView* treeView, d->treeViews )
00310     updateSearch( treeView );
00311 }
00312 
00313 void KTreeViewSearchLine::updateSearch( QTreeView *treeView )
00314 {
00315   if ( !treeView || !treeView->model()->rowCount() )
00316     return;
00317 
00318 
00319   // If there's a selected item that is visible, make sure that it's visible
00320   // when the search changes too (assuming that it still matches).
00321 
00322   QModelIndex currentIndex = treeView->currentIndex();
00323 
00324   bool wasUpdateEnabled = treeView->updatesEnabled();
00325   treeView->setUpdatesEnabled( false );
00326   if ( d->keepParentsVisible )
00327     for ( int i = 0; i < treeView->model()->rowCount(); ++i )
00328       d->checkItemParentsVisible( treeView, treeView->rootIndex() );
00329   else
00330     d->checkItemParentsNotVisible( treeView );
00331   treeView->setUpdatesEnabled( wasUpdateEnabled );
00332 
00333   if ( currentIndex.isValid() )
00334     treeView->scrollTo( currentIndex );
00335 }
00336 
00337 void KTreeViewSearchLine::setCaseSensitivity( Qt::CaseSensitivity caseSensitive )
00338 {
00339   if ( d->caseSensitive != caseSensitive ) {
00340     d->caseSensitive = caseSensitive;
00341     updateSearch();
00342   }
00343 }
00344 
00345 void KTreeViewSearchLine::setKeepParentsVisible( bool visible )
00346 {
00347   if ( d->keepParentsVisible != visible ) {
00348     d->keepParentsVisible = visible;
00349     updateSearch();
00350   }
00351 }
00352 
00353 void KTreeViewSearchLine::setSearchColumns( const QList<int> &columns )
00354 {
00355   if ( d->canChooseColumns )
00356     d->searchColumns = columns;
00357 }
00358 
00359 void KTreeViewSearchLine::setTreeView( QTreeView *treeView )
00360 {
00361   setTreeViews( QList<QTreeView *>() );
00362   addTreeView( treeView );
00363 }
00364 
00365 void KTreeViewSearchLine::setTreeViews( const QList<QTreeView *> &treeViews )
00366 {
00367   foreach ( QTreeView* treeView, d->treeViews )
00368     disconnectTreeView( treeView );
00369 
00370   d->treeViews = treeViews;
00371 
00372   foreach ( QTreeView* treeView, d->treeViews )
00373     connectTreeView( treeView );
00374 
00375   d->checkColumns();
00376 
00377   setEnabled( !d->treeViews.isEmpty() );
00378 }
00379 
00381 // protected members
00383 
00384 bool KTreeViewSearchLine::itemMatches( const QModelIndex &index, int row, const QString &pattern ) const
00385 {
00386   if ( pattern.isEmpty() )
00387     return true;
00388 
00389   if ( !index.isValid() )
00390     return false;
00391 
00392   // If the search column list is populated, search just the columns
00393   // specifified.  If it is empty default to searching all of the columns.
00394 
00395   const int columncount = index.model()->columnCount( index );
00396   if ( !d->searchColumns.isEmpty() ) {
00397     QList<int>::ConstIterator it = d->searchColumns.begin();
00398     for ( ; it != d->searchColumns.end(); ++it ) {
00399       if ( *it < columncount &&
00400            index.child( row, *it ).data( Qt::DisplayRole ).toString().indexOf( pattern, 0, d->caseSensitive ) >= 0 )
00401         return true;
00402     }
00403   } else {
00404     for ( int i = 0; i < columncount; ++i) {
00405       if ( index.child( row, i ).data( Qt::DisplayRole ).toString().indexOf( pattern, 0, d->caseSensitive ) >= 0 )
00406         return true;
00407     }
00408   }
00409 
00410   return false;
00411 }
00412 
00413 void KTreeViewSearchLine::contextMenuEvent( QContextMenuEvent *event )
00414 {
00415   QMenu *popup = KLineEdit::createStandardContextMenu();
00416 
00417   if ( d->canChooseColumns ) {
00418     popup->addSeparator();
00419     QMenu *subMenu = popup->addMenu( i18n("Search Columns") );
00420 
00421     QAction* allVisibleColumnsAction = subMenu->addAction( i18n("All Visible Columns"),
00422                                                            this, SLOT( slotAllVisibleColumns() ) );
00423     allVisibleColumnsAction->setCheckable( true );
00424     allVisibleColumnsAction->setChecked( !d->searchColumns.count() );
00425     subMenu->addSeparator();
00426 
00427     bool allColumnsAreSearchColumns = true;
00428 
00429     QActionGroup* group = new QActionGroup( popup );
00430     group->setExclusive( false );
00431     connect( group, SIGNAL( triggered( QAction* ) ), SLOT( slotColumnActivated( QAction* ) ) );
00432 
00433     QHeaderView* const header = d->treeViews.first()->header();
00434     for ( int j = 0; j < header->count(); j++ ) {
00435       int i = header->logicalIndex( j );
00436 
00437       if ( header->isSectionHidden( i ) )
00438         continue;
00439 
00440       QString columnText = header->model()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString();
00441       QAction* columnAction = subMenu->addAction( qvariant_cast<QIcon>( header->model()->headerData( i, Qt::Horizontal, Qt::DecorationRole ) ), columnText );
00442       columnAction->setCheckable( true );
00443       columnAction->setChecked( d->searchColumns.isEmpty() || d->searchColumns.contains( i ) );
00444       columnAction->setData( i );
00445       columnAction->setActionGroup( group );
00446 
00447       if ( d->searchColumns.isEmpty() || d->searchColumns.indexOf( i ) != -1 )
00448         columnAction->setChecked( true );
00449       else
00450         allColumnsAreSearchColumns = false;
00451     }
00452 
00453     allVisibleColumnsAction->setChecked( allColumnsAreSearchColumns );
00454 
00455     // searchColumnsMenuActivated() relies on one possible "all" representation
00456     if ( allColumnsAreSearchColumns && !d->searchColumns.isEmpty() )
00457       d->searchColumns.clear();
00458   }
00459 
00460   popup->exec( event->globalPos() );
00461   delete popup;
00462 }
00463 
00464 void KTreeViewSearchLine::connectTreeView( QTreeView *treeView )
00465 {
00466   connect( treeView, SIGNAL( destroyed( QObject* ) ),
00467            this, SLOT( treeViewDeleted( QObject* ) ) );
00468 
00469   connect( treeView->model(), SIGNAL( rowsInserted( const QModelIndex&, int, int) ),
00470            this, SLOT( rowsInserted( const QModelIndex&, int, int ) ) );
00471 }
00472 
00473 void KTreeViewSearchLine::disconnectTreeView( QTreeView *treeView )
00474 {
00475   disconnect( treeView, SIGNAL( destroyed( QObject* ) ),
00476               this, SLOT( treeViewDeleted( QObject* ) ) );
00477 
00478   disconnect( treeView->model(), SIGNAL( rowsInserted( const QModelIndex&, int, int) ),
00479               this, SLOT( rowsInserted( const QModelIndex&, int, int ) ) );
00480 }
00481 
00482 bool KTreeViewSearchLine::canChooseColumnsCheck()
00483 {
00484   // This is true if either of the following is true:
00485 
00486   // there are no listviews connected
00487   if ( d->treeViews.isEmpty() )
00488     return false;
00489 
00490   const QTreeView *first = d->treeViews.first();
00491 
00492   const int numcols = first->model()->columnCount();
00493   // the listviews have only one column,
00494   if ( numcols < 2 )
00495     return false;
00496 
00497   QStringList headers;
00498   for ( int i = 0; i < numcols; ++i )
00499     headers.append( first->header()->model()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString() );
00500 
00501   QList<QTreeView *>::ConstIterator it = d->treeViews.constBegin();
00502   for ( ++it /* skip the first one */; it != d->treeViews.constEnd(); ++it ) {
00503     // the listviews have different numbers of columns,
00504     if ( (*it)->model()->columnCount() != numcols )
00505       return false;
00506 
00507     // the listviews differ in column labels.
00508     QStringList::ConstIterator jt;
00509     int i;
00510     for ( i = 0, jt = headers.constBegin(); i < numcols; ++i, ++jt ) {
00511       Q_ASSERT( jt != headers.constEnd() );
00512 
00513       if ( (*it)->header()->model()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString() != *jt )
00514         return false;
00515     }
00516   }
00517 
00518   return true;
00519 }
00520 
00522 // protected slots
00524 
00525 void KTreeViewSearchLine::queueSearch( const QString &search )
00526 {
00527   d->queuedSearches++;
00528   d->search = search;
00529 
00530   QTimer::singleShot( 200, this, SLOT( activateSearch() ) );
00531 }
00532 
00533 void KTreeViewSearchLine::activateSearch()
00534 {
00535   --(d->queuedSearches);
00536 
00537   if ( d->queuedSearches == 0 )
00538     updateSearch( d->search );
00539 }
00540 
00542 // KTreeViewSearchLineWidget
00544 
00545 class KTreeViewSearchLineWidget::Private
00546 {
00547   public:
00548     Private()
00549       : treeView( 0 ),
00550         searchLine( 0 )
00551     {
00552     }
00553 
00554     QTreeView *treeView;
00555     KTreeViewSearchLine *searchLine;
00556 };
00557 
00558 KTreeViewSearchLineWidget::KTreeViewSearchLineWidget( QWidget *parent, QTreeView *treeView )
00559   : QWidget( parent ), d( new Private )
00560 {
00561   d->treeView = treeView;
00562 
00563   QTimer::singleShot( 0, this, SLOT( createWidgets() ) );
00564 }
00565 
00566 KTreeViewSearchLineWidget::~KTreeViewSearchLineWidget()
00567 {
00568   delete d;
00569 }
00570 
00571 KTreeViewSearchLine *KTreeViewSearchLineWidget::createSearchLine( QTreeView *treeView ) const
00572 {
00573   return new KTreeViewSearchLine( const_cast<KTreeViewSearchLineWidget*>(this), treeView );
00574 }
00575 
00576 void KTreeViewSearchLineWidget::createWidgets()
00577 {
00578   QLabel *label = new QLabel( i18n("S&earch:"), this );
00579   label->setObjectName( QLatin1String("kde toolbar widget") );
00580 
00581   searchLine()->show();
00582 
00583   label->setBuddy( d->searchLine );
00584   label->show();
00585 
00586   QHBoxLayout* layout = new QHBoxLayout( this );
00587   layout->setSpacing( 5 );
00588   layout->setMargin( 0 );
00589   layout->addWidget( label );
00590   layout->addWidget( d->searchLine );
00591 }
00592 
00593 KTreeViewSearchLine *KTreeViewSearchLineWidget::searchLine() const
00594 {
00595   if ( !d->searchLine )
00596     d->searchLine = createSearchLine( d->treeView );
00597 
00598   return d->searchLine;
00599 }
00600 
00601 #include "ktreeviewsearchline.moc"

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal