klistviewsearchline.cpp
/* This file is part of the KDE libraries
Copyright (c) 2003 Scott Wheeler <wheeler@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 "klistviewsearchline.h"
#include <klistview.h>
#include <kiconloader.h>
#include <ktoolbar.h>
#include <ktoolbarbutton.h>
#include <kdebug.h>
#include <klocale.h>
#include <qapplication.h>
#include <qtimer.h>
#include <qpopupmenu.h>
#include <qlabel.h>
#include <qheader.h>
#define KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID 2004
class KListViewSearchLine::KListViewSearchLinePrivate
{
public:
KListViewSearchLinePrivate() :
listView(0),
caseSensitive(false),
activeSearch(false),
keepParentsVisible(true),
queuedSearches(0) {}
KListView *listView;
bool caseSensitive;
bool activeSearch;
bool keepParentsVisible;
QString search;
int queuedSearches;
QValueList<int> searchColumns;
};
// public methods
KListViewSearchLine::KListViewSearchLine(QWidget *parent, KListView *listView, const char *name) :
KLineEdit(parent, name)
{
d = new KListViewSearchLinePrivate;
d->listView = listView;
connect(this, SIGNAL(textChanged(const QString &)),
this, SLOT(queueSearch(const QString &)));
if(listView) {
connect(listView, SIGNAL(destroyed()),
this, SLOT(listViewDeleted()));
connect(listView, SIGNAL(itemAdded(QListViewItem *)),
this, SLOT(itemAdded(QListViewItem *)));
}
else
setEnabled(false);
}
KListViewSearchLine::KListViewSearchLine(QWidget *parent, const char *name) :
KLineEdit(parent, name)
{
d = new KListViewSearchLinePrivate;
d->listView = 0;
connect(this, SIGNAL(textChanged(const QString &)),
this, SLOT(queueSearch(const QString &)));
setEnabled(false);
}
KListViewSearchLine::~KListViewSearchLine()
{
delete d;
}
bool KListViewSearchLine::caseSensitive() const
{
return d->caseSensitive;
}
QValueList<int> KListViewSearchLine::searchColumns() const
{
return d->searchColumns;
}
bool KListViewSearchLine::keepParentsVisible() const
{
return d->keepParentsVisible;
}
KListView *KListViewSearchLine::listView() const
{
return d->listView;
}
// public slots
void KListViewSearchLine::updateSearch(const QString &s)
{
if(!d->listView)
return;
d->search = s.isNull() ? text() : s;
// 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).
QListViewItem *currentItem = 0;
switch(d->listView->selectionMode())
{
case KListView::NoSelection:
break;
case KListView::Single:
currentItem = d->listView->selectedItem();
break;
default:
{
int flags = QListViewItemIterator::Selected | QListViewItemIterator::Visible;
for(QListViewItemIterator it(d->listView, flags);
it.current() && !currentItem;
++it)
{
if(d->listView->itemRect(it.current()).isValid())
currentItem = it.current();
}
}
}
if(d->keepParentsVisible)
checkItemParentsVisible(d->listView->firstChild());
else
checkItemParentsNotVisible();
if(currentItem)
d->listView->ensureItemVisible(currentItem);
}
void KListViewSearchLine::setCaseSensitive(bool cs)
{
d->caseSensitive = cs;
}
void KListViewSearchLine::setKeepParentsVisible(bool v)
{
d->keepParentsVisible = v;
}
void KListViewSearchLine::setSearchColumns(const QValueList<int> &columns)
{
d->searchColumns = columns;
}
void KListViewSearchLine::setListView(KListView *lv)
{
if(d->listView) {
disconnect(d->listView, SIGNAL(destroyed()),
this, SLOT(listViewDeleted()));
disconnect(d->listView, SIGNAL(itemAdded(QListViewItem *)),
this, SLOT(itemAdded(QListViewItem *)));
}
d->listView = lv;
if(lv) {
connect(d->listView, SIGNAL(destroyed()),
this, SLOT(listViewDeleted()));
connect(d->listView, SIGNAL(itemAdded(QListViewItem *)),
this, SLOT(itemAdded(QListViewItem *)));
}
setEnabled(bool(lv));
}
// protected members
bool KListViewSearchLine::itemMatches(const QListViewItem *item, const QString &s) const
{
if(s.isEmpty())
return true;
// 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()) {
QValueList<int>::ConstIterator it = d->searchColumns.begin();
for(; it != d->searchColumns.end(); ++it) {
if(*it < item->listView()->columns() &&
item->text(*it).find(s, 0, d->caseSensitive) >= 0)
return true;
}
}
else {
for(int i = 0; i < item->listView()->columns(); i++) {
if(item->listView()->columnWidth(i) > 0 &&
item->text(i).find(s, 0, d->caseSensitive) >= 0)
{
return true;
}
}
}
return false;
}
QPopupMenu *KListViewSearchLine::createPopupMenu()
{
QPopupMenu *popup = KLineEdit::createPopupMenu();
if (d->listView->columns()>1) {
QPopupMenu *subMenu = new QPopupMenu(popup);
connect(subMenu, SIGNAL(activated(int)), this, SLOT(searchColumnsMenuActivated(int)));
popup->insertSeparator();
popup->insertItem(i18n("Search Columns"), subMenu);
subMenu->insertItem(i18n("All Visible Columns"), KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID);
subMenu->insertSeparator();
bool allColumnsAreSearchColumns = true;
// TODO Make the entry order match the actual column order
QHeader* const header = d->listView->header();
int visibleColumns = 0;
for(int i = 0; i < d->listView->columns(); i++) {
if(d->listView->columnWidth(i)>0) {
QString columnText = d->listView->columnText(i);
if(columnText.isEmpty()) {
int visiblePosition=1;
for(int j = 0; j < header->mapToIndex(i); j++)
if(d->listView->columnWidth(header->mapToSection(j))>0)
visiblePosition++;
columnText = i18n("Column number %1","Column No. %1").arg(visiblePosition);
}
subMenu->insertItem(columnText, visibleColumns);
if(d->searchColumns.isEmpty() || d->searchColumns.find(i) != d->searchColumns.end())
subMenu->setItemChecked(visibleColumns, true);
else
allColumnsAreSearchColumns = false;
visibleColumns++;
}
}
subMenu->setItemChecked(KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID, allColumnsAreSearchColumns);
// searchColumnsMenuActivated() relies on one possible "all" representation
if(allColumnsAreSearchColumns && !d->searchColumns.isEmpty())
d->searchColumns.clear();
}
return popup;
}
// protected slots
void KListViewSearchLine::queueSearch(const QString &search)
{
d->queuedSearches++;
d->search = search;
QTimer::singleShot(200, this, SLOT(activateSearch()));
}
void KListViewSearchLine::activateSearch()
{
--(d->queuedSearches);
if(d->queuedSearches == 0)
updateSearch(d->search);
}
// private slots
void KListViewSearchLine::itemAdded(QListViewItem *item) const
{
item->setVisible(itemMatches(item, text()));
}
void KListViewSearchLine::listViewDeleted()
{
d->listView = 0;
setEnabled(false);
}
void KListViewSearchLine::searchColumnsMenuActivated(int id)
{
if(id == KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID) {
if(d->searchColumns.isEmpty())
d->searchColumns.append(0);
else
d->searchColumns.clear();
}
else {
if(d->searchColumns.find(id) != d->searchColumns.end())
d->searchColumns.remove(id);
else {
if(d->searchColumns.isEmpty()) {
for(int i = 0; i < d->listView->columns(); i++) {
if(i != id)
d->searchColumns.append(i);
}
}
else
d->searchColumns.append(id);
}
}
updateSearch();
}
// private methods
void KListViewSearchLine::checkItemParentsNotVisible()
{
QListViewItemIterator it(d->listView);
for(; it.current(); ++it)
{
QListViewItem *item = it.current();
if(itemMatches(item, d->search))
item->setVisible(true);
else
item->setVisible(false);
}
}
#include <kdebug.h>
bool KListViewSearchLine::checkItemParentsVisible(QListViewItem *item, QListViewItem *highestHiddenParent)
{
bool visible = false;
QListViewItem * first = item;
for(; item; item = item->nextSibling())
{
//What we pass to our children as highestHiddenParent:
QListViewItem * hhp = highestHiddenParent ? highestHiddenParent : item->isVisible() ? 0L : item;
bool childMatch = false;
if(item->firstChild() && checkItemParentsVisible(item->firstChild(), hhp))
childMatch = true;
// Should this item be shown? It should if any children should be, or if it matches.
if(childMatch || itemMatches(item, d->search))
{
visible = true;
if (highestHiddenParent)
{
highestHiddenParent->setVisible(true);
// Calling setVisible on our ancestor will unhide all its descendents. Hide the ones
// before us that should not be shown.
for(QListViewItem *hide = first; hide != item; hide = hide->nextSibling())
hide->setVisible(false);
highestHiddenParent = 0;
// If we matched, than none of our children matched, yet the setVisible() call on our
// ancestor unhid them, undo the damage:
if(!childMatch)
for(QListViewItem *hide = item->firstChild(); hide; hide = hide->nextSibling())
hide->setVisible(false);
}
else
item->setVisible(true);
}
else
item->setVisible(false);
}
return visible;
}
// KListViewSearchLineWidget
class KListViewSearchLineWidget::KListViewSearchLineWidgetPrivate
{
public:
KListViewSearchLineWidgetPrivate() : listView(0), searchLine(0), clearButton(0) {}
KListView *listView;
KListViewSearchLine *searchLine;
QToolButton *clearButton;
};
KListViewSearchLineWidget::KListViewSearchLineWidget(KListView *listView,
QWidget *parent,
const char *name) :
QHBox(parent, name)
{
d = new KListViewSearchLineWidgetPrivate;
d->listView = listView;
setSpacing(5);
QTimer::singleShot(0, this, SLOT(createWidgets()));
}
KListViewSearchLineWidget::~KListViewSearchLineWidget()
{
delete d;
}
KListViewSearchLine *KListViewSearchLineWidget::createSearchLine(KListView *listView)
{
if(!d->searchLine)
d->searchLine = new KListViewSearchLine(this, listView);
return d->searchLine;
}
void KListViewSearchLineWidget::createWidgets()
{
positionInToolBar();
if(!d->clearButton) {
d->clearButton = new QToolButton(this);
QIconSet icon = SmallIconSet(QApplication::reverseLayout() ? "clear_left" : "locationbar_erase");
d->clearButton->setIconSet(icon);
}
d->clearButton->show();
QLabel *label = new QLabel(i18n("S&earch:"), this, "kde toolbar widget");
d->searchLine = createSearchLine(d->listView);
d->searchLine->show();
label->setBuddy(d->searchLine);
label->show();
connect(d->clearButton, SIGNAL(clicked()), d->searchLine, SLOT(clear()));
}
KListViewSearchLine *KListViewSearchLineWidget::searchLine() const
{
return d->searchLine;
}
void KListViewSearchLineWidget::positionInToolBar()
{
KToolBar *toolBar = dynamic_cast<KToolBar *>(parent());
if(toolBar) {
// Here we have The Big Ugly. Figure out how many widgets are in the
// and do a hack-ish iteration over them to find this widget so that we
// can insert the clear button before it.
int widgetCount = toolBar->count();
for(int index = 0; index < widgetCount; index++) {
int id = toolBar->idAt(index);
if(toolBar->getWidget(id) == this) {
toolBar->setItemAutoSized(id);
if(!d->clearButton) {
QString icon = QApplication::reverseLayout() ? "clear_left" : "locationbar_erase";
d->clearButton = new KToolBarButton(icon, 2005, toolBar);
}
toolBar->insertWidget(2005, d->clearButton->width(), d->clearButton, index);
break;
}
}
}
if(d->searchLine)
d->searchLine->show();
}
#include "klistviewsearchline.moc"
KListViewSearchLine::caseSensitive
bool caseSensitive() const
Returns true if the search is case sensitive.
Definition: klistviewsearchline.cpp:98
KListViewSearchLineWidget::createSearchLine
virtual KListViewSearchLine * createSearchLine(KListView *listView)
Creates the search line.
Definition: klistviewsearchline.cpp:436
KListViewSearchLine
This class makes it easy to add a search line for filtering the items in a listview based on a simple...
Definition: klistviewsearchline.h:47
KListViewSearchLine::setKeepParentsVisible
void setKeepParentsVisible(bool v)
When a search is active on a list that's organized into a tree view if a parent or ancesestor of an i...
Definition: klistviewsearchline.cpp:168
KListViewSearchLine::setSearchColumns
void setSearchColumns(const QValueList< int > &columns)
Sets the list of columns to be searched.
Definition: klistviewsearchline.cpp:173
KListViewSearchLine::queueSearch
void queueSearch(const QString &search)
When keys are pressed a new search string is created and a timer is activated.
Definition: klistviewsearchline.cpp:284
KListViewSearchLine::listView
KListView * listView() const
Returns the listview that is currently filtered by the search.
Definition: klistviewsearchline.cpp:113
KToolBar::getWidget
QWidget * getWidget(int id)
Returns a pointer to the widget corresponding to id.
Definition: ktoolbar.cpp:650
KLineEdit::createPopupMenu
virtual QPopupMenu * createPopupMenu()
Re-implemented for internal reasons.
Definition: klineedit.cpp:862
KListViewSearchLine::updateSearch
virtual void updateSearch(const QString &s=QString::null)
Updates search to only make visible the items that match s.
Definition: klistviewsearchline.cpp:122
KListViewSearchLineWidget::KListViewSearchLineWidget
KListViewSearchLineWidget(KListView *listView=0, QWidget *parent=0, const char *name=0)
Creates a KListViewSearchLineWidget for listView with parent as the parent with and name...
Definition: klistviewsearchline.cpp:418
KToolBar::idAt
int idAt(int index)
Returns the id of the item at the given index.
Definition: ktoolbar.cpp:735
klocale.h
KListViewSearchLine::setListView
void setListView(KListView *lv)
Sets the KListView that is filtered by this search line.
Definition: klistviewsearchline.cpp:178
KListView
This Widget extends the functionality of QListView to honor the system wide settings for Single Click...
Definition: klistview.h:53
KToolBarButton
A toolbar button.
Definition: ktoolbarbutton.h:44
KToolBar::setItemAutoSized
void setItemAutoSized(int id, bool yes=true)
Set item autosized.
Definition: ktoolbar.cpp:657
KListViewSearchLine::createPopupMenu
virtual QPopupMenu * createPopupMenu()
Re-implemented for internal reasons.
Definition: klistviewsearchline.cpp:234
KListViewSearchLineWidget::~KListViewSearchLineWidget
~KListViewSearchLineWidget()
Destroys the KListViewSearchLineWidget.
Definition: klistviewsearchline.cpp:431
KListViewSearchLineWidget::createWidgets
virtual void createWidgets()
Creates the widgets inside of the widget.
Definition: klistviewsearchline.cpp:443
KToolBar::count
int count() const
Returns the total number of items in the toolbar.
Definition: ktoolbar.cpp:955
KListViewSearchLine::searchColumns
QValueList< int > searchColumns() const
Returns the current list of columns that will be searched.
Definition: klistviewsearchline.cpp:103
KListViewSearchLine::KListViewSearchLine
KListViewSearchLine(QWidget *parent=0, KListView *listView=0, const char *name=0)
Constructs a KListViewSearchLine with listView being the KListView to be filtered.
Definition: klistviewsearchline.cpp:59
KListViewSearchLine::activateSearch
void activateSearch()
When the timer started with queueSearch() expires this slot is called.
Definition: klistviewsearchline.cpp:291
KListViewSearchLine::~KListViewSearchLine
virtual ~KListViewSearchLine()
Destroys the KListViewSearchLine.
Definition: klistviewsearchline.cpp:93
KLineEdit
An enhanced QLineEdit widget for inputting text.
Definition: klineedit.h:145
KToolBar
Floatable toolbar with auto resize.
Definition: ktoolbar.h:103
KListViewSearchLine::itemMatches
virtual bool itemMatches(const QListViewItem *item, const QString &s) const
Returns true if item matches the search s.
Definition: klistviewsearchline.cpp:205
KListViewSearchLineWidget::searchLine
KListViewSearchLine * searchLine() const
Returns a pointer to the search line.
Definition: klistviewsearchline.cpp:466
KListViewSearchLine::setCaseSensitive
void setCaseSensitive(bool cs)
Make the search case sensitive or case insensitive.
Definition: klistviewsearchline.cpp:163
KToolBar::insertWidget
int insertWidget(int id, int width, QWidget *_widget, int index=-1)
Inserts a user-defined widget.
Definition: ktoolbar.cpp:409
KListViewSearchLine::keepParentsVisible
bool keepParentsVisible() const
If this is true (the default) then the parents of matched items will also be shown.
Definition: klistviewsearchline.cpp:108

KDE Home | KDE Accessibility Home | Description of Access Keys