File indexing completed on 2024-04-28 09:45:43

0001 /* This file is part of the KDE project
0002    Copyright (C) 2005 Daniel Teske <teske@squorn.de>
0003 
0004    This program is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU General Public License as
0006    published by the Free Software Foundation; either version 2 of
0007    the License, or (at your option) version 3.
0008 
0009    This program is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012    GNU General Public License for more details.
0013 
0014    You should have received a copy of the GNU General Public License
0015    along with this program.  If not, see <http://www.gnu.org/licenses/>
0016 */
0017 
0018 #ifndef __kebsearchline_h
0019 #define __kebsearchline_h
0020 
0021 #include <KLineEdit>
0022 #include <QAbstractItemView>
0023 #include <QList>
0024 
0025 class QAction;
0026 class KViewSearchLinePrivate;
0027 /**
0028  * This class makes it easy to add a search line for filtering the items in a
0029  * QListView/QTreeView based on a simple text search.
0030  *
0031  * No changes to the application other than instantiating this class with an
0032  * appropriate QListView/QTreeView should be needed.
0033  *
0034  * This class automatically responds to the dataChanged(), rowsInserted(),
0035  * rowsRemoved() and similar signals.
0036  * This means that the view needs to be bound to a model().
0037  *
0038  * Note: Don't call setModel() on the view while a KViewSearchLine filters
0039  * the view. (Instead call setView(0) before and setView(view) after calling
0040  * setModel()
0041  *
0042  *
0043  * Note: You need to call updateSearch() if you called QListView::setModelColumn()
0044  */
0045 
0046 // FIXME delete KViewSearchLine if there is a replacement in kdelibs
0047 class KViewSearchLine : public KLineEdit
0048 {
0049     Q_OBJECT
0050 
0051 public:
0052     /**
0053      * Constructs a KViewSearchLine with \a view being the QTreeView/QListView
0054      * to be filtered.
0055      *
0056      * If \a view is null then the widget will be disabled until a listview
0057      * is set with setListView().
0058      */
0059     explicit KViewSearchLine(QWidget *parent = nullptr, QAbstractItemView *view = nullptr);
0060 
0061     /**
0062      * Constructs a KViewSearchLine without any QListView/QTreeView to filter. The
0063      * QListView/QTreeView object has to be set later with setListView().
0064      */
0065     explicit KViewSearchLine(QWidget *parent);
0066 
0067     /**
0068      * Destroys the KViewSearchLine.
0069      */
0070     ~KViewSearchLine() override;
0071 
0072     /**
0073      * Returns true if the search is case sensitive.  This defaults to false.
0074      *
0075      * @see setCaseSensitive()
0076      */
0077     bool caseSensitive() const;
0078 
0079     /**
0080      * Returns the current list of columns that will be searched.  If the
0081      * returned list is empty all visible columns will be searched.
0082      *
0083      * @see setSearchColumns
0084      */
0085     QList<int> searchColumns() const;
0086 
0087     /**
0088      * If this is true (the default) then the parents of matched items will also
0089      * be shown.
0090      *
0091      * @see setKeepParentsVisible()
0092      */
0093     bool keepParentsVisible() const;
0094 
0095     /**
0096      * Returns the view that is currently filtered by the search.
0097      *
0098      * @see setView()
0099      */
0100     QAbstractItemView *view() const;
0101 
0102     using KLineEdit::setVisible;
0103 
0104 public Q_SLOTS:
0105     /**
0106      * Updates search to only make visible the items that match \a s.  If
0107      * \a s is null then the line edit's text will be used.
0108      */
0109     virtual void updateSearch(const QString &s = QString());
0110 
0111     /**
0112      * Make the search case sensitive or case insensitive.
0113      *
0114      * @see caseSenstive()
0115      */
0116     void setCaseSensitive(bool cs);
0117 
0118     /**
0119      * When a search is active on a list that's organized into a tree view if
0120      * a parent or ancestor of an item is does not match the search then it
0121      * will be hidden and as such so too will any children that match.
0122      *
0123      * If this is set to true (the default) then the parents of matching items
0124      * will be shown.
0125      *
0126      * This applies only to QTreeViews.
0127      *
0128      * @see keepParentsVisible
0129      */
0130     void setKeepParentsVisible(bool v);
0131 
0132     /**
0133      * Sets the list of columns to be searched.  The default is to search all,
0134      * visible columns which can be restored by passing \a columns as an empty
0135      * list.
0136      * This has no effect if the view is a QListView.
0137      *
0138      * @see searchColumns
0139      */
0140     void setSearchColumns(const QList<int> &columns);
0141 
0142     /**
0143      * Sets the view that is filtered by this search line.
0144      * If \a v is null then the widget will be disabled.
0145      * v must be either a QListView or a QTreeView
0146      * (That includes QListWidget and QTreeWidget)
0147      * @see view()
0148      */
0149     void setView(QAbstractItemView *v);
0150 
0151 protected:
0152     /**
0153      * Returns true if the row including \a item matches the search \a s.
0154      * This will be evaluated based on the value of caseSensitive() and
0155      * searchColumns().  This can be overridden in subclasses to implement
0156      * more complicated matching schemes.
0157      */
0158     virtual bool itemMatches(const QModelIndex &item, const QString &s) const;
0159 
0160     /**
0161      * Re-implemented for internal reasons.  API not affected.
0162      */
0163     void contextMenuEvent(QContextMenuEvent *e) override;
0164 
0165 protected Q_SLOTS:
0166     /**
0167      * When keys are pressed a new search string is created and a timer is
0168      * activated.  The most recent search is activated when this timer runs out
0169      * if another key has not yet been pressed.
0170      *
0171      * This method makes @param search the most recent search and starts the
0172      * timer.
0173      *
0174      * Together with activateSearch() this makes it such that searches are not
0175      * started until there is a short break in the users typing.
0176      *
0177      * @see activateSearch()
0178      */
0179     void queueSearch(const QString &search);
0180 
0181     /**
0182      * When the timer started with queueSearch() expires this slot is called.
0183      * If there has been another timer started then this slot does nothing.
0184      * However if there are no other pending searches this starts the list view
0185      * search.
0186      *
0187      * @see queueSearch()
0188      */
0189     void activateSearch();
0190 
0191 private:
0192     /**
0193      * QListView's and QTreeView's setRowHidden are slightly different.
0194      */
0195     void setVisible(const QModelIndex &index, bool v);
0196 
0197     /**
0198      * This is used in case parent items of matching items shouldn't be
0199      * visible.  It hides all items that don't match the search string.
0200      */
0201     void checkItemParentsNotVisible();
0202 
0203     /**
0204      * This is used in case parent items of matching items should be visible.
0205      * It makes a recursive call to all children.  It returns true if at least
0206      * one item in the subtree with the given root item is visible.
0207      */
0208     bool checkItemParentsVisible(QModelIndex index);
0209 
0210     /**
0211      * returns whether any row between first and last is visible
0212      */
0213     bool anyVisible(const QModelIndex &first, const QModelIndex &last);
0214 
0215     /**
0216      * rechecks indices first-last after a dataChanged() signal
0217      * sets their visibility and returns true if any item should be
0218      * visible
0219      */
0220     bool recheck(const QModelIndex &first, const QModelIndex &last);
0221 
0222     /**
0223      * Hide QListView/QTreeView's different isRowHidden
0224      */
0225     bool isVisible(const QModelIndex &index);
0226 
0227     /**
0228      * returns the model() of the view()
0229      */
0230     QAbstractItemModel *model() const;
0231 
0232     /**
0233      * returns the index exactly one row below \p index
0234      */
0235     QModelIndex nextRow(const QModelIndex &index);
0236 
0237 private Q_SLOTS:
0238     void listViewDeleted();
0239     void slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
0240     void slotRowsInserted(const QModelIndex &parent, int first, int last);
0241     void slotRowsRemoved(const QModelIndex &parent, int first, int last);
0242     void slotColumnsInserted(const QModelIndex &parent, int first, int last);
0243     void slotColumnsRemoved(const QModelIndex &parent, int first, int last);
0244     void slotModelReset();
0245     void searchColumnsMenuActivated(QAction *act);
0246 
0247 private:
0248     class KViewSearchLinePrivate;
0249     KViewSearchLinePrivate *d;
0250     QList<QAction *> actions;
0251 };
0252 
0253 /**
0254  * Creates a widget featuring a KViewSearchLine, a label with the text
0255  * "Search" and a button to clear the search.
0256  */
0257 class KViewSearchLineWidget : public QWidget
0258 {
0259     Q_OBJECT
0260 
0261 public:
0262     /**
0263      * Creates a KListViewSearchLineWidget for \a view with \a parent as the
0264      * parent
0265      */
0266     explicit KViewSearchLineWidget(QAbstractItemView *view = nullptr, QWidget *parent = nullptr);
0267 
0268     /**
0269      * Destroys the KListViewSearchLineWidget
0270      */
0271     ~KViewSearchLineWidget() override;
0272 
0273     /**
0274      * Creates the search line.  This can be useful to reimplement in cases where
0275      * a KViewSearchLine subclass is used.
0276      */
0277     virtual KViewSearchLine *createSearchLine(QAbstractItemView *view);
0278 
0279     /**
0280      * Returns a pointer to the search line.
0281      */
0282     KViewSearchLine *searchLine() const;
0283 
0284 protected Q_SLOTS:
0285     /**
0286      * Creates the widgets inside of the widget.  This is called from the
0287      * constructor via a single shot timer so that it it guaranteed to run
0288      * after construction is complete.  This makes it suitable for overriding in
0289      * subclasses.
0290      */
0291     virtual void createWidgets();
0292 
0293 private:
0294     class KViewSearchLineWidgetPrivate;
0295     KViewSearchLineWidgetPrivate *d;
0296 };
0297 
0298 #endif