RecursiveFilterProxy.hpp
1 #pragma once
2 #include <score/tools/Debug.hpp>
3 
4 #include <QFileSystemModel>
5 #include <QSortFilterProxyModel>
6 
7 namespace Library
8 {
9 class RecursiveFilterProxy : public QSortFilterProxyModel
10 {
11 public:
12  using QSortFilterProxyModel::QSortFilterProxyModel;
13 
14  const QString& pattern() const noexcept { return m_textPattern; }
15  void setPattern(const QString& p)
16  {
17  beginResetModel();
18  auto old = m_textPattern;
19  m_textPattern = p;
20  endResetModel();
21  // if(!p.contains(old))
22  // invalidateFilter();
23  }
24 
25 protected:
26  QString m_textPattern;
27  bool filterAcceptsRow(int srcRow, const QModelIndex& srcParent) const override
28  {
29  if(filterAcceptsRowItself(srcRow, srcParent))
30  {
31  return true;
32  }
33 
34  // Accept if any of the parents is accepted on its own
35  for(QModelIndex parent = srcParent; parent.isValid(); parent = parent.parent())
36  if(filterAcceptsRowItself(parent.row(), parent.parent()))
37  {
38  return true;
39  }
40 
41  // Accept if any of the children is accepted on its own
42  return hasAcceptedChildren(srcRow, srcParent);
43  }
44 
45  bool filterAcceptsRowItself(int srcRow, const QModelIndex& srcParent) const
46  {
47  QModelIndex index = sourceModel()->index(srcRow, 0, srcParent);
48  const QVariant& data = sourceModel()->data(index);
49 
50  return data.toString().contains(m_textPattern, Qt::CaseInsensitive);
51  }
52 
53  bool hasAcceptedChildren(int srcRow, const QModelIndex& srcParent) const
54  {
55  QModelIndex index = sourceModel()->index(srcRow, 0, srcParent);
56 
57  if(!index.isValid())
58  return false;
59 
60  SCORE_ASSERT(index.model());
61  const int childCount = index.model()->rowCount(index);
62 
63  if(childCount == 0)
64  return false;
65 
66  for(int i = 0; i < childCount; ++i)
67  {
68  if(filterAcceptsRowItself(i, index))
69  return true;
70 
71  if(hasAcceptedChildren(i, index))
72  return true;
73  }
74 
75  return false;
76  }
77 };
78 
80 {
81 public:
82  using RecursiveFilterProxy::RecursiveFilterProxy;
83 
84  QModelIndex fixedRootIndex{};
85 
86 private:
87  bool isChildOfRoot(const QModelIndex& m) const noexcept
88  {
89  if(!m.isValid())
90  {
91  return false;
92  }
93  if(m == fixedRootIndex)
94  return true;
95  if(auto parent = m.parent(); parent == fixedRootIndex)
96  {
97  return true;
98  }
99  else
100  {
101  return isChildOfRoot(parent);
102  }
103  }
104 
105  QFileSystemModel* sourceModel() const noexcept
106  {
107  return static_cast<QFileSystemModel*>(QSortFilterProxyModel::sourceModel());
108  }
109  bool filterAcceptsRow(int srcRow, const QModelIndex& srcParent) const override
110  {
111  const QModelIndex index = sourceModel()->index(srcRow, 0, srcParent);
112  if(!isChildOfRoot(index))
113  {
114  return false;
115  }
116 
117  if(filterAcceptsRowItself(srcRow, srcParent))
118  {
119  return true;
120  }
121 
122  // Accept if any of the parents is accepted on its own
123  for(QModelIndex parent = srcParent; parent.isValid(); parent = parent.parent())
124  {
125  // We went up to the root. We know that we are a child due to the startsWith.
126  if(parent == fixedRootIndex)
127  return false;
128 
129  if(filterAcceptsRowItself(parent.row(), parent.parent()))
130  {
131  return true;
132  }
133  }
134 
135  // Accept if any of the children is accepted on its own
136  return hasAcceptedChildren(srcRow, srcParent);
137  }
138 };
139 }
Definition: RecursiveFilterProxy.hpp:80
Definition: RecursiveFilterProxy.hpp:10