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"
2018-08-31 09:23:45 +00:00
# include <QApplication>
# include <QContextMenuEvent>
# include <QHBoxLayout>
# include <QHeaderView>
# include <QLabel>
# include <QList>
# include <QMenu>
2020-01-26 11:40:33 +00:00
# include <QRegularExpression>
2018-08-31 09:23:45 +00:00
# include <QTimer>
# include <QToolButton>
# include <QTreeView>
2014-10-14 05:37:01 +00:00
# include <KLocalizedString>
2020-07-08 11:54:37 +00:00
# include <KToolBar>
2018-08-31 09:23:45 +00:00
# include <QDebug>
2007-09-09 15:50:00 +00:00
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 ;
2019-12-20 15:40:59 +00:00
void treeViewDeleted ( QObject * object ) ;
2009-10-15 20:25:47 +00:00
void slotCaseSensitive ( ) ;
void slotRegularExpression ( ) ;
2007-09-09 15:50:00 +00:00
void checkItemParentsNotVisible ( QTreeView * treeView ) ;
2020-05-23 10:11:48 +00:00
bool filterItems ( QTreeView * treeView , const QModelIndex & index ) ;
2007-09-09 15:50:00 +00:00
} ;
////////////////////////////////////////////////////////////////////////////////
// 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
////////////////////////////////////////////////////////////////////////////////
2018-11-14 19:12:15 +00:00
/** Check whether \p item, its siblings and their descendants should be shown. Show or hide the items as necessary.
2007-09-09 15:50:00 +00:00
*
* \ 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 .
*/
2020-05-23 10:11:48 +00:00
bool KTreeViewSearchLine : : Private : : filterItems ( QTreeView * treeView , const QModelIndex & index )
2007-09-09 15:50:00 +00:00
{
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 )
2020-05-23 10:11:48 +00:00
childMatch | = filterItems ( treeView , treeView - > model ( ) - > index ( i , 0 , index ) ) ;
2020-07-10 22:15:05 +00:00
2007-09-09 15:50:00 +00:00
// 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
2018-10-28 10:49:50 +00:00
setClearButtonEnabled ( true ) ;
2007-09-09 15:50:00 +00:00
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 ( ) ;
bool wasUpdateEnabled = treeView - > updatesEnabled ( ) ;
2007-12-16 22:36:27 +00:00
treeView - > setUpdatesEnabled ( false ) ;
2007-09-09 15:50:00 +00:00
d - > filterItems ( 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 ) ;
}
2019-12-20 15:40:59 +00:00
void KTreeViewSearchLine : : setCaseSensitivity ( Qt : : CaseSensitivity caseSensitivity )
2007-09-09 15:50:00 +00:00
{
2019-12-20 15:40:59 +00:00
if ( d - > caseSensitive ! = caseSensitivity ) {
d - > caseSensitive = caseSensitivity ;
2007-09-09 15:50:00 +00:00
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 ;
2019-01-11 07:09:34 +00:00
// Construct a regular expression object with the right options.
2020-05-23 10:11:48 +00:00
QRegularExpression re ;
if ( d - > regularExpression ) {
re . setPattern ( pattern ) ;
re . setPatternOptions ( d - > caseSensitive ? QRegularExpression : : NoPatternOption : QRegularExpression : : CaseInsensitiveOption ) ;
2020-07-10 22:15:05 +00:00
}
2007-09-09 15:50:00 +00:00
// If the search column list is populated, search just the columns
2018-11-14 19:12:15 +00:00
// specified. 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 ) {
2020-01-26 11:40:33 +00:00
const QString str = model - > data ( model - > index ( row , i , parentIndex ) , Qt : : DisplayRole ) . toString ( ) ;
2020-05-23 10:11:48 +00:00
if ( d - > regularExpression ) {
return str . contains ( re ) ;
} else {
return str . contains ( pattern , d - > caseSensitive ? Qt : : CaseSensitive : Qt : : CaseInsensitive ) ;
2020-07-10 22:15:05 +00:00
}
2020-01-26 11:40:33 +00:00
}
2007-09-09 15:50:00 +00:00
return false ;
}
void KTreeViewSearchLine : : contextMenuEvent ( QContextMenuEvent * event )
{
QMenu * popup = KLineEdit : : createStandardContextMenu ( ) ;
2020-07-10 22:15:05 +00:00
2009-10-15 20:25:47 +00:00
popup - > addSeparator ( ) ;
QMenu * optionsSubMenu = popup - > addMenu ( i18n ( " Search Options " ) ) ;
2019-12-19 22:18:31 +00:00
QAction * caseSensitiveAction = optionsSubMenu - > addAction ( i18nc ( " Enable case sensitive search in the side navigation panels " , " Case Sensitive " ) , this , [ this ] { d - > slotCaseSensitive ( ) ; } ) ;
2009-10-15 20:25:47 +00:00
caseSensitiveAction - > setCheckable ( true ) ;
caseSensitiveAction - > setChecked ( d - > caseSensitive ) ;
2019-12-19 22:18:31 +00:00
QAction * regularExpressionAction = optionsSubMenu - > addAction ( i18nc ( " Enable regular expression search in the side navigation panels " , " Regular Expression " ) , this , [ this ] { d - > slotRegularExpression ( ) ; } ) ;
2009-10-15 20:25:47 +00:00
regularExpressionAction - > setCheckable ( true ) ;
regularExpressionAction - > setChecked ( d - > regularExpression ) ;
2020-07-10 22:15:05 +00:00
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 ) {
2019-12-19 22:18:31 +00:00
connect ( treeView , & QTreeView : : destroyed , this , & KTreeViewSearchLine : : treeViewDeleted ) ;
2007-09-09 15:50:00 +00:00
2019-12-19 22:18:31 +00:00
connect ( treeView - > model ( ) , & QAbstractItemModel : : rowsInserted , this , & KTreeViewSearchLine : : rowsInserted ) ;
2015-09-16 19:43:04 +00:00
}
2007-09-09 15:50:00 +00:00
}
void KTreeViewSearchLine : : disconnectTreeView ( QTreeView * treeView )
{
2015-09-16 19:43:04 +00:00
if ( treeView ) {
2019-12-19 22:18:31 +00:00
disconnect ( treeView , & QTreeView : : destroyed , this , & KTreeViewSearchLine : : treeViewDeleted ) ;
2007-09-09 15:50:00 +00:00
2019-12-19 22:18:31 +00:00
disconnect ( treeView - > model ( ) , & QAbstractItemModel : : rowsInserted , this , & KTreeViewSearchLine : : rowsInserted ) ;
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 ) ;
}
2019-12-19 22:18:31 +00:00
////////////////////////////////////////////////////////////////////////////////
// private functions
////////////////////////////////////////////////////////////////////////////////
void KTreeViewSearchLine : : rowsInserted ( const QModelIndex & parent , int start , int end ) const
{
d - > rowsInserted ( parent , start , end ) ;
}
void KTreeViewSearchLine : : treeViewDeleted ( QObject * treeView )
{
d - > treeViewDeleted ( treeView ) ;
}
2007-09-09 15:50:00 +00:00
////////////////////////////////////////////////////////////////////////////////
// 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 ) ;
2019-09-18 11:35:04 +00:00
layout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
2007-09-09 15:50:00 +00:00
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"