From f770c6b54291eb7b4006922ca7de7df2ce7aeec8 Mon Sep 17 00:00:00 2001 From: Pino Toscano Date: Sun, 9 Sep 2007 15:50:00 +0000 Subject: [PATCH] Add a port of the kdelibs classes KTreeWidgetSearchLine* that use QTreeView/QModelIndex instead of TreeWidget/QTreeWidgetItem. This way, we can really filter a tree view and avoid the limitations of QSortFilterProxyModel. svn path=/trunk/KDE/kdegraphics/okular/; revision=710310 --- CMakeLists.txt | 1 + ui/ktreeviewsearchline.cpp | 593 +++++++++++++++++++++++++++++++++++++ ui/ktreeviewsearchline.h | 314 ++++++++++++++++++++ 3 files changed, 908 insertions(+) create mode 100644 ui/ktreeviewsearchline.cpp create mode 100644 ui/ktreeviewsearchline.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 915fbe0a1..664a6ef97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,6 +117,7 @@ set(okularpart_SRCS ui/bookmarklist.cpp ui/findbar.cpp ui/formwidgets.cpp + ui/ktreeviewsearchline.cpp ui/minibar.cpp ui/pageitemdelegate.cpp ui/pagepainter.cpp diff --git a/ui/ktreeviewsearchline.cpp b/ui/ktreeviewsearchline.cpp new file mode 100644 index 000000000..75977a9c0 --- /dev/null +++ b/ui/ktreeviewsearchline.cpp @@ -0,0 +1,593 @@ +/* + Copyright (c) 2003 Scott Wheeler + Copyright (c) 2005 Rafal Rzepecki + Copyright (c) 2006 Hamish Rodda + Copyright 2007 Pino Toscano + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "ktreeviewsearchline.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +class KTreeViewSearchLine::Private +{ + public: + Private( KTreeViewSearchLine *_parent ) + : parent( _parent ), + caseSensitive( Qt::CaseInsensitive ), + activeSearch( false ), + keepParentsVisible( true ), + canChooseColumns( true ), + queuedSearches( 0 ) + { + } + + KTreeViewSearchLine *parent; + QList treeViews; + Qt::CaseSensitivity caseSensitive; + bool activeSearch; + bool keepParentsVisible; + bool canChooseColumns; + QString search; + int queuedSearches; + QList searchColumns; + + void rowsInserted(const QModelIndex & parent, int start, int end) const; + void treeViewDeleted( QObject *treeView ); + void slotColumnActivated(QAction* action); + void slotAllVisibleColumns(); + + void checkColumns(); + void checkItemParentsNotVisible(QTreeView *treeView); + bool checkItemParentsVisible(QTreeView *treeView, const QModelIndex &index); +}; + +//////////////////////////////////////////////////////////////////////////////// +// private slots +//////////////////////////////////////////////////////////////////////////////// + +void KTreeViewSearchLine::Private::rowsInserted( const QModelIndex & parentIndex, int start, int end ) const +{ + QAbstractItemModel* model = qobject_cast( parent->sender() ); + if ( !model ) + return; + + QTreeView* widget = 0L; + foreach ( QTreeView* tree, treeViews ) + if ( tree->model() == model ) { + widget = tree; + break; + } + + if ( !widget ) + return; + + for ( int i = start; i <= end; ++i ) { + widget->setRowHidden( i, parentIndex, !parent->itemMatches( parentIndex, i, parent->text() ) ); + } +} + +void KTreeViewSearchLine::Private::treeViewDeleted( QObject *object ) +{ + treeViews.removeAll( static_cast( object ) ); + parent->setEnabled( treeViews.isEmpty() ); +} + +void KTreeViewSearchLine::Private::slotColumnActivated( QAction *action ) +{ + if ( !action ) + return; + + bool ok; + int column = action->data().toInt( &ok ); + + if ( !ok ) + return; + + if ( action->isChecked() ) { + if ( !searchColumns.isEmpty() ) { + if ( !searchColumns.contains( column ) ) + searchColumns.append( column ); + + if ( searchColumns.count() == treeViews.first()->header()->count() - treeViews.first()->header()->hiddenSectionCount() ) + searchColumns.clear(); + + } else { + searchColumns.append( column ); + } + } else { + if ( searchColumns.isEmpty() ) { + QHeaderView* const header = treeViews.first()->header(); + + for ( int i = 0; i < header->count(); i++ ) { + if ( i != column && !header->isSectionHidden( i ) ) + searchColumns.append( i ); + } + + } else if ( searchColumns.contains( column ) ) { + searchColumns.removeAll( column ); + } + } + + parent->updateSearch(); +} + +void KTreeViewSearchLine::Private::slotAllVisibleColumns() +{ + if ( searchColumns.isEmpty() ) + searchColumns.append( 0 ); + else + searchColumns.clear(); + + parent->updateSearch(); +} + +//////////////////////////////////////////////////////////////////////////////// +// private methods +//////////////////////////////////////////////////////////////////////////////// + + +void KTreeViewSearchLine::Private::checkColumns() +{ + canChooseColumns = parent->canChooseColumnsCheck(); +} + +void KTreeViewSearchLine::Private::checkItemParentsNotVisible( QTreeView *treeView ) +{ +// TODO: PORT ME +#if 0 + QTreeWidgetItemIterator it( treeWidget ); + + for ( ; *it; ++it ) { + QTreeWidgetItem *item = *it; + item->treeWidget()->setItemHidden( item, !parent->itemMatches( item, search ) ); + } +#endif +} + +#include + +/** Check whether \p item, its siblings and their descendents should be shown. Show or hide the items as necessary. + * + * \p item The list view item to start showing / hiding items at. Typically, this is the first child of another item, or the + * the first child of the list view. + * \return \c true if an item which should be visible is found, \c false if all items found should be hidden. If this function + * returns true and \p highestHiddenParent was not 0, highestHiddenParent will have been shown. + */ +bool KTreeViewSearchLine::Private::checkItemParentsVisible( QTreeView *treeView, const QModelIndex &index ) +{ + bool childMatch = false; + for ( int i = 0; i < treeView->model()->rowCount( index ); ++i ) + childMatch |= checkItemParentsVisible( treeView, treeView->model()->index( i, 0, index ) ); + + // Should this item be shown? It should if any children should be, or if it matches. + if ( childMatch || parent->itemMatches( index.parent(), index.row(), search ) ) { + treeView->setRowHidden( index.row(), index.parent(), false ); + return true; + } + + treeView->setRowHidden( index.row(), index.parent(), true ); + + return false; +} + + +//////////////////////////////////////////////////////////////////////////////// +// public methods +//////////////////////////////////////////////////////////////////////////////// + +KTreeViewSearchLine::KTreeViewSearchLine( QWidget *parent, QTreeView *treeView ) + : KLineEdit( parent ), d( new Private( this ) ) +{ + connect( this, SIGNAL( textChanged( const QString& ) ), + this, SLOT( queueSearch( const QString& ) ) ); + + setClearButtonShown( true ); + setTreeView( treeView ); + + if ( !treeView ) { + setEnabled( false ); + } +} + +KTreeViewSearchLine::KTreeViewSearchLine( QWidget *parent, + const QList &treeViews ) + : KLineEdit( parent ), d( new Private( this ) ) +{ + connect( this, SIGNAL( textChanged( const QString& ) ), + this, SLOT( queueSearch( const QString& ) ) ); + + setClearButtonShown( true ); + setTreeViews( treeViews ); +} + +KTreeViewSearchLine::~KTreeViewSearchLine() +{ + delete d; +} + +Qt::CaseSensitivity KTreeViewSearchLine::caseSensitivity() const +{ + return d->caseSensitive; +} + +QList KTreeViewSearchLine::searchColumns() const +{ + if ( d->canChooseColumns ) + return d->searchColumns; + else + return QList(); +} + +bool KTreeViewSearchLine::keepParentsVisible() const +{ + return d->keepParentsVisible; +} + +QTreeView *KTreeViewSearchLine::treeView() const +{ + if ( d->treeViews.count() == 1 ) + return d->treeViews.first(); + else + return 0; +} + +QList KTreeViewSearchLine::treeViews() const +{ + return d->treeViews; +} + + +//////////////////////////////////////////////////////////////////////////////// +// public slots +//////////////////////////////////////////////////////////////////////////////// + +void KTreeViewSearchLine::addTreeView( QTreeView *treeView ) +{ + if ( treeView ) { + connectTreeView( treeView ); + + d->treeViews.append( treeView ); + setEnabled( !d->treeViews.isEmpty() ); + + d->checkColumns(); + } +} + +void KTreeViewSearchLine::removeTreeView( QTreeView *treeView ) +{ + if ( treeView ) { + int index = d->treeViews.indexOf( treeView ); + + if ( index != -1 ) { + d->treeViews.removeAt( index ); + d->checkColumns(); + + disconnectTreeView( treeView ); + + setEnabled( !d->treeViews.isEmpty() ); + } + } +} + +void KTreeViewSearchLine::updateSearch( const QString &pattern ) +{ + d->search = pattern.isNull() ? text() : pattern; + + foreach ( QTreeView* treeView, d->treeViews ) + updateSearch( treeView ); +} + +void KTreeViewSearchLine::updateSearch( QTreeView *treeView ) +{ + if ( !treeView || !treeView->model()->rowCount() ) + return; + + + // If there's a selected item that is visible, make sure that it's visible + // when the search changes too (assuming that it still matches). + + QModelIndex currentIndex = treeView->currentIndex(); + + if ( d->keepParentsVisible ) + for ( int i = 0; i < treeView->model()->rowCount(); ++i ) + d->checkItemParentsVisible( treeView, treeView->rootIndex() ); + else + d->checkItemParentsNotVisible( treeView ); + + if ( currentIndex.isValid() ) + treeView->scrollTo( currentIndex ); +} + +void KTreeViewSearchLine::setCaseSensitivity( Qt::CaseSensitivity caseSensitive ) +{ + if ( d->caseSensitive != caseSensitive ) { + d->caseSensitive = caseSensitive; + updateSearch(); + } +} + +void KTreeViewSearchLine::setKeepParentsVisible( bool visible ) +{ + if ( d->keepParentsVisible != visible ) { + d->keepParentsVisible = visible; + updateSearch(); + } +} + +void KTreeViewSearchLine::setSearchColumns( const QList &columns ) +{ + if ( d->canChooseColumns ) + d->searchColumns = columns; +} + +void KTreeViewSearchLine::setTreeView( QTreeView *treeView ) +{ + setTreeViews( QList() ); + addTreeView( treeView ); +} + +void KTreeViewSearchLine::setTreeViews( const QList &treeViews ) +{ + foreach ( QTreeView* treeView, d->treeViews ) + disconnectTreeView( treeView ); + + d->treeViews = treeViews; + + foreach ( QTreeView* treeView, d->treeViews ) + connectTreeView( treeView ); + + d->checkColumns(); + + setEnabled( !d->treeViews.isEmpty() ); +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +bool KTreeViewSearchLine::itemMatches( const QModelIndex &index, int row, const QString &pattern ) const +{ + if ( pattern.isEmpty() ) + return true; + + if ( !index.isValid() ) + return false; + + // If the search column list is populated, search just the columns + // specifified. If it is empty default to searching all of the columns. + + if ( !d->searchColumns.isEmpty() ) { + QList::ConstIterator it = d->searchColumns.begin(); + for ( ; it != d->searchColumns.end(); ++it ) { + if ( *it < index.model()->columnCount( index ) && + index.child( row, *it ).data( Qt::DisplayRole ).toString().indexOf( pattern, 0, d->caseSensitive ) >= 0 ) + return true; + } + } else { + for ( int i = 0; i < index.model()->columnCount( index ); ++i) { + if ( index.child( row, i ).data( Qt::DisplayRole ).toString().indexOf( pattern, 0, d->caseSensitive ) >= 0 ) + return true; + } + } + + return false; +} + +void KTreeViewSearchLine::contextMenuEvent( QContextMenuEvent *event ) +{ + QMenu *popup = KLineEdit::createStandardContextMenu(); + + if ( d->canChooseColumns ) { + popup->addSeparator(); + QMenu *subMenu = popup->addMenu( i18n("Search Columns") ); + + QAction* allVisibleColumnsAction = subMenu->addAction( i18n("All Visible Columns"), + this, SLOT( slotAllVisibleColumns() ) ); + allVisibleColumnsAction->setCheckable( true ); + allVisibleColumnsAction->setChecked( !d->searchColumns.count() ); + subMenu->addSeparator(); + + bool allColumnsAreSearchColumns = true; + + QActionGroup* group = new QActionGroup( popup ); + group->setExclusive( false ); + connect( group, SIGNAL( triggered( QAction* ) ), SLOT( slotColumnActivated( QAction* ) ) ); + + QHeaderView* const header = d->treeViews.first()->header(); + for ( int j = 0; j < header->count(); j++ ) { + int i = header->logicalIndex( j ); + + if ( header->isSectionHidden( i ) ) + continue; + + QString columnText = header->model()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString(); + QAction* columnAction = subMenu->addAction( qvariant_cast( header->model()->headerData( i, Qt::Horizontal, Qt::DecorationRole ) ), columnText ); + columnAction->setCheckable( true ); + columnAction->setChecked( d->searchColumns.isEmpty() || d->searchColumns.contains( i ) ); + columnAction->setData( i ); + columnAction->setActionGroup( group ); + + if ( d->searchColumns.isEmpty() || d->searchColumns.indexOf( i ) != -1 ) + columnAction->setChecked( true ); + else + allColumnsAreSearchColumns = false; + } + + allVisibleColumnsAction->setChecked( allColumnsAreSearchColumns ); + + // searchColumnsMenuActivated() relies on one possible "all" representation + if ( allColumnsAreSearchColumns && !d->searchColumns.isEmpty() ) + d->searchColumns.clear(); + } + + popup->exec( event->globalPos() ); + delete popup; +} + +void KTreeViewSearchLine::connectTreeView( QTreeView *treeView ) +{ + connect( treeView, SIGNAL( destroyed( QObject* ) ), + this, SLOT( treeViewDeleted( QObject* ) ) ); + + connect( treeView->model(), SIGNAL( rowsInserted( const QModelIndex&, int, int) ), + this, SLOT( rowsInserted( const QModelIndex&, int, int ) ) ); +} + +void KTreeViewSearchLine::disconnectTreeView( QTreeView *treeView ) +{ + disconnect( treeView, SIGNAL( destroyed( QObject* ) ), + this, SLOT( treeViewDeleted( QObject* ) ) ); + + disconnect( treeView->model(), SIGNAL( rowsInserted( const QModelIndex&, int, int) ), + this, SLOT( rowsInserted( const QModelIndex&, int, int ) ) ); +} + +bool KTreeViewSearchLine::canChooseColumnsCheck() +{ + // This is true if either of the following is true: + + // there are no listviews connected + if ( d->treeViews.isEmpty() ) + return false; + + const QTreeView *first = d->treeViews.first(); + + const int numcols = first->model()->columnCount(); + // the listviews have only one column, + if ( numcols < 2 ) + return false; + + QStringList headers; + for ( int i = 0; i < numcols; ++i ) + headers.append( first->header()->model()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString() ); + + QList::ConstIterator it = d->treeViews.constBegin(); + for ( ++it /* skip the first one */; it != d->treeViews.constEnd(); ++it ) { + // the listviews have different numbers of columns, + if ( (*it)->model()->columnCount() != numcols ) + return false; + + // the listviews differ in column labels. + QStringList::ConstIterator jt; + int i; + for ( i = 0, jt = headers.constBegin(); i < numcols; ++i, ++jt ) { + Q_ASSERT( jt != headers.constEnd() ); + + if ( (*it)->header()->model()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString() != *jt ) + return false; + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected slots +//////////////////////////////////////////////////////////////////////////////// + +void KTreeViewSearchLine::queueSearch( const QString &search ) +{ + d->queuedSearches++; + d->search = search; + + QTimer::singleShot( 200, this, SLOT( activateSearch() ) ); +} + +void KTreeViewSearchLine::activateSearch() +{ + --(d->queuedSearches); + + if ( d->queuedSearches == 0 ) + updateSearch( d->search ); +} + +//////////////////////////////////////////////////////////////////////////////// +// KTreeViewSearchLineWidget +//////////////////////////////////////////////////////////////////////////////// + +class KTreeViewSearchLineWidget::Private +{ + public: + Private() + : treeView( 0 ), + searchLine( 0 ) + { + } + + QTreeView *treeView; + KTreeViewSearchLine *searchLine; +}; + +KTreeViewSearchLineWidget::KTreeViewSearchLineWidget( QWidget *parent, QTreeView *treeView ) + : QWidget( parent ), d( new Private ) +{ + d->treeView = treeView; + + QTimer::singleShot( 0, this, SLOT( createWidgets() ) ); +} + +KTreeViewSearchLineWidget::~KTreeViewSearchLineWidget() +{ + delete d; +} + +KTreeViewSearchLine *KTreeViewSearchLineWidget::createSearchLine( QTreeView *treeView ) const +{ + return new KTreeViewSearchLine( const_cast(this), treeView ); +} + +void KTreeViewSearchLineWidget::createWidgets() +{ + QLabel *label = new QLabel( i18n("S&earch:"), this ); + label->setObjectName( QLatin1String("kde toolbar widget") ); + + searchLine()->show(); + + label->setBuddy( d->searchLine ); + label->show(); + + QHBoxLayout* layout = new QHBoxLayout( this ); + layout->setSpacing( 5 ); + layout->setMargin( 0 ); + layout->addWidget( label ); + layout->addWidget( d->searchLine ); +} + +KTreeViewSearchLine *KTreeViewSearchLineWidget::searchLine() const +{ + if ( !d->searchLine ) + d->searchLine = createSearchLine( d->treeView ); + + return d->searchLine; +} + +#include "ktreeviewsearchline.moc" diff --git a/ui/ktreeviewsearchline.h b/ui/ktreeviewsearchline.h new file mode 100644 index 000000000..b3f9b386c --- /dev/null +++ b/ui/ktreeviewsearchline.h @@ -0,0 +1,314 @@ +/* + Copyright (c) 2003 Scott Wheeler + Copyright (c) 2005 Rafal Rzepecki + Copyright (c) 2006 Hamish Rodda + Copyright 2007 Pino Toscano + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KTREEVIEWSEARCHLINE_H +#define KTREEVIEWSEARCHLINE_H + +#include + +class QModelIndex; +class QTreeView; + +/** + * This class makes it easy to add a search line for filtering the items in + * listviews based on a simple text search. + * + * No changes to the application other than instantiating this class with + * appropriate QTreeViews should be needed. + */ + +class KTreeViewSearchLine : public KLineEdit +{ + Q_OBJECT + + Q_PROPERTY( Qt::CaseSensitivity caseSensitity READ caseSensitivity WRITE setCaseSensitivity ) + Q_PROPERTY( bool keepParentsVisible READ keepParentsVisible WRITE setKeepParentsVisible ) + + + public: + /** + * Constructs a KTreeViewSearchLine with \a treeView being the QTreeView to + * be filtered. + * + * If \a treeView is null then the widget will be disabled until listviews + * are set with setTreeView(), setTreeViews() or added with addTreeView(). + */ + explicit KTreeViewSearchLine( QWidget *parent = 0, QTreeView *treeView = 0 ); + + /** + * Constructs a KTreeViewSearchLine with \a treeViews being the list of + * pointers to QTreeViews to be filtered. + * + * If \a treeViews is empty then the widget will be disabled until listviews + * are set with setTreeView(), setTreeViews() or added with addTreeView(). + */ + KTreeViewSearchLine( QWidget *parent, const QList &treeViews ); + + + /** + * Destroys the KTreeViewSearchLine. + */ + virtual ~KTreeViewSearchLine(); + + /** + * Returns true if the search is case sensitive. This defaults to false. + * + * @see setCaseSensitive() + */ + Qt::CaseSensitivity caseSensitivity() const; + + /** + * Returns the current list of columns that will be searched. If the + * returned list is empty all visible columns will be searched. + * + * @see setSearchColumns + */ + QList searchColumns() const; + + /** + * If this is true (the default) then the parents of matched items will also + * be shown. + * + * @see setKeepParentsVisible() + */ + bool keepParentsVisible() const; + + /** + * Returns the listview that is currently filtered by the search. + * If there are multiple listviews filtered, it returns 0. + * + * @see setTreeView(), treeView() + */ + QTreeView *treeView() const; + + /** + * Returns the list of pointers to listviews that are currently filtered by + * the search. + * + * @see setTreeViews(), addTreeView(), treeView() + */ + QList treeViews() const; + + public Q_SLOTS: + /** + * Adds a QTreeView to the list of listviews filtered by this search line. + * If \a treeView is null then the widget will be disabled. + * + * @see treeView(), setTreeViews(), removeTreeView() + */ + void addTreeView( QTreeView *treeView ); + + /** + * Removes a QTreeView from the list of listviews filtered by this search + * line. Does nothing if \a treeView is 0 or is not filtered by the quick search + * line. + * + * @see listVew(), setTreeView(), addTreeView() + */ + void removeTreeView( QTreeView *treeView ); + + /** + * Updates search to only make visible the items that match \a pattern. If + * \a s is null then the line edit's text will be used. + */ + virtual void updateSearch( const QString &pattern = QString() ); + + /** + * Make the search case sensitive or case insensitive. + * + * @see caseSenstivity() + */ + void setCaseSensitivity( Qt::CaseSensitivity caseSensitivity ); + + /** + * When a search is active on a list that's organized into a tree view if + * a parent or ancesestor of an item is does not match the search then it + * will be hidden and as such so too will any children that match. + * + * If this is set to true (the default) then the parents of matching items + * will be shown. + * + * @see keepParentsVisible + */ + void setKeepParentsVisible( bool value ); + + /** + * Sets the list of columns to be searched. The default is to search all, + * visible columns which can be restored by passing \a columns as an empty + * list. + * If listviews to be filtered have different numbers or labels of columns + * this method has no effect. + * + * @see searchColumns + */ + void setSearchColumns( const QList &columns ); + + /** + * Sets the QTreeView that is filtered by this search line, replacing any + * previously filtered listviews. If \a treeView is null then the widget will be + * disabled. + * + * @see treeView(), setTreeViews() + */ + void setTreeView( QTreeView *treeView ); + + /** + * Sets QTreeViews that are filtered by this search line, replacing any + * previously filtered listviews. If \a treeViews is empty then the widget will + * be disabled. + * + * @see treeViews(), addTreeView(), setTreeView() + */ + void setTreeViews( const QList &treeViews ); + + + protected: + /** + * Returns true if \a item matches the search \a pattern. This will be evaluated + * based on the value of caseSensitive(). This can be overridden in + * subclasses to implement more complicated matching schemes. + */ + virtual bool itemMatches( const QModelIndex &item, int row, const QString &pattern ) const; + + /** + * Re-implemented for internal reasons. API not affected. + */ + virtual void contextMenuEvent( QContextMenuEvent* ); + + /** + * Updates search to only make visible appropriate items in \a treeView. If + * \a treeView is null then nothing is done. + */ + virtual void updateSearch( QTreeView *treeView ); + + /** + * Connects signals of this listview to the appropriate slots of the search + * line. + */ + virtual void connectTreeView( QTreeView* ); + + /** + * Disconnects signals of a listviews from the search line. + */ + virtual void disconnectTreeView( QTreeView* ); + + /** + * Checks columns in all listviews and decides whether choosing columns to + * filter on makes any sense. + * + * Returns false if either of the following is true: + * * there are no listviews connected, + * * the listviews have different numbers of columns, + * * the listviews have only one column, + * * the listviews differ in column labels. + * + * Otherwise it returns true. + * + * @see setSearchColumns() + */ + virtual bool canChooseColumnsCheck(); + + protected Q_SLOTS: + /** + * When keys are pressed a new search string is created and a timer is + * activated. The most recent search is activated when this timer runs out + * if another key has not yet been pressed. + * + * This method makes @param search the most recent search and starts the + * timer. + * + * Together with activateSearch() this makes it such that searches are not + * started until there is a short break in the users typing. + * + * @see activateSearch() + */ + void queueSearch( const QString &search ); + + /** + * When the timer started with queueSearch() expires this slot is called. + * If there has been another timer started then this slot does nothing. + * However if there are no other pending searches this starts the list view + * search. + * + * @see queueSearch() + */ + void activateSearch(); + + private: + class Private; + Private* const d; + + Q_PRIVATE_SLOT( d, void rowsInserted( const QModelIndex&, int, int ) const ) + Q_PRIVATE_SLOT( d, void treeViewDeleted( QObject* ) ) + Q_PRIVATE_SLOT( d, void slotColumnActivated( QAction* ) ) + Q_PRIVATE_SLOT( d, void slotAllVisibleColumns() ) +}; + +/** + * Creates a widget featuring a KTreeViewSearchLine, a label with the text + * "Search" and a button to clear the search. + */ +class KTreeViewSearchLineWidget : public QWidget +{ + Q_OBJECT + + public: + /** + * Creates a KTreeViewSearchLineWidget for \a treeView with \a parent as the + * parent. + */ + explicit KTreeViewSearchLineWidget( QWidget *parent = 0, QTreeView *treeView = 0 ); + + /** + * Destroys the KTreeViewSearchLineWidget + */ + ~KTreeViewSearchLineWidget(); + + /** + * Returns a pointer to the search line. + */ + KTreeViewSearchLine *searchLine() const; + + protected Q_SLOTS: + /** + * Creates the widgets inside of the widget. This is called from the + * constructor via a single shot timer so that it it guaranteed to run + * after construction is complete. This makes it suitable for overriding in + * subclasses. + */ + virtual void createWidgets(); + + protected: + /** + * Creates the search line. This can be useful to reimplement in cases where + * a KTreeViewSearchLine subclass is used. + * + * It is const because it is be called from searchLine(), which to the user + * doesn't conceptually alter the widget. + */ + virtual KTreeViewSearchLine *createSearchLine( QTreeView *treeView ) const; + + private: + class Private; + Private* const d; +}; + +#endif