Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_node_filter_proxy_model.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QSet>
10#include <boost/optional.hpp>
11
12#include "kis_node.h"
13#include "kis_node_model.h"
14#include "kis_node_manager.h"
17
18#include "kis_image.h"
19
20
39
41 : QSortFilterProxyModel(parent),
42 m_d(new Private)
43{
44 connect(&m_d->activeNodeCompressor, SIGNAL(timeout()), SLOT(slotUpdateCurrentNodeFilter()), Qt::QueuedConnection);
45}
46
50
52{
53 m_d->modelConnections.clear();
54 m_d->modelConnections.addConnection(model, SIGNAL(sigBeforeBeginRemoveRows(const QModelIndex &, int, int)),
55 this, SLOT(slotBeforeBeginRemoveRows(const QModelIndex &, int, int)));
56
57 m_d->nodeModel = model;
58 setSourceModel(model);
59}
60
61bool KisNodeFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
62{
63 if (m_d->isUpdatingFilter && role == KisNodeModel::ActiveRole) {
64 return false;
65 }
66
67 return QSortFilterProxyModel::setData(index, value, role);
68}
69
71{
72 if (!srcIndex.isValid()) return false;
73
74 KisNodeSP node = nodeModel->nodeFromIndex(srcIndex);
75 const bool nodeTextFilterMatch = (!activeTextFilter || node->name().contains(activeTextFilter.get(), Qt::CaseInsensitive));
76
77 // directParentTextFilterMatch -- There's an argument to be made that searching for a parent name should show
78 // all of the direct children of said text-search. For now, it will remain unused.
79 const bool directParentTextFilterMatch = (!activeTextFilter || (node->parent() && node->parent()->name().contains(activeTextFilter.get(), Qt::CaseInsensitive)));
80 Q_UNUSED(directParentTextFilterMatch);
81
82 const bool nodeColorMatch = (acceptedColorLabels.count() == 0 || acceptedColorLabels.contains(node->colorLabelIndex()));
83 if ( node == activeNode ||
84 ( nodeColorMatch && nodeTextFilterMatch )) {
85 return true;
86 }
87
88 bool result = false;
89
90 const int numChildren = srcIndex.model()->rowCount(srcIndex);
91 for (int i = 0; i < numChildren; i++) {
92 QModelIndex child = nodeModel->index(i, 0, srcIndex);
94 result = true;
95 break;
96 }
97 }
98
99 return result;
100}
101
102bool KisNodeFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
103{
104 KIS_ASSERT_RECOVER(m_d->nodeModel) { return true; }
105
106 const QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
107 if (!index.isValid()) return false;
108
109 KisNodeSP node = m_d->nodeModel->nodeFromIndex(index);
110
111 return !node ||
112 (m_d->acceptedColorLabels.isEmpty() && !m_d->activeTextFilter) ||
113 m_d->checkIndexAllowedRecursively(index);
114}
115
117{
118 KIS_ASSERT_RECOVER(m_d->nodeModel) { return 0; }
119
120 QModelIndex srcIndex = mapToSource(index);
121 return m_d->nodeModel->nodeFromIndex(srcIndex);
122}
123
125{
126 KIS_ASSERT_RECOVER(m_d->nodeModel) { return QModelIndex(); }
127
128 QModelIndex srcIndex = m_d->nodeModel->indexFromNode(node);
129 return mapFromSource(srcIndex);
130}
131
133{
134 m_d->acceptedColorLabels = value;
135 invalidateFilter();
136}
137
139{
140 m_d->activeTextFilter = !text.isEmpty() ? boost::make_optional(text) : boost::none;
141 invalidateFilter();
142}
143
145{
146 // NOTE: the current node might change due to beginRemoveRows, in such case
147 // we must ensure we don't trigger recursive model invalidation.
148
149 // the new node may temporary become null when the last layer
150 // of the document in removed
151 m_d->pendingActiveNode = node;
152 m_d->activeNodeCompressor.start();
153}
154
156{
157 m_d->activeNode = m_d->pendingActiveNode;
158
167 m_d->isUpdatingFilter = true;
168 invalidateFilter();
169 m_d->isUpdatingFilter = false;
170}
171
172void KisNodeFilterProxyModel::slotBeforeBeginRemoveRows(const QModelIndex &parent, int start, int end)
173{
174 for (int row = start; row <= end; row++) {
175 const QModelIndex sourceIndex = sourceModel()->index(row, 0, parent);
176 const QModelIndex mappedIndex = mapFromSource(sourceIndex);
177
178 if (mappedIndex.isValid()) {
179 Q_EMIT sigBeforeBeginRemoveRows(mappedIndex.parent(), mappedIndex.row(), mappedIndex.row());
180 }
181 }
182}
183
185{
186 m_d->nodeModel->setDummiesFacade(0, 0, 0, 0, 0);
187 m_d->pendingActiveNode = 0;
188 m_d->activeNode = 0;
189}
float value(const T *src, size_t ch)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void setAcceptedLabels(const QSet< int > &value)
void setNodeModel(KisNodeModel *model)
QModelIndex indexFromNode(KisNodeSP node) const
void setTextFilter(const QString &text)
const QScopedPointer< Private > m_d
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
void sigBeforeBeginRemoveRows(const QModelIndex &parent, int start, int end)
bool setData(const QModelIndex &index, const QVariant &value, int role) override
void slotBeforeBeginRemoveRows(const QModelIndex &parent, int start, int end)
KisNodeSP nodeFromIndex(const QModelIndex &index) const
@ ActiveRole
Whether the section is the active one.
KisNodeSP nodeFromIndex(const QModelIndex &index) const
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
int colorLabelIndex() const
QString name() const
KisSignalAutoConnectionsStore modelConnections
bool checkIndexAllowedRecursively(QModelIndex srcIndex)
KisNodeWSP parent
Definition kis_node.cpp:86