Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_node_model.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2008 Cyrille Berger <cberger@cberger.net>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7#include "kis_node_model.h"
8
9#include <iostream>
10
11#include <QMimeData>
12#include <QBuffer>
13#include <QPointer>
14
17
18#include <klocalizedstring.h>
19
20#include "kis_mimedata.h"
21#include <kis_debug.h>
22#include <kis_node.h>
24#include <kis_image.h>
25#include <kis_selection.h>
26#include <kis_selection_mask.h>
27#include <kis_undo_adapter.h>
29#include <kis_paint_layer.h>
30#include <kis_group_layer.h>
31#include <kis_projection_leaf.h>
33
35#include "kis_filter_mask.h"
41#include "kis_node_manager.h"
44
45#include "kis_config.h"
46#include "kis_config_notifier.h"
50
51
84
85KisNodeModel::KisNodeModel(QObject * parent, int clonedColumns)
86 : QAbstractItemModel(parent)
87 , m_d(new Private)
88{
89 m_d->dummyColumns = qMax(0, clonedColumns);
90 connect(&m_d->updateCompressor, SIGNAL(timeout()), SLOT(processUpdateQueue()));
91 connect(&m_d->thumbnalCache, SIGNAL(sigLayerThumbnailUpdated(KisNodeSP)), SLOT(slotLayerThumbnailUpdated(KisNodeSP)));
92}
93
95{
96 delete m_d->indexConverter;
97 delete m_d;
98}
99
100KisNodeSP KisNodeModel::nodeFromIndex(const QModelIndex &index) const
101{
102 Q_ASSERT(index.isValid());
103
105 if (dummy) {
106 return dummy->node();
107 }
108 return 0;
109}
110
112{
113 KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(node);
114 if(dummy)
115 return m_d->indexConverter->indexFromDummy(dummy);
116 return QModelIndex();
117}
118
120{
121 KisNodeSP isolatedRoot = image->isolationRootNode();
122 if (!isolatedRoot) return true;
123
124 KisNodeDummy *isolatedRootDummy =
125 dummiesFacade->dummyForNode(isolatedRoot);
126 KisNodeDummy *dummy =
128
129 while (dummy) {
130 if (dummy == isolatedRootDummy) {
131 return true;
132 }
133 dummy = dummy->parent();
134 }
135
136 return false;
137}
138
143
153
162
164{
165 const QModelIndex &index = m_d->indexConverter->indexFromDummy(dummy);
166 Q_EMIT dataChanged(index.siblingAtColumn(0), index.siblingAtColumn(m_d->dummyColumns));
167
168 dummy = dummy->firstChild();
169 while (dummy) {
170 regenerateItems(dummy);
171 dummy = dummy->nextSibling();
172 }
173}
174
176{
177 KisNodeDummy *rootDummy = m_d->dummiesFacade->rootDummy();
178 if (!rootDummy) return;
179
180 regenerateItems(rootDummy);
181}
182
189
190void KisNodeModel::setPreferredThumnalSize(int preferredSize) const
191{
192 m_d->thumbnalCache.setMaxSize(preferredSize);
193}
194
201
202void KisNodeModel::slotNodeDisplayModeChanged(bool showRootNode, bool showGlobalSelectionMask)
203{
204 const bool oldShowRootLayer = m_d->showRootLayer;
205 const bool oldShowGlobalSelection = m_d->showGlobalSelection;
206 m_d->showRootLayer = showRootNode;
207 m_d->showGlobalSelection = showGlobalSelectionMask;
208
209 if (m_d->showRootLayer != oldShowRootLayer || m_d->showGlobalSelection != oldShowGlobalSelection) {
211 beginResetModel();
212 endResetModel();
213 }
214}
215
217{
218 if(!m_d->dummiesFacade) return;
219
220 // Need to check here as the node might already be removed, but there might
221 // still be some signals arriving from another thread
222 if (m_d->dummiesFacade->hasDummyForNode(node)) {
223 QModelIndex index = indexFromNode(node);
224
225 Q_EMIT dataChanged(index, index);
226 }
227}
228
230{
231 QModelIndex index = indexFromNode(node);
232 if (!index.isValid()) return;
233
234 Q_EMIT dataChanged(index, index);
235}
236
241
246
247void KisNodeModel::connectDummy(KisNodeDummy *dummy, bool needConnect)
248{
249 KisNodeSP node = dummy->node();
250 if (!node) {
251 qWarning() << "Dummy node has no node!" << dummy << dummy->node();
252 return;
253 }
254 KisNodeProgressProxy *progressProxy = node->nodeProgressProxy();
255 if(progressProxy) {
256 if(needConnect) {
257 connect(progressProxy, SIGNAL(percentageChanged(int,KisNodeSP)),
259 } else {
260 progressProxy->disconnect(this);
261 }
262 }
263}
264
265void KisNodeModel::connectDummies(KisNodeDummy *dummy, bool needConnect)
266{
267 connectDummy(dummy, needConnect);
268
269 dummy = dummy->firstChild();
270 while(dummy) {
271 connectDummies(dummy, needConnect);
272 dummy = dummy->nextSibling();
273 }
274}
275
277 KisImageWSP image,
278 KisShapeController *shapeController,
279 KisSelectionActionsAdapter *selectionActionsAdapter,
280 KisNodeManager *nodeManager)
281{
283 KisShapeController *oldShapeController = m_d->shapeController;
284
285 m_d->shapeController = shapeController;
286 m_d->nodeManager = nodeManager;
287 m_d->nodeSelectionAdapter = nodeManager ? nodeManager->nodeSelectionAdapter() : nullptr;
288 m_d->nodeInsertionAdapter = nodeManager ? nodeManager->nodeInsertionAdapter() : nullptr;
289 m_d->selectionActionsAdapter = selectionActionsAdapter;
290
292 m_d->nodeDisplayModeAdapter = nodeManager ? nodeManager->nodeDisplayModeAdapter() : nullptr;
295 m_d->nodeDisplayModeAdapter, SIGNAL(sigNodeDisplayModeChanged(bool,bool)),
296 this, SLOT(slotNodeDisplayModeChanged(bool,bool)));
297
298 // cold initialization
300 m_d->showRootLayer = false;
301 }
302
303 if (oldDummiesFacade && m_d->image) {
304 m_d->image->disconnect(this);
305 oldDummiesFacade->disconnect(this);
306 KisNodeDummy *oldRootDummy = m_d->dummiesFacade->rootDummy();
307 if (oldRootDummy) {
308 connectDummies(oldRootDummy, false);
309 }
310 }
311
312 m_d->image = image;
315 m_d->thumbnalCache.setImage(image);
317
318 if (m_d->dummiesFacade) {
319 KisNodeDummy *rootDummy = m_d->dummiesFacade->rootDummy();
320 if (rootDummy) {
321 connectDummies(rootDummy, true);
322 }
323
324 connect(m_d->dummiesFacade, SIGNAL(sigBeginInsertDummy(KisNodeDummy*,int,QString)),
325 SLOT(slotBeginInsertDummy(KisNodeDummy*,int,QString)));
326 connect(m_d->dummiesFacade, SIGNAL(sigEndInsertDummy(KisNodeDummy*)),
328 connect(m_d->dummiesFacade, SIGNAL(sigBeginRemoveDummy(KisNodeDummy*)),
330 connect(m_d->dummiesFacade, SIGNAL(sigEndRemoveDummy()),
331 SLOT(slotEndRemoveDummy()));
332
333 connect(m_d->dummiesFacade, SIGNAL(sigDummyChanged(KisNodeDummy*)),
335
336 if (m_d->image.isValid()) {
337 connect(m_d->image, SIGNAL(sigIsolatedModeChanged()), SLOT(slotIsolatedModeChanged()));
338 }
339 }
340
341 if (m_d->dummiesFacade != oldDummiesFacade || m_d->shapeController != oldShapeController) {
342 beginResetModel();
343 endResetModel();
344 }
345}
346
348{
349 m_d->thumbnalCache.setIdleTaskManager(idleTasksManager);
350}
351
352void KisNodeModel::slotBeginInsertDummy(KisNodeDummy *parent, int index, const QString &metaObjectType)
353{
354 int row = 0;
355 QModelIndex parentIndex;
356
357 bool willAdd =
359 metaObjectType,
360 parentIndex, row);
361
362 if(willAdd) {
363 beginInsertRows(parentIndex, row, row);
365 }
366}
367
369{
371 connectDummy(dummy, true);
372 endInsertRows();
373 m_d->needFinishInsertRows = false;
374 }
375
377}
378
380{
381 if (!dummy) return;
382
383 // FIXME: is it really what we want?
385 m_d->updateQueue.clear();
386
387 m_d->parentOfRemovedNode = dummy->parent();
388
389 QModelIndex parentIndex;
392 }
393
394 QModelIndex itemIndex = m_d->indexConverter->indexFromDummy(dummy);
395
396 if (itemIndex.isValid()) {
397 connectDummy(dummy, false);
398 Q_EMIT sigBeforeBeginRemoveRows(parentIndex, itemIndex.row(), itemIndex.row());
399 beginRemoveRows(parentIndex, itemIndex.row(), itemIndex.row());
401 }
402
404}
405
407{
409 endRemoveRows();
410 m_d->needFinishRemoveRows = false;
411 }
412}
413
415{
416 if (!m_d->updateQueue.contains(dummy)) {
417 m_d->updateQueue.append(dummy);
418 }
420}
421
422void addChangedIndex(const QModelIndex &idx, QSet<QModelIndex> *indexes)
423{
424 if (!idx.isValid() || indexes->contains(idx)) return;
425
426 indexes->insert(idx);
427
428 const int rowCount = idx.model()->rowCount(idx);
429 for (int i = 0; i < rowCount; i++) {
430 addChangedIndex(idx.model()->index(i, 0, idx), indexes);
431 }
432}
433
434
436{
437 QSet<QModelIndex> indexes;
438
439 Q_FOREACH (KisNodeDummy *dummy, m_d->updateQueue) {
440 QModelIndex index = m_d->indexConverter->indexFromDummy(dummy);
441 addChangedIndex(index, &indexes);
442 }
443
444 Q_FOREACH (const QModelIndex &index, indexes) {
445 Q_EMIT dataChanged(index.siblingAtColumn(0), index.siblingAtColumn(m_d->dummyColumns));
446 }
447
448 m_d->updateQueue.clear();
449}
450
451QModelIndex KisNodeModel::index(int row, int col, const QModelIndex &parent) const
452{
453 if(!m_d->dummiesFacade || !hasIndex(row, col, parent)) return QModelIndex();
454
455 QModelIndex itemIndex;
456
458 if(dummy) {
459 itemIndex = m_d->indexConverter->indexFromDummy(dummy);
460 }
461
462 if (itemIndex.isValid() && itemIndex.column() != col) {
463 itemIndex = createIndex(itemIndex.row(), col, itemIndex.internalPointer());
464 }
465
466 return itemIndex;
467}
468
469int KisNodeModel::rowCount(const QModelIndex &parent) const
470{
471 if(!m_d->dummiesFacade) return 0;
472 if (parent.column() > 0) {
473 return 0;
474 }
476}
477
478int KisNodeModel::columnCount(const QModelIndex &parent) const
479{
480 if (parent.column() > 0) {
481 return 0;
482 }
483 return 1 + m_d->dummyColumns;
484}
485
486QModelIndex KisNodeModel::parent(const QModelIndex &index) const
487{
488 if(!m_d->dummiesFacade || !index.isValid()) return QModelIndex();
489
491 KisNodeDummy *parentDummy = dummy->parent();
492
493 QModelIndex parentIndex;
494
495 if(parentDummy) {
496 parentIndex = m_d->indexConverter->indexFromDummy(parentDummy);
497 }
498
499 return parentIndex;
500}
501
502QModelIndex KisNodeModel::sibling(int row, int column, const QModelIndex &idx) const
503{
504 // if it's just a different clone column, there's no need to lookup anything
505 if (row == idx.row()) {
506 if (column == idx.column()) {
507 return idx;
508 }
509 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(idx.model() == this, QModelIndex());
510 return createIndex(row, column, idx.internalPointer());
511 }
512 return index(row, column, parent(idx));
513}
514
515QVariant KisNodeModel::data(const QModelIndex &index, int role) const
516{
517 if (!m_d->dummiesFacade || !index.isValid() || !m_d->image.isValid()) return QVariant();
518
520
521 switch (role) {
522 case Qt::DisplayRole: return node->name();
523 case Qt::DecorationRole: return node->icon();
524 case Qt::EditRole: return node->name();
525 case Qt::SizeHintRole: return m_d->image->size(); // FIXME
526 case Qt::ForegroundRole:
527 return belongsToIsolatedGroup(node) &&
528 !node->projectionLeaf()->isDroppedNode() ? QVariant() : QVariant(QColor(Qt::gray));
529 case Qt::FontRole: {
530 QFont baseFont;
531 if (node->projectionLeaf()->isDroppedNode()) {
532 baseFont.setStrikeOut(true);
533 }
534 if (m_d->activeNodeIndex == index) {
535 baseFont.setBold(true);
536 }
537 return baseFont;
538 }
539 case KisNodeModel::PropertiesRole: return QVariant::fromValue(node->sectionModelProperties());
540 case KisNodeModel::AspectRatioRole: return double(m_d->image->width()) / m_d->image->height();
543 return proxy ? proxy->percentage() : -1;
544 }
546 return m_d->activeNodeIndex == index;
547 }
549 return !node->visible(true);
550 }
552 return node->colorLabelIndex();
553 }
555 QString result;
556 KisProjectionLeaf::NodeDropReason reason = node->projectionLeaf()->dropReason();
557
559 result = i18nc("@info:tooltip", "Disabled: masks on pass-through groups are not supported!");
560 } else if (reason == KisProjectionLeaf::DropPassThroughClone) {
561 result = i18nc("@info:tooltip", "Disabled: cloning pass-through groups is not supported!");
562 }
563
564 return result;
565 }
567 return node->isAnimated();
568 }
570 // These layer types' opacity and blending modes cannot be changed,
571 // so there's little point in showing them
572 if (node->inherits("KisFilterMask") ||
573 node->inherits("KisTransparencyMask") ||
574 node->inherits("KisTransformMask") ||
575 node->inherits("KisSelectionMask")) {
576 return "";
577 }
578 const KisConfig::LayerInfoTextStyle infoTextStyle = KisConfig(true).layerInfoTextStyle();
579 const int opacity = round(node->opacity() * 100.0 / 255);
580 const QString opacityString = QString::number(opacity);
581 const QString compositeOpId = node->compositeOpId();
582 QString compositeOpDesc = "null";
583 // make sure the compositeOp exists to avoid crashing on specific layer undo
584 if (node->compositeOp()) {
585 compositeOpDesc = node->compositeOp()->description();
586 }
587 QString defaultOpId = COMPOSITE_OVER; // "normal";
588 if (node->inherits("KisAdjustmentLayer")) {
589 defaultOpId = COMPOSITE_COPY;
590 }
591 else if (node->inherits("KisColorizeMask")) {
592 defaultOpId = COMPOSITE_BEHIND;
593 }
594 QString infoText = "";
596 !(opacity == 100 && compositeOpId == defaultOpId)) {
598 if (opacity == 100) {
599 return QString(compositeOpDesc);
600 }
601 if (compositeOpId == defaultOpId) {
602 return i18nc("%1 is the percent value, % is the percent sign", "%1%", opacityString);
603 }
604 }
605 infoText = i18nc("%1 is the percent value, % is the percent sign", "%1% %2", opacityString, compositeOpDesc);
606 }
607 return infoText;
608 }
609 case FilterMaskColorRole: {
610 if (node->inherits("KisFilterMask")) {
611 KisFilterMaskSP mask = qobject_cast<KisFilterMask*>(node.data());
612 // The main use case is "fastcoloroverlay" filter, to display its color in the UI.
613 if (mask->filter()->hasProperty("color")) {
614 return mask->filter()->getColor("color").toQColor();
615 }
616 }
617 return QVariant();
618 }
620 if (node->inherits("KisLayer")) {
621 KisLayerSP layer = qobject_cast<KisLayer*>(node.data());
622 KisFilterMaskSP mask = layer->colorOverlayMask();
623 if (mask && mask->filter()->hasProperty("color")) {
624 return mask->filter()->getColor("color").toQColor();
625 }
626 }
627 return QVariant();
628 }
629 default:
630
636 if (role >= int(KisNodeModel::BeginThumbnailRole) &&
638 node->graphListener()) {
639
645 const int maxSize = role - int(KisNodeModel::BeginThumbnailRole);
646
647 if (maxSize == m_d->thumbnalCache.maxSize()) {
648 return m_d->thumbnalCache.thumbnail(node);
649 } else {
650 return node->createThumbnail(maxSize, maxSize, Qt::KeepAspectRatio);
651 }
652 } else {
653 return QVariant();
654 }
655 }
656
657 return QVariant();
658}
659
660Qt::ItemFlags KisNodeModel::flags(const QModelIndex &index) const
661{
662 if(!m_d->dummiesFacade || !index.isValid()) return Qt::ItemIsDropEnabled;
663
664 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsEditable;
665 // currently dummy columns are neither selectable nor drag&drop enabled
666 if (index.column() == 0) {
667 flags |= Qt::ItemIsDragEnabled | Qt::ItemIsSelectable;
668 if (m_d->dropEnabled.contains(index.internalId())) {
669 flags |= Qt::ItemIsDropEnabled;
670 }
671
672 }
673
674 return flags;
675}
676
677bool KisNodeModel::setData(const QModelIndex &index, const QVariant &value, int role)
678{
679 if (role == KisNodeModel::DropEnabled) {
680 const QMimeData *mimeData = static_cast<const QMimeData*>(value.value<void*>());
682 return true;
683 }
684
686 QModelIndex parentIndex;
687 if (!index.isValid() && m_d->parentOfRemovedNode && m_d->dummiesFacade && m_d->indexConverter) {
690 }
691
692 KisNodeSP activatedNode;
693
694 if (index.isValid() && value.toBool()) {
695 activatedNode = nodeFromIndex(index);
696 }
697 else if (parentIndex.isValid() && value.toBool()) {
698 activatedNode = nodeFromIndex(parentIndex);
699 }
700 else {
701 activatedNode = 0;
702 }
703
704 QModelIndex newActiveNode = activatedNode ? indexFromNode(activatedNode) : QModelIndex();
705 if (role == KisNodeModel::ActiveRole && value.toBool() &&
706 m_d->activeNodeIndex == newActiveNode) {
707
708 return true;
709 }
710
711 m_d->activeNodeIndex = newActiveNode;
712
714 m_d->nodeSelectionAdapter->setActiveNode(activatedNode);
715 }
716
719 }
720
721 Q_EMIT dataChanged(index.siblingAtColumn(0), index.siblingAtColumn(m_d->dummyColumns));
722 return true;
723 }
724
725 if(!m_d->dummiesFacade || !index.isValid()) return false;
726
727 bool result = true;
728 bool shouldUpdate = true;
729 bool shouldUpdateRecursively = false;
731
732 switch (role) {
733 case Qt::DisplayRole:
734 case Qt::EditRole:
735 m_d->nodeManager->setNodeName(node, value.toString());
736 break;
738 {
739 // don't record undo/redo for visibility, locked or alpha locked changes
741 m_d->nodeManager->trySetNodeProperties(node, m_d->image, proplist);
742 shouldUpdateRecursively = true;
743
744 break;
745 }
747 if (node && m_d->selectionActionsAdapter) {
748 SelectionAction action = SelectionAction(value.toInt());
750 }
751 shouldUpdate = false;
752 break;
755 break;
758 break;
759 default:
760 result = false;
761 }
762
763 if (result && shouldUpdate) {
764 if (shouldUpdateRecursively) {
765 QSet<QModelIndex> indexes;
766 addChangedIndex(index, &indexes);
767 Q_FOREACH (const QModelIndex &idx, indexes) {
768 Q_EMIT dataChanged(idx.siblingAtColumn(0), idx.siblingAtColumn(m_d->dummyColumns));
769 }
770 } else {
771 Q_EMIT dataChanged(index.siblingAtColumn(0), index.siblingAtColumn(m_d->dummyColumns));
772 }
773 }
774
775 return result;
776}
777
779{
780 return Qt::CopyAction | Qt::MoveAction;
781}
782
784{
785 return Qt::MoveAction | Qt::CopyAction;
786}
787
789{
790 return m_d->dummiesFacade != 0;
791}
792
794{
795 QStringList types;
796 types << QLatin1String("application/x-krita-node-internal-pointer");
797 types << QLatin1String("application/x-qt-image");
798 types << QLatin1String("application/x-color");
799 types << QLatin1String("krita/x-colorsetentry");
800 return types;
801}
802
803QMimeData * KisNodeModel::mimeData(const QModelIndexList &indexes) const
804{
805 bool hasLockedLayer = false;
806 KisNodeList nodes;
807 Q_FOREACH (const QModelIndex &idx, indexes) {
808 // Although clone columns should not be selectable, make sure we only use column 0,
809 // because nodeFromIndex doesn't like duplicate list entries.
810 if (idx.column() != 0) {
811 continue;
812 }
813
814 KisNodeSP node = nodeFromIndex(idx);
815
816 nodes << node;
817 hasLockedLayer |= !node->isEditable(false);
818 }
819
820 return KisMimeData::mimeForLayers(nodes, m_d->image, hasLockedLayer);
821}
822
823bool KisNodeModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent)
824{
825 Q_UNUSED(column);
826
827 bool copyNode = (action == Qt::CopyAction);
828
829 KisNodeDummy *parentDummy = 0;
830 KisNodeDummy *aboveThisDummy = 0;
831
832 parentDummy = parent.isValid() ?
834 m_d->dummiesFacade->rootDummy();
835
836 if (row == -1) {
837 aboveThisDummy = parent.isValid() ? parentDummy->lastChild() : 0;
838 }
839 else {
840 aboveThisDummy = row < m_d->indexConverter->rowCount(parent) ? m_d->indexConverter->dummyFromRow(row, parent) : 0;
841 }
842
844 m_d->image,
846 parentDummy,
847 aboveThisDummy,
848 copyNode,
850}
851
852bool KisNodeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const {
853 if (parent.isValid()) {
854 // drop occurred on an item. always return true as returning false will mess up
855 // QT5's drag handling (see KisNodeModel::setDropEnabled).
856 return true;
857 } else {
858 return QAbstractItemModel::canDropMimeData(data, action, row, column, parent);
859 }
860}
861
862void KisNodeModel::setDropEnabled(const QMimeData *data) {
863 // what happens here should really happen in KisNodeModel::canDropMimeData(), but QT5
864 // will mess up if an item's Qt::ItemIsDropEnabled does not match what is returned by
865 // canDropMimeData; specifically, if we set the flag, but decide in canDropMimeData()
866 // later on that an "onto" drag is not allowed, QT will display an drop indicator for
867 // insertion, but not perform any drop when the mouse is released.
868
869 // the only robust implementation seems to set all flags correctly, which is done here.
870
871 bool copyNode = false;
873 m_d->dropEnabled.clear();
874 updateDropEnabled(nodes);
875}
876
877void KisNodeModel::updateDropEnabled(const QList<KisNodeSP> &nodes, QModelIndex parent) {
878 for (int r = 0; r < rowCount(parent); r++) {
879 QModelIndex idx = index(r, 0, parent);
880
882
883 bool dropEnabled = true;
884 Q_FOREACH (const KisNodeSP &node, nodes) {
885 if (!target->allowAsChild(node) || !target->isEditable(false)) {
886 dropEnabled = false;
887 break;
888 }
889 }
890 if (dropEnabled) {
891 m_d->dropEnabled.insert(idx.internalId());
892 }
893 Q_EMIT dataChanged(idx, idx); // indicate to QT that flags() have changed
894
895 if (hasChildren(idx)) {
896 updateDropEnabled(nodes, idx);
897 }
898 }
899}
float value(const T *src, size_t ch)
KisMagneticGraph::vertex_descriptor target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
SelectionAction
const QString COMPOSITE_OVER
const QString COMPOSITE_COPY
const QString COMPOSITE_BEHIND
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
LayerInfoTextStyle layerInfoTextStyle(bool defaultValue=false) const
@ INFOTEXT_SIMPLE
Definition kis_config.h:751
@ INFOTEXT_DETAILED
Definition kis_config.h:753
virtual KisNodeDummy * dummyForNode(KisNodeSP node) const =0
qint32 width() const
QSize size() const
Definition kis_image.h:547
qint32 height() const
KisNodeSP isolationRootNode() const
void setImage(KisImageSP image)
QImage thumbnail(KisNodeSP node) const
void notifyNodeAdded(KisNodeSP node)
void setIdleTaskManager(KisIdleTasksManager *manager)
void notifyNodeRemoved(KisNodeSP node)
static QMimeData * mimeForLayers(const KisNodeList &nodes, KisImageSP image, bool forceCopy=false)
static KisNodeList loadNodesFast(const QMimeData *data, KisImageSP image, KisShapeController *shapeController, bool &copyNode)
static bool insertMimeLayers(const QMimeData *data, KisImageSP image, KisShapeController *shapeController, KisNodeDummy *parentDummy, KisNodeDummy *aboveThisDummy, bool copyNode, KisNodeInsertionAdapter *nodeInsertionAdapter, bool changeOffset=false, QPointF offset=QPointF(), KisProcessingApplicator *applicator=nullptr)
virtual int rowCount(QModelIndex parent)=0
virtual KisNodeDummy * dummyFromRow(int row, QModelIndex parent)=0
virtual QModelIndex indexFromDummy(KisNodeDummy *dummy)=0
virtual KisNodeDummy * dummyFromIndex(QModelIndex index)=0
virtual bool indexFromAddedDummy(KisNodeDummy *parentDummy, int index, const QString &newNodeMetaObjectType, QModelIndex &parentIndex, int &row)=0
KisNodeDummy * firstChild() const
KisNodeDummy * lastChild() const
KisNodeSP node() const
KisNodeDummy * parent() const
KisNodeDummy * nextSibling() const
KisNodeDisplayModeAdapter * nodeDisplayModeAdapter() const
KisNodeInsertionAdapter * nodeInsertionAdapter() const
void colorOverlayMaskProperties(KisNodeSP node)
void nodePropertiesIgnoreSelection(KisNodeSP node)
void setNodeName(KisNodeSP node, const QString &name)
KisNodeSelectionAdapter * nodeSelectionAdapter() const
bool trySetNodeProperties(KisNodeSP node, KisImageSP image, KisBaseNode::PropertyList properties) const
void slotBeginInsertDummy(KisNodeDummy *parent, int index, const QString &metaObjectType)
~KisNodeModel() override
QStringList mimeTypes() const override
void regenerateItems(KisNodeDummy *dummy)
static bool belongsToIsolatedGroup(KisImageSP image, KisNodeSP node, KisDummiesFacadeBase *dummiesFacade)
Qt::DropActions supportedDropActions() const override
@ LayerColorOverlayPropertiesRole
@ ProgressRole
Use to communicate a progress report to the section delegate on an action (a value of -1 or a QVarian...
@ PropertiesRole
A list of properties the part has.
@ AspectRatioRole
The aspect ratio of the section as a floating point value: width divided by height.
@ ActiveRole
Whether the section is the active one.
virtual KisModelIndexConverterBase * createIndexConverter()
void slotBeginRemoveDummy(KisNodeDummy *dummy)
void setShowGlobalSelection(bool value)
friend class KisModelIndexConverter
void setIdleTaskManager(KisIdleTasksManager *idleTasksManager)
void slotDummyChanged(KisNodeDummy *dummy)
KisNodeSP nodeFromIndex(const QModelIndex &index) const
void slotEndInsertDummy(KisNodeDummy *dummy)
bool showGlobalSelection() const
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override
KisDummiesFacadeBase * dummiesFacade() const
void toggleIsolateActiveNode()
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
void setPreferredThumnalSize(int preferredSize) const
void connectDummy(KisNodeDummy *dummy, bool needConnect)
KisModelIndexConverterBase * indexConverter() const
void slotNodeDisplayModeChanged(bool showRootNode, bool showGlobalSelectionMask)
void progressPercentageChanged(int, const KisNodeSP)
friend class KisModelIndexConverterShowAll
void updateDropEnabled(const QList< KisNodeSP > &nodes, QModelIndex parent=QModelIndex())
void connectDummies(KisNodeDummy *dummy, bool needConnect)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Private *const m_d
void setDummiesFacade(KisDummiesFacadeBase *dummiesFacade, KisImageWSP image, KisShapeController *shapeController, KisSelectionActionsAdapter *selectionActionsAdapter, KisNodeManager *nodeManager)
void resetIndexConverter()
QModelIndex indexFromNode(KisNodeSP node) const
void setDropEnabled(const QMimeData *data)
QModelIndex parent(const QModelIndex &index) const override
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
void sigBeforeBeginRemoveRows(const QModelIndex &parent, int start, int end)
KisNodeModel(QObject *parent, int clonedColumns=0)
Qt::ItemFlags flags(const QModelIndex &index) const override
QMimeData * mimeData(const QModelIndexList &indexes) const override
void slotLayerThumbnailUpdated(KisNodeSP node)
Qt::DropActions supportedDragActions() const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void processUpdateQueue()
void slotIsolatedModeChanged()
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void slotEndRemoveDummy()
QModelIndex sibling(int row, int column, const QModelIndex &idx) const override
void selectOpaqueOnNode(KisNodeSP node, SelectionAction action)
void addConnection(Sender sender, Signal signal, Receiver receiver, Method method, Qt::ConnectionType type=Qt::AutoConnection)
bool isValid() const
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
void addChangedIndex(const QModelIndex &idx, QSet< QModelIndex > *indexes)
const QString & compositeOpId() const
bool isEditable(bool checkVisibility=true) const
virtual QImage createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode=Qt::IgnoreAspectRatio)
QString compositeOp
int colorLabelIndex() const
bool isAnimated() const
virtual PropertyList sectionModelProperties() const
QString name() const
quint8 opacity() const
virtual bool visible(bool recursive=false) const
virtual QIcon icon() const
KisFilterMaskSP colorOverlayMask() const
Definition kis_layer.cc:567
KisSignalCompressor updateCompressor
QPersistentModelIndex activeNodeIndex
KisShapeController * shapeController
KisNodeDisplayModeAdapter * nodeDisplayModeAdapter
KisNodeManager * nodeManager
KisSignalAutoConnectionsStore nodeDisplayModeAdapterConnections
QSet< quintptr > dropEnabled
QPointer< KisNodeDummy > parentOfRemovedNode
KisNodeInsertionAdapter * nodeInsertionAdapter
QPointer< KisDummiesFacadeBase > dummiesFacade
KisNodeSelectionAdapter * nodeSelectionAdapter
KisLayerThumbnailCache thumbnalCache
QList< KisNodeDummy * > updateQueue
KisSelectionActionsAdapter * selectionActionsAdapter
KisModelIndexConverterBase * indexConverter
KisProjectionLeafSP projectionLeaf
Definition kis_node.cpp:93
KisNodeProgressProxy * nodeProgressProxy
Definition kis_node.cpp:89
KisNodeGraphListener * graphListener
Definition kis_node.cpp:87