[calligra/calligra/2.6] krita: Made the move tool iterational

Dmitry Kazakov dimula73 at gmail.com
Sun Dec 2 07:15:14 UTC 2012


Git commit 546a8c7ead456cd86a63b8853c424e230dfdad66 by Dmitry Kazakov.
Committed on 07/11/2012 at 14:34.
Pushed by dkazakov into branch 'calligra/2.6'.

Made the move tool iterational

Now the tool does not create new layers and does not create
numerous undo commands. It works in an iterational way: you move
the node (or selection) as many times as you wish. After the moving
done and you switch the tool (or apply any other action) the move
stroke will be finished and added to your undo history.

Please test it in 'krita-new-move-tool-kazakov' branch.

BUG:298584
CCMAIL:kimageshop at kde.org

M  +30   -0    krita/image/kis_image.cc
M  +43   -0    krita/image/kis_image.h
M  +8    -0    krita/image/kis_stroke_strategy_undo_command_based.cpp
M  +6    -1    krita/image/kis_stroke_strategy_undo_command_based.h
M  +1    -0    krita/plugins/tools/defaulttools/CMakeLists.txt
M  +63   -110  krita/plugins/tools/defaulttools/kis_tool_move.cc
M  +5    -1    krita/plugins/tools/defaulttools/kis_tool_move.h
A  +132  -0    krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.cpp     [License: GPL (v2+)]
A  +49   -0    krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.h     [License: GPL (v2+)]
M  +2    -0    krita/ui/kis_doc2_p.h
M  +8    -0    krita/ui/kis_filter_handler.cc
M  +12   -0    krita/ui/tool/kis_tool.cc
M  +14   -0    krita/ui/tool/kis_tool.h

http://commits.kde.org/calligra/546a8c7ead456cd86a63b8853c424e230dfdad66

diff --git a/krita/image/kis_image.cc b/krita/image/kis_image.cc
index 0336f01..077d638 100644
--- a/krita/image/kis_image.cc
+++ b/krita/image/kis_image.cc
@@ -149,6 +149,11 @@ KisImage::~KisImage()
     dbgImage << "deleting kisimage" << objectName();
 
     /**
+     * Request the tools to end currently running strokes
+     */
+    waitForDone();
+
+    /**
      * First delete the nodes, while strokes
      * and undo are still alive
      */
@@ -334,6 +339,8 @@ bool KisImage::locked() const
 void KisImage::barrierLock()
 {
     if (!locked()) {
+        requestStrokeEnd();
+
         if (m_d->scheduler) {
             m_d->scheduler->barrierLock();
         }
@@ -366,6 +373,8 @@ bool KisImage::tryBarrierLock()
 void KisImage::lock()
 {
     if (!locked()) {
+        requestStrokeEnd();
+
         if (m_d->scheduler) {
             m_d->scheduler->lock();
         }
@@ -1321,6 +1330,8 @@ KisImageSignalRouter* KisImage::signalRouter()
 
 void KisImage::waitForDone()
 {
+    requestStrokeEnd();
+
     if (m_d->scheduler) {
         m_d->scheduler->waitForDone();
     }
@@ -1328,6 +1339,15 @@ void KisImage::waitForDone()
 
 KisStrokeId KisImage::startStroke(KisStrokeStrategy *strokeStrategy)
 {
+    /**
+     * Ask open strokes to end gracefully. All the strokes clients
+     * (including the one calling this method right now) will get
+     * a notification that they should probably end their strokes.
+     * However this is purely their choice whether to end a stroke
+     * or not.
+     */
+    requestStrokeEnd();
+
     KisStrokeId id;
 
     if (m_d->scheduler) {
@@ -1360,6 +1380,16 @@ bool KisImage::cancelStroke(KisStrokeId id)
     return result;
 }
 
+void KisImage::requestStrokeCancellation()
+{
+    emit sigStrokeCancellationRequested();
+}
+
+void KisImage::requestStrokeEnd()
+{
+    emit sigStrokeEndRequested();
+}
+
 void KisImage::refreshGraph(KisNodeSP root)
 {
     refreshGraph(root, bounds(), bounds());
diff --git a/krita/image/kis_image.h b/krita/image/kis_image.h
index ebd27a7..e2601cb 100644
--- a/krita/image/kis_image.h
+++ b/krita/image/kis_image.h
@@ -576,6 +576,31 @@ signals:
      */
     void sigLayersChangedAsync();
 
+    /**
+     * Emitted when the UI has requested the cancellation of
+     * the stroke. The point is, we cannot cancel the stroke
+     * without its creator knowing about it (which most probably
+     * cause a crash), so we just forward this request from the UI
+     * to the creator of the stroke.
+     *
+     * If your tool supports cancelling of its work in the middle
+     * of operation, just listen to this signal and cancel
+     * the stroke when it comes
+     */
+    void sigStrokeCancellationRequested();
+
+    /**
+     * Emitted when the image decides that the stroke should better
+     * be ended. The point is, we cannot just end the stroke
+     * without its creator knowing about it (which most probably
+     * cause a crash), so we just forward this request from the UI
+     * to the creator of the stroke.
+     *
+     * If your tool supports long  strokes that may involve multiple
+     * mouse actions in one stroke, just listen to this signal and
+     * end the stroke when it comes.
+     */
+    void sigStrokeEndRequested();
 
 public slots:
     KisCompositeProgressProxy* compositeProgressProxy();
@@ -606,7 +631,25 @@ public slots:
     void refreshGraph(KisNodeSP root, const QRect& rc, const QRect &cropRect);
     void initialRefreshGraph();
 
+    /**
+     * This method is be called by the UI (*not* by the creator
+     * of the stroke) when it thinks current stroke should be
+     * cancelled. If the creator of the stroke supports cancelling
+     * of the stroke, it will be notified about the request and
+     * the stroke will be cancelled
+     */
+    void requestStrokeCancellation();
+
 private:
+    /**
+     * This method is called when image decides that the sroke
+     * should be ended. If the creator of the stroke supports it,
+     * it will be notified and the stroke will be cancelled
+     */
+    void requestStrokeEnd();
+
+private:
+
     KisImage(const KisImage& rhs);
     KisImage& operator=(const KisImage& rhs);
     void init(KisUndoStore *undoStore, qint32 width, qint32 height, const KoColorSpace * colorSpace);
diff --git a/krita/image/kis_stroke_strategy_undo_command_based.cpp b/krita/image/kis_stroke_strategy_undo_command_based.cpp
index 3eb998c..e3f802e 100644
--- a/krita/image/kis_stroke_strategy_undo_command_based.cpp
+++ b/krita/image/kis_stroke_strategy_undo_command_based.cpp
@@ -97,6 +97,14 @@ void KisStrokeStrategyUndoCommandBased::doStrokeCallback(KisStrokeJobData *data)
     notifyCommandDone(d->command, d->sequentiality(), d->exclusivity());
 }
 
+void KisStrokeStrategyUndoCommandBased::runAndSaveCommand(KUndo2CommandSP command,
+                                                          KisStrokeJobData::Sequentiality sequentiality,
+                                                          KisStrokeJobData::Exclusivity exclusivity)
+{
+    command->redo();
+    notifyCommandDone(command, sequentiality, exclusivity);
+}
+
 void KisStrokeStrategyUndoCommandBased::notifyCommandDone(KUndo2CommandSP command,
                                                           KisStrokeJobData::Sequentiality sequentiality,
                                                           KisStrokeJobData::Exclusivity exclusivity)
diff --git a/krita/image/kis_stroke_strategy_undo_command_based.h b/krita/image/kis_stroke_strategy_undo_command_based.h
index 0751493..da13b11 100644
--- a/krita/image/kis_stroke_strategy_undo_command_based.h
+++ b/krita/image/kis_stroke_strategy_undo_command_based.h
@@ -79,12 +79,17 @@ public:
     void doStrokeCallback(KisStrokeJobData *data);
 
 protected:
-    void executeCommand(KUndo2CommandSP command, bool undo);
+    void runAndSaveCommand(KUndo2CommandSP command,
+                           KisStrokeJobData::Sequentiality sequentiality,
+                           KisStrokeJobData::Exclusivity exclusivity);
     void notifyCommandDone(KUndo2CommandSP command,
                            KisStrokeJobData::Sequentiality sequentiality,
                            KisStrokeJobData::Exclusivity exclusivity);
 
 private:
+    void executeCommand(KUndo2CommandSP command, bool undo);
+
+private:
     bool m_undo;
     KUndo2CommandSP m_initCommand;
     KUndo2CommandSP m_finishCommand;
diff --git a/krita/plugins/tools/defaulttools/CMakeLists.txt b/krita/plugins/tools/defaulttools/CMakeLists.txt
index d10daea..6a38fc0 100644
--- a/krita/plugins/tools/defaulttools/CMakeLists.txt
+++ b/krita/plugins/tools/defaulttools/CMakeLists.txt
@@ -15,6 +15,7 @@ set(kritadefaulttools_PART_SRCS
     kis_tool_path.cc
     kis_tool_move.cc
     strokes/move_stroke_strategy.cpp
+    strokes/move_selection_stroke_strategy.cpp
     kis_tool_multihand.cpp
     )
 
diff --git a/krita/plugins/tools/defaulttools/kis_tool_move.cc b/krita/plugins/tools/defaulttools/kis_tool_move.cc
index fc20250..f2f4c4c 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_move.cc
+++ b/krita/plugins/tools/defaulttools/kis_tool_move.cc
@@ -22,29 +22,17 @@
 #include "kis_tool_move.h"
 
 #include <QPoint>
-#include <kundo2command.h>
-
-#include <klocale.h>
 
 #include "KoColorSpace.h"
-#include "KoColor.h"
-#include "KoCompositeOp.h"
 
 #include "kis_cursor.h"
-#include "kis_layer.h"
 #include "kis_selection.h"
-#include "kis_paint_layer.h"
-#include "kis_group_layer.h"
-#include "kis_painter.h"
 #include "kis_canvas2.h"
-#include "kis_view2.h"
-#include "kis_node_manager.h"
 #include "kis_image.h"
 
-#include <kis_transaction.h>
-#include <commands/kis_image_layer_add_command.h>
-#include <commands/kis_deselect_global_selection_command.h>
+#include "kis_paint_layer.h"
 #include "strokes/move_stroke_strategy.h"
+#include "strokes/move_selection_stroke_strategy.h"
 
 KisToolMove::KisToolMove(KoCanvasBase * canvas)
         :  KisTool(canvas, KisCursor::moveCursor())
@@ -55,6 +43,7 @@ KisToolMove::KisToolMove(KoCanvasBase * canvas)
 
 KisToolMove::~KisToolMove()
 {
+    endStroke();
 }
 
 void KisToolMove::paint(QPainter& gc, const KoViewConverter &converter)
@@ -63,6 +52,22 @@ void KisToolMove::paint(QPainter& gc, const KoViewConverter &converter)
     Q_UNUSED(converter);
 }
 
+void KisToolMove::deactivate()
+{
+    endStroke();
+    KisTool::deactivate();
+}
+
+void KisToolMove::requestStrokeEnd()
+{
+    endStroke();
+}
+
+void KisToolMove::requestStrokeCancellation()
+{
+    cancelStroke();
+}
+
 // recursively search a node with a non-transparent pixel
 KisNodeSP findNode(KisNodeSP node, const QPoint &point, bool wholeGroup)
 {
@@ -99,44 +104,6 @@ KisNodeSP findNode(KisNodeSP node, const QPoint &point, bool wholeGroup)
     return foundNode;
 }
 
-KisLayerSP createSelectionCopy(KisLayerSP srcLayer, KisSelectionSP selection, KisImageWSP image, KisStrokeId strokeId)
-{
-    QRect copyRect = srcLayer->extent() | selection->selectedRect();
-
-    KisPaintDeviceSP device = new KisPaintDevice(srcLayer->colorSpace());
-    KisPainter gc(device);
-    gc.setSelection(selection);
-    gc.setCompositeOp(COMPOSITE_OVER);
-    gc.setOpacity(OPACITY_OPAQUE_U8);
-    gc.bitBlt(copyRect.topLeft(), srcLayer->paintDevice(), copyRect);
-    gc.end();
-
-    KisTransaction transaction("cut", srcLayer->paintDevice());
-    srcLayer->paintDevice()->clearSelection(selection);
-    image->addJob(strokeId,
-                  new KisStrokeStrategyUndoCommandBased::Data(transaction.endAndTake()));
-
-    image->addJob(strokeId,
-        new KisStrokeStrategyUndoCommandBased::Data(
-            new KisDeselectGlobalSelectionCommand(image)));
-
-    KisPaintLayerSP newLayer =
-        new KisPaintLayer(image, srcLayer->name() + " (moved)",
-                          srcLayer->opacity(), device);
-
-    newLayer->setCompositeOp(srcLayer->compositeOpId());
-
-    // No updates while we adding a layer, so let's be "exclusive"
-    image->addJob(strokeId,
-        new KisStrokeStrategyUndoCommandBased::Data(
-            new KisImageLayerAddCommand(image, newLayer,
-                                        srcLayer->parent(), srcLayer),
-            false,
-            KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE));
-
-    return newLayer;
-}
-
 void KisToolMove::mousePressEvent(KoPointerEvent *event)
 {
     if(PRESS_CONDITION_OM(event, KisTool::HOVER_MODE,
@@ -145,13 +112,15 @@ void KisToolMove::mousePressEvent(KoPointerEvent *event)
 
         setMode(KisTool::PAINT_MODE);
 
+        QPoint pos = convertToPixelCoord(event).toPoint();
+        m_dragStart = pos;
+        m_lastDragPos = m_dragStart;
+
+        if (m_strokeId) return;
+
         KisNodeSP node;
-        KisImageWSP image = currentImage();
-        if (!image || !image->rootLayer()) {
-            return;
-        }
+        KisImageSP image = this->image();
 
-        QPoint pos = convertToPixelCoord(event).toPoint();
         KisSelectionSP selection = currentSelection();
 
         if(!m_optionsWidget->radioSelectedLayer->isChecked() &&
@@ -161,52 +130,33 @@ void KisToolMove::mousePressEvent(KoPointerEvent *event)
                 (m_optionsWidget->radioGroup->isChecked() ||
                  event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier));
 
-            node = findNode(image->rootLayer(), pos, wholeGroup);
+            node = findNode(image->root(), pos, wholeGroup);
         }
 
-        if(!node) {
-            node = currentNode();
-            if (!node) {
-                return;
-            }
-        }
+        if((!node && !(node = currentNode())) || !node->isEditable()) return;
 
-        if (!nodeEditable()) {
-            return;
-        }
 
-        /**
-         * NOTE: we use deferred initialization of the node of
-         * the stroke here. First, we set the node to null in
-         * the constructor, use jobs of undo-command-based
-         * strategy to initialize the stroke and then we set up
-         * the node itself.
-         */
-        MoveStrokeStrategy *strategy =
-            new MoveStrokeStrategy(0, image.data(),
-                                   image->postExecutionUndoAdapter(),
-                                   image->undoAdapter());
+        KisStrokeStrategy *strategy;
 
-        m_strokeId = image->startStroke(strategy);
+        KisPaintLayerSP paintLayer =
+            dynamic_cast<KisPaintLayer*>(node.data());
 
-        if (node->inherits("KisLayer") &&
-            !node->inherits("KisGroupLayer") &&
-            node->paintDevice() &&
-            selection &&
+        if (paintLayer && selection &&
             !selection->isTotallyUnselected(image->bounds())) {
 
-            KisLayerSP oldLayer = dynamic_cast<KisLayer*>(node.data());
-            KisLayerSP newLayer = createSelectionCopy(oldLayer, selection, image, m_strokeId);
-
-            node = newLayer;
+            strategy =
+                new MoveSelectionStrokeStrategy(paintLayer,
+                                                selection,
+                                                image.data(),
+                                                image->postExecutionUndoAdapter());
+        } else {
+            strategy =
+                new MoveStrokeStrategy(node, image.data(),
+                                       image->postExecutionUndoAdapter(),
+                                       image->undoAdapter());
         }
 
-        // the deferred initialization itself
-        strategy->setNode(node);
-        strategy = 0;
-
-        m_dragStart = pos;
-        m_lastDragPos = m_dragStart;
+        m_strokeId = image->startStroke(strategy);
     }
     else {
         KisTool::mousePressEvent(event);
@@ -216,16 +166,11 @@ void KisToolMove::mousePressEvent(KoPointerEvent *event)
 void KisToolMove::mouseMoveEvent(KoPointerEvent *event)
 {
     if(MOVE_CONDITION(event, KisTool::PAINT_MODE)) {
-        if (!m_strokeId)
-        {
-            return;
-        }
+        if (!m_strokeId) return;
 
         QPoint pos = convertToPixelCoord(event).toPoint();
         pos = applyModifiers(event->modifiers(), pos);
         drag(pos);
-
-        notifyModified();
     }
     else {
         KisTool::mouseMoveEvent(event);
@@ -236,21 +181,11 @@ void KisToolMove::mouseReleaseEvent(KoPointerEvent *event)
 {
     if(RELEASE_CONDITION(event, KisTool::PAINT_MODE, Qt::LeftButton)) {
         setMode(KisTool::HOVER_MODE);
-
-        if (!m_strokeId)
-        {
-            return;
-        }
+        if (!m_strokeId) return;
 
         QPoint pos = convertToPixelCoord(event).toPoint();
         pos = applyModifiers(event->modifiers(), pos);
         drag(pos);
-
-        KisImageWSP image = currentImage();
-        image->endStroke(m_strokeId);
-        m_strokeId.clear();
-
-        currentImage()->setModified();
     }
     else {
         KisTool::mouseReleaseEvent(event);
@@ -268,6 +203,24 @@ void KisToolMove::drag(const QPoint& newPos)
                   new MoveStrokeStrategy::Data(offset));
 }
 
+void KisToolMove::endStroke()
+{
+    if (!m_strokeId) return;
+
+    KisImageWSP image = currentImage();
+    image->endStroke(m_strokeId);
+    m_strokeId.clear();
+}
+
+void KisToolMove::cancelStroke()
+{
+    if (!m_strokeId) return;
+
+    KisImageWSP image = currentImage();
+    image->cancelStroke(m_strokeId);
+    m_strokeId.clear();
+}
+
 QWidget* KisToolMove::createOptionWidget()
 {
     m_optionsWidget = new MoveToolOptionsWidget(0);
diff --git a/krita/plugins/tools/defaulttools/kis_tool_move.h b/krita/plugins/tools/defaulttools/kis_tool_move.h
index 4ec1788..4d11710 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_move.h
+++ b/krita/plugins/tools/defaulttools/kis_tool_move.h
@@ -54,6 +54,9 @@ public:
     KisToolMove(KoCanvasBase * canvas);
     virtual ~KisToolMove();
 
+    void deactivate();
+    void requestStrokeEnd();
+    void requestStrokeCancellation();
 
 public:
 
@@ -67,7 +70,8 @@ public:
 
 private:
     void drag(const QPoint& newPos);
-
+    void endStroke();
+    void cancelStroke();
     QPoint applyModifiers(Qt::KeyboardModifiers modifiers, QPoint pos);
 
 private:
diff --git a/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.cpp b/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.cpp
new file mode 100644
index 0000000..9089f02
--- /dev/null
+++ b/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.cpp
@@ -0,0 +1,132 @@
+/*
+ *  Copyright (c) 2012 Dmitry Kazakov <dimula73 at 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 "move_selection_stroke_strategy.h"
+
+#include <KoColorSpace.h>
+#include "kis_image.h"
+#include "kis_paint_layer.h"
+#include "kis_painter.h"
+#include "kis_transaction.h"
+#include <commands/kis_deselect_global_selection_command.h>
+
+
+MoveSelectionStrokeStrategy::MoveSelectionStrokeStrategy(KisPaintLayerSP paintLayer,
+                                                         KisSelectionSP selection,
+                                                         KisUpdatesFacade *updatesFacade,
+                                                         KisPostExecutionUndoAdapter *undoAdapter)
+    : KisStrokeStrategyUndoCommandBased("Move Selection Stroke", false, undoAdapter),
+      m_paintLayer(paintLayer),
+      m_selection(selection),
+      m_updatesFacade(updatesFacade),
+      m_undoAdapter(undoAdapter)
+{
+    enableJob(KisSimpleStrokeStrategy::JOB_INIT);
+    enableJob(KisSimpleStrokeStrategy::JOB_FINISH);
+    enableJob(KisSimpleStrokeStrategy::JOB_CANCEL);
+}
+
+void MoveSelectionStrokeStrategy::initStrokeCallback()
+{
+    KisStrokeStrategyUndoCommandBased::initStrokeCallback();
+
+    KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
+
+    KisPaintDeviceSP movedDevice = new KisPaintDevice(m_paintLayer.data(), paintDevice->colorSpace());
+
+
+    QRect copyRect = m_selection->selectedRect();
+    KisPainter gc(movedDevice);
+    gc.setSelection(m_selection);
+    gc.bitBlt(copyRect.topLeft(), paintDevice, copyRect);
+    gc.end();
+
+    KisTransaction cutTransaction(name(), paintDevice);
+    paintDevice->clearSelection(m_selection);
+    runAndSaveCommand(KUndo2CommandSP(cutTransaction.endAndTake()),
+                      KisStrokeJobData::SEQUENTIAL,
+                      KisStrokeJobData::NORMAL);
+
+    KisIndirectPaintingSupport *indirect =
+        static_cast<KisIndirectPaintingSupport*>(m_paintLayer.data());
+    indirect->setTemporaryTarget(movedDevice);
+    indirect->setTemporaryCompositeOp(paintDevice->colorSpace()->compositeOp(COMPOSITE_OVER));
+    indirect->setTemporaryOpacity(OPACITY_OPAQUE_U8);
+
+    m_updatesFacade->blockUpdates();
+    runAndSaveCommand(
+        KUndo2CommandSP(new KisDeselectGlobalSelectionCommand(m_paintLayer->image())),
+        KisStrokeJobData::SEQUENTIAL,
+        KisStrokeJobData::EXCLUSIVE);
+    m_updatesFacade->unblockUpdates();
+}
+
+void MoveSelectionStrokeStrategy::finishStrokeCallback()
+{
+    KisIndirectPaintingSupport *indirect =
+        static_cast<KisIndirectPaintingSupport*>(m_paintLayer.data());
+
+    KisTransaction transaction(name(), m_paintLayer->paintDevice());
+    indirect->mergeToLayer(m_paintLayer, (KisUndoAdapter*)0, "");
+    runAndSaveCommand(KUndo2CommandSP(transaction.endAndTake()),
+                      KisStrokeJobData::SEQUENTIAL,
+                      KisStrokeJobData::NORMAL);
+
+    indirect->setTemporaryTarget(0);
+
+    KisStrokeStrategyUndoCommandBased::finishStrokeCallback();
+}
+
+void MoveSelectionStrokeStrategy::cancelStrokeCallback()
+{
+    KisIndirectPaintingSupport *indirect =
+        static_cast<KisIndirectPaintingSupport*>(m_paintLayer.data());
+
+    QRegion dirtyRegion = indirect->temporaryTarget()->region();
+
+    indirect->setTemporaryTarget(0);
+
+    m_paintLayer->setDirty(dirtyRegion);
+
+    KisStrokeStrategyUndoCommandBased::cancelStrokeCallback();
+}
+
+#include "move_stroke_strategy.h"
+
+void MoveSelectionStrokeStrategy::doStrokeCallback(KisStrokeJobData *data)
+{
+    MoveStrokeStrategy::Data *d = dynamic_cast<MoveStrokeStrategy::Data*>(data);
+
+    if (d) {
+        KisIndirectPaintingSupport *indirect =
+            static_cast<KisIndirectPaintingSupport*>(m_paintLayer.data());
+
+        KisPaintDeviceSP movedDevice = indirect->temporaryTarget();
+
+        QRegion dirtyRegion = movedDevice->region();
+        dirtyRegion |= dirtyRegion.translated(d->offset);
+
+        movedDevice->setX(movedDevice->x() + d->offset.x());
+        movedDevice->setY(movedDevice->y() + d->offset.y());
+
+        m_paintLayer->setDirty(dirtyRegion);
+    } else {
+        KisStrokeStrategyUndoCommandBased::doStrokeCallback(data);
+    }
+}
+
diff --git a/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.h b/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.h
new file mode 100644
index 0000000..440f2bf
--- /dev/null
+++ b/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.h
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2012 Dmitry Kazakov <dimula73 at 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 __MOVE_SELECTION_STROKE_STRATEGY_H
+#define __MOVE_SELECTION_STROKE_STRATEGY_H
+
+#include "kis_stroke_strategy_undo_command_based.h"
+#include "kis_types.h"
+
+class KisPostExecutionUndoAdapter;
+class KisUpdatesFacade;
+
+
+class MoveSelectionStrokeStrategy : public KisStrokeStrategyUndoCommandBased
+{
+public:
+    MoveSelectionStrokeStrategy(KisPaintLayerSP paintLayer,
+                                KisSelectionSP selection,
+                                KisUpdatesFacade *updatesFacade,
+                                KisPostExecutionUndoAdapter *undoAdapter);
+
+    void initStrokeCallback();
+    void finishStrokeCallback();
+    void cancelStrokeCallback();
+    void doStrokeCallback(KisStrokeJobData *data);
+
+private:
+    KisPaintLayerSP m_paintLayer;
+    KisSelectionSP m_selection;
+    KisUpdatesFacade *m_updatesFacade,;
+    KisPostExecutionUndoAdapter *m_undoAdapter;
+};
+
+#endif /* __MOVE_SELECTION_STROKE_STRATEGY_H */
diff --git a/krita/ui/kis_doc2_p.h b/krita/ui/kis_doc2_p.h
index 19a3e5f..e7ec1c4 100644
--- a/krita/ui/kis_doc2_p.h
+++ b/krita/ui/kis_doc2_p.h
@@ -32,6 +32,7 @@ public:
 
     void setIndex(int idx) {
         KisImageWSP image = this->image();
+        image->requestStrokeCancellation();
         if(image->tryBarrierLock()) {
             KUndo2Stack::setIndex(idx);
             image->unlock();
@@ -40,6 +41,7 @@ public:
 
     void undo() {
         KisImageWSP image = this->image();
+        image->requestStrokeCancellation();
         if(image->tryBarrierLock()) {
             KUndo2Stack::undo();
             image->unlock();
diff --git a/krita/ui/kis_filter_handler.cc b/krita/ui/kis_filter_handler.cc
index 2705b9d..e472a40 100644
--- a/krita/ui/kis_filter_handler.cc
+++ b/krita/ui/kis_filter_handler.cc
@@ -102,6 +102,14 @@ KisFilterHandler::~KisFilterHandler()
 
 void KisFilterHandler::showDialog()
 {
+    /**
+     * HACK ALERT:
+     * Until filters are ported to strokes, there should be a barrier
+     * to finish all the running strokes in the system
+     */
+    m_d->view->image()->barrierLock();
+    m_d->view->image()->unlock();
+
     KisPaintDeviceSP dev = m_d->view->activeDevice();
     if (dev->colorSpace()->willDegrade(m_d->filter->colorSpaceIndependence())) {
         // Warning bells!
diff --git a/krita/ui/tool/kis_tool.cc b/krita/ui/tool/kis_tool.cc
index 86b04ba..cde18c0 100644
--- a/krita/ui/tool/kis_tool.cc
+++ b/krita/ui/tool/kis_tool.cc
@@ -161,14 +161,26 @@ void KisTool::activate(ToolActivation, const QSet<KoShape*> &)
 
     connect(actions().value("toggle_fg_bg"), SIGNAL(triggered()), SLOT(slotToggleFgBg()), Qt::UniqueConnection);
     connect(actions().value("reset_fg_bg"), SIGNAL(triggered()), SLOT(slotResetFgBg()), Qt::UniqueConnection);
+    connect(image(), SIGNAL(sigStrokeCancellationRequested()), SLOT(requestStrokeCancellation()));
+    connect(image(), SIGNAL(sigStrokeEndRequested()), SLOT(requestStrokeEnd()));
 }
 
 void KisTool::deactivate()
 {
+    disconnect(image().data(), SIGNAL(sigStrokeCancellationRequested()));
+    disconnect(image().data(), SIGNAL(sigStrokeEndRequested()));
     disconnect(actions().value("toggle_fg_bg"), 0, this, 0);
     disconnect(actions().value("reset_fg_bg"), 0, this, 0);
 }
 
+void KisTool::requestStrokeCancellation()
+{
+}
+
+void KisTool::requestStrokeEnd()
+{
+}
+
 void KisTool::resourceChanged(int key, const QVariant & v)
 {
 
diff --git a/krita/ui/tool/kis_tool.h b/krita/ui/tool/kis_tool.h
index 073c9cb..a2ea4b6 100644
--- a/krita/ui/tool/kis_tool.h
+++ b/krita/ui/tool/kis_tool.h
@@ -224,6 +224,20 @@ protected slots:
      */
     virtual void resetCursorStyle();
 
+    /**
+     * Called when the user requested the cancellation of the current
+     * stroke. If you tool supports cancelling, override this method
+     * and do the needed work there
+     */
+    virtual void requestStrokeCancellation();
+
+    /**
+     * Called when the image decided that the stroke should better be
+     * ended. If you tool supports long strokes, override this method
+     * and do the needed work there
+     */
+    virtual void requestStrokeEnd();
+
 private slots:
     void slotToggleFgBg();
     void slotResetFgBg();



More information about the kimageshop mailing list