1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QML preview debug service.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlpreviewblacklist.h"
41
42QT_BEGIN_NAMESPACE
43
44void QQmlPreviewBlacklist::blacklist(const QString &path)
45{
46 if (!path.isEmpty())
47 m_root.insert(path, offset: 0);
48}
49
50void QQmlPreviewBlacklist::whitelist(const QString &path)
51{
52 if (!path.isEmpty())
53 m_root.remove(path, offset: 0);
54}
55
56bool QQmlPreviewBlacklist::isBlacklisted(const QString &path) const
57{
58 return path.isEmpty() ? true : m_root.containedPrefixLeaf(path, offset: 0) > 0;
59}
60
61void QQmlPreviewBlacklist::clear()
62{
63 m_root = Node();
64}
65
66QQmlPreviewBlacklist::Node::Node()
67{
68}
69
70QQmlPreviewBlacklist::Node::Node(const QQmlPreviewBlacklist::Node &other) :
71 m_mine(other.m_mine), m_isLeaf(other.m_isLeaf)
72{
73 for (auto it = other.m_next.begin(), end = other.m_next.end(); it != end; ++it)
74 m_next.insert(akey: it.key(), avalue: new Node(**it));
75}
76
77QQmlPreviewBlacklist::Node::Node(QQmlPreviewBlacklist::Node &&other) Q_DECL_NOEXCEPT
78{
79 m_mine.swap(other&: other.m_mine);
80 m_next.swap(other&: other.m_next);
81 m_isLeaf = other.m_isLeaf;
82}
83
84QQmlPreviewBlacklist::Node::~Node()
85{
86 qDeleteAll(c: m_next);
87}
88
89QQmlPreviewBlacklist::Node &QQmlPreviewBlacklist::Node::operator=(
90 const QQmlPreviewBlacklist::Node &other)
91{
92 if (&other != this) {
93 m_mine = other.m_mine;
94 for (auto it = other.m_next.begin(), end = other.m_next.end(); it != end; ++it)
95 m_next.insert(akey: it.key(), avalue: new Node(**it));
96 m_isLeaf = other.m_isLeaf;
97 }
98 return *this;
99}
100
101QQmlPreviewBlacklist::Node &QQmlPreviewBlacklist::Node::operator=(
102 QQmlPreviewBlacklist::Node &&other) Q_DECL_NOEXCEPT
103{
104 if (&other != this) {
105 m_mine.swap(other&: other.m_mine);
106 m_next.swap(other&: other.m_next);
107 m_isLeaf = other.m_isLeaf;
108 }
109 return *this;
110}
111
112void QQmlPreviewBlacklist::Node::split(QString::iterator it, QString::iterator end)
113{
114 QString existing;
115 existing.resize(size: end - it - 1);
116 std::copy(first: it + 1, last: end, result: existing.begin());
117
118 Node *node = new Node(existing, m_next, m_isLeaf);
119 m_next.clear();
120 m_next.insert(akey: *it, avalue: node);
121 m_mine.resize(size: it - m_mine.begin());
122 m_isLeaf = false;
123}
124
125void QQmlPreviewBlacklist::Node::insert(const QString &path, int offset)
126{
127 for (auto it = m_mine.begin(), end = m_mine.end(); it != end; ++it) {
128 if (offset == path.size()) {
129 split(it, end);
130 m_isLeaf = true;
131 return;
132 }
133
134 if (path.at(i: offset) != *it) {
135 split(it, end);
136
137 QString inserted;
138 inserted.resize(size: path.size() - offset - 1);
139 std::copy(first: path.begin() + offset + 1, last: path.end(), result: inserted.begin());
140 m_next.insert(akey: path.at(i: offset), avalue: new Node(inserted));
141 return;
142 }
143
144 ++offset;
145 }
146
147 if (offset == path.size()) {
148 m_isLeaf = true;
149 return;
150 }
151
152 Node *&node = m_next[path.at(i: offset++)];
153 if (node == nullptr) {
154 QString inserted;
155 inserted.resize(size: path.size() - offset);
156 std::copy(first: path.begin() + offset, last: path.end(), result: inserted.begin());
157 node = new Node(inserted);
158 } else {
159 node->insert(path, offset);
160 }
161}
162
163void QQmlPreviewBlacklist::Node::remove(const QString &path, int offset)
164{
165 for (auto it = m_mine.begin(), end = m_mine.end(); it != end; ++it) {
166 if (offset == path.size() || path.at(i: offset) != *it) {
167 split(it, end);
168 return;
169 }
170 ++offset;
171 }
172
173 m_isLeaf = false;
174 if (offset == path.size())
175 return;
176
177 auto it = m_next.find(akey: path.at(i: offset));
178 if (it != m_next.end())
179 (*it)->remove(path, offset: ++offset);
180}
181
182int QQmlPreviewBlacklist::Node::containedPrefixLeaf(const QString &path, int offset) const
183{
184 if (offset == path.size())
185 return (m_mine.isEmpty() && m_isLeaf) ? offset : -1;
186
187 for (auto it = m_mine.begin(), end = m_mine.end(); it != end; ++it) {
188 if (path.at(i: offset) != *it)
189 return -1;
190
191 if (++offset == path.size())
192 return (++it == end && m_isLeaf) ? offset : -1;
193 }
194
195 const QChar c = path.at(i: offset);
196 if (m_isLeaf && c == '/')
197 return offset;
198
199 auto it = m_next.find(akey: c);
200 if (it == m_next.end())
201 return -1;
202
203 return (*it)->containedPrefixLeaf(path, offset: ++offset);
204}
205
206QQmlPreviewBlacklist::Node::Node(const QString &mine,
207 const QHash<QChar, QQmlPreviewBlacklist::Node *> &next,
208 bool isLeaf)
209 : m_mine(mine), m_next(next), m_isLeaf(isLeaf)
210{
211}
212
213QT_END_NAMESPACE
214

source code of qtdeclarative/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewblacklist.cpp