File indexing completed on 2024-12-08 12:22:38

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)
0036     Q_PROPERTY(bool keepParentsVisible READ keepParentsVisible WRITE setKeepParentsVisible)
0037 #if KITEMVIEWS_BUILD_DEPRECATED_SINCE(5, 0)
0038     Q_PROPERTY(QString clickMessage READ clickMessage WRITE setClickMessage)
0039 #endif
0040 
0041 public:
0042     /**
0043      * Constructs a KTreeWidgetSearchLine with \a treeWidget being the QTreeWidget to
0044      * be filtered.
0045      *
0046      * If \a treeWidget is null then the widget will be disabled until listviews
0047      * are set with setTreeWidget(), setTreeWidgets() or added with addTreeWidget().
0048      */
0049     explicit KTreeWidgetSearchLine(QWidget *parent = nullptr, QTreeWidget *treeWidget = nullptr);
0050 
0051     /**
0052      * Constructs a KTreeWidgetSearchLine with \a treeWidgets being the list of
0053      * pointers to QTreeWidgets to be filtered.
0054      *
0055      * If \a treeWidgets is empty then the widget will be disabled until listviews
0056      * are set with setTreeWidget(), setTreeWidgets() or added with addTreeWidget().
0057      */
0058     KTreeWidgetSearchLine(QWidget *parent, const QList<QTreeWidget *> &treeWidgets);
0059 
0060     /**
0061      * Destroys the KTreeWidgetSearchLine.
0062      */
0063     ~KTreeWidgetSearchLine() override;
0064 
0065     /**
0066      * Returns true if the search is case sensitive.  This defaults to false.
0067      *
0068      * @see setCaseSensitive()
0069      */
0070     Qt::CaseSensitivity caseSensitivity() const;
0071 
0072     /**
0073      * Returns the current list of columns that will be searched.  If the
0074      * returned list is empty all visible columns will be searched.
0075      *
0076      * @see setSearchColumns
0077      */
0078     QList<int> searchColumns() const;
0079 
0080     /**
0081      * If this is true (the default) then the parents of matched items will also
0082      * be shown.
0083      *
0084      * @see setKeepParentsVisible()
0085      */
0086     bool keepParentsVisible() const;
0087 
0088     /**
0089      * Returns the listview that is currently filtered by the search.
0090      * If there are multiple listviews filtered, it returns 0.
0091      *
0092      * @see setTreeWidget(), treeWidgets()
0093      */
0094     QTreeWidget *treeWidget() const;
0095 
0096     /**
0097      * Returns the list of pointers to listviews that are currently filtered by
0098      * the search.
0099      *
0100      * @see setTreeWidgets(), addTreeWidget(), treeWidget()
0101      */
0102     QList<QTreeWidget *> treeWidgets() const;
0103 
0104 #if KITEMVIEWS_ENABLE_DEPRECATED_SINCE(5, 0)
0105     /**
0106      * @return the message set with setClickMessage
0107      * @deprecated since 5.0, use QLineEdit::placeholderText() instead.
0108      **/
0109     KITEMVIEWS_DEPRECATED_VERSION(5, 0, "Use QLineEdit::placeholderText()")
0110     QString clickMessage() const
0111     {
0112         return placeholderText();
0113     }
0114 #endif
0115 
0116 #if KITEMVIEWS_ENABLE_DEPRECATED_SINCE(5, 0)
0117     /**
0118      * This makes the line edit display a grayed-out hinting text as long as
0119      * the user didn't enter any text. It is often used as indication about
0120      * the purpose of the line edit.
0121      * @deprecated since 5.0, use QLineEdit::setPlaceholderText() instead.
0122      */
0123     KITEMVIEWS_DEPRECATED_VERSION(5, 0, "Use QLineEdit::setPlaceholderText(const QString&))")
0124     void setClickMessage(const QString &msg)
0125     {
0126         setPlaceholderText(msg);
0127     }
0128 #endif
0129 
0130 Q_SIGNALS:
0131     /**
0132      * This signal is emitted whenever an item gets hidden or unhidden due
0133      * to it not matching or matching the search string.
0134      */
0135     void hiddenChanged(QTreeWidgetItem *, bool);
0136 
0137     /**
0138      * This signal is emitted when user finished entering filter text or
0139      * when he made a pause long enough, after the QTreeWidget items got filtered
0140      * @param searchString is the text currently entered by the user
0141      * @since 5.0
0142      */
0143     void searchUpdated(const QString &searchString);
0144 
0145 public Q_SLOTS:
0146     /**
0147      * Adds a QTreeWidget to the list of listviews filtered by this search line.
0148      * If \a treeWidget is null then the widget will be disabled.
0149      *
0150      * @see treeWidget(), setTreeWidgets(), removeTreeWidget()
0151      */
0152     void addTreeWidget(QTreeWidget *treeWidget);
0153 
0154     /**
0155      * Removes a QTreeWidget from the list of listviews filtered by this search
0156      * line. Does nothing if \a treeWidget is 0 or is not filtered by the quick search
0157      * line.
0158      *
0159      * @see listVew(), setTreeWidgets(), addTreeWidget()
0160      */
0161     void removeTreeWidget(QTreeWidget *treeWidget);
0162 
0163     /**
0164      * Updates search to only make visible the items that match \a pattern.  If
0165      * \a s is null then the line edit's text will be used.
0166      */
0167     virtual void updateSearch(const QString &pattern = QString());
0168 
0169     /**
0170      * Make the search case sensitive or case insensitive.
0171      *
0172      * @see caseSenstivity()
0173      */
0174     void setCaseSensitivity(Qt::CaseSensitivity caseSensitivity);
0175 
0176     /**
0177      * When a search is active on a list that's organized into a tree view if
0178      * a parent or ancesestor of an item is does not match the search then it
0179      * will be hidden and as such so too will any children that match.
0180      *
0181      * If this is set to true (the default) then the parents of matching items
0182      * will be shown.
0183      *
0184      * \warning setKeepParentsVisible(true) does not have the expected effect
0185      * on items being added to or removed from the view while a search is active.
0186      * When a new search starts afterwards the behavior will be normal.
0187      *
0188      * @see keepParentsVisible
0189      */
0190     void setKeepParentsVisible(bool value);
0191 
0192     /**
0193      * Sets the list of columns to be searched.  The default is to search all,
0194      * visible columns which can be restored by passing \a columns as an empty
0195      * list.
0196      * If listviews to be filtered have different numbers or labels of columns
0197      * this method has no effect.
0198      *
0199      * @see searchColumns
0200      */
0201     void setSearchColumns(const QList<int> &columns);
0202 
0203     /**
0204      * Sets the QTreeWidget that is filtered by this search line, replacing any
0205      * previously filtered listviews.  If \a treeWidget is null then the widget will be
0206      * disabled.
0207      *
0208      * @see treeWidget(), setTreeWidgets()
0209      */
0210     void setTreeWidget(QTreeWidget *treeWidget);
0211 
0212     /**
0213      * Sets QTreeWidgets that are filtered by this search line, replacing any
0214      * previously filtered listviews.  If \a treeWidgets is empty then the widget will
0215      * be disabled.
0216      *
0217      * @see treeWidgets(), addTreeWidget(), setTreeWidget()
0218      */
0219     void setTreeWidgets(const QList<QTreeWidget *> &treeWidgets);
0220 
0221 protected:
0222     /**
0223      * Returns true if \a item matches the search \a pattern.  This will be evaluated
0224      * based on the value of caseSensitive().  This can be overridden in
0225      * subclasses to implement more complicated matching schemes.
0226      */
0227     virtual bool itemMatches(const QTreeWidgetItem *item, const QString &pattern) const;
0228 
0229     /**
0230      * Re-implemented for internal reasons.  API not affected.
0231      */
0232     void contextMenuEvent(QContextMenuEvent *) override;
0233 
0234     /**
0235      * Updates search to only make visible appropriate items in \a treeWidget.  If
0236      * \a treeWidget is null then nothing is done.
0237      */
0238     virtual void updateSearch(QTreeWidget *treeWidget);
0239 
0240     /**
0241      * Connects signals of this listview to the appropriate slots of the search
0242      * line.
0243      */
0244     virtual void connectTreeWidget(QTreeWidget *);
0245 
0246     /**
0247      * Disconnects signals of a listviews from the search line.
0248      */
0249     virtual void disconnectTreeWidget(QTreeWidget *);
0250 
0251     /**
0252      * Checks columns in all listviews and decides whether choosing columns to
0253      * filter on makes any sense.
0254      *
0255      * Returns false if either of the following is true:
0256      * * there are no listviews connected,
0257      * * the listviews have different numbers of columns,
0258      * * the listviews have only one column,
0259      * * the listviews differ in column labels.
0260      *
0261      * Otherwise it returns true.
0262      *
0263      * @see setSearchColumns()
0264      */
0265     virtual bool canChooseColumnsCheck();
0266 
0267     /**
0268      * Re-implemented for internal reasons.  API not affected.
0269      */
0270     bool event(QEvent *event) override;
0271 
0272 private:
0273     friend class KTreeWidgetSearchLinePrivate;
0274     std::unique_ptr<class KTreeWidgetSearchLinePrivate> const d;
0275 
0276     Q_PRIVATE_SLOT(d, void _k_rowsInserted(const QModelIndex &, int, int) const)
0277     Q_PRIVATE_SLOT(d, void _k_treeWidgetDeleted(QObject *))
0278     Q_PRIVATE_SLOT(d, void _k_slotColumnActivated(QAction *))
0279     Q_PRIVATE_SLOT(d, void _k_slotAllVisibleColumns())
0280     Q_PRIVATE_SLOT(d, void _k_queueSearch(const QString &))
0281     Q_PRIVATE_SLOT(d, void _k_activateSearch())
0282 };
0283 
0284 #endif