File indexing completed on 2024-06-16 04:59:04

0001 /*
0002   SPDX-FileCopyrightText: 2021 Intevation GmbH
0003   SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
0004 
0005   SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #pragma once
0009 
0010 #include <Qt>
0011 
0012 #include <vector>
0013 
0014 class QAbstractItemModel;
0015 class QModelIndex;
0016 class QRegularExpression;
0017 class QString;
0018 
0019 namespace MailCommon
0020 {
0021 /* This class allows filtering a hierarchical item model with path-like
0022  * patterns like "parent/sub" similar to file path globbing.
0023  *
0024  * The matching works as follows:
0025  * * The pattern is split into sub-patterns wherever "/" occurs.
0026  * * The sub-patterns are matched against each item and its ancestors.
0027  * * The pattern matches for an item if all sub-patterns match the item and
0028  *   its ancestors.
0029  * * The sub-pattern matching uses wildcard matching with implied "*" before
0030  *   and after each sub-pattern. For details see
0031  *   QRegularExpression::wildcardToRegularExpression().
0032  *
0033  * Examples:
0034  * * "foo" matches all items that contain "foo".
0035  * * "foo/bar" matches all items matching "bar" with parent items matching "foo".
0036  * * "foo/" matches all child items of items matching "foo".
0037  * * "/bar" matches all items matching "bar" which have a parent item.
0038  * * "foo//bar" matches all items matching "bar" with grandparents matching "foo".
0039  *
0040  * For more examples have a look at the tests in foldertreewidgettest.cpp.
0041  *
0042  * Design decisions:
0043  * * The original request was that "foo" should match items that contain "foo"
0044  *   *and* their (direct?) child items, so that one can easily narrow down the
0045  *   list of folders to the folders belonging to a subfolder tree, e.g. the
0046  *   subfolder tree for "project foo".
0047  *   I decided against this for the following reasons:
0048  *   * The requested result can be achieved with "foo/".
0049  *   * If there are multiple folders matching "foo" with a larger number of
0050  *     subfolders, then it would not have been easy to select the wanted
0051  *     folder matching "foo" because of all the subfolders that are also listed.
0052  *   * I also think that the behavior of the original request isn't really
0053  *     intuitive, at least for people who know file path globbing.
0054  */
0055 class HierarchicalFolderMatcher
0056 {
0057 public:
0058     HierarchicalFolderMatcher();
0059 
0060     [[nodiscard]] bool isNull() const;
0061 
0062     void setFilter(const QString &filter, Qt::CaseSensitivity caseSensitivity);
0063 
0064     [[nodiscard]] bool matches(const QAbstractItemModel *model, const QModelIndex &start, int role = Qt::DisplayRole);
0065 
0066     [[nodiscard]] QModelIndex findFirstMatch(const QAbstractItemModel *model, const QModelIndex &start, int role = Qt::DisplayRole);
0067 
0068 private:
0069     std::vector<QRegularExpression> filterRegExps;
0070 };
0071 }