summaryrefslogtreecommitdiffstats
path: root/tdeui/tdelistviewsearchline.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdeui/tdelistviewsearchline.cpp')
-rw-r--r--tdeui/tdelistviewsearchline.cpp501
1 files changed, 501 insertions, 0 deletions
diff --git a/tdeui/tdelistviewsearchline.cpp b/tdeui/tdelistviewsearchline.cpp
new file mode 100644
index 000000000..96bf82370
--- /dev/null
+++ b/tdeui/tdelistviewsearchline.cpp
@@ -0,0 +1,501 @@
+/* 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 <tqapplication.h>
+#include <tqtimer.h>
+#include <tqpopupmenu.h>
+#include <tqlabel.h>
+#include <tqheader.h>
+
+#define KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID 2004
+
+class TDEListViewSearchLine::TDEListViewSearchLinePrivate
+{
+public:
+ TDEListViewSearchLinePrivate() :
+ listView(0),
+ caseSensitive(false),
+ activeSearch(false),
+ keepParentsVisible(true),
+ queuedSearches(0) {}
+
+ TDEListView *listView;
+ bool caseSensitive;
+ bool activeSearch;
+ bool keepParentsVisible;
+ TQString search;
+ int queuedSearches;
+ TQValueList<int> searchColumns;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public methods
+////////////////////////////////////////////////////////////////////////////////
+
+TDEListViewSearchLine::TDEListViewSearchLine(TQWidget *parent, TDEListView *listView, const char *name) :
+ KLineEdit(parent, name)
+{
+ d = new TDEListViewSearchLinePrivate;
+
+ d->listView = listView;
+
+ connect(this, TQT_SIGNAL(textChanged(const TQString &)),
+ this, TQT_SLOT(queueSearch(const TQString &)));
+
+ if(listView) {
+ connect(listView, TQT_SIGNAL(destroyed()),
+ this, TQT_SLOT(listViewDeleted()));
+
+ connect(listView, TQT_SIGNAL(itemAdded(TQListViewItem *)),
+ this, TQT_SLOT(itemAdded(TQListViewItem *)));
+ }
+ else
+ setEnabled(false);
+}
+
+TDEListViewSearchLine::TDEListViewSearchLine(TQWidget *parent, const char *name) :
+ KLineEdit(parent, name)
+{
+ d = new TDEListViewSearchLinePrivate;
+
+ d->listView = 0;
+
+ connect(this, TQT_SIGNAL(textChanged(const TQString &)),
+ this, TQT_SLOT(queueSearch(const TQString &)));
+
+ setEnabled(false);
+}
+
+TDEListViewSearchLine::~TDEListViewSearchLine()
+{
+ delete d;
+}
+
+bool TDEListViewSearchLine::caseSensitive() const
+{
+ return d->caseSensitive;
+}
+
+TQValueList<int> TDEListViewSearchLine::searchColumns() const
+{
+ return d->searchColumns;
+}
+
+bool TDEListViewSearchLine::keepParentsVisible() const
+{
+ return d->keepParentsVisible;
+}
+
+TDEListView *TDEListViewSearchLine::listView() const
+{
+ return d->listView;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// public slots
+////////////////////////////////////////////////////////////////////////////////
+
+void TDEListViewSearchLine::updateSearch(const TQString &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).
+
+ TQListViewItem *currentItem = 0;
+
+ switch(d->listView->selectionMode())
+ {
+ case TDEListView::NoSelection:
+ break;
+ case TDEListView::Single:
+ currentItem = d->listView->selectedItem();
+ break;
+ default:
+ {
+ int flags = TQListViewItemIterator::Selected | TQListViewItemIterator::Visible;
+ for(TQListViewItemIterator 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 TDEListViewSearchLine::setCaseSensitive(bool cs)
+{
+ d->caseSensitive = cs;
+}
+
+void TDEListViewSearchLine::setKeepParentsVisible(bool v)
+{
+ d->keepParentsVisible = v;
+}
+
+void TDEListViewSearchLine::setSearchColumns(const TQValueList<int> &columns)
+{
+ d->searchColumns = columns;
+}
+
+void TDEListViewSearchLine::setListView(TDEListView *lv)
+{
+ if(d->listView) {
+ disconnect(d->listView, TQT_SIGNAL(destroyed()),
+ this, TQT_SLOT(listViewDeleted()));
+
+ disconnect(d->listView, TQT_SIGNAL(itemAdded(TQListViewItem *)),
+ this, TQT_SLOT(itemAdded(TQListViewItem *)));
+ }
+
+ d->listView = lv;
+
+ if(lv) {
+ connect(d->listView, TQT_SIGNAL(destroyed()),
+ this, TQT_SLOT(listViewDeleted()));
+
+ connect(d->listView, TQT_SIGNAL(itemAdded(TQListViewItem *)),
+ this, TQT_SLOT(itemAdded(TQListViewItem *)));
+ }
+
+ setEnabled(bool(lv));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// protected members
+////////////////////////////////////////////////////////////////////////////////
+
+bool TDEListViewSearchLine::itemMatches(const TQListViewItem *item, const TQString &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()) {
+ TQValueList<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;
+}
+
+TQPopupMenu *TDEListViewSearchLine::createPopupMenu()
+{
+ TQPopupMenu *popup = KLineEdit::createPopupMenu();
+
+ if (d->listView->columns()>1) {
+ TQPopupMenu *subMenu = new TQPopupMenu(popup);
+ connect(subMenu, TQT_SIGNAL(activated(int)), this, TQT_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
+ TQHeader* const header = d->listView->header();
+ int visibleColumns = 0;
+ for(int i = 0; i < d->listView->columns(); i++) {
+ if(d->listView->columnWidth(i)>0) {
+ TQString 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 TDEListViewSearchLine::queueSearch(const TQString &search)
+{
+ d->queuedSearches++;
+ d->search = search;
+ TQTimer::singleShot(200, this, TQT_SLOT(activateSearch()));
+}
+
+void TDEListViewSearchLine::activateSearch()
+{
+ --(d->queuedSearches);
+
+ if(d->queuedSearches == 0)
+ updateSearch(d->search);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// private slots
+////////////////////////////////////////////////////////////////////////////////
+
+void TDEListViewSearchLine::itemAdded(TQListViewItem *item) const
+{
+ item->setVisible(itemMatches(item, text()));
+}
+
+void TDEListViewSearchLine::listViewDeleted()
+{
+ d->listView = 0;
+ setEnabled(false);
+}
+
+void TDEListViewSearchLine::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 TDEListViewSearchLine::checkItemParentsNotVisible()
+{
+ TQListViewItemIterator it(d->listView);
+ for(; it.current(); ++it)
+ {
+ TQListViewItem *item = it.current();
+ if(itemMatches(item, d->search))
+ item->setVisible(true);
+ else
+ item->setVisible(false);
+ }
+}
+
+#include <kdebug.h>
+
+/** 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.
+ * \p highestHiddenParent The highest (closest to root) ancestor of \p item which is hidden. If 0, all parents of
+ * \p item must be visible.
+ * \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 TDEListViewSearchLine::checkItemParentsVisible(TQListViewItem *item, TQListViewItem *highestHiddenParent)
+{
+ bool visible = false;
+ TQListViewItem * first = item;
+ for(; item; item = item->nextSibling())
+ {
+ //What we pass to our children as highestHiddenParent:
+ TQListViewItem * 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(TQListViewItem *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(TQListViewItem *hide = item->firstChild(); hide; hide = hide->nextSibling())
+ hide->setVisible(false);
+ }
+ else
+ item->setVisible(true);
+ }
+ else
+ item->setVisible(false);
+ }
+ return visible;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TDEListViewSearchLineWidget
+////////////////////////////////////////////////////////////////////////////////
+
+class TDEListViewSearchLineWidget::TDEListViewSearchLineWidgetPrivate
+{
+public:
+ TDEListViewSearchLineWidgetPrivate() : listView(0), searchLine(0), clearButton(0) {}
+ TDEListView *listView;
+ TDEListViewSearchLine *searchLine;
+ TQToolButton *clearButton;
+};
+
+TDEListViewSearchLineWidget::TDEListViewSearchLineWidget(TDEListView *listView,
+ TQWidget *parent,
+ const char *name) :
+ TQHBox(parent, name)
+{
+ d = new TDEListViewSearchLineWidgetPrivate;
+ d->listView = listView;
+
+ setSpacing(5);
+
+ TQTimer::singleShot(0, this, TQT_SLOT(createWidgets()));
+}
+
+TDEListViewSearchLineWidget::~TDEListViewSearchLineWidget()
+{
+ delete d;
+}
+
+TDEListViewSearchLine *TDEListViewSearchLineWidget::createSearchLine(TDEListView *listView)
+{
+ if(!d->searchLine)
+ d->searchLine = new TDEListViewSearchLine(this, listView);
+ return d->searchLine;
+}
+
+void TDEListViewSearchLineWidget::createWidgets()
+{
+ positionInToolBar();
+
+ if(!d->clearButton) {
+ d->clearButton = new TQToolButton(this);
+ TQIconSet icon = SmallIconSet(TQApplication::reverseLayout() ? "clear_left" : "locationbar_erase");
+ d->clearButton->setIconSet(icon);
+ }
+
+ d->clearButton->show();
+
+ TQLabel *label = new TQLabel(i18n("S&earch:"), this, "kde toolbar widget");
+
+ d->searchLine = createSearchLine(d->listView);
+ d->searchLine->show();
+
+ label->setBuddy(d->searchLine);
+ label->show();
+
+ connect(d->clearButton, TQT_SIGNAL(clicked()), d->searchLine, TQT_SLOT(clear()));
+}
+
+TDEListViewSearchLine *TDEListViewSearchLineWidget::searchLine() const
+{
+ return d->searchLine;
+}
+
+void TDEListViewSearchLineWidget::positionInToolBar()
+{
+ TDEToolBar *toolBar = tqt_dynamic_cast<TDEToolBar *>(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) {
+ TQString icon = TQApplication::reverseLayout() ? "clear_left" : "locationbar_erase";
+ d->clearButton = new TDEToolBarButton(icon, 2005, toolBar);
+ }
+ toolBar->insertWidget(2005, d->clearButton->width(), d->clearButton, index);
+ break;
+ }
+ }
+ }
+
+ if(d->searchLine)
+ d->searchLine->show();
+}
+
+#include "klistviewsearchline.moc"