Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit b4795343 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement Cut/Copy/Paste Layer actions

Now you can copy-paste layers as in every other software
parent 9f7eca1f
......@@ -2465,6 +2465,45 @@
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="copy_layer_clipboard">
<icon></icon>
<text>Copy Layer</text>
<whatsThis></whatsThis>
<toolTip>Copy layer to clipboard</toolTip>
<iconText>Copy layer to clipboard</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<defaultShortcut></defaultShortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="cut_layer_clipboard">
<icon></icon>
<text>Cut Layer</text>
<whatsThis></whatsThis>
<toolTip>Cut layer to clipboard</toolTip>
<iconText>Cut layer to clipboard</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<defaultShortcut></defaultShortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="paste_layer_from_clipboard">
<icon></icon>
<text>Paste Layer</text>
<whatsThis></whatsThis>
<toolTip>Paste layer from clipboard</toolTip>
<iconText>Paste layer from clipboard</iconText>
<activationFlags>100000000000000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<defaultShortcut></defaultShortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="save_node_as_image">
<icon>document-save</icon>
<text>&amp;Save Layer/Mask...</text>
......
......@@ -163,6 +163,10 @@ xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0 http://www.kde.org
<Action name="convert_to_filter_mask"/>
<Action name="convert_to_selection_mask"/>
</Menu>
<Separator/>
<Action name="cut_layer_clipboard"/>
<Action name="copy_layer_clipboard"/>
<Action name="paste_layer_from_clipboard"/>
<Separator/>
<Menu name="LayerSplitAlpha">
<text>S&amp;plit Alpha</text>
......
......@@ -323,7 +323,7 @@ void KisLayerBox::setCanvas(KoCanvasBase *canvas)
if (m_canvas) {
m_canvas->disconnectCanvasObserver(this);
m_nodeModel->setDummiesFacade(0, 0, 0, 0);
m_nodeModel->setDummiesFacade(0, 0, 0, 0, 0);
disconnect(m_image, 0, this, 0);
disconnect(m_nodeManager, 0, this, 0);
......@@ -344,7 +344,7 @@ void KisLayerBox::setCanvas(KoCanvasBase *canvas)
dynamic_cast<KisShapeController*>(doc->shapeController());
KisDummiesFacadeBase *kritaDummiesFacade =
static_cast<KisDummiesFacadeBase*>(kritaShapeController);
m_nodeModel->setDummiesFacade(kritaDummiesFacade, m_image, kritaShapeController, m_nodeManager->nodeSelectionAdapter());
m_nodeModel->setDummiesFacade(kritaDummiesFacade, m_image, kritaShapeController, m_nodeManager->nodeSelectionAdapter(), m_nodeManager->nodeInsertionAdapter());
connect(m_image, SIGNAL(sigAboutToBeDeleted()), SLOT(notifyImageDeleted()));
connect(m_image, SIGNAL(sigNodeCollapsedChanged()), SLOT(slotNodeCollapsedChanged()));
......@@ -369,14 +369,6 @@ void KisLayerBox::setCanvas(KoCanvasBase *canvas)
connect(m_nodeModel, SIGNAL(toggleIsolateActiveNode()),
m_nodeManager, SLOT(toggleIsolateActiveNode()));
// Node manipulation methods are forwarded to the node manager
connect(m_nodeModel, SIGNAL(requestMoveNodes(KisNodeList, KisNodeSP, KisNodeSP)),
m_nodeManager, SLOT(moveNodesDirect(KisNodeList, KisNodeSP, KisNodeSP)));
connect(m_nodeModel, SIGNAL(requestCopyNodes(KisNodeList, KisNodeSP, KisNodeSP)),
m_nodeManager, SLOT(copyNodesDirect(KisNodeList, KisNodeSP, KisNodeSP)));
connect(m_nodeModel, SIGNAL(requestAddNodes(KisNodeList, KisNodeSP, KisNodeSP)),
m_nodeManager, SLOT(addNodesDirect(KisNodeList, KisNodeSP, KisNodeSP)));
m_wdgLayerBox->listLayers->expandAll();
expandNodesRecursively(m_image->rootLayer(), m_nodeModel, m_wdgLayerBox->listLayers);
m_wdgLayerBox->listLayers->scrollTo(m_wdgLayerBox->listLayers->currentIndex());
......@@ -405,7 +397,7 @@ void KisLayerBox::unsetCanvas()
m_newLayerMenu->clear();
}
m_nodeModel->setDummiesFacade(0, 0, 0, 0);
m_nodeModel->setDummiesFacade(0, 0, 0, 0, 0);
disconnect(m_image, 0, this, 0);
disconnect(m_nodeManager, 0, this, 0);
disconnect(m_nodeModel, 0, m_nodeManager, 0);
......
......@@ -261,7 +261,7 @@ void LayerModel::setView(QObject *newView)
d->layers.clear();
d->activeNode.clear();
d->canvas = 0;
d->nodeModel->setDummiesFacade(0, 0, 0, 0);
d->nodeModel->setDummiesFacade(0, 0, 0, 0, 0);
}
......@@ -283,7 +283,7 @@ void LayerModel::setView(QObject *newView)
KisDummiesFacadeBase *kritaDummiesFacade = dynamic_cast<KisDummiesFacadeBase*>(d->canvas->imageView()->document()->shapeController());
KisShapeController *shapeController = dynamic_cast<KisShapeController*>(d->canvas->imageView()->document()->shapeController());
d->nodeModel->setDummiesFacade(kritaDummiesFacade, d->image, shapeController, d->nodeManager->nodeSelectionAdapter());
d->nodeModel->setDummiesFacade(kritaDummiesFacade, d->image, shapeController, d->nodeManager->nodeSelectionAdapter(), d->nodeManager->nodeInsertionAdapter());
connect(d->image, SIGNAL(sigAboutToBeDeleted()), SLOT(notifyImageDeleted()));
connect(d->image, SIGNAL(sigNodeChanged(KisNodeSP)), SLOT(nodeChanged(KisNodeSP)));
......@@ -296,13 +296,6 @@ void LayerModel::setView(QObject *newView)
// Connection KisNodeManager -> KisLayerBox
connect(d->nodeManager, SIGNAL(sigUiNeedChangeActiveNode(KisNodeSP)), this, SLOT(currentNodeChanged(KisNodeSP)));
// Node manipulation methods are forwarded to the node manager
connect(d->nodeModel, SIGNAL(requestMoveNodes(KisNodeList, KisNodeSP, KisNodeSP)),
d->nodeManager, SLOT(moveNodesDirect(KisNodeList, KisNodeSP, KisNodeSP)));
connect(d->nodeModel, SIGNAL(requestCopyNodes(KisNodeList, KisNodeSP, KisNodeSP)),
d->nodeManager, SLOT(copyNodesDirect(KisNodeList, KisNodeSP, KisNodeSP)));
connect(d->nodeModel, SIGNAL(requestAddNodes(KisNodeList, KisNodeSP, KisNodeSP)),
d->nodeManager, SLOT(addNodesDirect(KisNodeList, KisNodeSP, KisNodeSP)));
d->rebuildLayerList();
reset();
}
......
......@@ -108,6 +108,7 @@ set(kritaui_LIB_SRCS
kis_node_manager.cpp
kis_node_juggler_compressed.cpp
kis_node_selection_adapter.cpp
kis_node_insertion_adapter.cpp
kis_node_model.cpp
kis_model_index_converter_base.cpp
kis_model_index_converter.cpp
......
......@@ -66,7 +66,7 @@ public:
PIXELS_IN_CLIPBOARD = 0x0800, ///< Activate if the clipboard contains pixels
SHAPES_IN_CLIPBOARD = 0x1000, ///< Activate if the clipboard contains vector data
NEVER_ACTIVATE = 0x2000, ///<
LAYERS_IN_CLIPBOARD = 0x4000
};
Q_DECLARE_FLAGS(ActivationFlags, ActivationFlag)
......
......@@ -31,6 +31,8 @@
#include "operations/kis_operation.h"
#include "kis_layer.h"
#include "KisDocument.h"
#include "kis_clipboard.h"
#include "QFile"
#include <QDomDocument>
......@@ -242,6 +244,10 @@ void KisActionManager::updateGUI()
flags |= KisAction::ACTIVE_SHAPE_LAYER;
}
if (KisClipboard::instance()->hasLayers()) {
flags |= KisAction::LAYERS_IN_CLIPBOARD;
}
if (selectionManager)
{
if (selectionManager->havePixelsSelected()) {
......
......@@ -40,10 +40,12 @@
#include <kis_paint_device.h>
#include <kis_debug.h>
#include <kis_annotation.h>
#include <kis_node.h>
// local
#include "kis_config.h"
#include "kis_store_paintdevice_writer.h"
#include "kis_mimedata.h"
Q_GLOBAL_STATIC(KisClipboard, s_instance)
......@@ -383,3 +385,26 @@ QSize KisClipboard::clipSize() const
return QSize();
}
void KisClipboard::setLayers(KisNodeList nodes, KisNodeSP imageRoot, bool forceCopy)
{
QMimeData *data = KisMimeData::mimeForLayers(nodes, imageRoot, forceCopy);
if (!data) return;
QClipboard *cb = QApplication::clipboard();
cb->setMimeData(data);
}
bool KisClipboard::hasLayers() const
{
QClipboard *cb = QApplication::clipboard();
const QMimeData *cbData = cb->mimeData();
return cbData->hasFormat("application/x-krita-node");
}
const QMimeData* KisClipboard::layersMimeData() const
{
QClipboard *cb = QApplication::clipboard();
const QMimeData *cbData = cb->mimeData();
return cbData->hasFormat("application/x-krita-node") ? cbData : 0;
}
......@@ -26,6 +26,7 @@
#include <kritaui_export.h>
class QRect;
class QMimeData;
enum enumPasteBehaviour {
PASTE_ASSUME_WEB,
......@@ -68,11 +69,14 @@ public:
QSize clipSize() const;
void setLayers(KisNodeList nodes, KisNodeSP imageRoot, bool forceCopy = false);
bool hasLayers() const;
const QMimeData* layersMimeData() const;
Q_SIGNALS:
void clipCreated();
private Q_SLOTS:
void clipboardDataChanged();
......
......@@ -30,6 +30,9 @@
#include "kis_shape_controller.h"
#include "KisPart.h"
#include "kis_layer_utils.h"
#include "kis_node_insertion_adapter.h"
#include "kis_dummies_facade_base.h"
#include "kis_node_dummies_graph.h"
#include <KoProperties.h>
#include <KoStore.h>
......@@ -45,9 +48,10 @@
#include <QTemporaryFile>
#include <QDesktopWidget>
KisMimeData::KisMimeData(QList<KisNodeSP> nodes)
KisMimeData::KisMimeData(QList<KisNodeSP> nodes, bool forceCopy)
: QMimeData()
, m_nodes(nodes)
, m_forceCopy(forceCopy)
{
Q_ASSERT(m_nodes.size() > 0);
}
......@@ -151,6 +155,7 @@ QVariant KisMimeData::retrieveData(const QString &mimetype, QVariant::Type prefe
QDomDocument doc("krita_internal_node_pointer");
QDomElement root = doc.createElement("pointer");
root.setAttribute("application_pid", (qint64)QApplication::applicationPid());
root.setAttribute("force_copy", m_forceCopy);
doc.appendChild(root);
Q_FOREACH (KisNodeSP node, m_nodes) {
......@@ -194,10 +199,13 @@ QList<KisNodeSP> KisMimeData::tryLoadInternalNodes(const QMimeData *data,
bool /* IN-OUT */ &copyNode)
{
QList<KisNodeSP> nodes;
// Qt 4.7 way
bool forceCopy = false;
// Qt 4.7 and Qt 5.5 way
const KisMimeData *mimedata = qobject_cast<const KisMimeData*>(data);
if (mimedata) {
nodes = mimedata->nodes();
forceCopy = mimedata->m_forceCopy;
}
// Qt 4.8 way
......@@ -209,6 +217,7 @@ QList<KisNodeSP> KisMimeData::tryLoadInternalNodes(const QMimeData *data,
QDomElement element = doc.documentElement();
qint64 pid = element.attribute("application_pid").toLongLong();
forceCopy = element.attribute("force_copy").toInt();
if (pid == QApplication::applicationPid()) {
......@@ -226,12 +235,14 @@ QList<KisNodeSP> KisMimeData::tryLoadInternalNodes(const QMimeData *data,
}
}
if (!nodes.isEmpty() && (copyNode || nodes.first()->graphListener() != image.data())) {
if (!nodes.isEmpty() && (forceCopy || copyNode || nodes.first()->graphListener() != image.data())) {
QList<KisNodeSP> clones;
copyNode = true;
Q_FOREACH (KisNodeSP node, nodes) {
node = node->clone();
KisLayerUtils::addCopyOfNameTag(node);
if (nodes.first()->graphListener()) {
KisLayerUtils::addCopyOfNameTag(node);
}
initializeExternalNode(node, image, shapeController);
clones << node;
}
......@@ -312,3 +323,94 @@ QList<KisNodeSP> KisMimeData::loadNodes(const QMimeData *data,
return nodes;
}
QMimeData* KisMimeData::mimeForLayers(const KisNodeList &nodes, KisNodeSP imageRoot, bool forceCopy)
{
KisNodeList inputNodes = nodes;
KisNodeList sortedNodes;
KisLayerUtils::sortMergableNodes(imageRoot, inputNodes, sortedNodes);
if (sortedNodes.isEmpty()) return 0;
KisMimeData* data = new KisMimeData(sortedNodes, forceCopy);
return data;
}
bool nodeAllowsAsChild(KisNodeSP parent, KisNodeList nodes)
{
bool result = true;
Q_FOREACH (KisNodeSP node, nodes) {
if (!parent->allowAsChild(node)) {
result = false;
break;
}
}
return result;
}
bool correctNewNodeLocation(KisNodeList nodes,
KisNodeDummy* &parentDummy,
KisNodeDummy* &aboveThisDummy)
{
KisNodeSP parentNode = parentDummy->node();
bool result = true;
if(!nodeAllowsAsChild(parentDummy->node(), nodes)) {
aboveThisDummy = parentDummy;
parentDummy = parentDummy->parent();
result = (!parentDummy) ? false :
correctNewNodeLocation(nodes, parentDummy, aboveThisDummy);
}
return result;
}
bool KisMimeData::insertMimeLayers(const QMimeData *data,
KisImageSP image,
KisShapeController *shapeController,
KisNodeDummy *parentDummy,
KisNodeDummy *aboveThisDummy,
bool copyNode,
KisNodeInsertionAdapter *nodeInsertionAdapter)
{
QList<KisNodeSP> nodes =
KisMimeData::tryLoadInternalNodes(data,
image,
shapeController,
copyNode /* IN-OUT */);
if (nodes.isEmpty()) {
QRect imageBounds = image->bounds();
nodes = KisMimeData::loadNodes(data,
imageBounds, imageBounds.center(),
false,
image, shapeController);
/**
* Don't try to move a node originating from another image,
* just copy it.
*/
copyNode = true;
}
if (nodes.isEmpty()) return false;
bool result = true;
if (!correctNewNodeLocation(nodes, parentDummy, aboveThisDummy)) {
return false;
}
KIS_ASSERT_RECOVER(nodeInsertionAdapter) { return false; }
Q_ASSERT(parentDummy);
KisNodeSP aboveThisNode = aboveThisDummy ? aboveThisDummy->node() : 0;
if (copyNode) {
nodeInsertionAdapter->addNodes(nodes, parentDummy->node(), aboveThisNode);
}
else {
Q_ASSERT(nodes.first()->graphListener() == image.data());
nodeInsertionAdapter->moveNodes(nodes, parentDummy->node(), aboveThisNode);
}
return result;
}
......@@ -26,6 +26,8 @@
#include <kritaui_export.h>
class KisShapeController;
class KisNodeDummy;
class KisNodeInsertionAdapter;
/**
* KisMimeData implements delayed retrieval of nodes for d&d and copy/paste.
......@@ -36,7 +38,7 @@ class KRITAUI_EXPORT KisMimeData : public QMimeData
{
Q_OBJECT
public:
KisMimeData(QList<KisNodeSP> nodes);
KisMimeData(QList<KisNodeSP> nodes, bool forceCopy = false);
/// return the node set on this mimedata object -- for internal use
QList<KisNodeSP> nodes() const;
......@@ -52,6 +54,7 @@ public:
*/
QStringList formats() const;
//private:
/**
* Try load the node, which belongs to the same Krita instance,
* that is can be fetched without serialization
......@@ -72,6 +75,16 @@ public:
KisImageWSP image,
KisShapeController *shapeController);
public:
static QMimeData* mimeForLayers(const KisNodeList &nodes, KisNodeSP imageRoot, bool forceCopy = false);
static bool insertMimeLayers(const QMimeData *data,
KisImageSP image,
KisShapeController *shapeController,
KisNodeDummy *parentDummy,
KisNodeDummy *aboveThisDummy,
bool copyNode,
KisNodeInsertionAdapter *nodeInsertionAdapter);
protected:
QVariant retrieveData(const QString &mimetype, QVariant::Type preferredType) const;
......@@ -84,6 +97,7 @@ private:
private:
QList<KisNodeSP> m_nodes;
bool m_forceCopy;
};
......
/*
* Copyright (c) 2016 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_node_insertion_adapter.h"
struct KisNodeInsertionAdapter::Private
{
KisNodeManager *nodeManager;
};
KisNodeInsertionAdapter::KisNodeInsertionAdapter(KisNodeManager *nodeManager)
: m_d(new Private)
{
m_d->nodeManager = nodeManager;
}
KisNodeInsertionAdapter::~KisNodeInsertionAdapter()
{
}
void KisNodeInsertionAdapter::moveNodes(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis)
{
m_d->nodeManager->moveNodesDirect(nodes, parent, aboveThis);
}
void KisNodeInsertionAdapter::copyNodes(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis)
{
m_d->nodeManager->copyNodesDirect(nodes, parent, aboveThis);
}
void KisNodeInsertionAdapter::addNodes(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis)
{
m_d->nodeManager->addNodesDirect(nodes, parent, aboveThis);
}
/*
* Copyright (c) 2016 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_NODE_INSERTION_ADAPTER_H
#define __KIS_NODE_INSERTION_ADAPTER_H
#include <QScopedPointer>
#include "kis_node_manager.h"
#include "kis_node.h"
class KisNodeInsertionAdapter
{
public:
KisNodeInsertionAdapter(KisNodeManager *nodeManager);
~KisNodeInsertionAdapter();
void moveNodes(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis);
void copyNodes(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis);
void addNodes(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis);
private:
struct Private;
const QScopedPointer<Private> m_d;
};
#endif /* __KIS_NODE_INSERTION_ADAPTER_H */
......@@ -67,7 +67,11 @@
#include "kis_sequential_iterator.h"
#include "kis_transaction.h"
#include "kis_node_selection_adapter.h"
#include "kis_node_insertion_adapter.h"
#include "kis_node_juggler_compressed.h"
#include "kis_clipboard.h"
#include "kis_node_dummies_graph.h"
#include "kis_mimedata.h"
#include "processing/kis_mirror_processing_visitor.h"
#include "KisView.h"
......@@ -82,6 +86,7 @@ struct KisNodeManager::Private {
, maskManager(v)
, commandsAdapter(v)
, nodeSelectionAdapter(new KisNodeSelectionAdapter(q))
, nodeInsertionAdapter(new KisNodeInsertionAdapter(q))
{
}
......@@ -91,7 +96,8 @@ struct KisNodeManager::Private {
KisLayerManager layerManager;
KisMaskManager maskManager;
KisNodeCommandsAdapter commandsAdapter;
QScopedPointer<KisNodeSelectionAdapter> nodeSelectionAdapter;
QScopedPointer<KisNodeSelectionAdapter> nodeSelectionAdapter;
QScopedPointer<KisNodeInsertionAdapter> nodeInsertionAdapter;
KisNodeList selectedNodes;
QPointer<KisNodeJugglerCompressed> nodeJuggler;
......@@ -239,6 +245,14 @@ void KisNodeManager::setup(KActionCollection * actionCollection, KisActionManage
action = actionManager->createAction("duplicatelayer");
connect(action, SIGNAL(triggered()), this, SLOT(duplicateActiveNode()));
action = actionManager->createAction("copy_layer_clipboard");
connect(action, SIGNAL(triggered()), this, SLOT(copyLayersToClipboard()));
action = actionManager->createAction("cut_layer_clipboard");
connect(action, SIGNAL(triggered()), this, SLOT(cutLayersToClipboard()));
action = actionManager->createAction("paste_layer_from_clipboard");
connect(action, SIGNAL(triggered()), this, SLOT(pasteLayersFromClipboard()));
NEW_LAYER_ACTION("add_new_paint_layer", "KisPaintLayer");
......@@ -298,10 +312,8 @@ void KisNodeManager::updateGUI()
// enable/disable all relevant actions
m_d->layerManager.updateGUI();
m_d->maskManager.updateGUI();
}
KisNodeSP KisNodeManager::activeNode()
{
if (m_d->imageView) {
......@@ -667,6 +679,11 @@ KisNodeSelectionAdapter* KisNodeManager::nodeSelectionAdapter() const
return m_d->nodeSelectionAdapter.data();
}
KisNodeInsertionAdapter* KisNodeManager::nodeInsertionAdapter() const
{
return m_d->nodeInsertionAdapter.data();
}
void KisNodeManager::nodeOpacityChanged(qreal opacity, bool finalChange)
{
KisNodeSP node = activeNode();
......@@ -1055,5 +1072,51 @@ void KisNodeManager::slotSplitAlphaSaveMerged()
m_d->mergeTransparencyMaskAsAlpha(false);
}
void KisNodeManager::cutLayersToClipboard()
{
KisNodeList nodes = this->selectedNodes();
KisNodeSP root = m_d->view->image()->root();
if (nodes.isEmpty()) return;
KisClipboard::instance()->setLayers(nodes, root, false);
KUndo2MagicString actionName = kundo2_i18n("Cut Nodes");
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
juggler->removeNode(nodes);
}
void KisNodeManager::copyLayersToClipboard()
{
KisNodeList nodes = this->selectedNodes();
KisNodeSP root = m_d->view->image()->root();
KisClipboard::instance()->setLayers(nodes, root, true);
}
void KisNodeManager::pasteLayersFromClipboard()
{
const QMimeData *data = KisClipboard::instance()->layersMimeData();
if (!data) return;
KisNodeSP activeNode = this->activeNode();
KisShapeController *shapeController = dynamic_cast<KisShapeController*>(m_d->imageView->document()->shapeController());
Q_ASSERT(shapeController);
KisDummiesFacadeBase *dummiesFacade = dynamic_cast<KisDummiesFacadeBase*>(m_d->imageView->document()->shapeController());
Q_ASSERT(dummiesFacade);
const bool copyNode = false;
KisImageSP image = m_d->view->image();
KisNodeDummy *parentDummy = dummiesFacade->dummyForNode(activeNode);
KisNodeDummy *aboveThisDummy = parentDummy ? parentDummy->lastChild() : 0;
KisMimeData::insertMimeLayers(data,
image,
shapeController,
parentDummy,
aboveThisDummy,
copyNode,
nodeInsertionAdapter());
}
......@@ -35,6 +35,7 @@ class KisViewManager;
class KisActionManager;
class KisView;
class KisNodeSelectionAdapter;
class KisNodeInsertionAdapter;
/**
* The node manager passes requests for new layers or masks on to the mask and layer
......@@ -101,6 +102,7 @@ public:
KisNodeList selectedNodes();
KisNodeSelectionAdapter* nodeSelectionAdapter() const;
KisNodeInsertionAdapter* nodeInsertionAdapter() const;
public Q_SLOTS:
......@@ -202,6 +204,10 @@ public Q_SLOTS:
void slotImageRequestNodeReselection(KisNodeSP activeNode, const KisNodeList &selectedNodes);
void cutLayersToClipboard();
void copyLayersToClipboard();
void pasteLayersFromClipboard();
public:
......