File indexing completed on 2024-05-19 04:29:01

0001 /*
0002  *  SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_node_manager.h"
0008 
0009 #include <QStandardPaths>
0010 #include <QMessageBox>
0011 #include <KisSignalMapper.h>
0012 #include <QApplication>
0013 
0014 #include <kactioncollection.h>
0015 
0016 #include <QKeySequence>
0017 
0018 #include <kis_icon.h>
0019 #include <KoSelection.h>
0020 #include <KoShapeManager.h>
0021 #include <KoShape.h>
0022 #include <KoShapeLayer.h>
0023 #include <KisImportExportManager.h>
0024 #include <KoFileDialog.h>
0025 #include <KoToolManager.h>
0026 #include <KoProperties.h>
0027 
0028 #include <KoColorSpace.h>
0029 #include <KoColorSpaceRegistry.h>
0030 #include <KoColorModelStandardIds.h>
0031 
0032 #include <kis_types.h>
0033 #include <kis_node.h>
0034 #include <kis_selection.h>
0035 #include <kis_selection_mask.h>
0036 #include <kis_layer.h>
0037 #include <kis_mask.h>
0038 #include <kis_image.h>
0039 #include <kis_painter.h>
0040 #include <kis_paint_layer.h>
0041 #include <KisMimeDatabase.h>
0042 #include <KisReferenceImagesLayer.h>
0043 
0044 #include "KisPart.h"
0045 #include "canvas/kis_canvas2.h"
0046 #include "kis_shape_controller.h"
0047 #include "kis_canvas_resource_provider.h"
0048 #include "KisViewManager.h"
0049 #include "KisDocument.h"
0050 #include "kis_mask_manager.h"
0051 #include "kis_group_layer.h"
0052 #include "kis_layer_manager.h"
0053 #include "kis_selection_manager.h"
0054 #include "kis_node_commands_adapter.h"
0055 #include "kis_action.h"
0056 #include "kis_action_manager.h"
0057 #include "kis_processing_applicator.h"
0058 #include "kis_sequential_iterator.h"
0059 #include "kis_transaction.h"
0060 #include "kis_node_selection_adapter.h"
0061 #include "kis_node_insertion_adapter.h"
0062 #include "kis_node_juggler_compressed.h"
0063 #include "KisNodeDisplayModeAdapter.h"
0064 #include "kis_clipboard.h"
0065 #include "kis_node_dummies_graph.h"
0066 #include "kis_mimedata.h"
0067 #include "kis_layer_utils.h"
0068 #include "krita_utils.h"
0069 #include "kis_shape_layer.h"
0070 #include "kis_keyframe_channel.h"
0071 #include "kis_raster_keyframe_channel.h"
0072 #include "kis_paint_device_frames_interface.h"
0073 #include "kis_layer_utils.h"
0074 
0075 #include "processing/kis_mirror_processing_visitor.h"
0076 #include "KisView.h"
0077 
0078 #include <kis_signals_blocker.h>
0079 #include <libs/image/kis_layer_properties_icons.h>
0080 #include <libs/image/commands/kis_node_property_list_command.h>
0081 #include <KisSynchronizedConnection.h>
0082 
0083 struct KisNodeManager::Private {
0084 
0085     Private(KisNodeManager *_q, KisViewManager *v)
0086         : q(_q)
0087         , view(v)
0088         , imageView(0)
0089         , layerManager(v)
0090         , maskManager(v)
0091         , commandsAdapter(v)
0092         , nodeSelectionAdapter(new KisNodeSelectionAdapter(q))
0093         , nodeInsertionAdapter(new KisNodeInsertionAdapter(q))
0094         , nodeDisplayModeAdapter(new KisNodeDisplayModeAdapter())
0095         , lastRequestedIsolatedModeStatus(false)
0096     {
0097     }
0098 
0099     KisNodeManager * q {nullptr};
0100     KisViewManager * view {nullptr};
0101     QPointer<KisView>imageView;
0102     KisLayerManager layerManager;
0103     KisMaskManager maskManager;
0104     KisNodeCommandsAdapter commandsAdapter;
0105     QScopedPointer<KisNodeSelectionAdapter> nodeSelectionAdapter;
0106     QScopedPointer<KisNodeInsertionAdapter> nodeInsertionAdapter;
0107     QScopedPointer<KisNodeDisplayModeAdapter> nodeDisplayModeAdapter;
0108 
0109     KisAction *pinToTimeline {nullptr};
0110 
0111     KisNodeList selectedNodes;
0112     QPointer<KisNodeJugglerCompressed> nodeJuggler;
0113 
0114     KisNodeWSP previouslyActiveNode;
0115 
0116     bool activateNodeImpl(KisNodeSP node);
0117 
0118     KisSignalMapper nodeCreationSignalMapper;
0119     KisSignalMapper nodeConversionSignalMapper;
0120 
0121     bool lastRequestedIsolatedModeStatus {false};
0122     KisSynchronizedConnection<KisNodeSP, KisNodeList> activateNodeConnection;
0123 
0124     void saveDeviceAsImage(KisPaintDeviceSP device,
0125                            const QString &defaultName,
0126                            const QRect &bounds,
0127                            qreal xRes,
0128                            qreal yRes,
0129                            quint8 opacity);
0130 
0131     void mergeTransparencyMaskAsAlpha(bool writeToLayers);
0132     KisNodeJugglerCompressed* lazyGetJuggler(const KUndo2MagicString &actionName);
0133 };
0134 
0135 bool KisNodeManager::Private::activateNodeImpl(KisNodeSP node)
0136 {
0137     Q_ASSERT(view);
0138     Q_ASSERT(view->canvasBase());
0139     Q_ASSERT(view->canvasBase()->globalShapeManager());
0140     Q_ASSERT(imageView);
0141     if (node && node == q->activeNode()) {
0142         return false;
0143     }
0144 
0145     // Set the selection on the shape manager to the active layer
0146     // and set call KoSelection::setActiveLayer( KoShapeLayer* layer )
0147     // with the parent of the active layer.
0148     KoSelection *selection = view->canvasBase()->globalShapeManager()->selection();
0149     Q_ASSERT(selection);
0150     selection->deselectAll();
0151 
0152     if (!node) {
0153         selection->setActiveLayer(0);
0154         imageView->setCurrentNode(0);
0155         maskManager.activateMask(0);
0156         layerManager.activateLayer(0);
0157         previouslyActiveNode = q->activeNode();
0158     } else {
0159 
0160         previouslyActiveNode = q->activeNode();
0161 
0162         KoShape * shape = view->document()->shapeForNode(node);
0163 
0164         //if (!shape) return false;
0165         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(shape, false);
0166 
0167         selection->select(shape);
0168         KoShapeLayer * shapeLayer = dynamic_cast<KoShapeLayer*>(shape);
0169 
0170         //if (!shapeLayer) return false;
0171         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(shapeLayer, false);
0172 
0173         //         shapeLayer->setGeometryProtected(node->userLocked());
0174         //         shapeLayer->setVisible(node->visible());
0175         selection->setActiveLayer(shapeLayer);
0176 
0177         imageView->setCurrentNode(node);
0178         if (KisLayerSP layer = qobject_cast<KisLayer*>(node.data())) {
0179             maskManager.activateMask(0);
0180             layerManager.activateLayer(layer);
0181         } else if (KisMaskSP mask = dynamic_cast<KisMask*>(node.data())) {
0182             maskManager.activateMask(mask);
0183             // XXX_NODE: for now, masks cannot be nested.
0184             layerManager.activateLayer(static_cast<KisLayer*>(node->parent().data()));
0185         }
0186     }
0187     return true;
0188 }
0189 
0190 KisNodeManager::KisNodeManager(KisViewManager *view)
0191     : m_d(new Private(this, view))
0192 {
0193     m_d->activateNodeConnection.connectOutputSlot(this, &KisNodeManager::slotImageRequestNodeReselection);
0194 }
0195 
0196 KisNodeManager::~KisNodeManager()
0197 {
0198     delete m_d;
0199 }
0200 
0201 void KisNodeManager::setView(QPointer<KisView>imageView)
0202 {
0203     m_d->maskManager.setView(imageView);
0204     m_d->layerManager.setView(imageView);
0205 
0206     if (m_d->imageView) {
0207         KisShapeController *shapeController = dynamic_cast<KisShapeController*>(m_d->imageView->document()->shapeController());
0208         Q_ASSERT(shapeController);
0209         shapeController->disconnect(SIGNAL(sigActivateNode(KisNodeSP)), this);
0210         m_d->imageView->image()->disconnect(this);
0211         m_d->imageView->image()->disconnect(&m_d->activateNodeConnection);
0212     }
0213 
0214     m_d->imageView = imageView;
0215 
0216     if (m_d->imageView) {
0217         KisShapeController *shapeController = dynamic_cast<KisShapeController*>(m_d->imageView->document()->shapeController());
0218         Q_ASSERT(shapeController);
0219         connect(shapeController, SIGNAL(sigActivateNode(KisNodeSP)), SLOT(slotNonUiActivatedNode(KisNodeSP)));
0220         m_d->activateNodeConnection.connectInputSignal(m_d->imageView->image(), &KisImage::sigRequestNodeReselection);
0221         m_d->imageView->resourceProvider()->slotNodeActivated(m_d->imageView->currentNode());
0222         connect(m_d->imageView->image(), SIGNAL(sigIsolatedModeChanged()), this, SLOT(handleExternalIsolationChange()));
0223     }
0224 
0225 }
0226 
0227 #define NEW_LAYER_ACTION(id, layerType)                                 \
0228 {                                                                   \
0229     action = actionManager->createAction(id);                       \
0230     m_d->nodeCreationSignalMapper.setMapping(action, layerType);    \
0231     connect(action, SIGNAL(triggered()),                            \
0232     &m_d->nodeCreationSignalMapper, SLOT(map()));           \
0233     }
0234 
0235 #define CONVERT_NODE_ACTION_2(id, layerType, exclude)                   \
0236 {                                                                   \
0237     action = actionManager->createAction(id);                       \
0238     action->setExcludedNodeTypes(QStringList(exclude));             \
0239     actionManager->addAction(id, action);                           \
0240     m_d->nodeConversionSignalMapper.setMapping(action, layerType);  \
0241     connect(action, SIGNAL(triggered()),                            \
0242     &m_d->nodeConversionSignalMapper, SLOT(map()));         \
0243     }
0244 
0245 #define CONVERT_NODE_ACTION(id, layerType)              \
0246     CONVERT_NODE_ACTION_2(id, layerType, layerType)
0247 
0248 void KisNodeManager::setup(KisKActionCollection * actionCollection, KisActionManager* actionManager)
0249 {
0250     m_d->layerManager.setup(actionManager);
0251     m_d->maskManager.setup(actionCollection, actionManager);
0252 
0253     KisAction * action = 0;
0254 
0255     action = actionManager->createAction("mirrorNodeX");
0256     connect(action, SIGNAL(triggered()), this, SLOT(mirrorNodeX()));
0257 
0258     action  = actionManager->createAction("mirrorNodeY");
0259     connect(action, SIGNAL(triggered()), this, SLOT(mirrorNodeY()));
0260 
0261     action = actionManager->createAction("mirrorAllNodesX");
0262     connect(action, SIGNAL(triggered()), this, SLOT(mirrorAllNodesX()));
0263 
0264     action  = actionManager->createAction("mirrorAllNodesY");
0265     connect(action, SIGNAL(triggered()), this, SLOT(mirrorAllNodesY()));
0266 
0267     action = actionManager->createAction("activateNextLayer");
0268     connect(action, SIGNAL(triggered()), this, SLOT(activateNextNode()));
0269 
0270     action = actionManager->createAction("activateNextSiblingLayer");
0271     connect(action, SIGNAL(triggered()), this, SLOT(activateNextSiblingNode()));
0272 
0273     action = actionManager->createAction("activatePreviousLayer");
0274     connect(action, SIGNAL(triggered()), this, SLOT(activatePreviousNode()));
0275 
0276     action = actionManager->createAction("activatePreviousSiblingLayer");
0277     connect(action, SIGNAL(triggered()), this, SLOT(activatePreviousSiblingNode()));
0278 
0279     action = actionManager->createAction("switchToPreviouslyActiveNode");
0280     connect(action, SIGNAL(triggered()), this, SLOT(switchToPreviouslyActiveNode()));
0281 
0282     action  = actionManager->createAction("save_node_as_image");
0283     connect(action, SIGNAL(triggered()), this, SLOT(saveNodeAsImage()));
0284 
0285     action  = actionManager->createAction("save_vector_node_to_svg");
0286     connect(action, SIGNAL(triggered()), this, SLOT(saveVectorLayerAsImage()));
0287     action->setActivationFlags(KisAction::ACTIVE_SHAPE_LAYER);
0288 
0289     action = actionManager->createAction("duplicatelayer");
0290     connect(action, SIGNAL(triggered()), this, SLOT(duplicateActiveNode()));
0291 
0292     action = actionManager->createAction("copy_layer_clipboard");
0293     connect(action, SIGNAL(triggered()), this, SLOT(copyLayersToClipboard()));
0294 
0295     action = actionManager->createAction("cut_layer_clipboard");
0296     connect(action, SIGNAL(triggered()), this, SLOT(cutLayersToClipboard()));
0297 
0298     action = actionManager->createAction("paste_layer_from_clipboard");
0299     connect(action, SIGNAL(triggered()), this, SLOT(pasteLayersFromClipboard()));
0300 
0301     action = actionManager->createAction("create_quick_group");
0302     connect(action, SIGNAL(triggered()), this, SLOT(createQuickGroup()));
0303 
0304     action = actionManager->createAction("create_quick_clipping_group");
0305     connect(action, SIGNAL(triggered()), this, SLOT(createQuickClippingGroup()));
0306 
0307     action = actionManager->createAction("quick_ungroup");
0308     connect(action, SIGNAL(triggered()), this, SLOT(quickUngroup()));
0309 
0310     action = actionManager->createAction("select_all_layers");
0311     connect(action, SIGNAL(triggered()), this, SLOT(selectAllNodes()));
0312 
0313     action = actionManager->createAction("select_visible_layers");
0314     connect(action, SIGNAL(triggered()), this, SLOT(selectVisibleNodes()));
0315 
0316     action = actionManager->createAction("select_locked_layers");
0317     connect(action, SIGNAL(triggered()), this, SLOT(selectLockedNodes()));
0318 
0319     action = actionManager->createAction("select_invisible_layers");
0320     connect(action, SIGNAL(triggered()), this, SLOT(selectInvisibleNodes()));
0321 
0322     action = actionManager->createAction("select_unlocked_layers");
0323     connect(action, SIGNAL(triggered()), this, SLOT(selectUnlockedNodes()));
0324 
0325     action = actionManager->createAction("new_from_visible");
0326     connect(action, SIGNAL(triggered()), this, SLOT(createFromVisible()));
0327 
0328     action = actionManager->createAction("pin_to_timeline");
0329     action->setCheckable(true);
0330     connect(action, SIGNAL(toggled(bool)), this, SLOT(slotPinToTimeline(bool)));
0331     m_d->pinToTimeline = action;
0332 
0333     NEW_LAYER_ACTION("add_new_paint_layer", "KisPaintLayer");
0334 
0335     NEW_LAYER_ACTION("add_new_group_layer", "KisGroupLayer");
0336 
0337     NEW_LAYER_ACTION("add_new_clone_layer", "KisCloneLayer");
0338 
0339     NEW_LAYER_ACTION("add_new_shape_layer", "KisShapeLayer");
0340 
0341     NEW_LAYER_ACTION("add_new_adjustment_layer", "KisAdjustmentLayer");
0342 
0343     NEW_LAYER_ACTION("add_new_fill_layer", "KisGeneratorLayer");
0344 
0345     NEW_LAYER_ACTION("add_new_file_layer", "KisFileLayer");
0346 
0347     NEW_LAYER_ACTION("add_new_transparency_mask", "KisTransparencyMask");
0348 
0349     NEW_LAYER_ACTION("add_new_filter_mask", "KisFilterMask");
0350 
0351     NEW_LAYER_ACTION("add_new_colorize_mask", "KisColorizeMask");
0352 
0353     NEW_LAYER_ACTION("add_new_transform_mask", "KisTransformMask");
0354 
0355     NEW_LAYER_ACTION("add_new_selection_mask", "KisSelectionMask");
0356 
0357     connect(&m_d->nodeCreationSignalMapper, SIGNAL(mapped(QString)),
0358             this, SLOT(createNode(QString)));
0359 
0360     CONVERT_NODE_ACTION("convert_to_paint_layer", "KisPaintLayer");
0361 
0362     CONVERT_NODE_ACTION_2("convert_to_selection_mask", "KisSelectionMask", QStringList() << "KisSelectionMask" << "KisColorizeMask");
0363 
0364     CONVERT_NODE_ACTION_2("convert_to_filter_mask", "KisFilterMask", QStringList() << "KisFilterMask" << "KisColorizeMask");
0365 
0366     CONVERT_NODE_ACTION_2("convert_to_transparency_mask", "KisTransparencyMask", QStringList() << "KisTransparencyMask" << "KisColorizeMask");
0367 
0368     CONVERT_NODE_ACTION("convert_to_animated", "animated");
0369 
0370     CONVERT_NODE_ACTION_2("convert_to_file_layer", "KisFileLayer", QStringList() << "KisFileLayer" << "KisCloneLayer");
0371 
0372     connect(&m_d->nodeConversionSignalMapper, SIGNAL(mapped(QString)),
0373             this, SLOT(convertNode(QString)));
0374 
0375     // Isolation Modes...
0376     // Post Qt5.14 this can be replaced with QActionGroup + ExclusionPolicy::ExclusiveOptional.
0377     action = actionManager->createAction("isolate_active_layer");
0378     connect(action, SIGNAL(toggled(bool)), this, SLOT(setIsolateActiveLayerMode(bool)));
0379     action = actionManager->createAction("isolate_active_group");
0380     connect(action, SIGNAL(triggered(bool)), this, SLOT(setIsolateActiveGroupMode(bool)));
0381     connect(this, SIGNAL(sigNodeActivated(KisNodeSP)), SLOT(changeIsolationRoot(KisNodeSP)));
0382 
0383     action = actionManager->createAction("toggle_layer_visibility");
0384     connect(action, SIGNAL(triggered()), this, SLOT(toggleVisibility()));
0385 
0386     action = actionManager->createAction("toggle_layer_lock");
0387     connect(action, SIGNAL(triggered()), this, SLOT(toggleLock()));
0388 
0389     action = actionManager->createAction("toggle_layer_inherit_alpha");
0390     connect(action, SIGNAL(triggered()), this, SLOT(toggleInheritAlpha()));
0391 
0392     action = actionManager->createAction("toggle_layer_alpha_lock");
0393     connect(action, SIGNAL(triggered()), this, SLOT(toggleAlphaLock()));
0394 
0395     action  = actionManager->createAction("split_alpha_into_mask");
0396     connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaIntoMask()));
0397 
0398     action  = actionManager->createAction("split_alpha_write");
0399     connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaWrite()));
0400 
0401     // HINT: we can save even when the nodes are not editable
0402     action  = actionManager->createAction("split_alpha_save_merged");
0403     connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaSaveMerged()));
0404 }
0405 
0406 void KisNodeManager::updateGUI()
0407 {
0408     // enable/disable all relevant actions
0409     m_d->layerManager.updateGUI();
0410     m_d->maskManager.updateGUI();
0411 }
0412 
0413 KisNodeSP KisNodeManager::activeNode()
0414 {
0415     if (m_d->imageView) {
0416         return m_d->imageView->currentNode();
0417     }
0418     return 0;
0419 }
0420 
0421 KisLayerSP KisNodeManager::activeLayer()
0422 {
0423     return m_d->layerManager.activeLayer();
0424 }
0425 
0426 const KoColorSpace* KisNodeManager::activeColorSpace()
0427 {
0428     if (m_d->maskManager.activeDevice()) {
0429         return m_d->maskManager.activeDevice()->colorSpace();
0430     } else {
0431         Q_ASSERT(m_d->layerManager.activeLayer());
0432         if (m_d->layerManager.activeLayer()->parentLayer())
0433             return m_d->layerManager.activeLayer()->parentLayer()->colorSpace();
0434         else
0435             return m_d->view->image()->colorSpace();
0436     }
0437 }
0438 
0439 bool KisNodeManager::canModifyLayers(KisNodeList nodes, bool showWarning)
0440 {
0441     KisNodeSP lockedNode;
0442     Q_FOREACH (KisNodeSP node, nodes) {
0443         if (!node->isEditable(false)) {
0444             lockedNode = node;
0445             break;
0446         }
0447     }
0448 
0449     if (lockedNode && showWarning) {
0450         QString errorMessage;
0451 
0452         if (nodes.size() <= 1) {
0453             errorMessage = i18n("Layer is locked");
0454         } else {
0455             errorMessage = i18n("Layer \"%1\" is locked", lockedNode->name());
0456         }
0457 
0458         m_d->view->showFloatingMessage(errorMessage, QIcon());
0459     }
0460 
0461     return !lockedNode;
0462 }
0463 
0464 bool KisNodeManager::canModifyLayer(KisNodeSP node, bool showWarning)
0465 {
0466     return canModifyLayers({node}, showWarning);
0467 }
0468 
0469 bool KisNodeManager::canMoveLayers(KisNodeList nodes, bool showWarning)
0470 {
0471     KisNodeSP lockedNode;
0472     Q_FOREACH (KisNodeSP node, nodes) {
0473         if (node->parent() && !node->parent()->isEditable(false)) {
0474             lockedNode = node->parent();
0475             break;
0476         }
0477     }
0478 
0479     if (lockedNode && showWarning) {
0480         QString errorMessage = i18n("Layer \"%1\" is locked", lockedNode->name());
0481         m_d->view->showFloatingMessage(errorMessage, QIcon());
0482     }
0483 
0484     return !lockedNode;
0485 }
0486 
0487 bool KisNodeManager::canMoveLayer(KisNodeSP node, bool showWarning)
0488 {
0489     return canMoveLayers({node}, showWarning);
0490 }
0491 
0492 void KisNodeManager::moveNodeAt(KisNodeSP node, KisNodeSP parent, int index)
0493 {
0494     if (parent->allowAsChild(node)) {
0495         if (node->inherits("KisSelectionMask") && parent->inherits("KisLayer")) {
0496             KisSelectionMask *m = dynamic_cast<KisSelectionMask*>(node.data());
0497             KisLayer *l = qobject_cast<KisLayer*>(parent.data());
0498             if (m && m->active() && l && l->selectionMask()) {
0499                 l->selectionMask()->setActive(false);
0500             }
0501         }
0502         m_d->commandsAdapter.moveNode(node, parent, index);
0503     }
0504 }
0505 
0506 void KisNodeManager::moveNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis)
0507 {
0508     KUndo2MagicString actionName = kundo2_i18n("Move Nodes");
0509     KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
0510     juggler->moveNode(nodes, parent, aboveThis);
0511 }
0512 
0513 void KisNodeManager::copyNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis)
0514 {
0515     KUndo2MagicString actionName = kundo2_i18n("Copy Nodes");
0516     KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
0517     juggler->copyNode(nodes, parent, aboveThis);
0518 }
0519 
0520 void KisNodeManager::addNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis)
0521 {
0522     KUndo2MagicString actionName = kundo2_i18n("Add Nodes");
0523     KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
0524     juggler->addNode(nodes, parent, aboveThis);
0525 }
0526 
0527 void KisNodeManager::toggleIsolateActiveNode()
0528 {
0529     QAction* action = m_d->view->actionManager()->actionByName("isolate_active_layer");
0530     action->toggle();
0531 }
0532 
0533 void KisNodeManager::setIsolateActiveLayerMode(bool checked)
0534 {
0535     KisImageWSP image = m_d->view->image();
0536     KIS_ASSERT_RECOVER_RETURN(image);
0537 
0538     const bool groupIsolationState = image->isIsolatingGroup();
0539     changeIsolationMode(checked, groupIsolationState);
0540 }
0541 
0542 void KisNodeManager::setIsolateActiveGroupMode(bool checked)
0543 {
0544     KisImageWSP image = m_d->view->image();
0545     KIS_ASSERT_RECOVER_RETURN(image);
0546 
0547     const bool layerIsolationState = image->isIsolatingLayer();
0548     changeIsolationMode(layerIsolationState, checked);
0549 }
0550 
0551 void KisNodeManager::changeIsolationMode(bool isolateActiveLayer, bool isolateActiveGroup)
0552 {
0553     KisImageWSP image = m_d->view->image();
0554     KisNodeSP activeNode = this->activeNode();
0555     KIS_ASSERT_RECOVER_RETURN(image && activeNode);
0556 
0557     if (isolateActiveLayer || isolateActiveGroup) {
0558         if (image->startIsolatedMode(activeNode, isolateActiveLayer, isolateActiveGroup) == false) {
0559             reinitializeIsolationActionGroup();
0560         }
0561     } else {
0562         image->stopIsolatedMode();
0563     }
0564 }
0565 
0566 void KisNodeManager::changeIsolationRoot(KisNodeSP isolationRoot)
0567 {
0568     KisImageWSP image = m_d->view->image();
0569     if (!image || !isolationRoot) return;
0570 
0571     const bool isIsolatingLayer = image->isIsolatingLayer();
0572     const bool isIsolatingGroup = image->isIsolatingGroup();
0573 
0574     // Restart isolation with a new root node and the same settings.
0575     if (image->startIsolatedMode(isolationRoot, isIsolatingLayer, isIsolatingGroup) == false) {
0576         reinitializeIsolationActionGroup();
0577     }
0578 }
0579 
0580 void KisNodeManager::handleExternalIsolationChange()
0581 {
0582     // It might be that we have multiple Krita windows open. In such a case
0583     // only the currently active one should restart isolated mode
0584     if (!m_d->view->mainWindowAsQWidget()->isActiveWindow()) return;
0585 
0586     KisImageWSP image = m_d->view->image();
0587     KisNodeSP activeNode = this->activeNode();
0588 
0589     const bool isIsolatingLayer = image->isIsolatingLayer();
0590     const bool isIsolatingGroup = image->isIsolatingGroup();
0591 
0592     m_d->view->actionManager()->actionByName("isolate_active_layer")->setChecked(isIsolatingLayer);
0593     m_d->view->actionManager()->actionByName("isolate_active_group")->setChecked(isIsolatingGroup);
0594 }
0595 
0596 void KisNodeManager::reinitializeIsolationActionGroup()
0597 {
0598     m_d->view->actionManager()->actionByName("isolate_active_layer")->setChecked(false);
0599     m_d->view->actionManager()->actionByName("isolate_active_group")->setChecked(false);
0600 }
0601 
0602 KisNodeSP  KisNodeManager::createNode(const QString & nodeType, bool quiet, KisPaintDeviceSP copyFrom)
0603 {
0604     if (!m_d->view->blockUntilOperationsFinished(m_d->view->image())) {
0605         return 0;
0606     }
0607 
0608     KisNodeSP activeNode = this->activeNode();
0609     if (!activeNode) {
0610         activeNode = m_d->view->image()->root();
0611     }
0612 
0613     KIS_ASSERT_RECOVER_RETURN_VALUE(activeNode, 0);
0614 
0615     /// the check for editability happens inside the functions
0616     /// themselves, because layers can be created anyway (in a
0617     /// different position), but masks cannot.
0618 
0619     // XXX: make factories for this kind of stuff,
0620     //      with a registry
0621 
0622     if (nodeType == "KisPaintLayer") {
0623         return m_d->layerManager.addPaintLayer(activeNode);
0624     } else if (nodeType == "KisGroupLayer") {
0625         return m_d->layerManager.addGroupLayer(activeNode);
0626     } else if (nodeType == "KisAdjustmentLayer") {
0627         return m_d->layerManager.addAdjustmentLayer(activeNode);
0628     } else if (nodeType == "KisGeneratorLayer") {
0629         return m_d->layerManager.addGeneratorLayer(activeNode);
0630     } else if (nodeType == "KisShapeLayer") {
0631         return m_d->layerManager.addShapeLayer(activeNode);
0632     } else if (nodeType == "KisCloneLayer") {
0633         KisNodeList nodes = selectedNodes();
0634         if (nodes.isEmpty()) {
0635             nodes.append(activeNode);
0636         }
0637 
0638         return m_d->layerManager.addCloneLayer(nodes);
0639     } else if (nodeType == "KisTransparencyMask") {
0640         return m_d->maskManager.createTransparencyMask(activeNode, copyFrom, false);
0641     } else if (nodeType == "KisFilterMask") {
0642         return m_d->maskManager.createFilterMask(activeNode, copyFrom, quiet, false);
0643     } else if (nodeType == "KisColorizeMask") {
0644         return m_d->maskManager.createColorizeMask(activeNode);
0645     } else if (nodeType == "KisTransformMask") {
0646         return m_d->maskManager.createTransformMask(activeNode);
0647     } else if (nodeType == "KisSelectionMask") {
0648         return m_d->maskManager.createSelectionMask(activeNode, copyFrom, false);
0649     } else if (nodeType == "KisFileLayer") {
0650         return m_d->layerManager.addFileLayer(activeNode);
0651     }
0652     return 0;
0653 }
0654 
0655 void KisNodeManager::createFromVisible()
0656 {
0657     KisLayerUtils::newLayerFromVisible(m_d->view->image(), m_d->view->image()->root()->lastChild());
0658 }
0659 
0660 void KisNodeManager::slotPinToTimeline(bool value)
0661 {
0662     Q_FOREACH (KisNodeSP node, selectedNodes()) {
0663         node->setPinnedToTimeline(value);
0664     }
0665 }
0666 
0667 KisLayerSP KisNodeManager::createPaintLayer()
0668 {
0669     KisNodeSP node = createNode("KisPaintLayer");
0670     return dynamic_cast<KisLayer*>(node.data());
0671 }
0672 
0673 void KisNodeManager::convertNode(const QString &nodeType)
0674 {
0675     if (!m_d->view->blockUntilOperationsFinished(m_d->view->image())) {
0676         return;
0677     }
0678 
0679     KisNodeSP activeNode = this->activeNode();
0680     if (!activeNode) return;
0681 
0682     if (!canModifyLayer(activeNode)) return;
0683 
0684     if (nodeType == "KisPaintLayer") {
0685         m_d->layerManager.convertNodeToPaintLayer(activeNode);
0686     } else if (nodeType == "KisSelectionMask" ||
0687                nodeType == "KisFilterMask" ||
0688                nodeType == "KisTransparencyMask") {
0689 
0690         KisPaintDeviceSP copyFrom = activeNode->paintDevice() ?
0691                     activeNode->paintDevice() : activeNode->projection();
0692 
0693         m_d->commandsAdapter.beginMacro(kundo2_i18n("Convert to a Selection Mask"));
0694 
0695         bool result = false;
0696 
0697         if (nodeType == "KisSelectionMask") {
0698             result = !m_d->maskManager.createSelectionMask(activeNode, copyFrom, true).isNull();
0699         } else if (nodeType == "KisFilterMask") {
0700             result = !m_d->maskManager.createFilterMask(activeNode, copyFrom, false, true).isNull();
0701         } else if (nodeType == "KisTransparencyMask") {
0702             result = !m_d->maskManager.createTransparencyMask(activeNode, copyFrom, true).isNull();
0703         }
0704 
0705         m_d->commandsAdapter.endMacro();
0706 
0707         if (!result) {
0708             m_d->view->blockUntilOperationsFinishedForced(m_d->imageView->image());
0709             m_d->commandsAdapter.undoLastCommand();
0710         }
0711 
0712     } else if (nodeType == "KisFileLayer") {
0713         m_d->layerManager.convertLayerToFileLayer(activeNode);
0714     } else {
0715         warnKrita << "Unsupported node conversion type:" << nodeType;
0716     }
0717 }
0718 
0719 void KisNodeManager::slotSomethingActivatedNodeImpl(KisNodeSP node)
0720 {
0721     KisDummiesFacadeBase *dummiesFacade = dynamic_cast<KisDummiesFacadeBase*>(m_d->imageView->document()->shapeController());
0722     KIS_SAFE_ASSERT_RECOVER_RETURN(dummiesFacade);
0723 
0724     const bool nodeVisible = !isNodeHidden(node, !m_d->nodeDisplayModeAdapter->showGlobalSelectionMask());
0725     if (!nodeVisible) {
0726         return;
0727     }
0728 
0729     KIS_ASSERT_RECOVER_RETURN(node != activeNode());
0730     if (m_d->activateNodeImpl(node)) {
0731         emit sigUiNeedChangeActiveNode(node);
0732         emit sigNodeActivated(node);
0733         nodesUpdated();
0734         if (node) {
0735             bool toggled =  m_d->view->actionCollection()->action("view_show_canvas_only")->isChecked();
0736             if (toggled) {
0737                 m_d->view->showFloatingMessage( activeLayer()->name(), QIcon(), 1600, KisFloatingMessage::Medium, Qt::TextSingleLine);
0738             }
0739         }
0740     }
0741 }
0742 
0743 void KisNodeManager::slotNonUiActivatedNode(KisNodeSP node)
0744 {
0745     // the node must still be in the graph, some asynchronous
0746     // signals may easily break this requirement
0747     if (node && !node->graphListener()) {
0748         node = 0;
0749     }
0750 
0751     if (node == activeNode()) return;
0752 
0753     slotSomethingActivatedNodeImpl(node);
0754 
0755     if (node) {
0756         bool toggled =  m_d->view->actionCollection()->action("view_show_canvas_only")->isChecked();
0757         if (toggled) {
0758             m_d->view->showFloatingMessage( activeLayer()->name(), QIcon(), 1600, KisFloatingMessage::Medium, Qt::TextSingleLine);
0759         }
0760     }
0761 }
0762 
0763 void KisNodeManager::slotUiActivatedNode(KisNodeSP node)
0764 {
0765     // the node must still be in the graph, some asynchronous
0766     // signals may easily break this requirement
0767     if (node && !node->graphListener()) {
0768         node = 0;
0769     }
0770 
0771     if (node) {
0772         QStringList vectorTools = QStringList()
0773                 << "InteractionTool"
0774                 << "KarbonGradientTool"
0775                 << "KarbonCalligraphyTool"
0776                 << "PathTool";
0777 
0778         QStringList pixelTools = QStringList()
0779                 << "KritaShape/KisToolBrush"
0780                 << "KritaShape/KisToolDyna"
0781                 << "KritaShape/KisToolMultiBrush"
0782                 << "KritaFill/KisToolFill"
0783                 << "KritaFill/KisToolGradient";
0784 
0785 
0786         KisSelectionMask *selectionMask = dynamic_cast<KisSelectionMask*>(node.data());
0787         const bool nodeHasVectorAbilities = node->inherits("KisShapeLayer") ||
0788                 (selectionMask && selectionMask->selection()->hasShapeSelection());
0789 
0790         if (nodeHasVectorAbilities) {
0791             if (pixelTools.contains(KoToolManager::instance()->activeToolId())) {
0792                 KoToolManager::instance()->switchToolRequested("InteractionTool");
0793             }
0794         }
0795         else {
0796             if (vectorTools.contains(KoToolManager::instance()->activeToolId())) {
0797                 KoToolManager::instance()->switchToolRequested("KritaShape/KisToolBrush");
0798             }
0799         }
0800     }
0801 
0802     if (node == activeNode()) return;
0803 
0804     slotSomethingActivatedNodeImpl(node);
0805 }
0806 
0807 void KisNodeManager::nodesUpdated()
0808 {
0809     KisNodeSP node = activeNode();
0810     if (!node) return;
0811 
0812     m_d->layerManager.layersUpdated();
0813     m_d->maskManager.masksUpdated();
0814 
0815     m_d->view->updateGUI();
0816     m_d->view->selectionManager()->selectionChanged();
0817 
0818     {
0819         KisSignalsBlocker b(m_d->pinToTimeline);
0820         m_d->pinToTimeline->setChecked(node->isPinnedToTimeline());
0821     }
0822 }
0823 
0824 KisPaintDeviceSP KisNodeManager::activePaintDevice()
0825 {
0826     return m_d->maskManager.activeMask() ?
0827                 m_d->maskManager.activeDevice() :
0828                 m_d->layerManager.activeDevice();
0829 }
0830 
0831 void KisNodeManager::nodeProperties(KisNodeSP node)
0832 {
0833     if ((selectedNodes().size() > 1 && node->inherits("KisLayer")) || node->inherits("KisLayer")) {
0834         m_d->layerManager.layerProperties();
0835     }
0836     else if (node->inherits("KisMask")) {
0837         m_d->maskManager.maskProperties();
0838     }
0839 }
0840 
0841 void KisNodeManager::changeCloneSource()
0842 {
0843     m_d->layerManager.changeCloneSource();
0844 }
0845 
0846 qint32 KisNodeManager::convertOpacityToInt(qreal opacity)
0847 {
0848     /**
0849      * Scales opacity from the range 0...100
0850      * to the integer range 0...255
0851      */
0852 
0853     return qMin(255, int(opacity * 2.55 + 0.5));
0854 }
0855 
0856 void KisNodeManager::setNodeName(KisNodeSP node, const QString &name)
0857 {
0858     if (!node) return;
0859     if (node->name() == name) return;
0860 
0861     m_d->commandsAdapter.setNodeName(node, name);
0862 
0863 }
0864 
0865 void KisNodeManager::setNodeOpacity(KisNodeSP node, qint32 opacity)
0866 {
0867     if (!node) return;
0868     if (node->opacity() == opacity) return;
0869 
0870     m_d->commandsAdapter.setOpacity(node, opacity);
0871 }
0872 
0873 void KisNodeManager::setNodeCompositeOp(KisNodeSP node,
0874                                         const KoCompositeOp* compositeOp)
0875 {
0876     if (!node) return;
0877     if (node->compositeOp() == compositeOp) return;
0878 
0879     m_d->commandsAdapter.setCompositeOp(node, compositeOp);
0880 }
0881 
0882 void KisNodeManager::slotImageRequestNodeReselection(KisNodeSP activeNode, const KisNodeList &selectedNodes)
0883 {
0884     if (activeNode) {
0885         slotNonUiActivatedNode(activeNode);
0886     }
0887     if (!selectedNodes.isEmpty()) {
0888         slotSetSelectedNodes(selectedNodes);
0889     }
0890 }
0891 
0892 void KisNodeManager::slotSetSelectedNodes(const KisNodeList &nodes)
0893 {
0894     m_d->selectedNodes = nodes;
0895     emit sigUiNeedChangeSelectedNodes(nodes);
0896 }
0897 
0898 KisNodeList KisNodeManager::selectedNodes()
0899 {
0900     return m_d->selectedNodes;
0901 }
0902 
0903 KisNodeSelectionAdapter* KisNodeManager::nodeSelectionAdapter() const
0904 {
0905     return m_d->nodeSelectionAdapter.data();
0906 }
0907 
0908 KisNodeInsertionAdapter* KisNodeManager::nodeInsertionAdapter() const
0909 {
0910     return m_d->nodeInsertionAdapter.data();
0911 }
0912 
0913 KisNodeDisplayModeAdapter *KisNodeManager::nodeDisplayModeAdapter() const
0914 {
0915     return m_d->nodeDisplayModeAdapter.data();
0916 }
0917 
0918 bool KisNodeManager::isNodeHidden(KisNodeSP node, bool isGlobalSelectionHidden)
0919 {
0920     if (node && node->isFakeNode()) {
0921         return true;
0922     }
0923 
0924     if (isGlobalSelectionHidden && dynamic_cast<KisSelectionMask *>(node.data()) &&
0925             (!node->parent() || !node->parent()->parent())) {
0926         return true;
0927     }
0928 
0929     return false;
0930 }
0931 
0932 bool KisNodeManager::trySetNodeProperties(KisNodeSP node, KisImageSP image, KisBaseNode::PropertyList properties) const
0933 {
0934     const KisPaintLayer *paintLayer = dynamic_cast<KisPaintLayer*>(node.data());
0935     if (paintLayer) {
0936         const auto onionSkinOn = KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::onionSkins, true);
0937 
0938         if (properties.contains(onionSkinOn)) {
0939             const KisPaintDeviceSP &paintDevice = paintLayer->paintDevice();
0940             if (paintDevice && paintDevice->defaultPixel().opacityU8() == 255) {
0941                 m_d->view->showFloatingMessage(i18n("Onion skins require a layer with transparent background."), QIcon());
0942                 return false;
0943             }
0944         }
0945     }
0946 
0947     KisNodePropertyListCommand::setNodePropertiesAutoUndo(node, image, properties);
0948 
0949     return true;
0950 }
0951 
0952 void KisNodeManager::nodeOpacityChanged(qreal opacity)
0953 {
0954     KisNodeSP node = activeNode();
0955 
0956     setNodeOpacity(node, convertOpacityToInt(opacity));
0957 }
0958 
0959 void KisNodeManager::nodeCompositeOpChanged(const KoCompositeOp* op)
0960 {
0961     KisNodeSP node = activeNode();
0962 
0963     setNodeCompositeOp(node, op);
0964 }
0965 
0966 void KisNodeManager::duplicateActiveNode()
0967 {
0968     KUndo2MagicString actionName = kundo2_i18n("Duplicate Nodes");
0969     KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
0970     juggler->duplicateNode(selectedNodes());
0971 }
0972 
0973 KisNodeJugglerCompressed* KisNodeManager::Private::lazyGetJuggler(const KUndo2MagicString &actionName)
0974 {
0975     KisImageWSP image = view->image();
0976 
0977     if (!nodeJuggler ||
0978             (nodeJuggler &&
0979              (nodeJuggler->isEnded() ||
0980               !nodeJuggler->canMergeAction(actionName)))) {
0981 
0982         nodeJuggler = new KisNodeJugglerCompressed(actionName, image, q, 750);
0983         nodeJuggler->setAutoDelete(true);
0984     }
0985 
0986     return nodeJuggler;
0987 }
0988 
0989 void KisNodeManager::raiseNode()
0990 {
0991     if (!canMoveLayers(selectedNodes())) return;
0992 
0993     KUndo2MagicString actionName = kundo2_i18n("Raise Nodes");
0994     KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
0995     juggler->raiseNode(selectedNodes());
0996 }
0997 
0998 void KisNodeManager::lowerNode()
0999 {
1000     if (!canMoveLayers(selectedNodes())) return;
1001 
1002     KUndo2MagicString actionName = kundo2_i18n("Lower Nodes");
1003     KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
1004     juggler->lowerNode(selectedNodes());
1005 }
1006 
1007 void KisNodeManager::removeSingleNode(KisNodeSP node)
1008 {
1009     if (!node || !node->parent()) {
1010         return;
1011     }
1012 
1013     KisNodeList nodes;
1014     nodes << node;
1015     removeSelectedNodes(nodes);
1016 }
1017 
1018 void KisNodeManager::removeSelectedNodes(KisNodeList nodes)
1019 {
1020     if (!canModifyLayers(nodes)) return;
1021 
1022     KUndo2MagicString actionName = kundo2_i18n("Remove Nodes");
1023     KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
1024     juggler->removeNode(nodes);
1025 }
1026 
1027 void KisNodeManager::removeNode()
1028 {
1029     removeSelectedNodes(selectedNodes());
1030 }
1031 
1032 void KisNodeManager::mirrorNodeX()
1033 {
1034     KisNodeList nodes = selectedNodes();
1035 
1036     KUndo2MagicString commandName;
1037     if (nodes.size() == 1 && nodes[0]->inherits("KisMask")) {
1038         commandName = kundo2_i18n("Mirror Mask Horizontally");
1039     }
1040     else {
1041         commandName = kundo2_i18np("Mirror Layer Horizontally", "Mirror %1 Layers Horizontally", nodes.size());
1042     }
1043     mirrorNodes(nodes, commandName, Qt::Horizontal, m_d->view->selection());
1044 }
1045 
1046 void KisNodeManager::mirrorNodeY()
1047 {
1048     KisNodeList nodes = selectedNodes();
1049 
1050     KUndo2MagicString commandName;
1051     if (nodes.size() == 1 && nodes[0]->inherits("KisMask")) {
1052         commandName = kundo2_i18n("Mirror Mask Vertically");
1053     }
1054     else {
1055         commandName = kundo2_i18np("Mirror Layer Vertically", "Mirror %1 Layers Vertically", nodes.size());
1056     }
1057     mirrorNodes(nodes, commandName, Qt::Vertical, m_d->view->selection());
1058 }
1059 
1060 void KisNodeManager::mirrorAllNodesX()
1061 {
1062     KisNodeSP node = m_d->view->image()->root();
1063     mirrorNode(node, kundo2_i18n("Mirror All Layers Horizontally"),
1064                Qt::Horizontal, m_d->view->selection());
1065 }
1066 
1067 void KisNodeManager::mirrorAllNodesY()
1068 {
1069     KisNodeSP node = m_d->view->image()->root();
1070     mirrorNode(node, kundo2_i18n("Mirror All Layers Vertically"),
1071                Qt::Vertical, m_d->view->selection());
1072 }
1073 
1074 void KisNodeManager::activateNextNode(bool siblingsOnly)
1075 {
1076     KisNodeSP activeNode = this->activeNode();
1077     if (!activeNode) return;
1078 
1079     KisNodeSP nextNode = activeNode->nextSibling();
1080 
1081     if (!siblingsOnly) {
1082         // Recurse groups...
1083         while (nextNode && nextNode->childCount() > 0) {
1084             nextNode = nextNode->firstChild();
1085         }
1086 
1087         // Out of nodes? Back out of group...
1088         if (!nextNode && activeNode->parent()) {
1089             nextNode = activeNode->parent();
1090         }
1091     }
1092 
1093     // Skip nodes hidden from tree view..
1094     while (nextNode && isNodeHidden(nextNode, m_d->nodeDisplayModeAdapter->showGlobalSelectionMask())) {
1095         nextNode = nextNode->nextSibling();
1096     }
1097 
1098     // Select node, unless root..
1099     if (nextNode && nextNode->parent()) {
1100         slotNonUiActivatedNode(nextNode);
1101     }
1102 }
1103 
1104 void KisNodeManager::activateNextSiblingNode()
1105 {
1106     activateNextNode(true);
1107 }
1108 
1109 void KisNodeManager::activatePreviousNode(bool siblingsOnly)
1110 {
1111     KisNodeSP activeNode = this->activeNode();
1112     if (!activeNode) return;
1113 
1114     KisNodeSP nextNode = activeNode->prevSibling();
1115 
1116     if (!siblingsOnly) {
1117         // Enter groups..
1118         if (activeNode->childCount() > 0) {
1119             nextNode = activeNode->lastChild();
1120         }
1121 
1122         // Out of nodes? Back out of group...
1123         if (!nextNode && activeNode->parent()) {
1124             nextNode = activeNode->parent()->prevSibling();
1125         }
1126     }
1127 
1128     // Skip nodes hidden from tree view..
1129     while (nextNode && isNodeHidden(nextNode, m_d->nodeDisplayModeAdapter->showGlobalSelectionMask())) {
1130         nextNode = nextNode->prevSibling();
1131     }
1132 
1133     // Select node, unless root..
1134     if (nextNode && nextNode->parent()) {
1135         slotNonUiActivatedNode(nextNode);
1136     }
1137 }
1138 
1139 void KisNodeManager::activatePreviousSiblingNode()
1140 {
1141     activatePreviousNode(true);
1142 }
1143 
1144 void KisNodeManager::switchToPreviouslyActiveNode()
1145 {
1146     if (m_d->previouslyActiveNode && m_d->previouslyActiveNode->parent()) {
1147         slotNonUiActivatedNode(m_d->previouslyActiveNode);
1148     }
1149 }
1150 
1151 void KisNodeManager::mirrorNode(KisNodeSP node,
1152                                 const KUndo2MagicString& actionName,
1153                                 Qt::Orientation orientation,
1154                                 KisSelectionSP selection)
1155 {
1156     KisNodeList nodes = {node};
1157     mirrorNodes(nodes, actionName, orientation, selection);
1158 }
1159 
1160 void KisNodeManager::mirrorNodes(KisNodeList nodes,
1161                                 const KUndo2MagicString& actionName,
1162                                 Qt::Orientation orientation,
1163                                 KisSelectionSP selection)
1164 {
1165     Q_FOREACH(KisNodeSP node, nodes) {
1166         if (!canModifyLayer(node)) return;
1167     }
1168 
1169     KisImageSignalVector emitSignals;
1170 
1171     KisProcessingApplicator applicator(m_d->view->image(), nodes,
1172                                        KisProcessingApplicator::RECURSIVE,
1173                                        emitSignals, actionName);
1174 
1175     KisProcessingVisitorSP visitor;
1176 
1177     if (selection) {
1178         visitor = new KisMirrorProcessingVisitor(selection, orientation);
1179     } else {
1180         visitor = new KisMirrorProcessingVisitor(m_d->view->image()->bounds(), orientation);
1181     }
1182 
1183     if (!selection) {
1184         applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
1185     } else {
1186         applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT);
1187     }
1188 
1189     applicator.end();
1190 
1191     nodesUpdated();
1192 }
1193 
1194 void KisNodeManager::Private::saveDeviceAsImage(KisPaintDeviceSP device,
1195                                                 const QString &defaultName,
1196                                                 const QRect &bounds,
1197                                                 qreal xRes,
1198                                                 qreal yRes,
1199                                                 quint8 opacity)
1200 {
1201     KoFileDialog dialog(view->mainWindowAsQWidget(), KoFileDialog::SaveFile, "savenodeasimage");
1202     dialog.setCaption(i18n("Export \"%1\"", defaultName));
1203     dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
1204     dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export));
1205     QString filename = dialog.filename();
1206 
1207     if (filename.isEmpty()) return;
1208 
1209 
1210     if (filename.isEmpty()) return;
1211 
1212     QString mimefilter = KisMimeDatabase::mimeTypeForFile(filename, false);
1213 
1214     QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
1215 
1216     KisImageSP dst = new KisImage(doc->createUndoStore(),
1217                                   bounds.width(),
1218                                   bounds.height(),
1219                                   device->compositionSourceColorSpace(),
1220                                   defaultName);
1221     dst->setResolution(xRes, yRes);
1222     doc->setCurrentImage(dst);
1223     KisPaintLayer* paintLayer = new KisPaintLayer(dst, "paint device", opacity);
1224     paintLayer->paintDevice()->makeCloneFrom(device, bounds);
1225     dst->addNode(paintLayer, dst->rootLayer(), KisLayerSP(0));
1226 
1227     dst->initialRefreshGraph();
1228 
1229     if (!doc->exportDocumentSync(filename, mimefilter.toLatin1())) {
1230         QMessageBox::warning(qApp->activeWindow(),
1231                              i18nc("@title:window", "Krita"),
1232                              i18n("Could not save the layer. %1", doc->errorMessage().toUtf8().data()),
1233                              QMessageBox::Ok);
1234 
1235     }
1236 }
1237 
1238 void KisNodeManager::saveNodeAsImage()
1239 {
1240     KisNodeSP node = activeNode();
1241 
1242     if (!node) {
1243         warnKrita << "BUG: Save Node As Image was called without any node selected";
1244         return;
1245     }
1246 
1247     KisPaintDeviceSP saveDevice = node->projection();
1248 
1249     if (!saveDevice) {
1250         m_d->view->showFloatingMessage(i18nc("warning message when trying to export a transform mask", "Layer has no pixel data"), QIcon());
1251         return;
1252     }
1253 
1254     KisImageSP image = m_d->view->image();
1255     QRect saveRect = image->bounds() | node->exactBounds();
1256 
1257     m_d->saveDeviceAsImage(saveDevice,
1258                            node->name(),
1259                            saveRect,
1260                            image->xRes(), image->yRes(),
1261                            node->opacity());
1262 }
1263 
1264 #include "SvgWriter.h"
1265 
1266 void KisNodeManager::saveVectorLayerAsImage()
1267 {
1268     KisShapeLayerSP shapeLayer = qobject_cast<KisShapeLayer*>(activeNode().data());
1269     if (!shapeLayer) {
1270         return;
1271     }
1272 
1273     KoFileDialog dialog(m_d->view->mainWindowAsQWidget(), KoFileDialog::SaveFile, "savenodeasimage");
1274     dialog.setCaption(i18nc("@title:window", "Export to SVG"));
1275     dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
1276     dialog.setMimeTypeFilters(QStringList() << "image/svg+xml", "image/svg+xml");
1277     QString filename = dialog.filename();
1278 
1279     if (filename.isEmpty()) return;
1280 
1281     QUrl url = QUrl::fromLocalFile(filename);
1282 
1283     if (url.isEmpty()) return;
1284 
1285     const QSizeF sizeInPx = m_d->view->image()->bounds().size();
1286     const QSizeF sizeInPt(sizeInPx.width() / m_d->view->image()->xRes(),
1287                           sizeInPx.height() / m_d->view->image()->yRes());
1288 
1289     QList<KoShape*> shapes = shapeLayer->shapes();
1290     std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
1291 
1292     SvgWriter writer(shapes);
1293     if (!writer.save(filename, sizeInPt, true)) {
1294         QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita"), i18n("Could not save to svg: %1", filename));
1295     }
1296 }
1297 
1298 void KisNodeManager::slotSplitAlphaIntoMask()
1299 {
1300 
1301     KisNodeSP node = activeNode();
1302     if (!canModifyLayer(node)) return;
1303 
1304     // guaranteed by KisActionManager
1305     KIS_ASSERT_RECOVER_RETURN(node->hasEditablePaintDevice());
1306 
1307     KisLayerUtils::splitAlphaToMask(node->image(), node, m_d->maskManager.createMaskNameCommon(node, "KisTransparencyMask",  i18n("Transparency Mask")));
1308 }
1309 
1310 void KisNodeManager::Private::mergeTransparencyMaskAsAlpha(bool writeToLayers)
1311 {
1312     KisNodeSP node = q->activeNode();
1313     KisNodeSP parentNode = node->parent();
1314 
1315     // guaranteed by KisActionManager
1316     KIS_ASSERT_RECOVER_RETURN(node->inherits("KisTransparencyMask"));
1317 
1318     if (writeToLayers && (!parentNode->hasEditablePaintDevice() || !node->isEditable(false))) {
1319         QMessageBox::information(view->mainWindowAsQWidget(),
1320                                  i18nc("@title:window", "Layer %1 is not editable", parentNode->name()),
1321                                  i18n("Cannot write alpha channel of "
1322                                       "the parent layer \"%1\".\n"
1323                                       "The operation will be cancelled.", parentNode->name()));
1324         return;
1325     }
1326 
1327     KisPaintDeviceSP dstDevice;
1328     if (writeToLayers) {
1329         KIS_ASSERT_RECOVER_RETURN(parentNode->paintDevice());
1330         dstDevice = parentNode->paintDevice();
1331     } else {
1332         KisPaintDeviceSP copyDevice = parentNode->paintDevice();
1333         if (!copyDevice) {
1334             copyDevice = parentNode->original();
1335         }
1336         dstDevice = new KisPaintDevice(*copyDevice);
1337     }
1338 
1339     const KoColorSpace *dstCS = dstDevice->colorSpace();
1340 
1341     KisPaintDeviceSP selectionDevice = node->paintDevice();
1342     KIS_ASSERT_RECOVER_RETURN(selectionDevice->colorSpace()->pixelSize() == 1);
1343 
1344     const QRect processRect =
1345             selectionDevice->exactBounds() |
1346             dstDevice->exactBounds() |
1347             selectionDevice->defaultBounds()->bounds();
1348 
1349     QScopedPointer<KisTransaction> transaction;
1350 
1351     if (writeToLayers) {
1352         commandsAdapter.beginMacro(kundo2_i18n("Write Alpha into a Layer"));
1353         transaction.reset(new KisTransaction(kundo2_noi18n("__write_alpha_channel__"), dstDevice));
1354     }
1355 
1356     KisSequentialIterator srcIt(selectionDevice, processRect);
1357     KisSequentialIterator dstIt(dstDevice, processRect);
1358 
1359     while (srcIt.nextPixel() && dstIt.nextPixel()) {
1360         quint8 *alpha8Ptr = srcIt.rawData();
1361         quint8 *dstPtr = dstIt.rawData();
1362 
1363         dstCS->setOpacity(dstPtr, *alpha8Ptr, 1);
1364     }
1365 
1366     if (writeToLayers) {
1367         commandsAdapter.addExtraCommand(transaction->endAndTake());
1368         commandsAdapter.removeNode(node);
1369         commandsAdapter.endMacro();
1370     } else {
1371         KisImageWSP image = view->image();
1372         QRect saveRect = image->bounds();
1373 
1374         saveDeviceAsImage(dstDevice, parentNode->name(),
1375                           saveRect,
1376                           image->xRes(), image->yRes(),
1377                           OPACITY_OPAQUE_U8);
1378     }
1379 }
1380 
1381 
1382 void KisNodeManager::slotSplitAlphaWrite()
1383 {
1384     m_d->mergeTransparencyMaskAsAlpha(true);
1385 }
1386 
1387 void KisNodeManager::slotSplitAlphaSaveMerged()
1388 {
1389     m_d->mergeTransparencyMaskAsAlpha(false);
1390 }
1391 
1392 void KisNodeManager::toggleLock()
1393 {
1394     KisNodeList nodes = this->selectedNodes();
1395     KisNodeSP active = activeNode();
1396     if (nodes.isEmpty() || !active) return;
1397 
1398     bool isLocked = active->userLocked();
1399 
1400     for (auto &node : nodes) {
1401         KisLayerPropertiesIcons::setNodePropertyAutoUndo(node, KisLayerPropertiesIcons::locked, !isLocked, m_d->view->image());
1402     }
1403 }
1404 
1405 void KisNodeManager::toggleVisibility()
1406 {
1407     KisNodeList nodes = this->selectedNodes();
1408     KisNodeSP active = activeNode();
1409     if (nodes.isEmpty() || !active) return;
1410 
1411     bool isVisible = active->visible();
1412 
1413     for (auto &node : nodes) {
1414         KisLayerPropertiesIcons::setNodePropertyAutoUndo(node, KisLayerPropertiesIcons::visible, !isVisible, m_d->view->image());
1415     }
1416 }
1417 
1418 void KisNodeManager::toggleAlphaLock()
1419 {
1420     KisNodeList nodes = this->selectedNodes();
1421     KisNodeSP active = activeNode();
1422     if (nodes.isEmpty() || !active) return;
1423 
1424     auto layer = qobject_cast<KisPaintLayer*>(active.data());
1425     if (!layer) {
1426         return;
1427     }
1428 
1429     bool isAlphaLocked = layer->alphaLocked();
1430     for (auto &node : nodes) {
1431         auto layer = qobject_cast<KisPaintLayer*>(node.data());
1432         if (layer) {
1433             KisLayerPropertiesIcons::setNodePropertyAutoUndo(node, KisLayerPropertiesIcons::alphaLocked, !isAlphaLocked, m_d->view->image());
1434         }
1435     }
1436 }
1437 
1438 void KisNodeManager::toggleInheritAlpha()
1439 {
1440     KisNodeList nodes = this->selectedNodes();
1441     KisNodeSP active = activeNode();
1442     if (nodes.isEmpty() || !active) return;
1443 
1444     auto layer = qobject_cast<KisLayer*>(active.data());
1445     if (!layer) {
1446         return;
1447     }
1448 
1449     bool isAlphaDisabled = layer->alphaChannelDisabled();
1450     for (auto &node : nodes) {
1451         auto layer = qobject_cast<KisLayer*>(node.data());
1452         if (layer) {
1453             KisLayerPropertiesIcons::setNodePropertyAutoUndo(node, KisLayerPropertiesIcons::inheritAlpha, !isAlphaDisabled, m_d->view->image());
1454         }
1455     }
1456 }
1457 
1458 void KisNodeManager::cutLayersToClipboard()
1459 {
1460     KisNodeList nodes = this->selectedNodes();
1461     if (nodes.isEmpty()) return;
1462 
1463     KisNodeList::Iterator it = nodes.begin();
1464     while (it != nodes.end()) {
1465         // make sure the deleted nodes aren't referenced here again
1466         if (!it->data()->parent()) {
1467             nodes.erase(it);
1468         }
1469         it++;
1470     }
1471 
1472     KisClipboard::instance()->setLayers(nodes, m_d->view->image(), false);
1473 
1474     if (canModifyLayers(nodes)) {
1475         KUndo2MagicString actionName = kundo2_i18n("Cut Nodes");
1476         KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
1477         juggler->removeNode(nodes);
1478     }
1479 }
1480 
1481 void KisNodeManager::copyLayersToClipboard()
1482 {
1483     KisNodeList nodes = this->selectedNodes();
1484     KisClipboard::instance()->setLayers(nodes, m_d->view->image(), true);
1485 }
1486 
1487 void KisNodeManager::pasteLayersFromClipboard(bool changeOffset, QPointF offset)
1488 {
1489     const QMimeData *data = KisClipboard::instance()->layersMimeData();
1490     if (!data) return;
1491 
1492     KisNodeSP activeNode = this->activeNode();
1493 
1494     KisShapeController *shapeController = dynamic_cast<KisShapeController*>(m_d->imageView->document()->shapeController());
1495     Q_ASSERT(shapeController);
1496 
1497     KisDummiesFacadeBase *dummiesFacade = dynamic_cast<KisDummiesFacadeBase*>(m_d->imageView->document()->shapeController());
1498     Q_ASSERT(dummiesFacade);
1499 
1500     const bool copyNode = false;
1501     KisImageSP image = m_d->view->image();
1502     KisNodeDummy *parentDummy = dummiesFacade->dummyForNode(activeNode);
1503     KisNodeDummy *aboveThisDummy = parentDummy ? parentDummy->lastChild() : 0;
1504 
1505     KisMimeData::insertMimeLayers(data,
1506                                   image,
1507                                   shapeController,
1508                                   parentDummy,
1509                                   aboveThisDummy,
1510                                   copyNode,
1511                                   nodeInsertionAdapter(),
1512                                   changeOffset,
1513                                   offset);
1514 }
1515 
1516 bool KisNodeManager::createQuickGroupImpl(KisNodeJugglerCompressed *juggler,
1517                                           const QString &overrideGroupName,
1518                                           KisNodeSP *newGroup,
1519                                           KisNodeSP *newLastChild)
1520 {
1521     KisNodeSP active = activeNode();
1522     if (!active) return false;
1523 
1524     if (!canMoveLayer(active)) return false;
1525 
1526     KisImageSP image = m_d->view->image();
1527     QString groupName = !overrideGroupName.isEmpty() ? overrideGroupName : image->nextLayerName(i18nc("A group of layers", "Group"));
1528     KisGroupLayerSP group = new KisGroupLayer(image.data(), groupName, OPACITY_OPAQUE_U8);
1529 
1530     KisNodeList nodes1;
1531     nodes1 << group;
1532 
1533     KisNodeList nodes2;
1534     nodes2 = KisLayerUtils::sortMergeableNodes(image->root(), selectedNodes());
1535     KisLayerUtils::filterMergeableNodes(nodes2);
1536 
1537     if (nodes2.size() == 0) return false;
1538 
1539     if (KisLayerUtils::checkIsChildOf(active, nodes2)) {
1540         active = nodes2.first();
1541     }
1542 
1543     KisNodeSP parent = active->parent();
1544     KisNodeSP aboveThis = active;
1545 
1546     juggler->addNode(nodes1, parent, aboveThis);
1547     juggler->moveNode(nodes2, group, 0);
1548 
1549     *newGroup = group;
1550     *newLastChild = nodes2.last();
1551 
1552     return true;
1553 }
1554 
1555 void KisNodeManager::createQuickGroup()
1556 {
1557     KUndo2MagicString actionName = kundo2_i18n("Quick Group");
1558     KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
1559 
1560     KisNodeSP parent;
1561     KisNodeSP above;
1562 
1563     createQuickGroupImpl(juggler, "", &parent, &above);
1564 }
1565 
1566 void KisNodeManager::createQuickClippingGroup()
1567 {
1568     KUndo2MagicString actionName = kundo2_i18n("Quick Clipping Group");
1569     KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
1570 
1571     KisNodeSP parent;
1572     KisNodeSP above;
1573 
1574     KisImageSP image = m_d->view->image();
1575     if (createQuickGroupImpl(juggler, image->nextLayerName(i18nc("default name for a clipping group layer", "Clipping Group")), &parent, &above)) {
1576         KisPaintLayerSP maskLayer = new KisPaintLayer(image.data(), i18nc("default name for quick clip group mask layer", "Mask Layer"), OPACITY_OPAQUE_U8, image->colorSpace());
1577         maskLayer->disableAlphaChannel(true);
1578 
1579         juggler->addNode(KisNodeList() << maskLayer, parent, above);
1580     }
1581 }
1582 
1583 void KisNodeManager::quickUngroup()
1584 {
1585     KisNodeSP active = activeNode();
1586     if (!active) return;
1587 
1588     if (!canModifyLayer(active)) return;
1589 
1590     KisNodeSP parent = active->parent();
1591     KisNodeSP aboveThis = active;
1592 
1593     auto checkCanMoveLayers = [this] (KisNodeList nodes, KisNodeSP newParent) -> bool {
1594         auto incompatibleNode =
1595             std::find_if(nodes.begin(), nodes.end(),
1596                 [newParent] (KisNodeSP node) {
1597                     return !newParent->allowAsChild(node);
1598                 });
1599 
1600         if (incompatibleNode != nodes.end()) {
1601             const QString message =
1602                     newParent->parent() ?
1603                         i18n("Cannot move layer \"%1\" into new parent \"%2\"",
1604                              (*incompatibleNode)->name(),
1605                              newParent->name()) :
1606                         i18n("Cannot move layer \"%1\" into the root layer",
1607                              (*incompatibleNode)->name());
1608             m_d->view->showFloatingMessage(message, QIcon());
1609             return false;
1610         }
1611         return true;
1612     };
1613 
1614     KUndo2MagicString actionName = kundo2_i18n("Quick Ungroup");
1615 
1616     if (parent && dynamic_cast<KisGroupLayer*>(active.data())) {
1617         KisNodeList nodes = active->childNodes(QStringList(), KoProperties());
1618 
1619         if (checkCanMoveLayers(nodes, parent)) {
1620             KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
1621             juggler->moveNode(nodes, parent, active);
1622             juggler->removeNode(KisNodeList() << active);
1623         }
1624     } else if (parent && parent->parent()) {
1625         KisNodeSP grandParent = parent->parent();
1626 
1627         KisNodeList allChildNodes = parent->childNodes(QStringList(), KoProperties());
1628         KisNodeList allSelectedNodes = selectedNodes();
1629 
1630         const bool removeParent = KritaUtils::compareListsUnordered(allChildNodes, allSelectedNodes);
1631 
1632         if (checkCanMoveLayers(allSelectedNodes, parent)) {
1633             KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
1634             juggler->moveNode(allSelectedNodes, grandParent, parent);
1635             if (removeParent) {
1636                 juggler->removeNode(KisNodeList() << parent);
1637             }
1638         }
1639     }
1640 }
1641 
1642 void KisNodeManager::selectLayersImpl(const KoProperties &props, const KoProperties &invertedProps)
1643 {
1644     KisImageSP image = m_d->view->image();
1645     KisNodeList nodes = KisLayerUtils::findNodesWithProps(image->root(), props, true);
1646 
1647     KisNodeList selectedNodes = this->selectedNodes();
1648 
1649     if (KritaUtils::compareListsUnordered(nodes, selectedNodes)) {
1650         nodes = KisLayerUtils::findNodesWithProps(image->root(), invertedProps, true);
1651     }
1652 
1653     if (!nodes.isEmpty()) {
1654         slotImageRequestNodeReselection(nodes.last(), nodes);
1655     }
1656 }
1657 
1658 void KisNodeManager::selectAllNodes()
1659 {
1660     KoProperties props;
1661     selectLayersImpl(props, props);
1662 }
1663 
1664 void KisNodeManager::selectVisibleNodes()
1665 {
1666     KoProperties props;
1667     props.setProperty("visible", true);
1668 
1669     KoProperties invertedProps;
1670     invertedProps.setProperty("visible", false);
1671 
1672     selectLayersImpl(props, invertedProps);
1673 }
1674 
1675 void KisNodeManager::selectLockedNodes()
1676 {
1677     KoProperties props;
1678     props.setProperty("locked", true);
1679 
1680     KoProperties invertedProps;
1681     invertedProps.setProperty("locked", false);
1682 
1683     selectLayersImpl(props, invertedProps);
1684 }
1685 
1686 void KisNodeManager::selectInvisibleNodes()
1687 {
1688     KoProperties props;
1689     props.setProperty("visible", false);
1690 
1691     KoProperties invertedProps;
1692     invertedProps.setProperty("visible", true);
1693 
1694     selectLayersImpl(props, invertedProps);
1695 }
1696 
1697 void KisNodeManager::selectUnlockedNodes()
1698 {
1699     KoProperties props;
1700     props.setProperty("locked", false);
1701 
1702     KoProperties invertedProps;
1703     invertedProps.setProperty("locked", true);
1704 
1705     selectLayersImpl(props, invertedProps);
1706 }
1707 
1708 void KisNodeManager::slotUiActivateNode()
1709 {
1710     if (!sender()->property("node").isNull()) {
1711         QString name = sender()->property("node").toString();
1712         KisNodeSP node = KisLayerUtils::findNodeByName(m_d->imageView->image()->rootLayer(),name);
1713         if (node) {
1714             slotUiActivatedNode(node);
1715         }
1716     }
1717 }