2007-09-09 15:50:00 +00:00
/*
Copyright ( c ) 2003 Scott Wheeler < wheeler @ kde . org >
Copyright ( c ) 2005 Rafal Rzepecki < divide @ users . sourceforge . net >
Copyright ( c ) 2006 Hamish Rodda < rodda @ kde . org >
Copyright 2007 Pino Toscano < pino @ kde . org >
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 <QtCore/QList>
# include <QtCore/QTimer>
2009-10-15 20:25:47 +00:00
# include <QtCore/QRegExp>
2014-08-09 19:08:17 +00:00
# include <QtWidgets/QApplication>
2007-09-09 15:50:00 +00:00
# include <QtGui/QContextMenuEvent>
2014-08-09 19:08:17 +00:00
# include <QtWidgets/QHBoxLayout>
# include <QtWidgets/QHeaderView>
2014-08-07 23:35:27 +00:00
# include <QtWidgets/QLabel>
2014-08-09 19:08:17 +00:00
# include <QtWidgets/QMenu>
# include <QtWidgets/QToolButton>
# include <QtWidgets/QTreeView>
2007-09-09 15:50:00 +00:00
2014-09-11 19:12:27 +00:00
# include <QtCore/QDebug>
2007-09-09 15:50:00 +00:00
# include <kiconloader.h>
2014-10-14 05:37:01 +00:00
# include <KLocalizedString>
2007-09-09 15:50:00 +00:00
# include <ktoolbar.h>
class KTreeViewSearchLine : : Private
{
public :
Private ( KTreeViewSearchLine * _parent )
: parent ( _parent ) ,
2017-09-05 21:27:18 +00:00
treeView ( nullptr ) ,
2007-09-09 15:50:00 +00:00
caseSensitive ( Qt : : CaseInsensitive ) ,
2009-10-15 20:25:47 +00:00
regularExpression ( false ) ,
2007-09-09 15:50:00 +00:00
activeSearch ( false ) ,
queuedSearches ( 0 )
{
}
KTreeViewSearchLine * parent ;
2015-09-16 19:43:04 +00:00
QTreeView * treeView ;
2007-09-09 15:50:00 +00:00
Qt : : CaseSensitivity caseSensitive ;
2009-10-15 20:25:47 +00:00
bool regularExpression ;
2007-09-09 15:50:00 +00:00
bool activeSearch ;
QString search ;
int queuedSearches ;
void rowsInserted ( const QModelIndex & parent , int start , int end ) const ;
void treeViewDeleted ( QObject * treeView ) ;
2009-10-15 20:25:47 +00:00
void slotCaseSensitive ( ) ;
void slotRegularExpression ( ) ;
2007-09-09 15:50:00 +00:00
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 < QAbstractItemModel * > ( parent - > sender ( ) ) ;
if ( ! model )
return ;
2017-09-05 21:27:18 +00:00
QTreeView * widget = nullptr ;
2015-09-16 19:43:04 +00:00
if ( treeView - > model ( ) = = model ) {
widget = treeView ;
}
2007-09-09 15:50:00 +00:00
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 )
{
2015-09-16 19:43:04 +00:00
if ( object = = treeView ) {
2017-09-05 21:27:18 +00:00
treeView = nullptr ;
2015-09-16 19:43:04 +00:00
parent - > setEnabled ( false ) ;
2007-09-09 15:50:00 +00:00
}
}
2009-10-15 20:25:47 +00:00
void KTreeViewSearchLine : : Private : : slotCaseSensitive ( )
{
if ( caseSensitive = = Qt : : CaseSensitive )
parent - > setCaseSensitivity ( Qt : : CaseInsensitive ) ;
else
parent - > setCaseSensitivity ( Qt : : CaseSensitive ) ;
parent - > updateSearch ( ) ;
}
void KTreeViewSearchLine : : Private : : slotRegularExpression ( )
{
if ( regularExpression )
parent - > setRegularExpression ( false ) ;
else
parent - > setRegularExpression ( true ) ;
parent - > updateSearch ( ) ;
}
2007-09-09 15:50:00 +00:00
////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////
/** 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 ;
2007-12-16 22:36:27 +00:00
const int rowcount = treeView - > model ( ) - > rowCount ( index ) ;
for ( int i = 0 ; i < rowcount ; + + i )
2007-09-09 15:50:00 +00:00
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.
2007-12-16 22:36:27 +00:00
const QModelIndex parentindex = index . parent ( ) ;
if ( childMatch | | parent - > itemMatches ( parentindex , index . row ( ) , search ) ) {
treeView - > setRowHidden ( index . row ( ) , parentindex , false ) ;
2007-09-09 15:50:00 +00:00
return true ;
}
2007-12-16 22:36:27 +00:00
treeView - > setRowHidden ( index . row ( ) , parentindex , true ) ;
2007-09-09 15:50:00 +00:00
return false ;
}
////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////
KTreeViewSearchLine : : KTreeViewSearchLine ( QWidget * parent , QTreeView * treeView )
: KLineEdit ( parent ) , d ( new Private ( this ) )
{
2014-10-01 17:40:48 +00:00
connect ( this , & KTreeViewSearchLine : : textChanged , this , & KTreeViewSearchLine : : queueSearch ) ;
2007-09-09 15:50:00 +00:00
setClearButtonShown ( true ) ;
setTreeView ( treeView ) ;
if ( ! treeView ) {
setEnabled ( false ) ;
}
}
KTreeViewSearchLine : : ~ KTreeViewSearchLine ( )
{
delete d ;
}
Qt : : CaseSensitivity KTreeViewSearchLine : : caseSensitivity ( ) const
{
return d - > caseSensitive ;
}
2009-10-15 20:25:47 +00:00
bool KTreeViewSearchLine : : regularExpression ( ) const
{
return d - > regularExpression ;
}
2007-09-09 15:50:00 +00:00
QTreeView * KTreeViewSearchLine : : treeView ( ) const
{
2015-09-16 19:43:04 +00:00
return d - > treeView ;
2007-09-09 15:50:00 +00:00
}
////////////////////////////////////////////////////////////////////////////////
// public slots
////////////////////////////////////////////////////////////////////////////////
void KTreeViewSearchLine : : updateSearch ( const QString & pattern )
{
d - > search = pattern . isNull ( ) ? text ( ) : pattern ;
2015-09-16 19:43:04 +00:00
updateSearch ( d - > treeView ) ;
2007-09-09 15:50:00 +00:00
}
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 ( ) ;
2007-12-16 22:36:27 +00:00
bool wasUpdateEnabled = treeView - > updatesEnabled ( ) ;
treeView - > setUpdatesEnabled ( false ) ;
2015-09-16 19:43:04 +00:00
for ( int i = 0 ; i < treeView - > model ( ) - > rowCount ( ) ; + + i )
d - > checkItemParentsVisible ( treeView , treeView - > rootIndex ( ) ) ;
2007-12-16 22:36:27 +00:00
treeView - > setUpdatesEnabled ( wasUpdateEnabled ) ;
2007-09-09 15:50:00 +00:00
if ( currentIndex . isValid ( ) )
treeView - > scrollTo ( currentIndex ) ;
}
void KTreeViewSearchLine : : setCaseSensitivity ( Qt : : CaseSensitivity caseSensitive )
{
if ( d - > caseSensitive ! = caseSensitive ) {
d - > caseSensitive = caseSensitive ;
updateSearch ( ) ;
2009-10-15 20:25:47 +00:00
emit searchOptionsChanged ( ) ;
}
}
void KTreeViewSearchLine : : setRegularExpression ( bool value )
{
if ( d - > regularExpression ! = value ) {
d - > regularExpression = value ;
updateSearch ( ) ;
emit searchOptionsChanged ( ) ;
2007-09-09 15:50:00 +00:00
}
}
void KTreeViewSearchLine : : setTreeView ( QTreeView * treeView )
{
2015-09-16 19:43:04 +00:00
disconnectTreeView ( d - > treeView ) ;
d - > treeView = treeView ;
connectTreeView ( treeView ) ;
2007-09-09 15:50:00 +00:00
2017-09-05 21:27:18 +00:00
setEnabled ( treeView ! = nullptr ) ;
2007-09-09 15:50:00 +00:00
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
2015-09-16 19:43:04 +00:00
bool KTreeViewSearchLine : : itemMatches ( const QModelIndex & parentIndex , int row , const QString & pattern ) const
2007-09-09 15:50:00 +00:00
{
if ( pattern . isEmpty ( ) )
return true ;
2015-09-16 19:43:04 +00:00
if ( ! parentIndex . isValid ( ) & & parentIndex ! = d - > treeView - > rootIndex ( ) )
2007-09-09 15:50:00 +00:00
return false ;
2009-10-15 20:25:47 +00:00
// Contruct a regular expression object with the right options.
QRegExp expression = QRegExp ( pattern ,
d - > caseSensitive ? Qt : : CaseSensitive : Qt : : CaseInsensitive ,
d - > regularExpression ? QRegExp : : RegExp : QRegExp : : FixedString ) ;
2007-09-09 15:50:00 +00:00
// If the search column list is populated, search just the columns
// specifified. If it is empty default to searching all of the columns.
2015-09-16 19:43:04 +00:00
QAbstractItemModel * model = d - > treeView - > model ( ) ;
const int columncount = model - > columnCount ( parentIndex ) ;
for ( int i = 0 ; i < columncount ; + + i ) {
if ( expression . indexIn ( model - > data ( model - > index ( row , i , parentIndex ) , Qt : : DisplayRole ) . toString ( ) ) > = 0 )
return true ;
2007-09-09 15:50:00 +00:00
}
return false ;
}
void KTreeViewSearchLine : : contextMenuEvent ( QContextMenuEvent * event )
{
QMenu * popup = KLineEdit : : createStandardContextMenu ( ) ;
2009-10-15 20:25:47 +00:00
popup - > addSeparator ( ) ;
QMenu * optionsSubMenu = popup - > addMenu ( i18n ( " Search Options " ) ) ;
2011-07-31 19:22:04 +00:00
QAction * caseSensitiveAction = optionsSubMenu - > addAction ( i18nc ( " Enable case sensitive search in the side navigation panels " , " Case Sensitive " ) , this , SLOT ( slotCaseSensitive ( ) ) ) ;
2009-10-15 20:25:47 +00:00
caseSensitiveAction - > setCheckable ( true ) ;
caseSensitiveAction - > setChecked ( d - > caseSensitive ) ;
2011-07-31 19:22:04 +00:00
QAction * regularExpressionAction = optionsSubMenu - > addAction ( i18nc ( " Enable regular expression search in the side navigation panels " , " Regular Expression " ) , this , SLOT ( slotRegularExpression ( ) ) ) ;
2009-10-15 20:25:47 +00:00
regularExpressionAction - > setCheckable ( true ) ;
regularExpressionAction - > setChecked ( d - > regularExpression ) ;
2007-09-09 15:50:00 +00:00
popup - > exec ( event - > globalPos ( ) ) ;
delete popup ;
}
void KTreeViewSearchLine : : connectTreeView ( QTreeView * treeView )
{
2015-09-16 19:43:04 +00:00
if ( treeView ) {
connect ( treeView , SIGNAL ( destroyed ( QObject * ) ) ,
this , SLOT ( treeViewDeleted ( QObject * ) ) ) ;
2007-09-09 15:50:00 +00:00
2015-09-16 19:43:04 +00:00
connect ( treeView - > model ( ) , SIGNAL ( rowsInserted ( QModelIndex , int , int ) ) ,
this , SLOT ( rowsInserted ( QModelIndex , int , int ) ) ) ;
}
2007-09-09 15:50:00 +00:00
}
void KTreeViewSearchLine : : disconnectTreeView ( QTreeView * treeView )
{
2015-09-16 19:43:04 +00:00
if ( treeView ) {
disconnect ( treeView , SIGNAL ( destroyed ( QObject * ) ) ,
this , SLOT ( treeViewDeleted ( QObject * ) ) ) ;
2007-09-09 15:50:00 +00:00
2015-09-16 19:43:04 +00:00
disconnect ( treeView - > model ( ) , SIGNAL ( rowsInserted ( QModelIndex , int , int ) ) ,
this , SLOT ( rowsInserted ( QModelIndex , int , int ) ) ) ;
2007-09-09 15:50:00 +00:00
}
}
////////////////////////////////////////////////////////////////////////////////
// protected slots
////////////////////////////////////////////////////////////////////////////////
void KTreeViewSearchLine : : queueSearch ( const QString & search )
{
d - > queuedSearches + + ;
d - > search = search ;
2015-10-29 12:37:11 +00:00
QTimer : : singleShot ( 200 , this , & KTreeViewSearchLine : : activateSearch ) ;
2007-09-09 15:50:00 +00:00
}
void KTreeViewSearchLine : : activateSearch ( )
{
- - ( d - > queuedSearches ) ;
if ( d - > queuedSearches = = 0 )
updateSearch ( d - > search ) ;
}
////////////////////////////////////////////////////////////////////////////////
// KTreeViewSearchLineWidget
////////////////////////////////////////////////////////////////////////////////
class KTreeViewSearchLineWidget : : Private
{
public :
Private ( )
2017-09-05 21:27:18 +00:00
: treeView ( nullptr ) ,
searchLine ( nullptr )
2007-09-09 15:50:00 +00:00
{
}
QTreeView * treeView ;
KTreeViewSearchLine * searchLine ;
} ;
KTreeViewSearchLineWidget : : KTreeViewSearchLineWidget ( QWidget * parent , QTreeView * treeView )
: QWidget ( parent ) , d ( new Private )
{
d - > treeView = treeView ;
2015-10-29 12:37:11 +00:00
QTimer : : singleShot ( 0 , this , & KTreeViewSearchLineWidget : : createWidgets ) ;
2007-09-09 15:50:00 +00:00
}
KTreeViewSearchLineWidget : : ~ KTreeViewSearchLineWidget ( )
{
delete d ;
}
KTreeViewSearchLine * KTreeViewSearchLineWidget : : createSearchLine ( QTreeView * treeView ) const
{
return new KTreeViewSearchLine ( const_cast < KTreeViewSearchLineWidget * > ( this ) , treeView ) ;
}
void KTreeViewSearchLineWidget : : createWidgets ( )
{
QLabel * label = new QLabel ( i18n ( " S&earch: " ) , this ) ;
2015-10-29 12:37:11 +00:00
label - > setObjectName ( QStringLiteral ( " kde toolbar widget " ) ) ;
2007-09-09 15:50:00 +00:00
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 ;
}
2014-08-08 22:00:07 +00:00
# include "moc_ktreeviewsearchline.cpp"