File indexing completed on 2024-12-08 03:41:11

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2003 Scott Wheeler <wheeler@kde.org>
0004     SPDX-FileCopyrightText: 2005 Rafal Rzepecki <divide@users.sourceforge.net>
0005     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-only
0008 */
0009 
0010 #ifndef KTREEWIDGETSEARCHLINE_H
0011 #define KTREEWIDGETSEARCHLINE_H
0012 
0013 #include <QLineEdit>
0014 #include <kitemviews_export.h>
0015 #include <memory>
0016 
0017 class QModelIndex;
0018 class QTreeWidget;
0019 class QTreeWidgetItem;
0020 
0021 /**
0022  * @class KTreeWidgetSearchLine ktreewidgetsearchline.h KTreeWidgetSearchLine
0023  *
0024  * This class makes it easy to add a search line for filtering the items in
0025  * listviews based on a simple text search.
0026  *
0027  * No changes to the application other than instantiating this class with
0028  * appropriate QTreeWidgets should be needed.
0029  */
0030 
0031 class KITEMVIEWS_EXPORT KTreeWidgetSearchLine : public QLineEdit
0032 {
0033     Q_OBJECT
0034 
0035     Q_PROPERTY(Qt::CaseSensitivity caseSensitity READ caseSensitivity WRITE setCaseSensitivity NOTIFY caseSensitivityChanged)
0036     Q_PROPERTY(bool keepParentsVisible READ keepParentsVisible WRITE setKeepParentsVisible NOTIFY keepParentsVisibleChanged)
0037 
0038 public:
0039     /**
0040      * Constructs a KTreeWidgetSearchLine with \a treeWidget being the QTreeWidget to
0041      * be filtered.
0042      *
0043      * If \a treeWidget is null then the widget will be disabled until listviews
0044      * are set with setTreeWidget(), setTreeWidgets() or added with addTreeWidget().
0045      */
0046     explicit KTreeWidgetSearchLine(QWidget *parent = nullptr, QTreeWidget *treeWidget = nullptr);
0047 
0048     /**
0049      * Constructs a KTreeWidgetSearchLine with \a treeWidgets being the list of
0050      * pointers to QTreeWidgets to be filtered.
0051      *
0052      * If \a treeWidgets is empty then the widget will be disabled until listviews
0053      * are set with setTreeWidget(), setTreeWidgets() or added with addTreeWidget().
0054      */
0055     KTreeWidgetSearchLine(QWidget *parent, const QList<QTreeWidget *> &treeWidgets);
0056 
0057     /**
0058      * Destroys the KTreeWidgetSearchLine.
0059      */
0060     ~KTreeWidgetSearchLine() override;
0061 
0062     /**
0063      * Returns true if the search is case sensitive.  This defaults to false.
0064      *
0065      * @see setCaseSensitive()
0066      */
0067     Qt::CaseSensitivity caseSensitivity() const;
0068 
0069     /**
0070      * Returns the current list of columns that will be searched.  If the
0071      * returned list is empty all visible columns will be searched.
0072      *
0073      * @see setSearchColumns
0074      */
0075     QList<int> searchColumns() const;
0076 
0077     /**
0078      * If this is true (the default) then the parents of matched items will also
0079      * be shown.
0080      *
0081      * @see setKeepParentsVisible()
0082      */
0083     bool keepParentsVisible() const;
0084 
0085     /**
0086      * Returns the listview that is currently filtered by the search.
0087      * If there are multiple listviews filtered, it returns 0.
0088      *
0089      * @see setTreeWidget(), treeWidgets()
0090      */
0091     QTreeWidget *treeWidget() const;
0092 
0093     /**
0094      * Returns the list of pointers to listviews that are currently filtered by
0095      * the search.
0096      *
0097      * @see setTreeWidgets(), addTreeWidget(), treeWidget()
0098      */
0099     QList<QTreeWidget *> treeWidgets() const;
0100 
0101 Q_SIGNALS:
0102     /**
0103      * This signal is emitted whenever an item gets hidden or unhidden due
0104      * to it not matching or matching the search string.
0105      */
0106     void hiddenChanged(QTreeWidgetItem *, bool);
0107 
0108     /**
0109      * This signal is emitted when user finished entering filter text or
0110      * when he made a pause long enough, after the QTreeWidget items got filtered
0111      * @param searchString is the text currently entered by the user
0112      * @since 5.0
0113      */
0114     void searchUpdated(const QString &searchString);
0115 
0116     void caseSensitivityChanged(Qt::CaseSensitivity caseSensitivity);
0117     void keepParentsVisibleChanged(bool keepParentsVisible);
0118 
0119 public Q_SLOTS:
0120     /**
0121      * Adds a QTreeWidget to the list of listviews filtered by this search line.
0122      * If \a treeWidget is null then the widget will be disabled.
0123      *
0124      * @see treeWidget(), setTreeWidgets(), removeTreeWidget()
0125      */
0126     void addTreeWidget(QTreeWidget *treeWidget);
0127 
0128     /**
0129      * Removes a QTreeWidget from the list of listviews filtered by this search
0130      * line. Does nothing if \a treeWidget is 0 or is not filtered by the quick search
0131      * line.
0132      *
0133      * @see listVew(), setTreeWidgets(), addTreeWidget()
0134      */
0135     void removeTreeWidget(QTreeWidget *treeWidget);
0136 
0137     /**
0138      * Updates search to only make visible the items that match \a pattern.  If
0139      * \a s is null then the line edit's text will be used.
0140      */
0141     virtual void updateSearch(const QString &pattern = QString());
0142 
0143     /**
0144      * Make the search case sensitive or case insensitive.
0145      *
0146      * @see caseSenstivity()
0147      */
0148     void setCaseSensitivity(Qt::CaseSensitivity caseSensitivity);
0149 
0150     /**
0151      * When a search is active on a list that's organized into a tree view if
0152      * a parent or ancesestor of an item is does not match the search then it
0153      * will be hidden and as such so too will any children that match.
0154      *
0155      * If this is set to true (the default) then the parents of matching items
0156      * will be shown.
0157      *
0158      * \warning setKeepParentsVisible(true) does not have the expected effect
0159      * on items being added to or removed from the view while a search is active.
0160      * When a new search starts afterwards the behavior will be normal.
0161      *
0162      * @see keepParentsVisible
0163      */
0164     void setKeepParentsVisible(bool value);
0165 
0166     /**
0167      * Sets the list of columns to be searched.  The default is to search all,
0168      * visible columns which can be restored by passing \a columns as an empty
0169      * list.
0170      * If listviews to be filtered have different numbers or labels of columns
0171      * this method has no effect.
0172      *
0173      * @see searchColumns
0174      */
0175     void setSearchColumns(const QList<int> &columns);
0176 
0177     /**
0178      * Sets the QTreeWidget that is filtered by this search line, replacing any
0179      * previously filtered listviews.  If \a treeWidget is null then the widget will be
0180      * disabled.
0181      *
0182      * @see treeWidget(), setTreeWidgets()
0183      */
0184     void setTreeWidget(QTreeWidget *treeWidget);
0185 
0186     /**
0187      * Sets QTreeWidgets that are filtered by this search line, replacing any
0188      * previously filtered listviews.  If \a treeWidgets is empty then the widget will
0189      * be disabled.
0190      *
0191      * @see treeWidgets(), addTreeWidget(), setTreeWidget()
0192      */
0193     void setTreeWidgets(const QList<QTreeWidget *> &treeWidgets);
0194 
0195 protected:
0196     /**
0197      * Returns true if \a item matches the search \a pattern.  This will be evaluated
0198      * based on the value of caseSensitive().  This can be overridden in
0199      * subclasses to implement more complicated matching schemes.
0200      */
0201     virtual bool itemMatches(const QTreeWidgetItem *item, const QString &pattern) const;
0202 
0203     /**
0204      * Re-implemented for internal reasons.  API not affected.
0205      */
0206     void contextMenuEvent(QContextMenuEvent *) override;
0207 
0208     /**
0209      * Updates search to only make visible appropriate items in \a treeWidget.  If
0210      * \a treeWidget is null then nothing is done.
0211      */
0212     virtual void updateSearch(QTreeWidget *treeWidget);
0213 
0214     /**
0215      * Connects signals of this listview to the appropriate slots of the search
0216      * line.
0217      */
0218     virtual void connectTreeWidget(QTreeWidget *);
0219 
0220     /**
0221      * Disconnects signals of a listviews from the search line.
0222      */
0223     virtual void disconnectTreeWidget(QTreeWidget *);
0224 
0225     /**
0226      * Checks columns in all listviews and decides whether choosing columns to
0227      * filter on makes any sense.
0228      *
0229      * Returns false if either of the following is true:
0230      * * there are no listviews connected,
0231      * * the listviews have different numbers of columns,
0232      * * the listviews have only one column,
0233      * * the listviews differ in column labels.
0234      *
0235      * Otherwise it returns true.
0236      *
0237      * @see setSearchColumns()
0238      */
0239     virtual bool canChooseColumnsCheck();
0240 
0241     /**
0242      * Re-implemented for internal reasons.  API not affected.
0243      */
0244     bool event(QEvent *event) override;
0245 
0246 private:
0247     friend class KTreeWidgetSearchLinePrivate;
0248     std::unique_ptr<class KTreeWidgetSearchLinePrivate> const d;
0249 
0250     Q_PRIVATE_SLOT(d, void _k_rowsInserted(const QModelIndex &, int, int) const)
0251     Q_PRIVATE_SLOT(d, void _k_treeWidgetDeleted(QObject *))
0252     Q_PRIVATE_SLOT(d, void _k_slotColumnActivated(QAction *))
0253     Q_PRIVATE_SLOT(d, void _k_slotAllVisibleColumns())
0254     Q_PRIVATE_SLOT(d, void _k_queueSearch(const QString &))
0255     Q_PRIVATE_SLOT(d, void _k_activateSearch())
0256 };
0257 
0258 #endif