diff --git a/krita/benchmarks/kis_floodfill_benchmark.cpp b/krita/benchmarks/kis_floodfill_benchmark.cpp
index 5f3dc6a..da9854f 100644
--- a/krita/benchmarks/kis_floodfill_benchmark.cpp
+++ b/krita/benchmarks/kis_floodfill_benchmark.cpp
@@ -101,7 +101,7 @@ void KisFloodFillBenchmark::benchmarkFlood()
         fillPainter.fillColor(1, 1, false);
 
         dirty = fillPainter.dirtyRegion();
-        delete fillPainter.endTransaction();
+        fillPainter.deleteTransaction();
     }
     
     // uncomment this to see the output
diff --git a/krita/benchmarks/kis_gradient_benchmark.cpp b/krita/benchmarks/kis_gradient_benchmark.cpp
index 2b1921b..f224050 100644
--- a/krita/benchmarks/kis_gradient_benchmark.cpp
+++ b/krita/benchmarks/kis_gradient_benchmark.cpp
@@ -78,7 +78,7 @@ void KisGradientBenchmark::benchmarkGradient()
         fillPainter.paintGradient(QPointF(0,0), QPointF(3000,3000), KisGradientPainter::GradientShapeBiLinear, KisGradientPainter::GradientRepeatNone, true, false, 0, 0, GMP_IMAGE_WIDTH,GMP_IMAGE_HEIGHT);
 
         dirty = fillPainter.dirtyRegion();
-        delete fillPainter.endTransaction();
+        fillPainter.deleteTransaction();
     }
     
     // uncomment this to see the output
diff --git a/krita/benchmarks/kis_projection_benchmark.cpp b/krita/benchmarks/kis_projection_benchmark.cpp
index c5f833b..161d92e 100644
--- a/krita/benchmarks/kis_projection_benchmark.cpp
+++ b/krita/benchmarks/kis_projection_benchmark.cpp
@@ -50,6 +50,14 @@ void KisProjectionBenchmark::benchmarkProjection()
     }
 }
 
+void KisProjectionBenchmark::benchmarkLoading()
+{
+    QBENCHMARK{
+        KisDoc2 doc;
+        doc.loadNativeFormat(QString(FILES_DATA_DIR) + QDir::separator() + "load_test.kra");
+    }
+}
+
 #include "kis_wait_update_done.h"
 
 void KisProjectionBenchmark::benchmarkOverlapping()
diff --git a/krita/benchmarks/kis_projection_benchmark.h b/krita/benchmarks/kis_projection_benchmark.h
index 39721ed..dd4cf90 100644
--- a/krita/benchmarks/kis_projection_benchmark.h
+++ b/krita/benchmarks/kis_projection_benchmark.h
@@ -27,11 +27,11 @@ class KisProjectionBenchmark : public QObject
     Q_OBJECT
 
 private slots:
-    
     void initTestCase();
     void cleanupTestCase();
-    
+
     void benchmarkProjection();
+    void benchmarkLoading();
     void benchmarkOverlapping();
 };
 
diff --git a/krita/image/CMakeLists.txt b/krita/image/CMakeLists.txt
index 14ea692..63fa807 100644
--- a/krita/image/CMakeLists.txt
+++ b/krita/image/CMakeLists.txt
@@ -73,7 +73,7 @@ set(kritaimage_LIB_SRCS
    commands/kis_deselect_global_selection_command.cpp
    commands/kis_image_change_layers_command.cpp
    commands/kis_image_command.cpp
-   commands/kis_image_convert_type_command.cpp
+   commands/kis_image_set_projection_color_space_command.cpp
    commands/kis_image_layer_add_command.cpp
    commands/kis_image_layer_move_command.cpp
    commands/kis_image_layer_remove_command.cpp
@@ -82,7 +82,6 @@ set(kritaimage_LIB_SRCS
    commands/kis_image_node_to_bottom_command.cpp
    commands/kis_image_node_to_top_command.cpp
    commands/kis_image_lock_command.cpp
-   commands/kis_image_props_command.cpp
    commands/kis_image_resize_command.cpp
    commands/kis_layer_command.cpp
    commands/kis_layer_props_command.cpp
@@ -162,14 +161,14 @@ set(kritaimage_LIB_SRCS
    kis_random_generator.cc
    kis_random_sub_accessor.cpp
    kis_shear_visitor.cpp
-   kis_selected_transaction.cc
+   kis_selected_transaction_data.cpp
    kis_selection.cc
    kis_selection_mask.cpp
-   kis_selection_transaction.cc
+   kis_selection_transaction_data.cpp
    kis_serializable_configuration.cc
    kis_shared.cc
    kis_threaded_applicator.cpp
-   kis_transaction.cc
+   kis_transaction_data.cpp
    kis_transform_worker.cc
    kis_transformation_mask.cpp
    kis_transparency_mask.cc
diff --git a/krita/image/commands/kis_image_change_layers_command.cpp b/krita/image/commands/kis_image_change_layers_command.cpp
index 89e5ef4..d12f811 100644
--- a/krita/image/commands/kis_image_change_layers_command.cpp
+++ b/krita/image/commands/kis_image_change_layers_command.cpp
@@ -18,21 +18,11 @@
  */
 
 #include "kis_image_commands.h"
-#include <QString>
-#include <QBitArray>
+#include "kis_image.h"
+#include "kis_group_layer.h"
 
 #include <klocale.h>
 
-#include "KoColorSpaceRegistry.h"
-#include "KoColor.h"
-#include "KoColorProfile.h"
-#include "KoColorSpace.h"
-
-
-#include "kis_image.h"
-#include "kis_layer.h"
-#include "kis_group_layer.h"
-#include "kis_undo_adapter.h"
 
 KisImageChangeLayersCommand::KisImageChangeLayersCommand(KisImageWSP image, KisNodeSP oldRootLayer, KisNodeSP newRootLayer, const QString& name)
         : KisImageCommand(name, image)
@@ -43,22 +33,18 @@ KisImageChangeLayersCommand::KisImageChangeLayersCommand(KisImageWSP image, KisN
 
 void KisImageChangeLayersCommand::redo()
 {
-    setUndo(false);
     m_image->lock();
     m_image->setRootLayer(static_cast<KisGroupLayer*>(m_newRootLayer.data()));
     m_image->unlock();
     m_image->refreshGraph();
     m_image->notifyLayersChanged();
-    setUndo(true);
 }
 
 void KisImageChangeLayersCommand::undo()
 {
-    setUndo(false);
     m_image->lock();
     m_image->setRootLayer(static_cast<KisGroupLayer*>(m_oldRootLayer.data()));
     m_image->unlock();
     m_image->refreshGraph();
     m_image->notifyLayersChanged();
-    setUndo(true);
 }
diff --git a/krita/image/commands/kis_image_change_layers_command.h b/krita/image/commands/kis_image_change_layers_command.h
index e26bdde..71f0d6f 100644
--- a/krita/image/commands/kis_image_change_layers_command.h
+++ b/krita/image/commands/kis_image_change_layers_command.h
@@ -21,17 +21,9 @@
 #define KIS_IMAGE_CHANGE_LAYERS_COMMAND_H_
 
 #include <krita_export.h>
-
-#include <QUndoCommand>
-#include <QSize>
-#include <QBitArray>
 #include "kis_types.h"
 #include "kis_image_command.h"
 
-class KoCompositeOp;
-class KoColorSpace;
-class KoColorProfile;
-
 class KisImageChangeLayersCommand : public KisImageCommand
 {
 
diff --git a/krita/image/commands/kis_image_command.cpp b/krita/image/commands/kis_image_command.cpp
index 7f715f2..985d488 100644
--- a/krita/image/commands/kis_image_command.cpp
+++ b/krita/image/commands/kis_image_command.cpp
@@ -18,21 +18,11 @@
  */
 
 #include "kis_image_commands.h"
-#include <QString>
-#include <QBitArray>
-
 #include <klocale.h>
 
-#include "KoColorSpaceRegistry.h"
-#include "KoColor.h"
-#include "KoColorProfile.h"
-#include "KoColorSpace.h"
-
-
 #include "kis_image.h"
 #include "kis_layer.h"
-#include "kis_group_layer.h"
-#include "kis_undo_adapter.h"
+
 
 KisImageCommand::KisImageCommand(const QString& name, KisImageWSP image)
         : QUndoCommand(name)
@@ -44,13 +34,6 @@ KisImageCommand::~KisImageCommand()
 {
 }
 
-void KisImageCommand::setUndo(bool undo)
-{
-    if (m_image->undoAdapter()) {
-        m_image->undoAdapter()->setUndo(undo);
-    }
-}
-
 static inline bool isLayer(KisNodeSP node) {
     return qobject_cast<KisLayer*>(node.data());
 }
diff --git a/krita/image/commands/kis_image_command.h b/krita/image/commands/kis_image_command.h
index d69021a..b980b97 100644
--- a/krita/image/commands/kis_image_command.h
+++ b/krita/image/commands/kis_image_command.h
@@ -25,12 +25,8 @@
 #include <QUndoCommand>
 #include <QSize>
 #include <QRect>
-#include <QBitArray>
 #include "kis_types.h"
 
-class KoCompositeOp;
-class KoColorSpace;
-class KoColorProfile;
 
 /// the base command for commands altering a KisImage
 class KisImageCommand : public QUndoCommand
@@ -67,13 +63,6 @@ protected:
     };
 
 protected:
-    /**
-     * Lock/Unlocks the undoAdapter for undo operations.
-     * Set this at start and end of commands, which use recursion.
-     * @param undo State the undoAdapter will be set to.
-     */
-    void setUndo(bool undo);
-
     KisImageWSP m_image;
 };
 
diff --git a/krita/image/commands/kis_image_commands.h b/krita/image/commands/kis_image_commands.h
index 151f834..1e81d1e 100644
--- a/krita/image/commands/kis_image_commands.h
+++ b/krita/image/commands/kis_image_commands.h
@@ -21,12 +21,11 @@
 
 #include "kis_image_change_layers_command.h"
 #include "kis_image_command.h"
-#include "kis_image_convert_type_command.h"
+#include "kis_image_set_projection_color_space_command.h"
 #include "kis_image_layer_add_command.h"
 #include "kis_image_layer_move_command.h"
 #include "kis_image_layer_remove_command.h"
 #include "kis_image_lock_command.h"
-#include "kis_image_props_command.h"
 #include "kis_image_resize_command.h"
 
 #endif
diff --git a/krita/image/commands/kis_image_convert_type_command.cpp b/krita/image/commands/kis_image_convert_type_command.cpp
deleted file mode 100644
index 1440d0d..0000000
--- a/krita/image/commands/kis_image_convert_type_command.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
- *  Copyright (c) 2007 Sven Langkamp <sven.langkamp@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_image_commands.h"
-#include <QString>
-#include <QBitArray>
-
-#include <klocale.h>
-
-#include "KoColorSpaceRegistry.h"
-#include "KoColor.h"
-#include "KoColorProfile.h"
-#include "KoColorSpace.h"
-
-
-#include "kis_image.h"
-#include "kis_layer.h"
-#include "kis_group_layer.h"
-#include "kis_undo_adapter.h"
-
-KisImageConvertTypeCommand::KisImageConvertTypeCommand(KisImageWSP image, const KoColorSpace * beforeColorSpace, const KoColorSpace * afterColorSpace)
-        : KisImageCommand(i18n("Convert Image Type"), image)
-{
-    m_beforeColorSpace = beforeColorSpace;
-    m_afterColorSpace = afterColorSpace;
-}
-
-void KisImageConvertTypeCommand::redo()
-{
-    setUndo(false);
-    m_image->setColorSpace(m_afterColorSpace);
-    m_image->setProfile(m_afterColorSpace->profile());
-    setUndo(true);
-}
-
-void KisImageConvertTypeCommand::undo()
-{
-    setUndo(false);
-    m_image->setColorSpace(m_beforeColorSpace);
-    m_image->setProfile(m_beforeColorSpace->profile());
-    setUndo(true);
-}
diff --git a/krita/image/commands/kis_image_convert_type_command.h b/krita/image/commands/kis_image_convert_type_command.h
deleted file mode 100644
index 0a2f08e..0000000
--- a/krita/image/commands/kis_image_convert_type_command.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
- *  Copyright (c) 2007 Sven Langkamp <sven.langkamp@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_IMAGE_CONVERT_TYPE_COMMAND_H_
-#define KIS_IMAGE_CONVERT_TYPE_COMMAND_H_
-
-#include <krita_export.h>
-
-#include <QUndoCommand>
-#include <QSize>
-#include <QBitArray>
-#include "kis_types.h"
-#include "kis_image_command.h"
-
-class KoCompositeOp;
-class KoColorSpace;
-class KoColorProfile;
-class KisImageConvertTypeCommand : public KisImageCommand
-{
-
-public:
-    KisImageConvertTypeCommand(KisImageWSP image, const KoColorSpace * beforeColorSpace, const KoColorSpace * afterColorSpace);
-
-    virtual void redo();
-    virtual void undo();
-
-private:
-    const KoColorSpace * m_beforeColorSpace;
-    const KoColorSpace * m_afterColorSpace;
-};
-
-
-#endif
diff --git a/krita/image/commands/kis_image_layer_add_command.cpp b/krita/image/commands/kis_image_layer_add_command.cpp
index 038cc9f..997a46f 100644
--- a/krita/image/commands/kis_image_layer_add_command.cpp
+++ b/krita/image/commands/kis_image_layer_add_command.cpp
@@ -18,20 +18,10 @@
  */
 
 #include "kis_image_commands.h"
-#include <QString>
-#include <QBitArray>
+#include "kis_image.h"
 
 #include <klocale.h>
 
-#include "KoColorSpaceRegistry.h"
-#include "KoColor.h"
-#include "KoColorProfile.h"
-#include "KoColorSpace.h"
-
-#include "kis_image.h"
-#include "kis_layer.h"
-#include "kis_group_layer.h"
-#include "kis_undo_adapter.h"
 
 KisImageLayerAddCommand::KisImageLayerAddCommand(KisImageWSP image, KisNodeSP layer, KisNodeSP parent, KisNodeSP aboveThis)
         : KisImageCommand(i18n("Add Layer"), image), m_index(-1)
diff --git a/krita/image/commands/kis_image_layer_add_command.h b/krita/image/commands/kis_image_layer_add_command.h
index c2b95b1..15d8e4d 100644
--- a/krita/image/commands/kis_image_layer_add_command.h
+++ b/krita/image/commands/kis_image_layer_add_command.h
@@ -22,17 +22,10 @@
 
 #include <krita_export.h>
 
-#include <QUndoCommand>
-#include <QSize>
-#include <QBitArray>
 #include "kis_types.h"
 #include "kis_image_command.h"
 
 
-class KoCompositeOp;
-class KoColorSpace;
-class KoColorProfile;
-
 /// The command for adding a layer
 class KRITAIMAGE_EXPORT KisImageLayerAddCommand : public KisImageCommand
 {
diff --git a/krita/image/commands/kis_image_layer_remove_command.cpp b/krita/image/commands/kis_image_layer_remove_command.cpp
index a274b43..3ce8f45 100644
--- a/krita/image/commands/kis_image_layer_remove_command.cpp
+++ b/krita/image/commands/kis_image_layer_remove_command.cpp
@@ -18,21 +18,10 @@
  */
 
 #include "kis_image_commands.h"
-#include <QString>
-#include <QBitArray>
+#include "kis_image.h"
 
 #include <klocale.h>
 
-#include "KoColorSpaceRegistry.h"
-#include "KoColor.h"
-#include "KoColorProfile.h"
-#include "KoColorSpace.h"
-
-
-#include "kis_image.h"
-#include "kis_layer.h"
-#include "kis_group_layer.h"
-#include "kis_undo_adapter.h"
 
 KisImageLayerRemoveCommand::KisImageLayerRemoveCommand(KisImageWSP image, KisNodeSP layer)
         : KisImageCommand(i18n("Remove Layer"), image)
diff --git a/krita/image/commands/kis_image_layer_remove_command.h b/krita/image/commands/kis_image_layer_remove_command.h
index da78d72..8e2a188 100644
--- a/krita/image/commands/kis_image_layer_remove_command.h
+++ b/krita/image/commands/kis_image_layer_remove_command.h
@@ -22,17 +22,10 @@
 
 #include <krita_export.h>
 
-#include <QUndoCommand>
-#include <QSize>
-#include <QBitArray>
 #include "kis_types.h"
 #include "kis_image_command.h"
 
 
-class KoCompositeOp;
-class KoColorSpace;
-class KoColorProfile;
-
 /// The command for removing a layer
 class KRITAIMAGE_EXPORT KisImageLayerRemoveCommand : public KisImageCommand
 {
diff --git a/krita/image/commands/kis_image_lock_command.cpp b/krita/image/commands/kis_image_lock_command.cpp
index b1105ee..b6e7186 100644
--- a/krita/image/commands/kis_image_lock_command.cpp
+++ b/krita/image/commands/kis_image_lock_command.cpp
@@ -18,21 +18,10 @@
  */
 
 #include "kis_image_commands.h"
-#include <QString>
-#include <QBitArray>
+#include "kis_image.h"
 
 #include <klocale.h>
 
-#include "KoColorSpaceRegistry.h"
-#include "KoColor.h"
-#include "KoColorProfile.h"
-#include "KoColorSpace.h"
-
-
-#include "kis_image.h"
-#include "kis_layer.h"
-#include "kis_group_layer.h"
-#include "kis_undo_adapter.h"
 
 KisImageLockCommand::KisImageLockCommand(KisImageWSP image, bool lockImage)
         : KisImageCommand("lock image", image)  // Not for translation, this is only ever used inside a macro command.
@@ -42,25 +31,21 @@ KisImageLockCommand::KisImageLockCommand(KisImageWSP image, bool lockImage)
 
 void KisImageLockCommand::redo()
 {
-    setUndo(false);
     if (m_lockImage) {
         m_image->lock();
     } else {
         m_image->unlock();
     }
     m_image->refreshGraph();
-    setUndo(true);
 }
 
 void KisImageLockCommand::undo()
 {
-    setUndo(false);
     if (m_lockImage) {
         m_image->unlock();
     } else {
         m_image->lock();
     }
     m_image->refreshGraph();
-    setUndo(true);
 }
 
diff --git a/krita/image/commands/kis_image_lock_command.h b/krita/image/commands/kis_image_lock_command.h
index 84b6471..2b8cdce 100644
--- a/krita/image/commands/kis_image_lock_command.h
+++ b/krita/image/commands/kis_image_lock_command.h
@@ -23,8 +23,6 @@
 #include <krita_export.h>
 
 #include <QUndoCommand>
-#include <QSize>
-#include <QBitArray>
 #include "kis_types.h"
 #include "kis_image_command.h"
 
diff --git a/krita/image/commands/kis_image_props_command.cpp b/krita/image/commands/kis_image_props_command.cpp
deleted file mode 100644
index 2a9cc66..0000000
--- a/krita/image/commands/kis_image_props_command.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
- *  Copyright (c) 2007 Sven Langkamp <sven.langkamp@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_image_commands.h"
-#include <QString>
-#include <QBitArray>
-
-#include <klocale.h>
-
-#include "KoColorSpaceRegistry.h"
-#include "KoColor.h"
-#include "KoColorProfile.h"
-#include "KoColorSpace.h"
-
-
-#include "kis_image.h"
-#include "kis_layer.h"
-#include "kis_group_layer.h"
-#include "kis_undo_adapter.h"
-
-KisImagePropsCommand::KisImagePropsCommand(KisImageWSP image, const KoColorSpace* newColorSpace)
-        : KisImageCommand(i18n("Property Changes"), image)
-        , m_newColorSpace(newColorSpace)
-{
-    m_oldColorSpace = m_image->colorSpace();
-}
-
-void KisImagePropsCommand::redo()
-{
-    setUndo(false);
-    m_image->setColorSpace(m_newColorSpace);
-    m_image->rootLayer()->setDirty();
-    setUndo(true);
-}
-
-void KisImagePropsCommand::undo()
-{
-    setUndo(false);
-    m_image->setColorSpace(m_oldColorSpace);
-    m_image->rootLayer()->setDirty();
-    setUndo(true);
-}
diff --git a/krita/image/commands/kis_image_props_command.h b/krita/image/commands/kis_image_props_command.h
deleted file mode 100644
index f5e0fb2..0000000
--- a/krita/image/commands/kis_image_props_command.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
- *  Copyright (c) 2007 Sven Langkamp <sven.langkamp@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_IMAGE_PROPS_COMMAND_H_
-#define KIS_IMAGE_PROPS_COMMAND_H_
-
-#include <krita_export.h>
-
-#include <QUndoCommand>
-#include <QSize>
-#include <QBitArray>
-#include "kis_types.h"
-#include "kis_image_command.h"
-
-class KoCompositeOp;
-class KoColorSpace;
-class KoColorProfile;
-/// The command for image property changes
-class KRITAIMAGE_EXPORT KisImagePropsCommand : public KisImageCommand
-{
-
-public:
-    /**
-     * Command for image property changes
-     *
-     * This command stores the current image properties and set the new propertys.
-     *
-     * @param image the image
-     * @param newColorSpace the new image color space
-     * @param newResolution the new image resolution which will be used for xRes and yRes
-     */
-    KisImagePropsCommand(KisImageWSP image, const KoColorSpace* newColorSpace);
-
-    virtual void redo();
-    virtual void undo();
-
-private:
-    const KoColorSpace * m_newColorSpace;
-    const KoColorSpace * m_oldColorSpace;
-    const KoColorProfile* m_newProfile;
-    const KoColorProfile* m_oldProfile;
-};
-#endif
diff --git a/krita/image/commands/kis_image_resize_command.cpp b/krita/image/commands/kis_image_resize_command.cpp
index 293a4f7..04364a5 100644
--- a/krita/image/commands/kis_image_resize_command.cpp
+++ b/krita/image/commands/kis_image_resize_command.cpp
@@ -18,45 +18,26 @@
  */
 
 #include "kis_image_commands.h"
-#include <QString>
-#include <QBitArray>
+#include "kis_image.h"
 
 #include <klocale.h>
 
-#include "KoColorSpaceRegistry.h"
-#include "KoColor.h"
-#include "KoColorProfile.h"
-#include "KoColorSpace.h"
-
-
-#include "kis_image.h"
-#include "kis_layer.h"
-#include "kis_group_layer.h"
-#include "kis_undo_adapter.h"
 
-KisImageResizeCommand::KisImageResizeCommand(KisImageWSP image, qint32 width, qint32 height, qint32 oldWidth, qint32 oldHeight)
+KisImageResizeCommand::KisImageResizeCommand(KisImageWSP image,
+                                             const QSize& newSize)
         : KisImageCommand(i18n("Resize Image"), image)
 {
-    m_before = QSize(oldWidth, oldHeight);
-    m_after = QSize(width, height);
+    // do we really need a translatable name for the command?
+    m_sizeBefore = image->size();
+    m_sizeAfter = newSize;
 }
 
 void KisImageResizeCommand::redo()
 {
-    setUndo(false);
-    m_image->lock();
-    m_image->resize(m_after.width(), m_after.height());
-    m_image->unlock();
-    m_image->refreshGraph();
-    setUndo(true);
+    m_image->setSize(m_sizeAfter);
 }
 
 void KisImageResizeCommand::undo()
 {
-    setUndo(false);
-    m_image->lock();
-    m_image->resize(m_before.width(), m_before.height());
-    m_image->unlock();
-    m_image->refreshGraph();
-    setUndo(true);
+    m_image->setSize(m_sizeBefore);
 }
diff --git a/krita/image/commands/kis_image_resize_command.h b/krita/image/commands/kis_image_resize_command.h
index b9c4810..c40c6b8 100644
--- a/krita/image/commands/kis_image_resize_command.h
+++ b/krita/image/commands/kis_image_resize_command.h
@@ -35,16 +35,15 @@ class KoColorProfile;
 
 class KisImageResizeCommand : public KisImageCommand
 {
-
 public:
-    KisImageResizeCommand(KisImageWSP image, qint32 width, qint32 height, qint32 oldWidth, qint32 oldHeight);
+    KisImageResizeCommand(KisImageWSP image, const QSize& newRect);
 
-    virtual void redo();
-    virtual void undo();
+    void redo();
+    void undo();
 
 private:
-    QSize m_before;
-    QSize m_after;
+    QSize m_sizeBefore;
+    QSize m_sizeAfter;
 };
 
 #endif
diff --git a/krita/image/commands/kis_image_set_projection_color_space_command.cpp b/krita/image/commands/kis_image_set_projection_color_space_command.cpp
new file mode 100644
index 0000000..8c9cdbb
--- /dev/null
+++ b/krita/image/commands/kis_image_set_projection_color_space_command.cpp
@@ -0,0 +1,43 @@
+/*
+ *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *  Copyright (c) 2007 Sven Langkamp <sven.langkamp@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_image_commands.h"
+
+#include "KoColorSpace.h"
+#include "kis_image.h"
+
+#include <klocale.h>
+
+
+KisImageSetProjectionColorSpaceCommand::KisImageSetProjectionColorSpaceCommand(KisImageWSP image, const KoColorSpace * afterColorSpace)
+    : KisImageCommand(i18n("Convert Image Type"), image)
+{
+    m_beforeColorSpace = image->colorSpace();
+    m_afterColorSpace = afterColorSpace;
+}
+
+void KisImageSetProjectionColorSpaceCommand::redo()
+{
+    m_image->setProjectionColorSpace(m_afterColorSpace);
+}
+
+void KisImageSetProjectionColorSpaceCommand::undo()
+{
+    m_image->setProjectionColorSpace(m_beforeColorSpace);
+}
diff --git a/krita/image/commands/kis_image_set_projection_color_space_command.h b/krita/image/commands/kis_image_set_projection_color_space_command.h
new file mode 100644
index 0000000..617b92d
--- /dev/null
+++ b/krita/image/commands/kis_image_set_projection_color_space_command.h
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *  Copyright (c) 2007 Sven Langkamp <sven.langkamp@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_IMAGE_SET_PROJECTION_COLOR_SPACE_COMMAND_H_
+#define KIS_IMAGE_SET_PROJECTION_COLOR_SPACE_COMMAND_H_
+
+#include <krita_export.h>
+#include "kis_image_command.h"
+
+class KoColorSpace;
+
+class KisImageSetProjectionColorSpaceCommand : public KisImageCommand
+{
+public:
+    KisImageSetProjectionColorSpaceCommand(KisImageWSP image, const KoColorSpace * afterColorSpace);
+
+    virtual void redo();
+    virtual void undo();
+
+private:
+    const KoColorSpace * m_beforeColorSpace;
+    const KoColorSpace * m_afterColorSpace;
+};
+
+
+#endif /* KIS_IMAGE_SET_PROJECTION_COLOR_SPACE_COMMAND_H_ */
diff --git a/krita/image/commands/kis_set_global_selection_command.h b/krita/image/commands/kis_set_global_selection_command.h
index ab46915..777c500 100644
--- a/krita/image/commands/kis_set_global_selection_command.h
+++ b/krita/image/commands/kis_set_global_selection_command.h
@@ -33,7 +33,7 @@ public:
      * @param parent the parent command
      * @param selection the selection that will be set a global selection, if 0 a new selection will be created
      */
-    KisSetGlobalSelectionCommand(KisImageWSP image, QUndoCommand * parent, KisSelectionSP selection = 0);
+    KisSetGlobalSelectionCommand(KisImageWSP image, QUndoCommand * parent = 0, KisSelectionSP selection = 0);
     virtual ~KisSetGlobalSelectionCommand();
 
     virtual void redo();
diff --git a/krita/image/kis_colorspace_convert_visitor.cpp b/krita/image/kis_colorspace_convert_visitor.cpp
index f8dd5c8..fc9f403 100644
--- a/krita/image/kis_colorspace_convert_visitor.cpp
+++ b/krita/image/kis_colorspace_convert_visitor.cpp
@@ -17,10 +17,14 @@
  */
 
 #include "kis_colorspace_convert_visitor.h"
-#include "kis_transaction.h"
 #include "kis_image.h"
+#include "kis_paint_device.h"
 #include "kis_undo_adapter.h"
 #include "commands/kis_layer_props_command.h"
+#include "kis_adjustment_layer.h"
+#include "kis_paint_layer.h"
+#include "kis_group_layer.h"
+#include "kis_external_layer_iface.h"
 #include "filter/kis_filter_configuration.h"
 #include "filter/kis_filter_registry.h"
 #include "filter/kis_filter.h"
@@ -102,43 +106,31 @@ bool KisColorSpaceConvertVisitor::convertPaintDevice(KisLayer* layer)
             layer->name(), layer->name(),
             layer->channelFlags(), m_emptyChannelFlags);
 
-    if (m_image && m_image->undoAdapter()) {
-        m_image->undoAdapter()->addCommand(propsCommand);
-    }
+    m_image->undoAdapter()->addCommand(propsCommand);
 
     if (layer->original()) {
         QUndoCommand* cmd = layer->original()->convertTo(m_dstColorSpace, m_renderingIntent);
-        if (m_image->undoAdapter()) {
-            if (cmd) {
-                m_image->undoAdapter()->addCommand(cmd);
-            }
-        }
-        else {
+        if (cmd)
+            m_image->undoAdapter()->addCommand(cmd);
+        else
             delete cmd;
-        }
     }
 
     if (layer->paintDevice()) {
         QUndoCommand* cmd = layer->paintDevice()->convertTo(m_dstColorSpace, m_renderingIntent);
-        if (m_image->undoAdapter()) {
-            if (cmd) {
-                m_image->undoAdapter()->addCommand(cmd);
-            }
-        }
-        else {
+        if (cmd)
+            m_image->undoAdapter()->addCommand(cmd);
+        else
             delete cmd;
-        }    }
+    }
 
     if (layer->projection()) {
         QUndoCommand* cmd = layer->projection()->convertTo(m_dstColorSpace, m_renderingIntent);
-        if (m_image->undoAdapter()) {
-            if (cmd) {
-                m_image->undoAdapter()->addCommand(cmd);
-            }
-        }
-        else {
+        if (cmd)
+            m_image->undoAdapter()->addCommand(cmd);
+        else
             delete cmd;
-        }    }
+    }
 
     layer->setDirty();
 
diff --git a/krita/image/kis_colorspace_convert_visitor.h b/krita/image/kis_colorspace_convert_visitor.h
index 5e248ec..e7d02d7 100644
--- a/krita/image/kis_colorspace_convert_visitor.h
+++ b/krita/image/kis_colorspace_convert_visitor.h
@@ -18,21 +18,15 @@
 #ifndef KIS_COLORSPACE_CONVERT_VISITOR_H_
 #define KIS_COLORSPACE_CONVERT_VISITOR_H_
 
-#include <QBitArray>
 
 #include <KoColorConversionTransformation.h>
 #include <KoColorSpace.h>
-#include <KoCompositeOp.h>
 
 #include <krita_export.h>
 #include "kis_global.h"
 #include "kis_types.h"
 #include "kis_node_visitor.h"
-#include "kis_paint_layer.h"
-#include "kis_paint_device.h"
-#include "kis_adjustment_layer.h"
-#include "kis_group_layer.h"
-#include "kis_external_layer_iface.h"
+
 
 /**
  * This will convert all layers to the destination color space.
diff --git a/krita/image/kis_crop_visitor.h b/krita/image/kis_crop_visitor.h
index a26e4de..3e6139c 100644
--- a/krita/image/kis_crop_visitor.h
+++ b/krita/image/kis_crop_visitor.h
@@ -29,7 +29,6 @@
 #include "kis_paint_layer.h"
 #include "kis_adjustment_layer.h"
 #include "kis_transaction.h"
-#include "kis_selected_transaction.h"
 #include "kis_selection.h"
 #include "kis_external_layer_iface.h"
 #include "kis_undo_adapter.h"
@@ -57,12 +56,10 @@ public:
     }
 
     bool visit(KisExternalLayer *layer) {
-        KisUndoAdapter* undoAdapter = layer->image()->undoAdapter();
-        
-        QUndoCommand* cmd = layer->crop(m_rect);
-        if (cmd && undoAdapter && undoAdapter->undo()) {
-            undoAdapter->addCommand(cmd);
-        }
+        KisUndoAdapter *undoAdapter = layer->image()->undoAdapter();
+        QUndoCommand* command = layer->crop(m_rect);
+        if (command)
+            undoAdapter->addCommand(command);
         return true;
     }
 
@@ -119,28 +116,17 @@ public:
 private:
 
     bool cropPaintDeviceLayer(KisLayer * layer) {
+        KisUndoAdapter *undoAdapter = layer->image()->undoAdapter();
 
-        KisPaintDeviceSP dev = layer->paintDevice();
-        KisUndoAdapter* undoAdapter = layer->image()->undoAdapter();
-
-        KisSelectedTransaction * t = 0;
-        if (undoAdapter && undoAdapter->undo())
-            t = new KisSelectedTransaction(i18n("Crop"), layer);
-
-        layer->setDirty();
-        dev->crop(m_rect);
-
-        if (undoAdapter && undoAdapter->undo()) {
-            undoAdapter->addCommand(t);
-        }
+        KisSelectedTransaction transaction(i18n("Crop"), layer);
+        layer->paintDevice()->crop(m_rect);
+        transaction.commit(undoAdapter);
 
         if (m_movelayers) {
-            if (undoAdapter && undoAdapter->undo()) {
-                QPoint oldPos(layer->x(), layer->y());
-                QPoint newPos(layer->x() - m_rect.x(), layer->y() - m_rect.y());
-                QUndoCommand * cmd = new KisNodeMoveCommand(layer, oldPos, newPos);
-                undoAdapter->addCommand(cmd);
-            }
+            QPoint oldPos(layer->x(), layer->y());
+            QPoint newPos(layer->x() - m_rect.x(), layer->y() - m_rect.y());
+            QUndoCommand *cmd = new KisNodeMoveCommand(layer, oldPos, newPos);
+            undoAdapter->addCommand(cmd);
         }
         return true;
     }
diff --git a/krita/image/kis_gradient_job.cpp b/krita/image/kis_gradient_job.cpp
index ba703c4..84139f4 100644
--- a/krita/image/kis_gradient_job.cpp
+++ b/krita/image/kis_gradient_job.cpp
@@ -58,7 +58,7 @@ void KisGradientJob::run()
     painter.setCompositeOp(m_config->compositeOp);
     painter.setGradient(m_config->gradient);
     painter.setPaintColor(m_config->fgColor);
-    painter.beginTransaction(m_config->transaction);
+    painter.putTransaction(m_config->transaction);
 
     painter.paintGradient(m_config->vectorStart, m_config->vectorEnd,
                           m_config->shape, m_config->repeat,
@@ -66,7 +66,7 @@ void KisGradientJob::run()
                           m_config->reverse,
                           m_rc.x(), m_rc.y(), m_rc.width(), m_rc.height());
 
-    painter.endTransaction();
+    painter.takeTransaction();
 
     m_updater->setProgress(100);
 }
diff --git a/krita/image/kis_image.cc b/krita/image/kis_image.cc
index aba8a01..3924880 100644
--- a/krita/image/kis_image.cc
+++ b/krita/image/kis_image.cc
@@ -350,67 +350,42 @@ void KisImage::notifyLayerUpdated(KisLayerSP layer)
     }
 }
 
-
-void KisImage::resize(const QRect& rc, bool cropLayers)
+void KisImage::setSize(const QSize& size)
 {
-    resize(rc.width(), rc.height(), rc.x(), rc.y(), cropLayers);
+    m_d->width = size.width();
+    m_d->height = size.height();
+    emitSizeChanged();
 }
 
-void KisImage::resize(qint32 w, qint32 h, qint32 x, qint32 y, bool cropLayers)
+void KisImage::resize(const QRect& newRect, bool cropLayers)
 {
-    if (w != width() || h != height()) {
-
-        if (undo()) {
-            if (cropLayers)
-                m_d->adapter->beginMacro(i18n("Crop Image"));
-            else
-                m_d->adapter->beginMacro(i18n("Resize Image"));
+    if(newRect == bounds())
+        return;
 
-            m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
-            m_d->adapter->addCommand(new KisImageResizeCommand(KisImageWSP(this), w, h, width(), height()));
-        }
+    QString macroName = cropLayers ? i18n("Crop Image") : i18n("Resize Image");
+    m_d->adapter->beginMacro(macroName);
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
+    m_d->adapter->addCommand(new KisImageResizeCommand(KisImageWSP(this), newRect.size()));
 
-        m_d->width = w;
-        m_d->height = h;
+    if(cropLayers) {
+        KisCropVisitor visitor(newRect, m_d->adapter);
+        m_d->rootLayer->accept(visitor);
+    }
 
-        if (cropLayers) {
-            KisCropVisitor v(QRect(x, y, w, h), m_d->adapter);
-            m_d->rootLayer->accept(v);
-        }
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
+    m_d->adapter->endMacro();
 
-        emitSizeChanged();
+    setModified();
+}
 
-        if (undo()) {
-            m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
-            m_d->adapter->endMacro();
-        }
-    }
+void KisImage::resize(qint32 w, qint32 h, qint32 x, qint32 y, bool cropLayers)
+{
+    resize(QRect(x, y, w, h), cropLayers);
 }
 
 void KisImage::resizeWithOffset(qint32 w, qint32 h, qint32 xOffset, qint32 yOffset)
 {
-    if (w == width() && h == height() && xOffset == 0 && yOffset == 0)
-        return;
-
-    lock();
-    if (undo()) {
-        m_d->adapter->beginMacro(i18n("Size Canvas"));
-        m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
-        m_d->adapter->addCommand(new KisImageResizeCommand(KisImageWSP(this), w, h, width(), height()));
-    }
-
-    KisCropVisitor v(QRect(-xOffset, -yOffset, w, h), m_d->adapter);
-    m_d->rootLayer->accept(v);
-
-    emitSizeChanged();
-
-    unlock();
-
-    if (undo()) {
-        m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
-        m_d->adapter->endMacro();
-    }
-
+    resize(QRect(-xOffset, -yOffset, w, h), true);
 }
 
 void KisImage::emitSizeChanged()
@@ -425,54 +400,28 @@ void KisImage::emitSizeChanged()
 
 void KisImage::scale(double sx, double sy, KoUpdater *progress, KisFilterStrategy *filterStrategy)
 {
-    QStringList list;
-    list << "KisLayer";
-
-    KisCountVisitor visitor(list, KoProperties());
-    m_d->rootLayer->accept(visitor);
-
-    if (visitor.count() == 0) return; // Nothing to scale
-
     // New image size. XXX: Pass along to discourage rounding errors?
     qint32 w, h;
     w = (qint32)((width() * sx) + 0.5);
     h = (qint32)((height() * sy) + 0.5);
 
-    if (w != width() || h != height()) {
-
-        lock();
-
-        if (undo()) {
-            m_d->adapter->beginMacro(i18n("Scale Image"));
-            m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
-        }
-
-        {
-            KisTransformVisitor visitor(KisImageWSP(this), sx, sy, 0.0, 0.0, 0.0, 0, 0, progress, filterStrategy);
-            m_d->rootLayer->accept(visitor);
-        }
-
-        if (undo()) {
-            m_d->adapter->addCommand(new KisImageResizeCommand(KisImageWSP(this), w, h, width(), height()));
-        }
+    QSize newSize(w, h);
+    if(newSize == size()) return;
 
-        m_d->width = w;
-        m_d->height = h;
+    m_d->adapter->beginMacro(i18n("Scale Image"));
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
+    m_d->adapter->addCommand(new KisImageResizeCommand(KisImageWSP(this), newSize));
 
-        emitSizeChanged();
+    KisTransformVisitor visitor(KisImageWSP(this), sx, sy, 0.0, 0.0, 0.0, 0, 0, progress, filterStrategy);
+    m_d->rootLayer->accept(visitor);
 
-        unlock();
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
+    m_d->adapter->endMacro();
 
-        if (undo()) {
-            m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
-            m_d->adapter->endMacro();
-        }
-    }
+    setModified();
 }
 void KisImage::rotate(double radians, KoUpdater *progress)
 {
-    lock();
-
     qint32 w = width();
     qint32 h = height();
     qint32 tx = qint32((w * cos(radians) - h * sin(radians) - w) / 2 + 0.5);
@@ -483,28 +432,19 @@ void KisImage::rotate(double radians, KoUpdater *progress)
     tx -= (w - width()) / 2;
     ty -= (h - height()) / 2;
 
-    if (undo()) {
-        m_d->adapter->beginMacro(i18n("Rotate Image"));
-        m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
-    }
+    m_d->adapter->beginMacro(i18n("Rotate Image"));
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
+    m_d->adapter->addCommand(new KisImageResizeCommand(KisImageWSP(this), QSize(w,h)));
 
     KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value("Triangle");
+
     KisTransformVisitor visitor(KisImageWSP(this), 1.0, 1.0, 0, 0, radians, -tx, -ty, progress, filter);
     m_d->rootLayer->accept(visitor);
 
-    if (undo()) m_d->adapter->addCommand(new KisImageResizeCommand(KisImageWSP(this), w, h, width(), height()));
-
-    m_d->width = w;
-    m_d->height = h;
-
-    emitSizeChanged();
-
-    unlock();
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
+    m_d->adapter->endMacro();
 
-    if (undo()) {
-        m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
-        m_d->adapter->endMacro();
-    }
+    setModified();
 }
 
 void KisImage::shear(double angleX, double angleY, KoUpdater *progress)
@@ -531,91 +471,89 @@ void KisImage::shear(double angleX, double angleY, KoUpdater *progress)
             h = (qint32)(height() + qAbs(w * tan(angleY * pi / 180)));
     }
 
-    if (w != width() || h != height()) {
+    QSize newSize(w, h);
+    if(newSize == size()) return;
 
-        lock();
+    m_d->adapter->beginMacro(i18n("Shear Image"));
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
+    m_d->adapter->addCommand(new KisImageResizeCommand(KisImageWSP(this), newSize));
 
-        if (undo()) {
-            m_d->adapter->beginMacro(i18n("Shear Image"));
-            m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
-        }
+    KisShearVisitor visitor(angleX, angleY, progress);
+    visitor.setUndoAdapter(m_d->adapter);
+    rootLayer()->accept(visitor);
 
-        KisShearVisitor v(angleX, angleY, progress);
-        v.setUndoAdapter(m_d->adapter);
-        rootLayer()->accept(v);
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
+    m_d->adapter->endMacro();
 
-        if (undo()) m_d->adapter->addCommand(new KisImageResizeCommand(KisImageWSP(this), w, h, width(), height()));
+    setModified();
+}
 
-        m_d->width = w;
-        m_d->height = h;
+void KisImage::convertImageColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent)
+{
+    if (*m_d->colorSpace == *dstColorSpace) return;
 
-        emitSizeChanged();
+    m_d->adapter->beginMacro(i18n("Convert Image Color Space"));
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
+    m_d->adapter->addCommand(new KisImageSetProjectionColorSpaceCommand(KisImageWSP(this), dstColorSpace));
 
-        unlock();
+    KisColorSpaceConvertVisitor visitor(this, dstColorSpace, renderingIntent);
+    m_d->rootLayer->accept(visitor);
 
-        if (undo()) {
-            m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
-            m_d->adapter->endMacro();
-        }
-    }
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
+    m_d->adapter->endMacro();
+
+    setModified();
 }
 
-void KisImage::convertTo(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent)
+void KisImage::assignImageProfile(const KoColorProfile *profile)
 {
-    if (*m_d->colorSpace == *dstColorSpace) {
-        return;
-    }
+    if(!profile) return;
 
-    lock();
-
-    const KoColorSpace * oldCs = m_d->colorSpace;
+    m_d->adapter->beginMacro(i18n("Assign Profile"));
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
 
-    if (undo()) {
-        m_d->adapter->beginMacro(i18n("Convert Image Type"));
-        m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
-    }
+    const KoColorSpace *dstCs = KoColorSpaceRegistry::instance()->colorSpace(colorSpace()->colorModelId().id(), colorSpace()->colorDepthId().id(), profile);
+    const KoColorSpace *srcCs = colorSpace();
 
-    KisColorSpaceConvertVisitor visitor(this, dstColorSpace, renderingIntent);
+    KisChangeProfileVisitor visitor(srcCs, dstCs);
     m_d->rootLayer->accept(visitor);
 
-    if (undo()) {
-
-        m_d->adapter->addCommand(new KisImageConvertTypeCommand(KisImageWSP(this), oldCs, dstColorSpace));
-        m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
-        m_d->adapter->endMacro();
-    } else {
-        setColorSpace(dstColorSpace);
-    }
-
-    unlock();
-    refreshGraph();
-}
+    m_d->adapter->addCommand(new KisImageSetProjectionColorSpaceCommand(KisImageWSP(this), dstCs));
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
+    m_d->adapter->endMacro();
 
-const KoColorProfile * KisImage::profile() const
-{
-    return colorSpace()->profile();
+    setModified();
+    emit sigProfileChanged(profile);
 }
 
-void KisImage::setProfile(const KoColorProfile *profile)
+void KisImage::convertProjectionColorSpace(const KoColorSpace *dstColorSpace)
 {
-    if (profile == 0) return;
+    if (*m_d->colorSpace == *dstColorSpace) return;
 
-    kDebug() << profile;
-
-    const KoColorSpace *dstCs = KoColorSpaceRegistry::instance()->colorSpace(colorSpace()->colorModelId().id(), colorSpace()->colorDepthId().id(), profile);
-    if (dstCs) {
+    m_d->adapter->beginMacro(i18n("Convert Projection Color Space"));
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), true));
+    m_d->adapter->addCommand(new KisImageSetProjectionColorSpaceCommand(KisImageWSP(this), dstColorSpace));
+    m_d->adapter->addCommand(new KisImageLockCommand(KisImageWSP(this), false));
+    m_d->adapter->endMacro();
 
-        lock();
+    setModified();
+}
 
-        const KoColorSpace *oldCs = colorSpace();
-        setColorSpace(dstCs);
-        emit(sigProfileChanged(const_cast<KoColorProfile*>(profile)));
+void KisImage::setProjectionColorSpace(const KoColorSpace * colorSpace)
+{
+    m_d->colorSpace = colorSpace;
+    m_d->rootLayer->resetCache();
+    emit sigColorSpaceChanged(colorSpace);
+}
 
-        KisChangeProfileVisitor visitor(oldCs, dstCs);
-        m_d->rootLayer->accept(visitor);
+const KoColorSpace * KisImage::colorSpace() const
+{
+    return m_d->colorSpace;
+}
 
-        unlock();
-    }
+const KoColorProfile * KisImage::profile() const
+{
+    return colorSpace()->profile();
 }
 
 double KisImage::xRes() const
@@ -738,16 +676,14 @@ void KisImage::flatten()
         new KisPaintLayer(this, nextLayerName(), OPACITY_OPAQUE_U8, projectionCopy);
     Q_CHECK_PTR(flattenLayer);
 
-    m_d->adapter->beginMacro(i18n("Flatten Image"));
-    m_d->adapter->addCommand(new KisImageChangeLayersCommand(KisImageWSP(this), oldRootLayer, newRootLayer, ""));
-
     addNode(flattenLayer, newRootLayer, 0);
 
-    // notify once again to be sure tools have set
-    // their current paint devices
-    notifyLayersChanged();
-
+    m_d->adapter->beginMacro(i18n("Flatten Image"));
+    // NOTE: KisImageChangeLayersCommand performs all the locking for us
+    m_d->adapter->addCommand(new KisImageChangeLayersCommand(KisImageWSP(this), oldRootLayer, newRootLayer, ""));
     m_d->adapter->endMacro();
+
+    setModified();
 }
 
 // FIXME: Rename to Merge Down?
@@ -777,7 +713,6 @@ KisLayerSP KisImage::mergeLayer(KisLayerSP layer, const KisMetaData::MergeStrate
     KisPaintLayerSP mergedLayer = new KisPaintLayer(this, prevLayer->name(), OPACITY_OPAQUE_U8, mergedDevice);
     Q_CHECK_PTR(mergedLayer);
 
-
     // Merge meta data
     QList<const KisMetaData::Store*> srcs;
     srcs.append(prevLayer->metaData());
@@ -811,7 +746,13 @@ KisLayerSP KisImage::flattenLayer(KisLayerSP layer)
 
     undoAdapter()->beginMacro(i18n("Flatten Layer"));
 
+    /**
+     * Make the copy operation synchronous
+     */
+    lock();
     KisPaintDeviceSP mergedDevice = new KisPaintDevice(*layer->projection());
+    unlock();
+
     KisPaintLayerSP newLayer = new KisPaintLayer(this, layer->name(), layer->opacity(), mergedDevice);
     newLayer->setCompositeOp(layer->compositeOp()->id());
 
@@ -1024,23 +965,6 @@ KisActionRecorder* KisImage::actionRecorder() const
     return m_d->recorder;
 }
 
-bool KisImage::undo() const
-{
-    return (m_d->adapter && m_d->adapter->undo());
-}
-
-const KoColorSpace * KisImage::colorSpace() const
-{
-    return m_d->colorSpace;
-}
-
-void KisImage::setColorSpace(const KoColorSpace * colorSpace)
-{
-    m_d->colorSpace = colorSpace;
-    m_d->rootLayer->resetCache();
-    emit sigColorSpaceChanged(colorSpace);
-}
-
 void KisImage::setRootLayer(KisGroupLayerSP rootLayer)
 {
     if(m_d->rootLayer)
diff --git a/krita/image/kis_image.h b/krita/image/kis_image.h
index e83af97..744c55b 100644
--- a/krita/image/kis_image.h
+++ b/krita/image/kis_image.h
@@ -233,20 +233,29 @@ public:
     /**
      * Convert the image and all its layers to the dstColorSpace
      */
-    void convertTo(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::IntentPerceptual);
+    void convertImageColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::IntentPerceptual);
+
+    /**
+     * Set the color space of  the projection (and the root layer)
+     * to dstColorSpace. No conversion is done for other layers,
+     * their colorspace can differ.
+     * NOTE: Note conversion is done, only regeneration, so no rendering
+     * intent needed
+     */
+    void convertProjectionColorSpace(const KoColorSpace *dstColorSpace);
 
     // Get the profile associated with this image
     const KoColorProfile *  profile() const;
 
     /**
      * Set the profile of the image to the new profile and do the same for
-     * all layers that have the same colorspace and profile as the image.
+     * all layers that have the same colorspace and profile of the image.
      * It doesn't do any pixel conversion.
      *
      * This is essential if you have loaded an image that didn't
      * have an embedded profile to which you want to attach the right profile.
      */
-    void setProfile(const KoColorProfile * profile);
+    void assignImageProfile(const KoColorProfile *profile);
 
     /**
      * Replace the current undo adapter with the specified undo adapter.
@@ -266,11 +275,6 @@ public:
     KisActionRecorder* actionRecorder() const;
 
     /**
-     * Returns true if this image wants undo information, false otherwise
-     */
-    bool undo() const;
-
-    /**
      * Tell the image it's modified; this emits the sigImageModified
      * signal. This happens when the image needs to be saved
      */
@@ -433,8 +437,6 @@ public:
     */
     void notifyLayerUpdated(KisLayerSP layer);
 
-    void setColorSpace(const KoColorSpace * colorSpace);
-
     void setRootLayer(KisGroupLayerSP rootLayer);
 
     /**
@@ -490,7 +492,7 @@ signals:
     void sigImageModified();
 
     void sigSizeChanged(qint32 w, qint32 h);
-    void sigProfileChanged(KoColorProfile *  profile);
+    void sigProfileChanged(const KoColorProfile *  profile);
     void sigColorSpaceChanged(const KoColorSpace*  cs);
     void sigResolutionChanged(double xRes, double yRes);
 
@@ -540,6 +542,11 @@ private:
     void emitSizeChanged();
     void preparePaintLayerAfterAdding(KisLayerSP layer);
 
+    friend class KisImageResizeCommand;
+    void setSize(const QSize& size);
+
+    friend class KisImageSetProjectionColorSpaceCommand;
+    void setProjectionColorSpace(const KoColorSpace * colorSpace);
 private:
     class KisImagePrivate;
     KisImagePrivate * const m_d;
diff --git a/krita/image/kis_paint_device.cc b/krita/image/kis_paint_device.cc
index 7b01a0c..b3758bd 100644
--- a/krita/image/kis_paint_device.cc
+++ b/krita/image/kis_paint_device.cc
@@ -374,21 +374,20 @@ QRect KisPaintDevice::exactBounds() const
 
 void KisPaintDevice::crop(qint32 x, qint32 y, qint32 w, qint32 h)
 {
-    m_datamanager->setExtent(x - m_d->x, y - m_d->y, w, h);
+    crop(QRect(x, y, w, h));
 }
 
 
-void KisPaintDevice::crop(const QRect & r)
+void KisPaintDevice::crop(const QRect &rect)
 {
-    QRect rc(r);
-    rc.translate(-m_d->x, -m_d->y);
-    m_datamanager->setExtent(rc);
+    m_datamanager->setExtent(rect.translated(-m_d->x, -m_d->y));
+    m_d->cache.invalidate();
 }
 
 void KisPaintDevice::setDefaultPixel(const quint8 *defPixel)
 {
-    m_d->cache.invalidate();
     m_datamanager->setDefaultPixel(defPixel);
+    m_d->cache.invalidate();
 }
 
 const quint8 *KisPaintDevice::defaultPixel() const
@@ -398,21 +397,21 @@ const quint8 *KisPaintDevice::defaultPixel() const
 
 void KisPaintDevice::clear()
 {
-    m_d->cache.invalidate();
     m_datamanager->clear();
+    m_d->cache.invalidate();
 }
 
 void KisPaintDevice::fill(qint32 x, qint32 y, qint32 w, qint32 h, const quint8 *fillPixel)
 {
-    m_d->cache.invalidate();
     m_datamanager->clear(x, y, w, h, fillPixel);
+    m_d->cache.invalidate();
 }
 
 
 void KisPaintDevice::clear(const QRect & rc)
 {
-    m_d->cache.invalidate();
     m_datamanager->clear(rc.x(), rc.y(), rc.width(), rc.height(), m_datamanager->defaultPixel());
+    m_d->cache.invalidate();
 }
 
 bool KisPaintDevice::write(KoStore *store)
@@ -425,10 +424,10 @@ bool KisPaintDevice::write(KoStore *store)
 
 bool KisPaintDevice::read(KoStore *store)
 {
-    m_d->cache.invalidate();
     bool retval = m_datamanager->read(store);
-    emit ioProgress(100);
+    m_d->cache.invalidate();
 
+    emit ioProgress(100);
     return retval;
 }
 
diff --git a/krita/image/kis_painter.cc b/krita/image/kis_painter.cc
index 27fe4dd..b291d67 100644
--- a/krita/image/kis_painter.cc
+++ b/krita/image/kis_painter.cc
@@ -156,9 +156,10 @@ void KisPainter::init()
 
 KisPainter::~KisPainter()
 {
-    QUndoCommand* cmd = end();
-    Q_ASSERT(cmd == 0);
-    delete cmd;
+    // TODO: Maybe, don't be that strict?
+    // deleteTransaction();
+    end();
+
     delete d->paintOp;
     delete d->maskPainter;
     delete d->fillPainter;
@@ -176,43 +177,67 @@ void KisPainter::begin(KisPaintDeviceSP device, KisSelectionSP selection)
     d->selection = selection;
     Q_ASSERT(device->colorSpace());
 
-    delete d->transaction;
-    d->transaction = 0;
+    end();
 
     d->device = device;
     d->colorSpace = device->colorSpace();
     d->compositeOp = d->colorSpace->compositeOp(COMPOSITE_OVER);
     d->pixelSize = device->pixelSize();
 }
-QUndoCommand *KisPainter::end()
+
+void KisPainter::end()
 {
-    return endTransaction();
+    Q_ASSERT_X(!d->transaction, "KisPainter::end()",
+               "end() was called for the painter having a transaction. "
+               "Please use end/deleteTransaction() instead");
 }
 
-void KisPainter::beginTransaction(const QString& customName)
+void KisPainter::beginTransaction(const QString& transactionName)
 {
-    delete d->transaction;
-    d->transaction = new KisTransaction(customName, d->device);
+    Q_ASSERT_X(!d->transaction, "KisPainter::beginTransaction()",
+               "You asked for a new transaction while still having "
+               "another one. Please finish the first one with "
+               "end/deleteTransaction() first");
+
+    d->transaction = new KisTransaction(transactionName, d->device);
     Q_CHECK_PTR(d->transaction);
 }
 
-void KisPainter::beginTransaction(KisTransaction* command)
+void KisPainter::endTransaction(KisUndoAdapter *undoAdapter)
 {
+    Q_ASSERT_X(d->transaction, "KisPainter::endTransaction()",
+               "No transaction is in progress");
+
+    d->transaction->commit(undoAdapter);
     delete d->transaction;
-    d->transaction = command;
+    d->transaction = 0;
 }
 
+void KisPainter::deleteTransaction()
+{
+    if (!d->transaction) return;
 
-QUndoCommand* KisPainter::endTransaction()
+    delete d->transaction;
+    d->transaction = 0;
+}
+
+void KisPainter::putTransaction(KisTransaction* transaction)
 {
-    if (!d->transaction) return 0;
+    Q_ASSERT_X(!d->transaction, "KisPainter::putTransaction()",
+               "You asked for a new transaction while still having "
+               "another one. Please finish the first one with "
+               "end/deleteTransaction() first");
 
-    if (d->device)
-        d->device->disconnect(d->transaction);
+    d->transaction = transaction;
+}
 
-    QUndoCommand *command = d->transaction;
+KisTransaction* KisPainter::takeTransaction()
+{
+    Q_ASSERT_X(d->transaction, "KisPainter::takeTransaction()",
+               "No transaction is in progress");
+    KisTransaction *temp = d->transaction;
     d->transaction = 0;
-    return command;
+    return temp;
 }
 
 QRegion KisPainter::dirtyRegion()
diff --git a/krita/image/kis_painter.h b/krita/image/kis_painter.h
index 84a8195..3809bde 100644
--- a/krita/image/kis_painter.h
+++ b/krita/image/kis_painter.h
@@ -42,6 +42,7 @@ class KoUpdater;
 class KoColor;
 class KoCompositeOp;
 
+class KisUndoAdapter;
 class KisTransaction;
 class KisPattern;
 class KisFilterConfiguration;
@@ -93,7 +94,7 @@ public:
     /**
      * Finish painting on the current device
      */
-    QUndoCommand *end();
+    void end();
 
     /**
      * If set, the painter action is cancelable, if the action supports that.
@@ -101,13 +102,23 @@ public:
     void setProgress(KoUpdater * progressUpdater);
 
     /// Begin an undoable paint operation
-    void beginTransaction(const QString& customName = "");
+    void beginTransaction(const QString& transactionName = "");
 
     /// Finish the undoable paint operation
-    QUndoCommand *endTransaction();
+    void endTransaction(KisUndoAdapter *undoAdapter);
 
-    /// begin a transaction with the given command
-    void beginTransaction(KisTransaction* command);
+    /**
+     * Finish the transaction and delete it's undo information.
+     * NOTE: Be careful, because all the previous transactions
+     * will become non-undoable after execution of this method.
+     */
+    void deleteTransaction();
+
+    /// continue a transaction started somewhere else
+    void putTransaction(KisTransaction* transaction);
+
+    /// take transaction out of the reach of KisPainter
+    KisTransaction* takeTransaction();
 
     /// Returns the current paint device.
     const KisPaintDeviceSP device() const;
diff --git a/krita/image/kis_selected_transaction.cc b/krita/image/kis_selected_transaction.cc
deleted file mode 100644
index b62ec1f..0000000
--- a/krita/image/kis_selected_transaction.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
- *
- *  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_selected_transaction.h"
-#include "kis_types.h"
-#include "kis_global.h"
-
-#include "kis_selection.h"
-#include "kis_pixel_selection.h"
-#include "kis_image.h"
-#include "kis_layer.h"
-#include "kis_undo_adapter.h"
-
-KisSelectedTransaction::KisSelectedTransaction(const QString& name, KisNodeSP node, QUndoCommand* parent)
-        : KisTransaction(name, node->paintDevice(), parent)
-        , m_selTransaction(0)
-        , m_hadSelection(false /*device->hasSelection()*/)
-{
-    m_layer = dynamic_cast<KisLayer*>(node.data());
-    while (!m_layer && node->parent()) {
-        m_layer = dynamic_cast<KisLayer*>(node->parent().data());
-        node = node->parent();
-    }
-
-    if (m_layer->selection())
-        m_selTransaction = new KisTransaction(name, KisPaintDeviceSP(m_layer->selection()->getOrCreatePixelSelection().data()));
-//     if(! m_hadSelection) {
-//         m_device->deselect(); // let us not be the cause of select
-//     }
-}
-
-KisSelectedTransaction::~KisSelectedTransaction()
-{
-    delete m_selTransaction;
-}
-
-void KisSelectedTransaction::redo()
-{
-    // Both transactions will block on the first redo
-    KisTransaction::redo();
-
-    if (m_selTransaction)
-        m_selTransaction->redo();
-//     if(m_redoHasSelection)
-//         m_device->selection();
-//     else
-//         m_device->deselect();
-
-    m_layer->setDirty(m_layer->image()->bounds());
-    m_layer->image()->undoAdapter()->emitSelectionChanged();
-}
-
-void KisSelectedTransaction::undo()
-{
-//     m_redoHasSelection = m_device->hasSelection();
-
-    KisTransaction::undo();
-
-    if (m_selTransaction)
-        m_selTransaction->undo();
-//     if(m_hadSelection)
-//         m_device->selection();
-//     else
-//         m_device->deselect();
-//
-    m_layer->setDirty(m_layer->image()->bounds());
-    m_layer->image()->undoAdapter()->emitSelectionChanged();
-}
-
-void KisSelectedTransaction::undoNoUpdate()
-{
-//     m_redoHasSelection = m_device->hasSelection();
-//
-//     KisTransaction::undoNoUpdate();
-//     m_selTransaction->undoNoUpdate();
-//     if(m_hadSelection)
-//         m_device->selection();
-//     else
-//         m_device->deselect();
-}
-
-KisLayerSP KisSelectedTransaction::layer()
-{
-    return m_layer;
-}
diff --git a/krita/image/kis_selected_transaction.h b/krita/image/kis_selected_transaction.h
deleted file mode 100644
index e185895..0000000
--- a/krita/image/kis_selected_transaction.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *  Copyright (c) 2005 Casper Boemann <cbr@boemann.dk>
- *
- *  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_SELECTED_TRANSACTION_H_
-#define KIS_SELECTED_TRANSACTION_H_
-
-#include <map>
-#include <qglobal.h>
-#include <QString>
-
-#include "kis_transaction.h"
-
-#include "krita_export.h"
-
-/**
- * KisSelectedTransaction records changes to the selection for the undo stack. There
- * are two selections in Krita: the global selection and the per-layer selection mask.
- * A particular action only works with one of these selections (in the future, we may
- * want to merge the global and local selection).
- *
- * KisSelectedTransaction remembers which selection was changed.
- */
-class KRITAIMAGE_EXPORT KisSelectedTransaction : public KisTransaction
-{
-
-public:
-    KisSelectedTransaction(const QString& name, KisNodeSP node, QUndoCommand* parent = 0);
-    virtual ~KisSelectedTransaction();
-
-public:
-    void redo();
-    void undo();
-    void undoNoUpdate();
-protected:
-    KisLayerSP layer();
-private:
-    KisLayerSP m_layer;
-    KisTransaction *m_selTransaction;
-    bool m_hadSelection;
-    bool m_redoHasSelection;
-};
-
-#endif // KIS_SELECTED_TRANSACTION_H_
diff --git a/krita/image/kis_selected_transaction_data.cpp b/krita/image/kis_selected_transaction_data.cpp
new file mode 100644
index 0000000..5a958f0
--- /dev/null
+++ b/krita/image/kis_selected_transaction_data.cpp
@@ -0,0 +1,105 @@
+/*
+ *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ *  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_selected_transaction_data.h"
+
+#include "kis_selection.h"
+#include "kis_pixel_selection.h"
+#include "kis_image.h"
+#include "kis_layer.h"
+#include "kis_undo_adapter.h"
+
+KisSelectedTransactionData::KisSelectedTransactionData(const QString& name, KisNodeSP node, QUndoCommand* parent)
+        : KisTransactionData(name, node->paintDevice(), parent)
+        , m_selTransaction(0)
+        , m_hadSelection(false /*device->hasSelection()*/)
+{
+    m_layer = dynamic_cast<KisLayer*>(node.data());
+    while (!m_layer && node->parent()) {
+        m_layer = dynamic_cast<KisLayer*>(node->parent().data());
+        node = node->parent();
+    }
+
+    if (m_layer->selection())
+        m_selTransaction = new KisTransactionData(name, KisPaintDeviceSP(m_layer->selection()->getOrCreatePixelSelection().data()));
+//     if(! m_hadSelection) {
+//         m_device->deselect(); // let us not be the cause of select
+//     }
+}
+
+KisSelectedTransactionData::~KisSelectedTransactionData()
+{
+    delete m_selTransaction;
+}
+
+void KisSelectedTransactionData::redo()
+{
+    // Both transactions will block on the first redo
+    KisTransactionData::redo();
+
+    if (m_selTransaction)
+        m_selTransaction->redo();
+//     if(m_redoHasSelection)
+//         m_device->selection();
+//     else
+//         m_device->deselect();
+
+    m_layer->setDirty(m_layer->image()->bounds());
+    m_layer->image()->undoAdapter()->emitSelectionChanged();
+}
+
+void KisSelectedTransactionData::undo()
+{
+//     m_redoHasSelection = m_device->hasSelection();
+
+    KisTransactionData::undo();
+
+    if (m_selTransaction)
+        m_selTransaction->undo();
+//     if(m_hadSelection)
+//         m_device->selection();
+//     else
+//         m_device->deselect();
+//
+    m_layer->setDirty(m_layer->image()->bounds());
+    m_layer->image()->undoAdapter()->emitSelectionChanged();
+}
+
+void KisSelectedTransactionData::undoNoUpdate()
+{
+//     m_redoHasSelection = m_device->hasSelection();
+//
+//     KisTransactionData::undoNoUpdate();
+//     m_selTransaction->undoNoUpdate();
+//     if(m_hadSelection)
+//         m_device->selection();
+//     else
+//         m_device->deselect();
+}
+
+void KisSelectedTransactionData::endTransaction()
+{
+    KisTransactionData::endTransaction();
+    if(m_selTransaction)
+        m_selTransaction->endTransaction();
+}
+
+KisLayerSP KisSelectedTransactionData::layer()
+{
+    return m_layer;
+}
diff --git a/krita/image/kis_selected_transaction_data.h b/krita/image/kis_selected_transaction_data.h
new file mode 100644
index 0000000..4d97253
--- /dev/null
+++ b/krita/image/kis_selected_transaction_data.h
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2005 Casper Boemann <cbr@boemann.dk>
+ *
+ *  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_SELECTED_TRANSACTION_DATA_H_
+#define KIS_SELECTED_TRANSACTION_DATA_H_
+
+#include "kis_transaction_data.h"
+
+#include "kis_selection.h"
+
+/**
+ * KisSelectedTransactionData records changes to the selection for the undo stack. There
+ * are two selections in Krita: the global selection and the per-layer selection mask.
+ * A particular action only works with one of these selections (in the future, we may
+ * want to merge the global and local selection).
+ *
+ * KisSelectedTransactionData remembers which selection was changed.
+ */
+class KRITAIMAGE_EXPORT KisSelectedTransactionData : public KisTransactionData
+{
+
+public:
+    KisSelectedTransactionData(const QString& name, KisNodeSP node, QUndoCommand* parent = 0);
+    virtual ~KisSelectedTransactionData();
+
+public:
+    void redo();
+    void undo();
+    void undoNoUpdate();
+protected:
+    void endTransaction();
+
+protected:
+    KisLayerSP layer();
+private:
+    KisLayerSP m_layer;
+    KisTransactionData *m_selTransaction;
+    bool m_hadSelection;
+    bool m_redoHasSelection;
+};
+
+#endif // KIS_SELECTED_TRANSACTION_DATA_H_
diff --git a/krita/image/kis_selection_transaction.cc b/krita/image/kis_selection_transaction.cc
deleted file mode 100644
index de40bf6..0000000
--- a/krita/image/kis_selection_transaction.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
- *  Copyright (c) 2008 Sven Langkamp <sven.langkamp@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_selection_transaction.h"
-
-#include "kis_types.h"
-#include "kis_selection.h"
-#include "kis_pixel_selection.h"
-#include "kis_image.h"
-#include "kis_undo_adapter.h"
-
-KisSelectionTransaction::KisSelectionTransaction(const QString& name, KisImageWSP image, KisSelectionSP selection, QUndoCommand* parent) :
-        KisTransaction(name, selection->getOrCreatePixelSelection().data(), parent)
-        , m_image(image)
-        , m_selection(selection)
-        , m_wasDeselected(selection->isDeselected())
-{
-    if (m_selection->isDeselected()) {
-        m_selection->getOrCreatePixelSelection()->clear();
-        m_selection->setDeselected(false);
-    }
-}
-
-KisSelectionTransaction::~KisSelectionTransaction()
-{
-}
-
-void KisSelectionTransaction::redo()
-{
-    KisTransaction::redo();
-    m_selection->setDirty(m_image->bounds());
-    m_image->undoAdapter()->emitSelectionChanged();
-}
-
-void KisSelectionTransaction::undo()
-{
-    KisTransaction::undo();
-    m_selection->setDirty(m_image->bounds());
-    m_selection->setDeselected(m_wasDeselected);
-    m_image->undoAdapter()->emitSelectionChanged();
-}
diff --git a/krita/image/kis_selection_transaction.h b/krita/image/kis_selection_transaction.h
deleted file mode 100644
index 1b22ee3..0000000
--- a/krita/image/kis_selection_transaction.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- *  Copyright (c) 2005 Casper Boemann <cbr@boemann.dk>
- *  Copyright (c) 2008 Sven Langkamp <sven.langkamp@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_SELECTION_TRANSACTION_H_
-#define KIS_SELECTION_TRANSACTION_H_
-
-#include <map>
-#include <qglobal.h>
-#include <QString>
-
-#include "kis_transaction.h"
-
-#include "krita_export.h"
-
-/**
- * KisSelectedTransaction records changes to the selection for the undo stack. There
- * are two selections in Krita: the global selection and the per-layer selection mask.
- * A particular action only works with one of these selections (in the future, we may
- * want to merge the global and local selection).
- *
- * KisSelectedTransaction remembers which selection was changed.
- */
-class KRITAIMAGE_EXPORT KisSelectionTransaction : public KisTransaction
-{
-
-public:
-    KisSelectionTransaction(const QString& name, KisImageWSP image, KisSelectionSP selection, QUndoCommand* parent = 0);
-    virtual ~KisSelectionTransaction();
-
-public:
-    void redo();
-    void undo();
-
-private:
-    KisImageWSP m_image;
-    KisSelectionSP m_selection;
-    bool m_wasDeselected;
-};
-
-#endif // KIS_SELECTION_TRANSACTION_H_
diff --git a/krita/image/kis_selection_transaction_data.cpp b/krita/image/kis_selection_transaction_data.cpp
new file mode 100644
index 0000000..3192404
--- /dev/null
+++ b/krita/image/kis_selection_transaction_data.cpp
@@ -0,0 +1,56 @@
+/*
+ *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *  Copyright (c) 2008 Sven Langkamp <sven.langkamp@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_selection_transaction_data.h"
+
+#include "kis_selection.h"
+#include "kis_pixel_selection.h"
+#include "kis_image.h"
+#include "kis_undo_adapter.h"
+
+KisSelectionTransactionData::KisSelectionTransactionData(const QString& name, KisImageWSP image, KisSelectionSP selection, QUndoCommand* parent) :
+        KisTransactionData(name, selection->getOrCreatePixelSelection().data(), parent)
+        , m_image(image)
+        , m_selection(selection)
+        , m_wasDeselected(selection->isDeselected())
+{
+    if (m_selection->isDeselected()) {
+        m_selection->getOrCreatePixelSelection()->clear();
+        m_selection->setDeselected(false);
+    }
+}
+
+KisSelectionTransactionData::~KisSelectionTransactionData()
+{
+}
+
+void KisSelectionTransactionData::redo()
+{
+    KisTransactionData::redo();
+    m_selection->setDirty(m_image->bounds());
+    m_image->undoAdapter()->emitSelectionChanged();
+}
+
+void KisSelectionTransactionData::undo()
+{
+    KisTransactionData::undo();
+    m_selection->setDirty(m_image->bounds());
+    m_selection->setDeselected(m_wasDeselected);
+    m_image->undoAdapter()->emitSelectionChanged();
+}
diff --git a/krita/image/kis_selection_transaction_data.h b/krita/image/kis_selection_transaction_data.h
new file mode 100644
index 0000000..5e2e3da
--- /dev/null
+++ b/krita/image/kis_selection_transaction_data.h
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2005 Casper Boemann <cbr@boemann.dk>
+ *  Copyright (c) 2008 Sven Langkamp <sven.langkamp@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_SELECTION_TRANSACTION_DATA_H_
+#define KIS_SELECTION_TRANSACTION_DATA_H_
+
+#include "kis_transaction_data.h"
+
+#include "kis_selection.h"
+
+/**
+ * KisSelectionTransactionData records changes to the selection for the undo stack. There
+ * are two selections in Krita: the global selection and the per-layer selection mask.
+ * A particular action only works with one of these selections (in the future, we may
+ * want to merge the global and local selection).
+ *
+ * KisSelectionTransactionData remembers which selection was changed.
+ */
+class KRITAIMAGE_EXPORT KisSelectionTransactionData : public KisTransactionData
+{
+
+public:
+    KisSelectionTransactionData(const QString& name, KisImageWSP image, KisSelectionSP selection, QUndoCommand* parent = 0);
+    virtual ~KisSelectionTransactionData();
+
+public:
+    void redo();
+    void undo();
+
+private:
+    KisImageWSP m_image;
+    KisSelectionSP m_selection;
+    bool m_wasDeselected;
+};
+
+#endif /* KIS_SELECTION_TRANSACTION_DATA_H_ */
diff --git a/krita/image/kis_shear_visitor.h b/krita/image/kis_shear_visitor.h
index d84e00c..a98f40a 100644
--- a/krita/image/kis_shear_visitor.h
+++ b/krita/image/kis_shear_visitor.h
@@ -41,13 +41,13 @@ public:
     using KisNodeVisitor::visit;
 
     KisShearVisitor(double xshear, double yshear, KoUpdater *progress)
-            : m_xshear(xshear), m_yshear(yshear), m_progress(progress), m_strategy(0), m_undo(0) {}
+            : m_xshear(xshear), m_yshear(yshear), m_progress(progress), m_strategy(0), m_undoAdapter(0) {}
 
     void setStrategy(KisFilterStrategy* strategy) {
         m_strategy = strategy;
     }
-    void setUndoAdapter(KisUndoAdapter* undo) {
-        m_undo = undo;
+    void setUndoAdapter(KisUndoAdapter* undoAdapter) {
+        m_undoAdapter = undoAdapter;
     }
 public:
 
@@ -66,10 +66,7 @@ public:
         else
             strategy = new KisMitchellFilterStrategy;
 
-        KisTransaction* t = 0;
-
-        if (m_undo && m_undo->undo())
-            t = new KisTransaction("", dev);
+        KisTransaction transaction("", dev);
 
         //Doesn't do anything, internally transforms x and y shear to 0 each :-///
         //KisTransformWorker w(dev, 1.0, 1.0, m_xshear, m_yshear, 0, 0, 0, m_progress, strategy);
@@ -77,8 +74,10 @@ public:
 
         shear(dev, m_xshear, m_yshear, m_progress);
 
-        if (m_undo && m_undo->undo())
-            m_undo->addCommand(t);
+        if (m_undoAdapter)
+            transaction.commit(m_undoAdapter);
+        else
+            transaction.end();
 
         if (!m_strategy)
             delete strategy;
@@ -133,7 +132,7 @@ private:
     double m_yshear;
     KoUpdater* m_progress;
     KisFilterStrategy* m_strategy;
-    KisUndoAdapter* m_undo;
+    KisUndoAdapter* m_undoAdapter;
 };
 
 #endif // KIS_SHEAR_VISITOR_H_
diff --git a/krita/image/kis_transaction.cc b/krita/image/kis_transaction.cc
deleted file mode 100644
index dfc9683..0000000
--- a/krita/image/kis_transaction.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
- *
- *  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_transaction.h"
-
-
-#include "kis_types.h"
-#include "kis_global.h"
-#include "kis_paint_device.h"
-#include "kis_datamanager.h"
-
-#include "config-tiles.h" // For the next define
-#include KIS_MEMENTO_HEADER
-
-
-class KisTransaction::Private
-{
-public:
-    QString name;
-    KisPaintDeviceSP device;
-    KisMementoSP memento;
-    bool firstRedo;
-};
-
-KisTransaction::KisTransaction(const QString& name, KisPaintDeviceSP device, QUndoCommand* parent)
-        : QUndoCommand(name, parent)
-        , m_d(new Private())
-{
-    m_d->device = device;
-    m_d->memento = device->dataManager()->getMemento();
-    m_d->firstRedo = true;
-}
-
-KisTransaction::~KisTransaction()
-{
-    if (m_d->memento) {
-        m_d->memento->setInvalid();
-        m_d->device->dataManager()->purgeHistory(m_d->memento);
-    }
-    delete m_d;
-}
-
-void KisTransaction::redo()
-{
-    //QUndoStack calls redo(), so the first call needs to be blocked
-    if (m_d->firstRedo) {
-        m_d->firstRedo = false;
-        return;
-    }
-
-    Q_ASSERT(!m_d->memento.isNull());
-
-    m_d->device->dataManager()->rollforward(m_d->memento);
-
-    QRect rc;
-    qint32 x, y, width, height;
-    m_d->memento->extent(x, y, width, height);
-    rc.setRect(x + m_d->device->x(), y + m_d->device->y(), width, height);
-
-    m_d->device->setDirty(rc);
-}
-
-void KisTransaction::undo()
-{
-    Q_ASSERT(!m_d->memento.isNull());
-    m_d->device->dataManager()->rollback(m_d->memento);
-
-    QRect rc;
-    qint32 x, y, width, height;
-    m_d->memento->extent(x, y, width, height);
-    rc.setRect(x + m_d->device->x(), y + m_d->device->y(), width, height);
-
-    m_d->device->setDirty(rc);
-}
-
-void KisTransaction::undoNoUpdate()
-{
-    Q_ASSERT(!m_d->memento.isNull());
-    m_d->device->dataManager()->rollback(m_d->memento);
-}
-
-#include "kis_transaction.moc"
diff --git a/krita/image/kis_transaction.h b/krita/image/kis_transaction.h
index 81d2baf..7b61d0e 100644
--- a/krita/image/kis_transaction.h
+++ b/krita/image/kis_transaction.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *  Copyright (c) 2010 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
@@ -19,40 +19,99 @@
 #ifndef KIS_TRANSACTION_H_
 #define KIS_TRANSACTION_H_
 
-#include <QString>
 #include <QUndoCommand>
 
 #include "kis_types.h"
 #include <krita_export.h>
 
-/**
- * A tile based undo command.
- *
- * Ordinary QUndoCommand subclasses store parameters and apply the action in
- * the redo() command, however, Krita doesn't work like this. Undo replaces
- * the current tiles in a paint device with the old tiles, redo replaces them
- * again with the new tiles without actually executing the command that changed
- * the image data again.
- */
-class KRITAIMAGE_EXPORT KisTransaction : public QObject, public QUndoCommand
-{
+#include "kis_transaction_data.h"
+#include "kis_selection_transaction_data.h"
+#include "kis_selected_transaction_data.h"
+#include "kis_paint_device.h"
 
-    Q_OBJECT
+#include "kis_undo_adapter.h"
 
+class KisTransaction
+{
 public:
+    KisTransaction(const QString& name, KisPaintDeviceSP device, QUndoCommand* parent = 0) {
+        m_transactionData = new KisTransactionData(name, device, parent);
+    }
+
+    virtual ~KisTransaction() {
+        if(m_transactionData) {
+            m_transactionData->endTransaction();
+            delete m_transactionData;
+        }
+    }
+
+    QUndoCommand* undoCommand() {
+        return m_transactionData;
+    }
+
+    void commit(KisUndoAdapter* undoAdapter) {
+        Q_ASSERT_X(m_transactionData, "KisTransaction::commit()",
+                   "the transaction has been tried to be committed twice");
+
+        m_transactionData->endTransaction();
+        undoAdapter->addCommand(m_transactionData);
+        m_transactionData = 0;
+    }
+
+    void end() {
+        Q_ASSERT_X(m_transactionData, "KisTransaction::end()",
+                   "nothing to end!");
+        m_transactionData->endTransaction();
+        delete m_transactionData;
+        m_transactionData = 0;
+    }
 
-    KisTransaction(const QString& name, KisPaintDeviceSP device, QUndoCommand* parent = 0);
-    virtual ~KisTransaction();
+    void revert() {
+        Q_ASSERT_X(m_transactionData, "KisTransaction::reverted()",
+                   "the transaction is tried to be reverted()"
+                   "after it has already been added to undo adapter");
 
+        m_transactionData->endTransaction();
+        /**
+         * FIXME: Should we emulate first redo() here?
+         */
+        m_transactionData->undo();
+        delete m_transactionData;
+        m_transactionData = 0;
+    }
+/*
+    QUndoCommand* endAndTakeUndoCommand() {
+        Q_ASSERT_X(m_transactionData, "KisTransaction::endAndTakeUndoCommand()",
+                   "the transaction has been tried to be ended twice");
+
+        m_transactionData->endTransaction();
+        QUndoCommand *command = m_transactionData;
+        m_transactionData = 0;
+        return command;
+    }
+*/
+protected:
+    KisTransaction() {}
+    KisTransactionData* m_transactionData;
+};
+
+class KisSelectedTransaction : public KisTransaction
+{
 public:
-    virtual void redo();
-    virtual void undo();
-    virtual void undoNoUpdate();
+    KisSelectedTransaction(const QString& name, KisNodeSP node, QUndoCommand* parent = 0)
+    {
+        m_transactionData = new KisSelectedTransactionData(name, node, parent);
+    }
+};
 
-private:
-    class Private;
-    Private * const m_d;
+class KisSelectionTransaction : public KisTransaction
+{
+public:
+    KisSelectionTransaction(const QString& name, KisImageWSP image, KisSelectionSP selection, QUndoCommand* parent = 0)
+    {
+        m_transactionData = new KisSelectionTransactionData(name, image, selection, parent);
+    }
 };
 
-#endif // KIS_TILE_COMMAND_H_
+#endif /* KIS_TRANSACTION_H_ */
 
diff --git a/krita/image/kis_transaction_data.cpp b/krita/image/kis_transaction_data.cpp
new file mode 100644
index 0000000..69eb743
--- /dev/null
+++ b/krita/image/kis_transaction_data.cpp
@@ -0,0 +1,116 @@
+/*
+ *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ *  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_transaction_data.h"
+
+#include "kis_paint_device.h"
+#include "kis_datamanager.h"
+
+#include "config-tiles.h" // For the next define
+#include KIS_MEMENTO_HEADER
+
+
+//#define DEBUG_TRANSACTIONS
+
+#ifdef DEBUG_TRANSACTIONS
+    #define DEBUG_ACTION(action) qDebug() << action << "for" << m_d->device->dataManager()
+#else
+    #define DEBUG_ACTION(action)
+#endif
+
+
+class KisTransactionData::Private
+{
+public:
+    QString name;
+    KisPaintDeviceSP device;
+    KisMementoSP memento;
+    bool firstRedo;
+    bool transactionFinished;
+};
+
+KisTransactionData::KisTransactionData(const QString& name, KisPaintDeviceSP device, QUndoCommand* parent)
+        : QUndoCommand(name, parent)
+        , m_d(new Private())
+{
+    m_d->device = device;
+    DEBUG_ACTION("Transaction started");
+    m_d->memento = device->dataManager()->getMemento();
+    m_d->firstRedo = true;
+    m_d->transactionFinished = false;
+}
+
+KisTransactionData::~KisTransactionData()
+{
+    Q_ASSERT(m_d->memento);
+    endTransaction();
+    m_d->device->dataManager()->purgeHistory(m_d->memento);
+
+    delete m_d;
+}
+
+void KisTransactionData::endTransaction()
+{
+    if(!m_d->transactionFinished) {
+        DEBUG_ACTION("Transaction ended");
+        m_d->transactionFinished = true;
+        m_d->device->dataManager()->commit();
+    }
+}
+
+void KisTransactionData::redo()
+{
+    //QUndoStack calls redo(), so the first call needs to be blocked
+    if (m_d->firstRedo) {
+        m_d->firstRedo = false;
+        return;
+    }
+
+    DEBUG_ACTION("Redo()");
+
+    Q_ASSERT(m_d->memento);
+    m_d->device->dataManager()->rollforward(m_d->memento);
+
+    QRect rc;
+    qint32 x, y, width, height;
+    m_d->memento->extent(x, y, width, height);
+    rc.setRect(x + m_d->device->x(), y + m_d->device->y(), width, height);
+
+    m_d->device->setDirty(rc);
+}
+
+void KisTransactionData::undo()
+{
+    DEBUG_ACTION("Undo()");
+
+    Q_ASSERT(m_d->memento);
+    m_d->device->dataManager()->rollback(m_d->memento);
+
+    QRect rc;
+    qint32 x, y, width, height;
+    m_d->memento->extent(x, y, width, height);
+    rc.setRect(x + m_d->device->x(), y + m_d->device->y(), width, height);
+
+    m_d->device->setDirty(rc);
+}
+
+void KisTransactionData::undoNoUpdate()
+{
+    Q_ASSERT(m_d->memento);
+    m_d->device->dataManager()->rollback(m_d->memento);
+}
diff --git a/krita/image/kis_transaction_data.h b/krita/image/kis_transaction_data.h
new file mode 100644
index 0000000..6b65aa0
--- /dev/null
+++ b/krita/image/kis_transaction_data.h
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ *  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_TRANSACTION_DATA_H_
+#define KIS_TRANSACTION_DATA_H_
+
+#include <QUndoCommand>
+
+#include "kis_types.h"
+#include <krita_export.h>
+
+/**
+ * A tile based undo command.
+ *
+ * Ordinary QUndoCommand subclasses store parameters and apply the action in
+ * the redo() command, however, Krita doesn't work like this. Undo replaces
+ * the current tiles in a paint device with the old tiles, redo replaces them
+ * again with the new tiles without actually executing the command that changed
+ * the image data again.
+ */
+class KRITAIMAGE_EXPORT KisTransactionData : public QUndoCommand
+{
+public:
+    KisTransactionData(const QString& name, KisPaintDeviceSP device, QUndoCommand* parent = 0);
+    virtual ~KisTransactionData();
+
+public:
+    virtual void redo();
+    virtual void undo();
+
+    virtual void endTransaction();
+
+protected:
+    virtual void undoNoUpdate();
+
+private:
+    class Private;
+    Private * const m_d;
+};
+
+#endif /* KIS_TRANSACTION_DATA_H_ */
+
diff --git a/krita/image/kis_transform_visitor.h b/krita/image/kis_transform_visitor.h
index d4cfbf4..22e18f4 100644
--- a/krita/image/kis_transform_visitor.h
+++ b/krita/image/kis_transform_visitor.h
@@ -28,9 +28,8 @@
 #include "kis_group_layer.h"
 #include "kis_paint_layer.h"
 #include "kis_adjustment_layer.h"
-#include "kis_transaction.h"
 #include "kis_transform_worker.h"
-#include "kis_selected_transaction.h"
+#include "kis_transaction.h"
 #include "kis_external_layer_iface.h"
 #include "kis_undo_adapter.h"
 #include "kis_image.h"
@@ -66,11 +65,10 @@ public:
 
     bool visit(KisExternalLayer * layer) {
         KisUndoAdapter* undoAdapter = layer->image()->undoAdapter();
-        
-        QUndoCommand* cmd = layer->transform(m_sx, m_sy, 0.0, 0.0, m_angle, m_tx, m_ty);
-        if (cmd && undoAdapter && undoAdapter->undo()) {
-            undoAdapter->addCommand(cmd);
-        }
+
+        QUndoCommand* command = layer->transform(m_sx, m_sy, 0.0, 0.0, m_angle, m_tx, m_ty);
+        if (command)
+            undoAdapter->addCommand(command);
         return true;
     }
 
@@ -131,18 +129,12 @@ private:
     void transformPaintDevice(KisNode * node) {
         KisPaintDeviceSP dev = node->paintDevice();
 
-        KisTransaction * t = 0;
-        if (m_image->undo()) {
-            t = new KisTransaction(i18n("Rotate Node"), dev);
-            Q_CHECK_PTR(t);
-        }
+        KisTransaction transaction(i18n("Rotate Node"), dev);
 
         KisTransformWorker tw(dev, m_sx, m_sy, 0.0, 0.0, m_angle, m_tx, m_ty, m_progress, m_filter, true);
         tw.run();
 
-        if (m_image->undo()) {
-            m_image->undoAdapter()->addCommand(t);
-        }
+        transaction.commit(m_image->undoAdapter());
         node->setDirty();
     }
 
diff --git a/krita/image/kis_undo_adapter.cc b/krita/image/kis_undo_adapter.cc
index dc0bf6f..a1a0ff7 100644
--- a/krita/image/kis_undo_adapter.cc
+++ b/krita/image/kis_undo_adapter.cc
@@ -24,7 +24,6 @@
 
 KisUndoAdapter::KisUndoAdapter(KoDocument* doc): m_doc(doc)
 {
-    m_undo = true;
 }
 
 KisUndoAdapter::~KisUndoAdapter()
@@ -86,16 +85,6 @@ void KisUndoAdapter::undoLastCommand()
     m_doc->undoStack()->undo();
 }
 
-void KisUndoAdapter::setUndo(bool undo)
-{
-    m_undo = undo;
-}
-
-bool KisUndoAdapter::undo() const
-{
-    return m_undo;
-}
-
 void KisUndoAdapter::beginMacro(const QString& macroName)
 {
     m_doc->beginMacro(macroName);
diff --git a/krita/image/kis_undo_adapter.h b/krita/image/kis_undo_adapter.h
index 36690b2..ed9201d 100644
--- a/krita/image/kis_undo_adapter.h
+++ b/krita/image/kis_undo_adapter.h
@@ -62,8 +62,6 @@ public:
     virtual const QUndoCommand * presentCommand();
     virtual void addCommand(QUndoCommand *cmd);
     virtual void undoLastCommand();
-    virtual void setUndo(bool undo);
-    virtual bool undo() const;
 
     /// XXX: is this actually threadsafe?
     virtual void beginMacro(const QString& macroName);
@@ -82,7 +80,6 @@ private:
 
     QVector<KisCommandHistoryListener*> m_undoListeners;
     KoDocument* m_doc;
-    bool m_undo;
 };
 
 
diff --git a/krita/image/recorder/kis_recorded_filter_action.cpp b/krita/image/recorder/kis_recorded_filter_action.cpp
index c63d103..f65839a 100644
--- a/krita/image/recorder/kis_recorded_filter_action.cpp
+++ b/krita/image/recorder/kis_recorded_filter_action.cpp
@@ -92,10 +92,8 @@ void KisRecordedFilterAction::play(KisNodeSP node, const KisPlayInfo& info) cons
     foreach(KisNodeSP node, nodes) {
         KisPaintDeviceSP dev = node->paintDevice();
         KisLayerSP layer = dynamic_cast<KisLayer*>(node.data());
-        KisTransaction * cmd = 0;
-        if (info.undoAdapter()) cmd = new KisTransaction(d->filter->name(), dev);
-
         QRect r1 = dev->extent();
+        KisTransaction transaction(d->filter->name(), dev);
 
         // Ugly hack to get at the image without bloating the node interface
         KisImageWSP image;
@@ -108,7 +106,8 @@ void KisRecordedFilterAction::play(KisNodeSP node, const KisPlayInfo& info) cons
 
         d->filter->process(dev, r1, kfc);
         node->setDirty(r1);
-        if (info.undoAdapter()) info.undoAdapter()->addCommand(cmd);
+
+        transaction.commit(info.undoAdapter());
     }
 }
 
diff --git a/krita/image/recorder/kis_recorded_paint_action.cpp b/krita/image/recorder/kis_recorded_paint_action.cpp
index bdbedae..af84c94 100644
--- a/krita/image/recorder/kis_recorded_paint_action.cpp
+++ b/krita/image/recorder/kis_recorded_paint_action.cpp
@@ -270,8 +270,7 @@ void KisRecordedPaintAction::play(KisNodeSP node, const KisPlayInfo& info) const
     QList<KisNodeSP> nodes = nodeQueryPath().queryNodes(info.image(), info.currentNode());
     foreach(KisNodeSP node, nodes) {
         dbgUI << "Play recorded paint action on node : " << node->name() ;
-        KisTransaction * cmd = 0;
-        if (info.undoAdapter()) cmd = new KisTransaction("", node->paintDevice());
+        KisTransaction transaction("", node->paintDevice());
 
         KisPaintDeviceSP target = 0;
         if (d->paintIncremental) {
@@ -326,9 +325,11 @@ void KisRecordedPaintAction::play(KisNodeSP node, const KisPlayInfo& info) const
             node->setDirty(painter->dirtyRegion());
         }
         delete painter;
-        if (info.undoAdapter()) info.undoAdapter()->addCommand(cmd);
+
         if (d->paintOpPreset)
             d->paintOpPreset->settings()->setNode(0);
+
+        transaction.commit(info.undoAdapter());
     }
 }
 
diff --git a/krita/image/tests/kis_filter_selections_benchmark.cpp b/krita/image/tests/kis_filter_selections_benchmark.cpp
index a47b7d2..dffb880 100644
--- a/krita/image/tests/kis_filter_selections_benchmark.cpp
+++ b/krita/image/tests/kis_filter_selections_benchmark.cpp
@@ -256,7 +256,7 @@ void KisFilterSelectionsBenchmark::testBitBltWOSelections(int num)
         painter.beginTransaction("");
         painter.setCompositeOp(projection->colorSpace()->compositeOp(COMPOSITE_ALPHA_DARKEN));
         painter.bitBlt(filterRect.topLeft(), cacheDevice, filterRect);
-        delete painter.endTransaction();
+        painter.deleteTransaction();
     }
     avTime = double(timer.elapsed()) / num;
 
@@ -291,7 +291,7 @@ void KisFilterSelectionsBenchmark::testBitBltSelections(int num)
         gc.setCompositeOp(projection->colorSpace()->compositeOp(COMPOSITE_ALPHA_DARKEN));
         gc.setSelection(m_selection);
         gc.bitBlt(filterRect.topLeft(), cacheDevice, filterRect);
-        delete gc.endTransaction();
+        gc.deleteTransaction();
     }
     avTime = double(timer.elapsed()) / num;
 
diff --git a/krita/image/tests/kis_paint_device_test.cpp b/krita/image/tests/kis_paint_device_test.cpp
index a79dfa9..146f3b0 100644
--- a/krita/image/tests/kis_paint_device_test.cpp
+++ b/krita/image/tests/kis_paint_device_test.cpp
@@ -418,7 +418,9 @@ void KisPaintDeviceTest::testDeviceDuplication()
     KisTransaction transaction1("", device);
 //    qDebug()<<"CLEARING";
     device->clear(clearRect);
-    transaction1.undo();
+
+    transaction1.revert();
+
     resultImage = device->convertToQImage(0);
     QVERIFY(resultImage == referenceImage);
 
@@ -427,7 +429,9 @@ void KisPaintDeviceTest::testDeviceDuplication()
     KisTransaction transaction("", clone);
 //    qDebug()<<"CLEARING";
     clone->clear(clearRect);
-    transaction.undo();
+
+    transaction.revert();
+
     resultImage = clone->convertToQImage(0);
     QVERIFY(resultImage == referenceImage);
 
diff --git a/krita/image/tests/kis_selected_transaction_test.cpp b/krita/image/tests/kis_selected_transaction_test.cpp
index e3951a8..fe9ab97 100644
--- a/krita/image/tests/kis_selected_transaction_test.cpp
+++ b/krita/image/tests/kis_selected_transaction_test.cpp
@@ -19,7 +19,7 @@
 #include "kis_selected_transaction_test.h"
 
 #include <qtest_kde.h>
-#include "kis_selected_transaction.h"
+#include "kis_transaction.h"
 #include <KoColorSpace.h>
 #include "kis_image.h"
 #include "kis_paint_layer.h"
@@ -39,6 +39,5 @@ void KisSelectedTransactionTest::testCreation()
 
 }
 
-
 QTEST_KDEMAIN(KisSelectedTransactionTest, GUI)
 #include "kis_selected_transaction_test.moc"
diff --git a/krita/image/tests/kis_transaction_test.cpp b/krita/image/tests/kis_transaction_test.cpp
index 989e072..c87ef54 100644
--- a/krita/image/tests/kis_transaction_test.cpp
+++ b/krita/image/tests/kis_transaction_test.cpp
@@ -29,9 +29,32 @@
 #include "kis_paint_device.h"
 #include "kis_transaction.h"
 
+class KisTestingUndoAdapter : public KisUndoAdapter
+{
+public:
+    KisTestingUndoAdapter()
+        : KisUndoAdapter(0)
+    {}
+
+    void addCommand(QUndoCommand *command) {
+        m_stack.push(command);
+    }
+
+    void undo() {
+        m_stack.undo();
+    }
+
+    void redo() {
+        m_stack.redo();
+    }
+
+private:
+    QUndoStack m_stack;
+};
+
 void KisTransactionTest::testUndo()
 {
-    QUndoStack stack;
+    KisTestingUndoAdapter undoAdapter;
 
     const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
     KisPaintDeviceSP dev = new KisPaintDevice(cs);
@@ -50,9 +73,8 @@ void KisTransactionTest::testUndo()
     QVERIFY(c1 == Qt::white);
     QVERIFY(c2 == Qt::black);
 
-    KisTransaction* t = new KisTransaction("mirror", dev, 0);
+    KisTransaction transaction("mirror", dev, 0);
     KisTransformWorker::mirrorX(dev);
-    stack.push(t);
 
     dev->pixel(5, 5, &c1);
     dev->pixel(517, 5, &c2);
@@ -60,7 +82,8 @@ void KisTransactionTest::testUndo()
     QVERIFY(c1 == Qt::black);
     QVERIFY(c2 == Qt::white);
 
-    t->undo();
+    transaction.commit(&undoAdapter);
+    undoAdapter.undo();
 
     dev->pixel(5, 5, &c1);
     dev->pixel(517, 5, &c2);
@@ -72,7 +95,7 @@ void KisTransactionTest::testUndo()
 
 void KisTransactionTest::testRedo()
 {
-    QUndoStack stack;
+    KisTestingUndoAdapter undoAdapter;
 
     const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
     KisPaintDeviceSP dev = new KisPaintDevice(cs);
@@ -91,9 +114,8 @@ void KisTransactionTest::testRedo()
     QVERIFY(c1 == Qt::white);
     QVERIFY(c2 == Qt::black);
 
-    KisTransaction* t = new KisTransaction("mirror", dev, 0);
+    KisTransaction transaction("mirror", dev, 0);
     KisTransformWorker::mirrorX(dev);
-    stack.push(t);
 
     dev->pixel(5, 5, &c1);
     dev->pixel(517, 5, &c2);
@@ -101,7 +123,8 @@ void KisTransactionTest::testRedo()
     QVERIFY(c1 == Qt::black);
     QVERIFY(c2 == Qt::white);
 
-    t->undo();
+    transaction.commit(&undoAdapter);
+    undoAdapter.undo();
 
     dev->pixel(5, 5, &c1);
     dev->pixel(517, 5, &c2);
@@ -109,7 +132,7 @@ void KisTransactionTest::testRedo()
     QVERIFY(c1 == Qt::white);
     QVERIFY(c2 == Qt::black);
 
-    t->redo();
+    undoAdapter.redo();
 
     dev->pixel(5, 5, &c1);
     dev->pixel(517, 5, &c2);
diff --git a/krita/image/tests/kis_transform_worker_test.cpp b/krita/image/tests/kis_transform_worker_test.cpp
index aec8481..f7b9a81 100644
--- a/krita/image/tests/kis_transform_worker_test.cpp
+++ b/krita/image/tests/kis_transform_worker_test.cpp
@@ -127,7 +127,7 @@ void KisTransformWorkerTest::testMirrorTransaction()
     QVERIFY(c2 == Qt::black);
     dev->convertToQImage(0, 0, 0, 1024, 512).save("transaction_before.png");
 
-    KisTransaction* t = new KisTransaction("mirror", dev, 0);
+    KisTransaction transaction1("mirror", dev);
     KisTransformWorker::mirrorX(dev);
 
     dev->pixel(5, 5, &c1);
@@ -149,7 +149,9 @@ void KisTransformWorkerTest::testMirrorTransaction()
     QVERIFY(c1 == Qt::white);
     QVERIFY(c2 == Qt::black);
 
-    KisTransaction* t2 = new KisTransaction("mirror", dev, 0);
+    transaction1.end();
+
+    KisTransaction transaction2("mirror", dev);
     KisTransformWorker::mirrorY(dev);
     dev->convertToQImage(0, 0, 0, 1024, 512).save("transaction_mirror_y.png");
 
@@ -159,17 +161,16 @@ void KisTransformWorkerTest::testMirrorTransaction()
     QVERIFY(c1 == Qt::black);
     QVERIFY(c2 == Qt::white);
 
+    transaction2.end();
 
     {
         QImage image(QString(FILES_DATA_DIR) + QDir::separator() + "mirror_source.png");
         KisPaintDeviceSP dev2 = new KisPaintDevice(cs);
         dev2->convertFromQImage(image, "");
-        KisTransaction t("mirror", dev2, 0);
+        KisTransaction t("mirror", dev2);
         KisTransformWorker::mirrorX(dev2);
         dev2->convertToQImage(0, 0, 0, image.width(), image.height()).save("mirror_test_t_2.png");
     }
-    delete t;
-    delete t2;
 }
 
 
diff --git a/krita/image/tiles3/kis_memento.h b/krita/image/tiles3/kis_memento.h
index 9c09b67..7698413 100644
--- a/krita/image/tiles3/kis_memento.h
+++ b/krita/image/tiles3/kis_memento.h
@@ -75,16 +75,16 @@ public:
         return false; // Compiller would be happy! =)
     }
 
+
     /**
-     * Some tricky equivalet to 'commit()'
-     * FIXME: do a usual commit instead
+     * Not used, happily
      */
-    inline bool valid() const {
-        return m_valid;
-    }
-    inline void setInvalid() {
-        m_valid = false;
-    }
+//    inline bool valid() const {
+//        return m_valid;
+//    }
+//    inline void setInvalid() {
+//        m_valid = false;
+//    }
 
 private:
     friend class KisMementoManager;
diff --git a/krita/image/tiles3/kis_memento_manager.cc b/krita/image/tiles3/kis_memento_manager.cc
index e6c71ea..a2260e1 100644
--- a/krita/image/tiles3/kis_memento_manager.cc
+++ b/krita/image/tiles3/kis_memento_manager.cc
@@ -46,19 +46,42 @@
 #endif
 
 
+/**
+ * The class is supposed to store the changes of the paint device
+ * it is associated with. The history of changes is presented in form
+ * of transactions (revisions). If you purge the history of one
+ * transaction (revision) with purgeHistory() we won't be able to undo
+ * the changes made by this transactions.
+ *
+ * The Memento Manager can be in two states:
+ *     - Named Transaction is in progress - it means the caller
+ *       has explicitly requested creation of a new transaction.
+ *       The handle for the transaction is stored on a side of
+ *       the caller. And the history will be automatically purged
+ *       when the handler dies.
+ *     - Anonymous Transaction is in progress - the caller isn't
+ *       bothered about transactions at all. We pretend as we do
+ *       not support any versioning and do not have any historical
+ *       information. The history of such transactions is not purged
+ *       automatically, but it is free'd when younger named transaction
+ *       is purged.
+ */
+
+#define blockRegistration() (m_registrationBlocked = true)
+#define unblockRegistration() (m_registrationBlocked = false)
+#define registrationBlocked() (m_registrationBlocked)
+
+#define namedTransactionInProgress() ((bool)m_currentMemento)
+
 KisMementoManager::KisMementoManager()
     : m_index(0),
-      m_headsHashTable(0)
+      m_headsHashTable(0),
+      m_registrationBlocked(false)
 {
     /**
-     * Get an initial memento to show we want history for ALL the devices.
-     * If we don't do it, we won't be able to start history later,
-     * as we don't have any special api for this.
-     * It shouldn't create much overhead for unversioned devices as
-     * no tile-duplication accurs without calling a commit()
-     * method regularily.
+     * Tile change/delete registration is enabled for all
+     * devices by default. It can't be delayed.
      */
-    (void) getMemento();
 }
 
 KisMementoManager::KisMementoManager(const KisMementoManager& rhs)
@@ -66,11 +89,12 @@ KisMementoManager::KisMementoManager(const KisMementoManager& rhs)
         m_revisions(rhs.m_revisions),
         m_cancelledRevisions(rhs.m_cancelledRevisions),
         m_headsHashTable(rhs.m_headsHashTable, 0),
-        m_currentMemento(rhs.m_currentMemento)
+        m_currentMemento(rhs.m_currentMemento),
+        m_registrationBlocked(rhs.m_registrationBlocked)
 {
-    Q_ASSERT_X(m_currentMemento,
+    Q_ASSERT_X(!m_registrationBlocked,
                "KisMementoManager", "(impossible happened) "
-               "Seems like a device was created without history support");
+               "The device has been copied while registration was blocked");
 }
 
 KisMementoManager::~KisMementoManager()
@@ -100,7 +124,7 @@ KisMementoManager::~KisMementoManager()
 
 void KisMementoManager::registerTileChange(KisTile *tile)
 {
-    if (!m_currentMemento) return;
+    if (registrationBlocked()) return;
     m_cancelledRevisions.clear();
 
     DEBUG_LOG_TILE_ACTION("reg. [C]", tile, tile->col(), tile->row());
@@ -111,7 +135,9 @@ void KisMementoManager::registerTileChange(KisTile *tile)
         mi = new KisMementoItem();
         mi->changeTile(tile);
         m_index.addTile(mi);
-        m_currentMemento->updateExtent(mi->col(), mi->row());
+
+        if(namedTransactionInProgress())
+            m_currentMemento->updateExtent(mi->col(), mi->row());
     }
     else {
         mi->reset();
@@ -121,7 +147,7 @@ void KisMementoManager::registerTileChange(KisTile *tile)
 
 void KisMementoManager::registerTileDeleted(KisTile *tile)
 {
-    if (!m_currentMemento) return;
+    if (registrationBlocked()) return;
     m_cancelledRevisions.clear();
 
     DEBUG_LOG_TILE_ACTION("reg. [D]", tile, tile->col(), tile->row());
@@ -132,7 +158,9 @@ void KisMementoManager::registerTileDeleted(KisTile *tile)
         mi = new KisMementoItem();
         mi->deleteTile(tile, m_headsHashTable.defaultTileData());
         m_index.addTile(mi);
-        m_currentMemento->updateExtent(mi->col(), mi->row());
+
+        if(namedTransactionInProgress())
+            m_currentMemento->updateExtent(mi->col(), mi->row());
     }
     else {
         mi->reset();
@@ -142,7 +170,12 @@ void KisMementoManager::registerTileDeleted(KisTile *tile)
 
 void KisMementoManager::commit()
 {
-    if (m_index.isEmpty()) return;
+    if (m_index.isEmpty()) {
+        if(namedTransactionInProgress())
+            warnTiles << "Named Transaction is empty";
+        m_currentMemento = 0;
+        return;
+    }
 
     KisMementoItemList revisionList;
     KisMementoItemSP mi;
@@ -168,8 +201,11 @@ void KisMementoManager::commit()
     hItem.memento = m_currentMemento.data();
     m_revisions.append(hItem);
 
+    m_currentMemento = 0;
     Q_ASSERT(m_index.isEmpty());
 
+    DEBUG_DUMP_MESSAGE("COMMIT_DONE");
+
     // Waking up pooler to prepare copies for us
     globalTileDataStore.kickPooler();
 }
@@ -177,34 +213,29 @@ void KisMementoManager::commit()
 KisTileSP KisMementoManager::getCommitedTile(qint32 col, qint32 row)
 {
     /**
-     * Our getOldTile mechanism is supposed to return current tile, if
-     * the history is disabled. So we return zero if no transaction
-     * is in progress.
+     * Our getOldTile mechanism is supposed to return current
+     * tile, if the history is disabled. So we return zero if
+     * no named transaction is in progress.
      */
-    if(!m_currentMemento || !m_currentMemento->valid())
+    if(!namedTransactionInProgress())
         return 0;
 
-//    KisMementoItemSP mi = m_headsHashTable.getReadOnlyTileLazy(col, row);
-//    Q_ASSERT(mi);
-//    return mi->tile(0);
-
-    /**
-     * FIXME: We emulate unversioned devices here
-     * It means that if there is no history present,
-     * we return null, instead of a default tile.
-     * This may lead to wrong results in filters
-     * I guess, should be fixed after transaction refactor...
-     */
-    KisMementoItemSP mi = m_headsHashTable.getExistedTile(col, row);
-    return mi ? mi->tile(0) : 0;
+    KisMementoItemSP mi = m_headsHashTable.getReadOnlyTileLazy(col, row);
+    Q_ASSERT(mi);
+    return mi->tile(0);
 }
 
 KisMementoSP KisMementoManager::getMemento()
 {
+    /**
+     * We do not allow nested transactions
+     */
+    Q_ASSERT(!namedTransactionInProgress());
+
     commit();
     m_currentMemento = new KisMemento(this);
 
-    DEBUG_DUMP_MESSAGE("GET_MEMENTO");
+    DEBUG_LOG_SIMPLE_ACTION("GET_MEMENTO_DONE");
 
     return m_currentMemento;
 }
@@ -212,8 +243,6 @@ KisMementoSP KisMementoManager::getMemento()
 #define forEachReversed(iter, list) \
         for(iter=list.end(); iter-- != list.begin();)
 
-#define saveAndClearMemento(memento) KisMementoSP _mem = (memento); memento=0
-#define restoreMemento(memento) (memento) = _mem
 
 void KisMementoManager::rollback(KisTileHashTable *ht)
 {
@@ -227,7 +256,7 @@ void KisMementoManager::rollback(KisTileHashTable *ht)
     KisMementoItemSP parentMI;
     KisMementoItemList::iterator iter;
 
-    saveAndClearMemento(m_currentMemento);
+    blockRegistration();
     forEachReversed(iter, changeList.itemList) {
         mi=*iter;
         parentMI = mi->parent();
@@ -245,16 +274,21 @@ void KisMementoManager::rollback(KisTileHashTable *ht)
     }
     /**
      * NOTE: tricky hack alert.
-     * We have  just deleted some tiles  from original hash  table.  And they
-     * accurately reported to us about  their death. Should have reported...
-     * But we   prevented   addition   of  their   bodies   with   zeroing
-     * m_currentMemento. All dead tiles are going to /dev/null :)
+     * We have just deleted some tiles from the original hash table.
+     * And they accurately reported to us about their death. Should
+     * have reported... But we have prevented their registration with
+     * explicitly blocking the process. So all the dead tiles are
+     * going to /dev/null :)
      *
-     * PS: It could cause some race condition... But for now we can insist on
-     * serialization  of rollback()/rollforward()  requests.Speaking  truly i
-     * can't see sny sense in calling rollback() concurrently.
+     * PS: It could cause some race condition... But we insist on
+     * serialization  of rollback()/rollforward() requests. There is
+     * not much sense in calling rollback() concurrently.
      */
-    restoreMemento(m_currentMemento);
+    unblockRegistration();
+
+    // We have just emulated a commit so:
+    m_currentMemento = 0;
+    Q_ASSERT(!namedTransactionInProgress());
 
     m_cancelledRevisions.prepend(changeList);
     DEBUG_DUMP_MESSAGE("UNDONE");
@@ -270,7 +304,7 @@ void KisMementoManager::rollforward(KisTileHashTable *ht)
 
     KisMementoItemSP mi;
 
-    saveAndClearMemento(m_currentMemento);
+    blockRegistration();
     foreach(mi, changeList.itemList) {
         if (mi->parent()->type() == KisMementoItem::CHANGED)
             ht->deleteTile(mi->col(), mi->row());
@@ -279,21 +313,11 @@ void KisMementoManager::rollforward(KisTileHashTable *ht)
 
         m_index.addTile(mi);
     }
-    /**
-     * NOTE: tricky hack alert.
-     * We have  just deleted some tiles  from original hash  table.  And they
-     * accurately reported to us about  their death. Should have reported...
-     * But we   prevented   addition   of  their   bodies   with   zeroing
-     * m_currentMemento. All dead tiles are going to /dev/null :)
-     *
-     * PS: It could cause some race condition... But for now we can insist on
-     * serialization  of rollback()/rollforward()  requests.Speaking  truly i
-     * can't see sny sense in calling rollback() concurrently.
-     */
+    // see comment in rollback()
 
     m_currentMemento = changeList.memento;
     commit();
-    restoreMemento(m_currentMemento);
+    unblockRegistration();
     DEBUG_DUMP_MESSAGE("REDONE");
 }
 
@@ -312,6 +336,8 @@ void KisMementoManager::purgeHistory(KisMementoSP oldestMemento)
 
     Q_ASSERT(m_revisions.first().memento == oldestMemento);
     resetRevisionHistory(m_revisions.first().itemList);
+
+    DEBUG_DUMP_MESSAGE("PURGE_HISTORY");
 }
 
 qint32 KisMementoManager::findRevisionByMemento(KisMementoSP memento) const
diff --git a/krita/image/tiles3/kis_memento_manager.h b/krita/image/tiles3/kis_memento_manager.h
index 8a1e68c..8509e82 100644
--- a/krita/image/tiles3/kis_memento_manager.h
+++ b/krita/image/tiles3/kis_memento_manager.h
@@ -140,10 +140,19 @@ protected:
 
     /**
      * Stores extent of current INDEX.
-     *
-     * Used for reporting to the stuff at the top about our work
+     * It is the "name" of current named transaction
      */
     KisMementoSP m_currentMemento;
+
+    /**
+     * The flag that blocks registration of changes on tiles.
+     * This is a temporary state of the memento manager, that
+     * is used for travelling in history
+     *
+     * \see rollback()
+     * \see rollforward()
+     */
+    bool m_registrationBlocked;
 };
 
 #endif /* KIS_MEMENTO_MANAGER_ */
diff --git a/krita/image/tiles3/kis_tile_hash_table.h b/krita/image/tiles3/kis_tile_hash_table.h
index 952ff62..53e433f 100644
--- a/krita/image/tiles3/kis_tile_hash_table.h
+++ b/krita/image/tiles3/kis_tile_hash_table.h
@@ -38,6 +38,7 @@ class KisTileHashTableTraits
 public:
     typedef T               TileType;
     typedef KisSharedPtr<T> TileTypeSP;
+    typedef KisWeakSharedPtr<T> TileTypeWSP;
 
     KisTileHashTableTraits(KisMementoManager *mm);
     KisTileHashTableTraits(const KisTileHashTableTraits<T> &ht,
diff --git a/krita/image/tiles3/kis_tile_hash_table_p.h b/krita/image/tiles3/kis_tile_hash_table_p.h
index 3fcdb56..9bb5b2f 100644
--- a/krita/image/tiles3/kis_tile_hash_table_p.h
+++ b/krita/image/tiles3/kis_tile_hash_table_p.h
@@ -141,6 +141,16 @@ KisTileHashTableTraits<T>::unlinkTile(qint32 col, qint32 row)
 
 #ifdef SANITY_CHECKS
             tile->setNext(0);
+            TileTypeWSP checkTile = tile;
+            tile = 0;
+            Q_ASSERT_X(!m_mementoManager || !checkTile.isValid(),
+                       "KisTileHashTableTraits::unlinkTile()",
+                       "sanity check failed: "
+                       "the tile is going to be unlinked from "
+                       "the hash table, while still being accessed "
+                       "from the outer world. It can (will) lead to wrong "
+                       "history registered by KisMementoManager. "
+                       "We'll better crash right now!");
 #endif
             m_numTiles--;
             return tile;
diff --git a/krita/image/tiles3/kis_tiled_data_manager.cc b/krita/image/tiles3/kis_tiled_data_manager.cc
index 289356f..e4370e6 100644
--- a/krita/image/tiles3/kis_tiled_data_manager.cc
+++ b/krita/image/tiles3/kis_tiled_data_manager.cc
@@ -160,8 +160,8 @@ bool KisTiledDataManager::read(KoStore *store)
 
     QIODevice *stream = store->device();
     if (!stream) {
-      nothing->setInvalid();
-      return false;
+        m_mementoManager->commit();
+        return false;
     }
 
     quint32 numTiles;
@@ -188,7 +188,7 @@ bool KisTiledDataManager::read(KoStore *store)
         tile->unlock();
     }
 
-    nothing->setInvalid();
+    m_mementoManager->commit();
     return true;
 }
 
diff --git a/krita/image/tiles3/kis_tiled_data_manager.h b/krita/image/tiles3/kis_tiled_data_manager.h
index 897e5f3..eafe111 100644
--- a/krita/image/tiles3/kis_tiled_data_manager.h
+++ b/krita/image/tiles3/kis_tiled_data_manager.h
@@ -144,6 +144,14 @@ public:
         return m_mementoManager->getMemento();
     }
 
+    /**
+     * Finishes having already started transaction
+     */
+    void commit() {
+        QWriteLocker locker(&m_lock);
+        m_mementoManager->commit();
+    }
+
     void rollback(KisMementoSP memento) {
         Q_UNUSED(memento);
         QWriteLocker locker(&m_lock);
diff --git a/krita/image/tiles3/tests/kis_tiled_data_manager_test.cpp b/krita/image/tiles3/tests/kis_tiled_data_manager_test.cpp
index 00c4e83..3062d4a 100644
--- a/krita/image/tiles3/tests/kis_tiled_data_manager_test.cpp
+++ b/krita/image/tiles3/tests/kis_tiled_data_manager_test.cpp
@@ -34,43 +34,54 @@ bool KisTiledDataManagerTest::memoryIsFilled(quint8 c, quint8 *mem, qint32 size)
 
 #define TILESIZE 64*64
 
-void KisTiledDataManagerTest::testMemento()
+void KisTiledDataManagerTest::testTransactions()
 {
     quint8 defaultPixel = 0;
     KisTiledDataManager dm(1, &defaultPixel);
 
-    quint8 oddPixel = 128;
-
-    dm.clear(0, 0, 64, 64, &oddPixel);
-    KisMementoSP memento1 = dm.getMemento();
+    quint8 oddPixel1 = 128;
+    quint8 oddPixel2 = 129;
+    quint8 oddPixel3 = 130;
 
-    dm.clear(64, 0, 64, 64, &oddPixel);
+    KisTileSP tile00;
+    KisTileSP oldTile00;
 
+    // Create a named transaction: versioning is enabled
+    KisMementoSP memento1 = dm.getMemento();
+    dm.clear(0, 0, 64, 64, &oddPixel1);
 
-    KisTileSP tile00 = dm.getTile(0, 0, false);
-    KisTileSP tile10 = dm.getTile(1, 0, false);
-    KisTileSP oldTile00 = dm.getOldTile(0, 0);
-    KisTileSP oldTile10 = dm.getOldTile(1, 0);
+    tile00 = dm.getTile(0, 0, false);
+    oldTile00 = dm.getOldTile(0, 0);
+    QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
+    QVERIFY(memoryIsFilled(defaultPixel, oldTile00->data(), TILESIZE));
+    tile00 = oldTile00 = 0;
 
-    qDebug()<<ppVar(tile10)<<ppVar(oldTile10);
+    // Create an anonymous transaction: versioning is disabled
+    dm.commit();
+    tile00 = dm.getTile(0, 0, false);
+    oldTile00 = dm.getOldTile(0, 0);
+    QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
+    QVERIFY(memoryIsFilled(oddPixel1, oldTile00->data(), TILESIZE));
+    tile00 = oldTile00 = 0;
 
-    QVERIFY(memoryIsFilled(oddPixel, tile00->data(), TILESIZE));
-    QVERIFY(memoryIsFilled(oddPixel, tile10->data(), TILESIZE));
-    QVERIFY(memoryIsFilled(oddPixel, oldTile00->data(), TILESIZE));
-    QVERIFY(memoryIsFilled(defaultPixel, oldTile10->data(), TILESIZE));
+    dm.clear(0, 0, 64, 64, &oddPixel2);
 
+    // Versioning is disabled, i said! >:)
+    tile00 = dm.getTile(0, 0, false);
+    oldTile00 = dm.getOldTile(0, 0);
+    QVERIFY(memoryIsFilled(oddPixel2, tile00->data(), TILESIZE));
+    QVERIFY(memoryIsFilled(oddPixel2, oldTile00->data(), TILESIZE));
+    tile00 = oldTile00 = 0;
 
+    // And the last round: named transaction:
     KisMementoSP memento2 = dm.getMemento();
+    dm.clear(0, 0, 64, 64, &oddPixel3);
 
     tile00 = dm.getTile(0, 0, false);
-    tile10 = dm.getTile(1, 0, false);
     oldTile00 = dm.getOldTile(0, 0);
-    oldTile10 = dm.getOldTile(1, 0);
-
-    QVERIFY(memoryIsFilled(oddPixel, tile00->data(), TILESIZE));
-    QVERIFY(memoryIsFilled(oddPixel, tile10->data(), TILESIZE));
-    QVERIFY(memoryIsFilled(oddPixel, oldTile00->data(), TILESIZE));
-    QVERIFY(memoryIsFilled(oddPixel, oldTile10->data(), TILESIZE));
+    QVERIFY(memoryIsFilled(oddPixel3, tile00->data(), TILESIZE));
+    QVERIFY(memoryIsFilled(oddPixel2, oldTile00->data(), TILESIZE));
+    tile00 = oldTile00 = 0;
 
 }
 
@@ -86,11 +97,11 @@ void KisTiledDataManagerTest::testPurgeHistory()
 
     KisMementoSP memento1 = dm.getMemento();
     dm.clear(0, 0, 64, 64, &oddPixel1);
+    dm.commit();
 
     KisMementoSP memento2 = dm.getMemento();
     dm.clear(0, 0, 64, 64, &oddPixel2);
 
-
     KisTileSP tile00;
     KisTileSP oldTile00;
 
@@ -110,6 +121,8 @@ void KisTiledDataManagerTest::testPurgeHistory()
     QVERIFY(memoryIsFilled(oddPixel2, tile00->data(), TILESIZE));
     QVERIFY(memoryIsFilled(oddPixel1, oldTile00->data(), TILESIZE));
 
+    dm.commit();
+
     dm.purgeHistory(memento2);
 
     /**
@@ -131,9 +144,11 @@ void KisTiledDataManagerTest::testPurgeHistory()
 
     KisMementoSP memento3 = dm.getMemento();
     dm.clear(0, 0, 64, 64, &oddPixel3);
+    dm.commit();
 
     KisMementoSP memento4 = dm.getMemento();
     dm.clear(0, 0, 64, 64, &oddPixel4);
+    dm.commit();
 
     dm.rollback(memento4);
 
diff --git a/krita/image/tiles3/tests/kis_tiled_data_manager_test.h b/krita/image/tiles3/tests/kis_tiled_data_manager_test.h
index dd753d6..145ce1b 100644
--- a/krita/image/tiles3/tests/kis_tiled_data_manager_test.h
+++ b/krita/image/tiles3/tests/kis_tiled_data_manager_test.h
@@ -29,7 +29,7 @@ private:
     bool memoryIsFilled(quint8 c, quint8 *mem, qint32 size);
 
 private slots:
-    void testMemento();
+    void testTransactions();
     void testPurgeHistory();
     void stressTest();
 };
diff --git a/krita/plugins/extensions/colorrange/colorrange.cc b/krita/plugins/extensions/colorrange/colorrange.cc
index 1a42e58..af96003 100644
--- a/krita/plugins/extensions/colorrange/colorrange.cc
+++ b/krita/plugins/extensions/colorrange/colorrange.cc
@@ -124,9 +124,7 @@ void ColorRange::selectOpaque()
         selIter.nextRow();
     }
 
-    QUndoCommand* cmd = helper.selectPixelSelection(tmpSel, SELECTION_ADD);
-    canvas->addCommand(cmd);
-    
+    helper.selectPixelSelection(tmpSel, SELECTION_ADD);
 }
 
 #include "colorrange.moc"
diff --git a/krita/plugins/extensions/colorrange/dlg_colorrange.cc b/krita/plugins/extensions/colorrange/dlg_colorrange.cc
index e475e78..2e6f004 100644
--- a/krita/plugins/extensions/colorrange/dlg_colorrange.cc
+++ b/krita/plugins/extensions/colorrange/dlg_colorrange.cc
@@ -47,7 +47,7 @@
 #include <kis_types.h>
 #include <kis_undo_adapter.h>
 #include <kis_view2.h>
-#include <kis_selected_transaction.h>
+#include <kis_transaction.h>
 #include <kis_cursor.h>
 
 namespace
@@ -184,8 +184,10 @@ DlgColorRange::DlgColorRange(KisView2 * view, KisPaintDeviceSP dev, QWidget *  p
     setMainWidget(m_page);
     resize(m_page->sizeHint());
 
-    // XXX_SELECTION
-    // if (m_view->image()->undo()) m_transaction = new KisSelectedTransaction(i18n("Select by Color Range"), m_dev);
+
+#warning "Activate transactions for colorrange selections!"
+//    XXX_SELECTION
+//    m_transaction = new KisSelectedTransaction(i18n("Select by Color Range"), m_dev);
 
     KisSelectionSP selection = m_view->selection();
 
@@ -246,9 +248,9 @@ void DlgColorRange::updatePreview()
 
 void DlgColorRange::okClicked()
 {
-    if (m_view && m_view->undoAdapter() && m_transaction) {
-        m_view->undoAdapter()->addCommand(m_transaction);
-    }
+//    m_transaction->commit(m_view->image()->undoAdapter());
+//    delete m_transaction;
+
     accept();
 }
 
@@ -256,9 +258,10 @@ void DlgColorRange::cancelClicked()
 {
     if (!m_view) return;
     if (!m_view->image()) return;
-    if (!m_transaction) return;
+//    if (!m_transaction) return;
 
-    if (m_view->image()->undo()) m_transaction->undo();
+//    m_transaction->revert();
+//    delete m_transaction;
 
     m_view->canvas()->update();
     reject();
diff --git a/krita/plugins/extensions/colorspaceconversion/colorspaceconversion.cc b/krita/plugins/extensions/colorspaceconversion/colorspaceconversion.cc
index 8e033da..77b95cb 100644
--- a/krita/plugins/extensions/colorspaceconversion/colorspaceconversion.cc
+++ b/krita/plugins/extensions/colorspaceconversion/colorspaceconversion.cc
@@ -106,8 +106,7 @@ void ColorSpaceConversion::slotImageColorSpaceConversion()
         const KoColorSpace * cs = dlgColorSpaceConversion->m_page->colorSpaceSelector->currentColorSpace();
 
         QApplication::setOverrideCursor(KisCursor::waitCursor());
-        image->convertTo(cs, (KoColorConversionTransformation::Intent)dlgColorSpaceConversion->m_intentButtonGroup.checkedId());
-        image->rootLayer()->setDirty();
+        image->convertImageColorSpace(cs, (KoColorConversionTransformation::Intent)dlgColorSpaceConversion->m_intentButtonGroup.checkedId());
         QApplication::restoreOverrideCursor();
     }
     delete dlgColorSpaceConversion;
@@ -133,16 +132,12 @@ void ColorSpaceConversion::slotLayerColorSpaceConversion()
 
         const KoColorSpace * cs = dlgColorSpaceConversion->m_page->colorSpaceSelector->currentColorSpace();
 
-        if (image->undo()) {
-            image->undoAdapter()->beginMacro(i18n("Convert Layer Type"));
-        }
+        image->undoAdapter()->beginMacro(i18n("Convert Layer Type"));
 
         KisColorSpaceConvertVisitor visitor(image, cs, (KoColorConversionTransformation::Intent)dlgColorSpaceConversion->m_intentButtonGroup.checkedId());
         layer->accept(visitor);
 
-        if (image->undo()) {
-            image->undoAdapter()->endMacro();
-        }
+        image->undoAdapter()->endMacro();
 
         QApplication::restoreOverrideCursor();
         m_view->nodeManager()->nodesUpdated();
diff --git a/krita/plugins/extensions/dropshadow/kis_dropshadow.cc b/krita/plugins/extensions/dropshadow/kis_dropshadow.cc
index df70896..4a90b8a 100644
--- a/krita/plugins/extensions/dropshadow/kis_dropshadow.cc
+++ b/krita/plugins/extensions/dropshadow/kis_dropshadow.cc
@@ -88,9 +88,7 @@ void KisDropshadow::dropshadow(KoUpdater * progressUpdater,
     KisPaintDeviceSP dev = m_view->activeDevice();
     if (!dev) return;
 
-    if (image->undo()) {
-        image->undoAdapter()->beginMacro(i18n("Add Drop Shadow"));
-    }
+    image->undoAdapter()->beginMacro(i18n("Add Drop Shadow"));
 
     KisPaintDeviceSP shadowDev = new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8());
     KisPaintDeviceSP bShadowDev;
@@ -166,9 +164,7 @@ void KisDropshadow::dropshadow(KoUpdater * progressUpdater,
         m_view->image()->setModified();
     }
 
-    if (image->undo()) {
-        image->undoAdapter()->endMacro();
-    }
+    image->undoAdapter()->endMacro();
 
     progressUpdater->setProgress(100);
 }
diff --git a/krita/plugins/extensions/scripting/kritacore/krs_image.cpp b/krita/plugins/extensions/scripting/kritacore/krs_image.cpp
index a55826d..5e0616c 100644
--- a/krita/plugins/extensions/scripting/kritacore/krs_image.cpp
+++ b/krita/plugins/extensions/scripting/kritacore/krs_image.cpp
@@ -70,7 +70,7 @@ bool Image::convertToColorSpace(const QString& model, const QString& depth)
         warnScript << QString("ColorSpace %1 %2 is not available, please check your installation.").arg(model).arg(depth) << endl;
         return false;
     }
-    m_image->convertTo(dstCS);
+    m_image->convertImageColorSpace(dstCS);
     return true;
 }
 
diff --git a/krita/plugins/extensions/scripting/kritacore/krs_paint_device.cpp b/krita/plugins/extensions/scripting/kritacore/krs_paint_device.cpp
index 9436932..d808cf8 100644
--- a/krita/plugins/extensions/scripting/kritacore/krs_paint_device.cpp
+++ b/krita/plugins/extensions/scripting/kritacore/krs_paint_device.cpp
@@ -42,7 +42,7 @@ using namespace Scripting;
 PaintDevice::PaintDevice(KisPaintDeviceSP device, KisDoc2* doc)
         : ConstPaintDevice(device, doc)
         , m_device(device)
-        , m_cmd(0)
+        , m_transaction(0)
 {
     setObjectName("KritaLayer");
 }
@@ -89,11 +89,11 @@ QObject* PaintDevice::createPainter()
 
 void PaintDevice::beginPainting(const QString& name)
 {
-    if (m_cmd != 0) {
-        delete m_cmd;
+    if (m_transaction) {
+        delete m_transaction;
     }
-    m_cmd = new KisTransaction(name, paintDevice());
-    Q_CHECK_PTR(m_cmd);
+    m_transaction = new KisTransaction(name, paintDevice());
+    Q_CHECK_PTR(m_transaction);
 }
 
 void PaintDevice::endPainting()
@@ -102,8 +102,9 @@ void PaintDevice::endPainting()
         doc()->setModified(true);
         m_device->setDirty();
     }
-    if (m_cmd != 0) {
-        doc()->image()->undoAdapter()->addCommand(m_cmd);
+    if (m_transaction) {
+        m_transaction->commit(doc()->image()->undoAdapter());
+        delete m_transaction;
     }
 }
 
diff --git a/krita/plugins/extensions/scripting/kritacore/krs_paint_device.h b/krita/plugins/extensions/scripting/kritacore/krs_paint_device.h
index 6f0e84c..a5846ca 100644
--- a/krita/plugins/extensions/scripting/kritacore/krs_paint_device.h
+++ b/krita/plugins/extensions/scripting/kritacore/krs_paint_device.h
@@ -182,7 +182,7 @@ public:
     }
 private:
     KisPaintDeviceSP m_device;
-    KisTransaction* m_cmd;
+    KisTransaction* m_transaction;
 };
 
 }
diff --git a/krita/plugins/extensions/separate_channels/kis_channel_separator.cc b/krita/plugins/extensions/separate_channels/kis_channel_separator.cc
index 7db1e05..a8fc596 100644
--- a/krita/plugins/extensions/separate_channels/kis_channel_separator.cc
+++ b/krita/plugins/extensions/separate_channels/kis_channel_separator.cc
@@ -207,8 +207,8 @@ void KisChannelSeparator::separate(KoUpdater * progressUpdater, enumSepAlphaOpti
 
     if (!progressUpdater->interrupted()) {
 
-        KisUndoAdapter * undo = 0;
-        if (outputOps == TO_LAYERS && (undo = image->undoAdapter()) && undo->undo()) {
+        KisUndoAdapter * undo = image->undoAdapter();
+        if (outputOps == TO_LAYERS) {
             undo->beginMacro(i18n("Separate Image"));
         }
 
@@ -233,11 +233,7 @@ void KisChannelSeparator::separate(KoUpdater * progressUpdater, enumSepAlphaOpti
 
             if (outputOps == TO_LAYERS) {
                 KisPaintLayerSP l = KisPaintLayerSP(new KisPaintLayer(image.data(), ch->name(), OPACITY_OPAQUE_U8, *deviceIt));
-                if (undo && undo->undo()) {
-                    adapter.addNode(l.data(), image->rootLayer(), 0);
-                } else {
-                    image->addNode(l.data(), image->rootLayer());
-                }
+                adapter.addNode(l.data(), image->rootLayer(), 0);
             } else {
                 QStringList listMimeFilter = KoFilterManager::mimeFilter("application/x-krita", KoFilterManager::Export);
                 QString mimelist = listMimeFilter.join(" ");
@@ -279,7 +275,7 @@ void KisChannelSeparator::separate(KoUpdater * progressUpdater, enumSepAlphaOpti
             ++deviceIt;
         }
 
-        if (outputOps == TO_LAYERS && undo && undo->undo()) {
+        if (outputOps == TO_LAYERS) {
             undo->endMacro();
         }
         m_view->image()->unlock();
diff --git a/krita/plugins/extensions/tonemapping/kis_tonemapping_dialog.cc b/krita/plugins/extensions/tonemapping/kis_tonemapping_dialog.cc
index c1287e7..9de2207 100644
--- a/krita/plugins/extensions/tonemapping/kis_tonemapping_dialog.cc
+++ b/krita/plugins/extensions/tonemapping/kis_tonemapping_dialog.cc
@@ -79,33 +79,25 @@ KisToneMappingDialog::KisToneMappingDialog(QWidget* parent, KisLayerSP _layer) :
 
 void KisToneMappingDialog::apply()
 {
+    KisUndoAdapter *undoAdapter = d->layer->image()->undoAdapter();
+
     d->layer->image()->lock();
     KisPropertiesConfiguration* config = (d->currentConfigurationWidget) ? d->currentConfigurationWidget->configuration() : new KisPropertiesConfiguration;
     const KoColorSpace* colorSpace = d->currentOperator->colorSpace();
 
-    if (d->layer->image()->undo()) {
-        d->layer->image()->undoAdapter()->beginMacro(d->currentOperator->name());
-    }
+    undoAdapter->beginMacro(d->currentOperator->name());
+
     if (!(*d->layer->paintDevice()->colorSpace() == *colorSpace)) {
         QUndoCommand* cmd = d->layer->paintDevice()->convertTo(colorSpace);
-        if (d->layer->image()->undo()) {
-            d->layer->image()->undoAdapter()->addCommand(cmd);
-        } else {
-            delete cmd;
-        }
+        undoAdapter->addCommand(cmd);
     }
-    KisTransaction * cmd = 0;
 
-    if (d->layer->image()->undo()) cmd = new KisTransaction(d->currentOperator->name(), d->layer->paintDevice());
+    KisTransaction transaction(d->currentOperator->name(), d->layer->paintDevice());
     d->currentOperator->toneMap(d->layer->paintDevice(), config);
-    if (cmd) d->layer->image()->undoAdapter()->addCommand(cmd);
+    transaction.commit(undoAdapter);
+    undoAdapter->endMacro();
 
     d->currentOperator->bookmarkManager()->save(KisBookmarkedConfigurationManager::ConfigLastUsed.id(), config);
-
-    if (d->layer->image()->undo()) {
-        d->layer->image()->undoAdapter()->endMacro();
-    }
-
     d->layer->setDirty();
     d->layer->image()->unlock();
     delete config;
diff --git a/krita/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp b/krita/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp
index dddeaa1..4c71693 100644
--- a/krita/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp
+++ b/krita/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp
@@ -110,8 +110,8 @@ void KisSimpleNoiseReducer::process(KisConstProcessingInformation srcInfo,
     KisConvolutionPainter painter(interm);
     painter.beginTransaction("bouuh");
     painter.applyMatrix(kernel, interm, srcTopLeft, dstTopLeft, size, BORDER_REPEAT);
-    delete painter.endTransaction();
-    
+    painter.deleteTransaction();
+
     if (progressUpdater && progressUpdater->interrupted()) {
         return;
     }
diff --git a/krita/plugins/filters/unsharp/kis_unsharp_filter.cpp b/krita/plugins/filters/unsharp/kis_unsharp_filter.cpp
index 3f06eda..0a95815 100644
--- a/krita/plugins/filters/unsharp/kis_unsharp_filter.cpp
+++ b/krita/plugins/filters/unsharp/kis_unsharp_filter.cpp
@@ -109,8 +109,8 @@ void KisUnsharpFilter::process(KisConstProcessingInformation src,
     painter.setChannelFlags(channelFlags);
     painter.beginTransaction("convolution step");
     painter.applyMatrix(kernel, interm, src.topLeft(), dst.topLeft(), areaSize, BORDER_REPEAT);
-    delete painter.endTransaction();
-    
+    painter.deleteTransaction();
+
     if (progressUpdater && progressUpdater->interrupted()) {
         return;
     }
diff --git a/krita/plugins/tools/defaulttools/kis_tool_ellipse.cc b/krita/plugins/tools/defaulttools/kis_tool_ellipse.cc
index 54d4148..78f40b1 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_ellipse.cc
+++ b/krita/plugins/tools/defaulttools/kis_tool_ellipse.cc
@@ -69,13 +69,12 @@ void KisToolEllipse::finishEllipse(const QRectF& rect)
         setupPainter(&painter);
         painter.setOpacity(m_opacity);
         painter.setCompositeOp(m_compositeOp);
-
         painter.paintEllipse(rect);
+        painter.endTransaction(image()->undoAdapter());
+
         QRegion bound = painter.dirtyRegion();
         device->setDirty(bound);
         notifyModified();
-
-        canvas()->addCommand(painter.endTransaction());
     } else {
         QRectF r = convertToPt(rect);
         KoShape* shape = KisShapeToolHelper::createEllipseShape(r);
diff --git a/krita/plugins/tools/defaulttools/kis_tool_fill.cc b/krita/plugins/tools/defaulttools/kis_tool_fill.cc
index d643fdd..507ace5 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_fill.cc
+++ b/krita/plugins/tools/defaulttools/kis_tool_fill.cc
@@ -140,7 +140,7 @@ bool KisToolFill::flood(int startX, int startY)
             ++it;
         }
 
-        canvas->addCommand(m_painter->endTransaction());
+        m_painter->endTransaction(image()->undoAdapter());
 
     } else {
 
@@ -162,8 +162,8 @@ bool KisToolFill::flood(int startX, int startY)
         else
             fillPainter.fillColor(startX, startY, currentImage()->mergedImage());
 
+        fillPainter.endTransaction(image()->undoAdapter());
         dirty = fillPainter.dirtyRegion();
-        canvas->addCommand(fillPainter.endTransaction());
     }
     device->setDirty(dirty);
     delete updater;
diff --git a/krita/plugins/tools/defaulttools/kis_tool_gradient.cc b/krita/plugins/tools/defaulttools/kis_tool_gradient.cc
index fc2f66d..9affbbd 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_gradient.cc
+++ b/krita/plugins/tools/defaulttools/kis_tool_gradient.cc
@@ -291,12 +291,12 @@ void KisToolGradient::mouseReleaseEvent(KoPointerEvent *e)
             painter.setProgress(updater->startSubtask());
 
             painter.paintGradient(m_startPos, m_endPos, m_shape, m_repeat, m_antiAliasThreshold, m_reverse, 0, 0, currentImage()->width(), currentImage()->height());
-            canvas->addCommand(painter.endTransaction());
+            painter.endTransaction(image()->undoAdapter());
 
             qApp->restoreOverrideCursor();
 #else
             // XXX: figure out why threaded gradients give weird noise
-            KisTransaction* transaction = new KisTransaction(i18n("Gradient"), device);
+            KisTransaction transaction(i18n("Gradient"), device);
 
             KisCanvas2 * canvas = dynamic_cast<KisCanvas2 *>(canvas());
             KoProgressUpdater * updater = canvas->view()->createProgressUpdater();
@@ -321,7 +321,7 @@ void KisToolGradient::mouseReleaseEvent(KoPointerEvent *e)
 
             applicator.execute();
 
-            canvas()->addCommand(transaction);
+            transaction.commit(image()->undoAdapter());
 #endif
             currentNode()->setDirty();
             notifyModified();
diff --git a/krita/plugins/tools/defaulttools/kis_tool_line.cc b/krita/plugins/tools/defaulttools/kis_tool_line.cc
index ddd0e90..acbb6df 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_line.cc
+++ b/krita/plugins/tools/defaulttools/kis_tool_line.cc
@@ -185,7 +185,7 @@ void KisToolLine::mouseReleaseEvent(KoPointerEvent *e)
                     notifyModified();
 
 
-                    canvas()->addCommand(m_painter->endTransaction());
+                    m_painter->endTransaction(image()->undoAdapter());
                     delete m_painter;
                     m_painter = 0;
                 }
diff --git a/krita/plugins/tools/defaulttools/kis_tool_move.cc b/krita/plugins/tools/defaulttools/kis_tool_move.cc
index bece05b..d4b4a0f 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_move.cc
+++ b/krita/plugins/tools/defaulttools/kis_tool_move.cc
@@ -149,9 +149,7 @@ void KisToolMove::mousePressEvent(KoPointerEvent *e)
             node = currentNode();
         }
 
-        if (currentImage()->undo()) {
-            currentImage()->undoAdapter()->beginMacro(i18n("Move"));
-        }
+        currentImage()->undoAdapter()->beginMacro(i18n("Move"));
 
         if (selection && !selection->isTotallyUnselected(image->bounds())) {
             //selection->convertToQImage(0).save("selection.png");
@@ -174,12 +172,15 @@ void KisToolMove::mousePressEvent(KoPointerEvent *e)
                 gc.bitBlt(rc.topLeft(), oldLayer->paintDevice(), rc);
                 gc.end();
 
-                // clear the old layer
-                currentImage()->undoAdapter()->addCommand(new KisTransaction("cut", oldLayer->paintDevice()));
-                oldLayer->paintDevice()->clearSelection(selection);
+                {
+                    KisTransaction transaction("cut", oldLayer->paintDevice());
+                    // clear the old layer
+                    oldLayer->paintDevice()->clearSelection(selection);
+                    transaction.commit(image->undoAdapter());
 
-                // deselect away the selection???
-                selection->clear();
+                    // deselect away the selection???
+                    selection->clear();
+                }
 
                 KisCanvas2* kisCanvas = dynamic_cast<KisCanvas2*>(canvas());
                 KisView2* view = 0;
diff --git a/krita/plugins/tools/defaulttools/kis_tool_path.cc b/krita/plugins/tools/defaulttools/kis_tool_path.cc
index 0e8b5b8..dc5ed16 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_path.cc
+++ b/krita/plugins/tools/defaulttools/kis_tool_path.cc
@@ -133,12 +133,12 @@ void KisToolPath::addPathShape(KoPathShape* pathShape)
         painter.setPaintOpPreset(preset, image);
 
         painter.paintPainterPath(mapedOutline);
+        painter.endTransaction(image->undoAdapter());
+
         QRegion dirtyRegion = painter.dirtyRegion();
         dev->setDirty(dirtyRegion);
         image->setModified();
 
-        kiscanvas->addCommand(painter.endTransaction());
-
     } else {
         pathShape->normalize();
         QUndoCommand * cmd = canvas()->shapeController()->addShape(pathShape);
diff --git a/krita/plugins/tools/defaulttools/kis_tool_rectangle.cc b/krita/plugins/tools/defaulttools/kis_tool_rectangle.cc
index 0359159..fe73757 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_rectangle.cc
+++ b/krita/plugins/tools/defaulttools/kis_tool_rectangle.cc
@@ -81,13 +81,12 @@ void KisToolRectangle::finishRect(const QRectF &rect)
         setupPainter(&painter);
         painter.setOpacity(m_opacity);
         painter.setCompositeOp(m_compositeOp);
-
         painter.paintRect(rect);
+        painter.endTransaction(image()->undoAdapter());
+
         QRegion bound = painter.dirtyRegion();
         device->setDirty(bound);
         notifyModified();
-
-        canvas()->addCommand(painter.endTransaction());
     } else {
         QRectF r = convertToPt(rect);
         KoShape* shape = KisShapeToolHelper::createRectangleShape(r);
diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_brush.cc b/krita/plugins/tools/selectiontools/kis_tool_select_brush.cc
index c580853..93703dd 100644
--- a/krita/plugins/tools/selectiontools/kis_tool_select_brush.cc
+++ b/krita/plugins/tools/selectiontools/kis_tool_select_brush.cc
@@ -192,8 +192,7 @@ void KisToolSelectBrush::applyToSelection(const QPainterPath &selection) {
 
         painter.fillPainterPath(selection);
 
-        QUndoCommand* cmd = helper.selectPixelSelection(tmpSel, m_selectAction);
-        canvas()->addCommand(cmd);
+        helper.selectPixelSelection(tmpSel, m_selectAction);
 
         resetSelection();
     }
diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_contiguous.cc b/krita/plugins/tools/selectiontools/kis_tool_select_contiguous.cc
index 839f510..13716a8 100644
--- a/krita/plugins/tools/selectiontools/kis_tool_select_contiguous.cc
+++ b/krita/plugins/tools/selectiontools/kis_tool_select_contiguous.cc
@@ -91,8 +91,7 @@ void KisToolSelectContiguous::mousePressEvent(KoPointerEvent * e)
             return;
 
         KisSelectionToolHelper helper(kisCanvas, currentNode(), i18n("Contiguous Area Selection"));
-        QUndoCommand* cmd = helper.selectPixelSelection(selection->pixelSelection(), m_selectAction);
-        canvas()->addCommand(cmd);
+        helper.selectPixelSelection(selection->pixelSelection(), m_selectAction);
 
         QApplication::restoreOverrideCursor();
     }
diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_elliptical.cc b/krita/plugins/tools/selectiontools/kis_tool_select_elliptical.cc
index 3d564ee..5ffda5f 100644
--- a/krita/plugins/tools/selectiontools/kis_tool_select_elliptical.cc
+++ b/krita/plugins/tools/selectiontools/kis_tool_select_elliptical.cc
@@ -43,7 +43,6 @@
 #include "kis_paintop_registry.h"
 #include "kis_layer.h"
 #include "kis_selection_options.h"
-#include "kis_selected_transaction.h"
 #include "canvas/kis_canvas2.h"
 #include "kis_pixel_selection.h"
 #include "kis_selection_tool_helper.h"
@@ -93,8 +92,7 @@ void KisToolSelectElliptical::LocalTool::finishEllipse(const QRectF &rect)
 
         painter.paintEllipse(rect);
 
-        QUndoCommand* cmd = helper.selectPixelSelection(tmpSel, m_selectingTool->m_selectAction);
-        canvas()->addCommand(cmd);
+        helper.selectPixelSelection(tmpSel, m_selectingTool->m_selectAction);
     } else {
         QRectF ptRect = convertToPt(rect);
         KoShape* shape = KisShapeToolHelper::createEllipseShape(ptRect);
diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_magnetic.cc b/krita/plugins/tools/selectiontools/kis_tool_select_magnetic.cc
index fd43b0c..904bd63 100644
--- a/krita/plugins/tools/selectiontools/kis_tool_select_magnetic.cc
+++ b/krita/plugins/tools/selectiontools/kis_tool_select_magnetic.cc
@@ -439,13 +439,14 @@ void KisToolSelectMagnetic::LocalTool::cleanDetectedBorder()
         QVector2D relativeVectorToAfterNext = QVector2D(afterNext)-QVector2D(current);
 
         qreal distToNext = relativeVectorToNext.length();
-        qreal distToAfterNext = relativeVectorToAfterNext.length();
+        // FIXME: seems to be unused!
+        //qreal distToAfterNext = relativeVectorToAfterNext.length();
 
         qreal angleToNext = std::atan2((qreal)relativeVectorToNext.y(), (qreal) relativeVectorToNext.x());
         qreal angleToAfterNext = std::atan2((qreal)relativeVectorToAfterNext.y(), (qreal) relativeVectorToAfterNext.x());
 
         if(fabs((angleToAfterNext-angleToNext)*distToNext)<1) {
-            qDebug()<<"dleting: "<<(angleToAfterNext-angleToNext)*distToNext;
+            qDebug()<<"deleting: "<<(angleToAfterNext-angleToNext)*distToNext;
             iter = detectedBorder.erase(iter);
         }
         else {
@@ -487,8 +488,7 @@ void KisToolSelectMagnetic::LocalTool::addPathShape(KoPathShape* pathShape)
 
     painter.paintPolygon(QPolygonF(m_detectedBorder));
 
-    QUndoCommand* cmd = helper.selectPixelSelection(tmpSel, m_selectingTool->m_selectAction);
-    canvas()->addCommand(cmd);
+    helper.selectPixelSelection(tmpSel, m_selectingTool->m_selectAction);
 
     m_detectedBorder.clear();
     m_tmpDetectedBorder.clear();
diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_outline.cc b/krita/plugins/tools/selectiontools/kis_tool_select_outline.cc
index 6fe5805..56d9721 100644
--- a/krita/plugins/tools/selectiontools/kis_tool_select_outline.cc
+++ b/krita/plugins/tools/selectiontools/kis_tool_select_outline.cc
@@ -45,7 +45,6 @@
 #include <kis_cursor.h>
 #include <kis_image.h>
 
-#include "kis_selected_transaction.h"
 #include "kis_painter.h"
 #include "kis_paintop_registry.h"
 #include "canvas/kis_canvas2.h"
@@ -128,8 +127,7 @@ void KisToolSelectOutline::mouseReleaseEvent(KoPointerEvent *event)
                 painter.setCompositeOp(tmpSel->colorSpace()->compositeOp(COMPOSITE_OVER));
                 painter.paintPolygon(m_points);
 
-                QUndoCommand* cmd = helper.selectPixelSelection(tmpSel, m_selectAction);
-                canvas()->addCommand(cmd);
+                helper.selectPixelSelection(tmpSel, m_selectAction);
             } else {
 
                 KoPathShape* path = new KoPathShape();
diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_path.cc b/krita/plugins/tools/selectiontools/kis_tool_select_path.cc
index 64e6c0a..df74a2d 100644
--- a/krita/plugins/tools/selectiontools/kis_tool_select_path.cc
+++ b/krita/plugins/tools/selectiontools/kis_tool_select_path.cc
@@ -168,8 +168,7 @@ void KisToolSelectPath::LocalTool::addPathShape(KoPathShape* pathShape)
         matrix.translate(pathShape->position().x(), pathShape->position().y());
         painter.fillPainterPath(matrix.map(pathShape->outline()));
 
-        QUndoCommand* cmd = helper.selectPixelSelection(tmpSel, m_selectingTool->m_selectAction);
-        canvas()->addCommand(cmd);
+        helper.selectPixelSelection(tmpSel, m_selectingTool->m_selectAction);
 
         delete pathShape;
     } else {
diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_polygonal.cc b/krita/plugins/tools/selectiontools/kis_tool_select_polygonal.cc
index adb1c8b..908cdd3 100644
--- a/krita/plugins/tools/selectiontools/kis_tool_select_polygonal.cc
+++ b/krita/plugins/tools/selectiontools/kis_tool_select_polygonal.cc
@@ -97,8 +97,7 @@ void KisToolSelectPolygonal::LocalTool::finishPolyline(const QVector<QPointF> &p
         painter.setCompositeOp(tmpSel->colorSpace()->compositeOp(COMPOSITE_OVER));
         painter.paintPolygon(points);
 
-        QUndoCommand* cmd = helper.selectPixelSelection(tmpSel, m_selectingTool->m_selectAction);
-        canvas()->addCommand(cmd);
+        helper.selectPixelSelection(tmpSel, m_selectingTool->m_selectAction);
     } else {
         KoPathShape* path = new KoPathShape();
         path->setShapeId(KoPathShapeId);
diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_rectangular.cc b/krita/plugins/tools/selectiontools/kis_tool_select_rectangular.cc
index d7143e3..90d4042 100644
--- a/krita/plugins/tools/selectiontools/kis_tool_select_rectangular.cc
+++ b/krita/plugins/tools/selectiontools/kis_tool_select_rectangular.cc
@@ -90,8 +90,7 @@ void KisToolSelectRectangular::LocalTool::finishRect(const QRectF& rect)
             KisPixelSelectionSP tmpSel = KisPixelSelectionSP(new KisPixelSelection());
             tmpSel->select(rc);
 
-            QUndoCommand* cmd = helper.selectPixelSelection(tmpSel, m_selectingTool->m_selectAction);
-            canvas()->addCommand(cmd);
+            helper.selectPixelSelection(tmpSel, m_selectingTool->m_selectAction);
         }
     } else {
         QRectF documentRect = convertToPt(rect);
diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_similar.cc b/krita/plugins/tools/selectiontools/kis_tool_select_similar.cc
index b50628c..592b62d 100644
--- a/krita/plugins/tools/selectiontools/kis_tool_select_similar.cc
+++ b/krita/plugins/tools/selectiontools/kis_tool_select_similar.cc
@@ -44,7 +44,6 @@
 #include <kis_selection.h>
 #include <kis_paint_device.h>
 #include <kis_iterators_pixel.h>
-#include <kis_selected_transaction.h>
 #include "canvas/kis_canvas2.h"
 #include <kis_pixel_selection.h>
 #include "kis_selection_tool_helper.h"
@@ -128,9 +127,8 @@ void KisToolSelectSimilar::mousePressEvent(KoPointerEvent *e)
         selectByColor(dev, tmpSel, c.data(), m_fuzziness);
 
         KisSelectionToolHelper helper(kisCanvas, currentNode(), i18n("Similar Selection"));
-        QUndoCommand* cmd = helper.selectPixelSelection(tmpSel, m_selectAction);
+        helper.selectPixelSelection(tmpSel, m_selectAction);
 
-        canvas()->addCommand(cmd);
         QApplication::restoreOverrideCursor();
     }
 }
diff --git a/krita/plugins/tools/tool_crop/kis_tool_crop.cc b/krita/plugins/tools/tool_crop/kis_tool_crop.cc
index 7999387..d0f919d 100644
--- a/krita/plugins/tools/tool_crop/kis_tool_crop.cc
+++ b/krita/plugins/tools/tool_crop/kis_tool_crop.cc
@@ -44,7 +44,6 @@
 #include <kis_image.h>
 #include <kis_undo_adapter.h>
 #include <KoPointerEvent.h>
-#include <kis_selected_transaction.h>
 #include <kis_selection.h>
 #include <kis_layer.h>
 #include <kis_crop_visitor.h>
@@ -442,15 +441,13 @@ void KisToolCrop::crop()
     if (m_optWidget->cmbType->currentIndex() == 0 && currentNode()->paintDevice()) {
         // The layer(s) under the current layer will take care of adding
         // undo information to the Crop macro.
-        if (currentImage()->undo())
-            currentImage()->undoAdapter()->beginMacro(i18n("Crop"));
+        currentImage()->undoAdapter()->beginMacro(i18n("Crop"));
 
         KisCropVisitor v(cropRect, false);
         KisNodeSP node = currentNode();
         node->accept(v);
 
-        if (currentImage()->undo())
-            currentImage()->undoAdapter()->endMacro();
+        currentImage()->undoAdapter()->endMacro();
 
     } else {
         // Resize creates the undo macro itself
diff --git a/krita/plugins/tools/tool_curves/kis_tool_curve.cc b/krita/plugins/tools/tool_curves/kis_tool_curve.cc
index 1377e46..c2a4ad5 100644
--- a/krita/plugins/tools/tool_curves/kis_tool_curve.cc
+++ b/krita/plugins/tools/tool_curves/kis_tool_curve.cc
@@ -428,7 +428,7 @@ void KisToolCurve::paintCurve()
     if (!device) return;
 
     KisPainter painter(device);
-    if (m_currentImage->undo()) painter.beginTransaction(m_transactionMessage);
+    painter.beginTransaction(m_transactionMessage);
     painter.setBounds(m_currentImage->bounds());
     painter.setPaintColor(m_subject->fgColor());
     painter.setBrush(m_subject->currentBrush());
@@ -446,9 +446,7 @@ void KisToolCurve::paintCurve()
     device->setDirty(painter.dirtyRegion());
     notifyModified();
 
-    if (m_currentImage->undo()) {
-        m_currentImage->undoAdapter()->addCommandOld(painter.endTransaction());
-    }
+    m_currentImage->undoAdapter()->addCommandOld(painter.endTransaction());
 
     draw(false);
 }
@@ -489,8 +487,8 @@ void KisToolCurve::selectCurve()
     QApplication::setOverrideCursor(KisCursor::waitCursor());
     KisPaintDeviceSP dev = currentNode()->paintDevice();
     bool hasSelection = dev->hasSelection();
-    KisSelectedTransaction *t = 0;
-    if (m_currentImage->undo() && hasSelection) t = new KisSelectedTransaction(m_transactionMessage, dev);
+    KisSelectedTransaction *transaction = 0;
+    if (hasSelection) transaction = new KisSelectedTransaction(m_transactionMessage, currentNode());
     KisSelectionSP selection = dev->selection();
 
     if (!hasSelection) {
@@ -527,10 +525,11 @@ void KisToolCurve::selectCurve()
     } else {
         dev->setDirty();
     }
-    /*
-        if (m_currentImage->undo())
-            m_currentImage->undoAdapter()->addCommandOld(t);
-    */
+
+    if (transaction) {
+        transaction->commit(m_currentImage->undoAdapter());
+        delete transaction;
+    }
     QApplication::restoreOverrideCursor();
 
     draw(false);
diff --git a/krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc b/krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc
index fc45e68..74bac41 100644
--- a/krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc
+++ b/krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc
@@ -39,7 +39,6 @@
 #include <KoViewConverter.h>
 #include <canvas/kis_perspective_grid_manager.h>
 #include <kis_canvas_resource_provider.h>
-#include <kis_selected_transaction.h>
 #include <kis_painter.h>
 #include <kis_paintop_registry.h>
 #include <kis_view2.h>
diff --git a/krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc b/krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc
index 9e595f2..0fbeceb 100644
--- a/krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc
+++ b/krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc
@@ -53,7 +53,7 @@
 #include <kis_cursor.h>
 #include <kis_image.h>
 #include <kis_undo_adapter.h>
-#include <kis_selected_transaction.h>
+#include <kis_transaction.h>
 #include <kis_selection.h>
 #include <kis_filter_strategy.h>
 #include <kis_perspectivetransform_worker.h>
@@ -63,11 +63,11 @@
 
 namespace
 {
-class PerspectiveTransformCmd : public KisSelectedTransaction
+class PerspectiveTransformCmdData : public KisSelectedTransactionData
 {
 public:
-    PerspectiveTransformCmd(KisToolPerspectiveTransform *tool, KisNodeSP node, KisPaintDeviceSP device, KisPaintDeviceSP origDevice,  QPointF topleft, QPointF topright, QPointF bottomleft, QPointF bottomright, KisSelectionSP origSel, QRect initialRect);
-    virtual ~PerspectiveTransformCmd();
+    PerspectiveTransformCmdData(KisToolPerspectiveTransform *tool, KisNodeSP node, KisPaintDeviceSP device, KisPaintDeviceSP origDevice,  QPointF topleft, QPointF topright, QPointF bottomleft, QPointF bottomright, KisSelectionSP origSel, QRect initialRect);
+    virtual ~PerspectiveTransformCmdData();
 
 public:
     virtual void redo();
@@ -86,8 +86,8 @@ private:
     KisPaintDeviceSP m_origDevice;
 };
 
-PerspectiveTransformCmd::PerspectiveTransformCmd(KisToolPerspectiveTransform *tool, KisNodeSP node, KisPaintDeviceSP device, KisPaintDeviceSP origDevice, QPointF topleft, QPointF topright, QPointF bottomleft, QPointF bottomright, KisSelectionSP origSel, QRect initialRect) :
-        KisSelectedTransaction(i18n("Perspective Transform"), node)
+PerspectiveTransformCmdData::PerspectiveTransformCmdData(KisToolPerspectiveTransform *tool, KisNodeSP node, KisPaintDeviceSP device, KisPaintDeviceSP origDevice, QPointF topleft, QPointF topright, QPointF bottomleft, QPointF bottomright, KisSelectionSP origSel, QRect initialRect) :
+        KisSelectedTransactionData(i18n("Perspective Transform"), node)
         , m_initialRect(initialRect)
         , m_topleft(topleft), m_topright(topright), m_bottomleft(bottomleft), m_bottomright(bottomright)
         , m_tool(tool)
@@ -97,11 +97,11 @@ PerspectiveTransformCmd::PerspectiveTransformCmd(KisToolPerspectiveTransform *to
 {
 }
 
-PerspectiveTransformCmd::~PerspectiveTransformCmd()
+PerspectiveTransformCmdData::~PerspectiveTransformCmdData()
 {
 }
 
-void PerspectiveTransformCmd::transformArgs(QPointF &topleft, QPointF &topright, QPointF &bottomleft, QPointF& bottomright) const
+void PerspectiveTransformCmdData::transformArgs(QPointF &topleft, QPointF &topright, QPointF &bottomleft, QPointF& bottomright) const
 {
     topleft = m_topleft;
     topright = m_topright;
@@ -109,33 +109,49 @@ void PerspectiveTransformCmd::transformArgs(QPointF &topleft, QPointF &topright,
     bottomright = m_bottomright;
 }
 
-KisSelectionSP PerspectiveTransformCmd::origSelection(QRect& initialRect) const
+KisSelectionSP PerspectiveTransformCmdData::origSelection(QRect& initialRect) const
 {
     initialRect = m_initialRect;
     return m_origSelection;
 }
 
-void PerspectiveTransformCmd::redo()
+void PerspectiveTransformCmdData::redo()
 {
-    KisSelectedTransaction::redo();
+    KisSelectedTransactionData::redo();
 }
 
-void PerspectiveTransformCmd::undo()
+void PerspectiveTransformCmdData::undo()
 {
-    KisSelectedTransaction::undo();
+    KisSelectedTransactionData::undo();
 }
 
-KisPaintDeviceSP PerspectiveTransformCmd::theDevice()
+KisPaintDeviceSP PerspectiveTransformCmdData::theDevice()
 {
     return m_device;
 }
 
-KisPaintDeviceSP PerspectiveTransformCmd::origDevice()
+KisPaintDeviceSP PerspectiveTransformCmdData::origDevice()
 {
     return m_origDevice;
 }
 }
 
+class PerspectiveTransformCmd : public KisTransaction
+{
+public:
+    PerspectiveTransformCmd(KisToolPerspectiveTransform *tool, KisNodeSP node,
+                            KisPaintDeviceSP device, KisPaintDeviceSP origDevice,
+                            QPointF topleft, QPointF topright,
+                            QPointF bottomleft, QPointF bottomright,
+                            KisSelectionSP origSel, QRect initialRect)
+    {
+        m_transactionData =
+            new PerspectiveTransformCmdData(tool, node, device, origDevice,
+                                            topleft, topright, bottomleft, bottomright,
+                                            origSel, initialRect);
+    }
+};
+
 KisToolPerspectiveTransform::KisToolPerspectiveTransform(KoCanvasBase * canvas)
         : KisTool(canvas, KisCursor::load("tool_perspectivetransform_cursor.png", 6, 6)), m_optWidget(0), m_optForm(0)
 {
@@ -174,10 +190,10 @@ void KisToolPerspectiveTransform::activate(ToolActivation toolActivation, const
     if (image() && currentImage() && currentNode()->paintDevice()) {
         image()->undoAdapter()->setCommandHistoryListener(this);
 
-        const PerspectiveTransformCmd *cmd = 0;
+        const PerspectiveTransformCmdData *cmd = 0;
 
         if (image()->undoAdapter()->presentCommand())
-            cmd = dynamic_cast<const PerspectiveTransformCmd*>(image()->undoAdapter()->presentCommand());
+            cmd = dynamic_cast<const PerspectiveTransformCmdData*>(image()->undoAdapter()->presentCommand());
 
         if (cmd == 0) {
             m_interractionMode = DRAWRECTINTERRACTION;
@@ -624,7 +640,7 @@ void KisToolPerspectiveTransform::transform()
     KoUpdater *progress = updater->startSubtask();
 
     // This mementoes the current state of the active device.
-    PerspectiveTransformCmd * transaction = new PerspectiveTransformCmd(this, currentNode(), currentNode()->paintDevice(), m_origDevice,
+    PerspectiveTransformCmd transaction (this, currentNode(), currentNode()->paintDevice(), m_origDevice,
             m_topleft, m_topright, m_bottomleft, m_bottomright, m_origSelection, m_initialRect);
 
     // Copy the original state back.
@@ -658,8 +674,7 @@ void KisToolPerspectiveTransform::transform()
     /*
         // If canceled, go back to the memento
         if (worker.isCanceled()) {
-            transaction->undo();
-            delete transaction;
+            transaction.revert()
             return;
         }
     */
@@ -668,17 +683,12 @@ void KisToolPerspectiveTransform::transform()
     // Else add the command -- this will have the memento from the previous state,
     // and the transformed state from the original device we cached in our activated()
     // method.
-    if (transaction) {
-        if (currentImage()->undo())
-            currentImage()->undoAdapter()->addCommand(transaction);
-        else
-            delete transaction;
-    }
+    transaction.commit(image()->undoAdapter());
 }
 
 void KisToolPerspectiveTransform::notifyCommandAdded(const QUndoCommand * command)
 {
-    const PerspectiveTransformCmd * cmd = dynamic_cast<const PerspectiveTransformCmd*>(command);
+    const PerspectiveTransformCmdData* cmd = dynamic_cast<const PerspectiveTransformCmdData*>(command);
     if (cmd == 0) {
         // The last added command wasn't one of ours;
         // we should reset to the new state of the canvas.
@@ -691,10 +701,10 @@ void KisToolPerspectiveTransform::notifyCommandAdded(const QUndoCommand * comman
 void KisToolPerspectiveTransform::notifyCommandExecuted(const QUndoCommand * command)
 {
     Q_UNUSED(command);
-    const PerspectiveTransformCmd * cmd = 0;
+    const PerspectiveTransformCmdData* cmd = 0;
 
     if (image()->undoAdapter()->presentCommand())
-        cmd = dynamic_cast<const PerspectiveTransformCmd*>(image()->undoAdapter()->presentCommand());
+        cmd = dynamic_cast<const PerspectiveTransformCmdData*>(image()->undoAdapter()->presentCommand());
 
     if (cmd == 0) {
         // The command now on the top of the stack isn't one of ours
diff --git a/krita/plugins/tools/tool_polygon/kis_tool_polygon.cc b/krita/plugins/tools/tool_polygon/kis_tool_polygon.cc
index f084def..fb8f342 100644
--- a/krita/plugins/tools/tool_polygon/kis_tool_polygon.cc
+++ b/krita/plugins/tools/tool_polygon/kis_tool_polygon.cc
@@ -74,7 +74,7 @@ void KisToolPolygon::finishPolyline(const QVector<QPointF>& points)
 
         if (device) {
             KisPainter painter(device, currentSelection());
-            if (currentImage()->undo()) painter.beginTransaction(i18n("Polygon"));
+            painter.beginTransaction(i18n("Polygon"));
             setupPainter(&painter);
             painter.setOpacity(m_opacity);
             painter.setCompositeOp(m_compositeOp);
@@ -82,7 +82,7 @@ void KisToolPolygon::finishPolyline(const QVector<QPointF>& points)
             device->setDirty(painter.dirtyRegion());
             notifyModified();
 
-            canvas()->addCommand(painter.endTransaction());
+            painter.endTransaction(image()->undoAdapter());
         }
     } else {
         KoPathShape* path = new KoPathShape();
diff --git a/krita/plugins/tools/tool_polyline/kis_tool_polyline.cc b/krita/plugins/tools/tool_polyline/kis_tool_polyline.cc
index 3fe8d97..24f7cba 100644
--- a/krita/plugins/tools/tool_polyline/kis_tool_polyline.cc
+++ b/krita/plugins/tools/tool_polyline/kis_tool_polyline.cc
@@ -89,7 +89,7 @@ void KisToolPolyline::finishPolyline(const QVector<QPointF>& points)
             }
         }
         device->setDirty(painter.dirtyRegion());
-        canvas()->addCommand(painter.endTransaction());
+        painter.endTransaction(image()->undoAdapter());
     } else {
         KoPathShape* path = new KoPathShape();
         path->setShapeId(KoPathShapeId);
diff --git a/krita/plugins/tools/tool_star/kis_tool_star.cc b/krita/plugins/tools/tool_star/kis_tool_star.cc
index 6e910d2..81ccdc5 100644
--- a/krita/plugins/tools/tool_star/kis_tool_star.cc
+++ b/krita/plugins/tools/tool_star/kis_tool_star.cc
@@ -142,7 +142,7 @@ void KisToolStar::mouseReleaseEvent(KoPointerEvent *event)
             notifyModified();
             updatePreview();
 
-            canvas()->addCommand(painter.endTransaction());
+            painter.endTransaction(image()->undoAdapter());
         } else {
             KoPathShape* path = new KoPathShape();
             path->setShapeId(KoPathShapeId);
diff --git a/krita/plugins/tools/tool_transform/kis_tool_transform.cc b/krita/plugins/tools/tool_transform/kis_tool_transform.cc
index 7ccc240..56833aa 100644
--- a/krita/plugins/tools/tool_transform/kis_tool_transform.cc
+++ b/krita/plugins/tools/tool_transform/kis_tool_transform.cc
@@ -53,7 +53,7 @@
 #include <kis_cursor.h>
 #include <kis_image.h>
 #include <kis_undo_adapter.h>
-#include <kis_selected_transaction.h>
+#include <kis_transaction.h>
 #include <kis_selection.h>
 #include <kis_filter_strategy.h>
 #include <widgets/kis_cmb_idlist.h>
@@ -73,12 +73,12 @@
 
 namespace
 {
-class TransformCmd : public KisSelectedTransaction
+class TransformCmdData : public KisSelectedTransactionData
 {
 
 public:
-    TransformCmd(KisToolTransform *tool, KisNodeSP node, double scaleX, double scaleY, QPointF translate, double a, KisSelectionSP origSel, QPoint startPos, QPoint endPos);
-    virtual ~TransformCmd();
+    TransformCmdData(KisToolTransform *tool, KisNodeSP node, double scaleX, double scaleY, QPointF translate, double a, KisSelectionSP origSel, QPoint startPos, QPoint endPos);
+    virtual ~TransformCmdData();
 
 public:
     virtual void redo();
@@ -98,8 +98,8 @@ private:
     QPoint m_newPosition;
 };
 
-TransformCmd::TransformCmd(KisToolTransform *tool, KisNodeSP node, double scaleX, double scaleY, QPointF translate, double a, KisSelectionSP origSel, QPoint originalTopLeft, QPoint originalBottomRight)
-        : KisSelectedTransaction(i18n("Transform"), node)
+TransformCmdData::TransformCmdData(KisToolTransform *tool, KisNodeSP node, double scaleX, double scaleY, QPointF translate, double a, KisSelectionSP origSel, QPoint originalTopLeft, QPoint originalBottomRight)
+        : KisSelectedTransactionData(i18n("Transform"), node)
         , m_scaleX(scaleX)
         , m_scaleY(scaleY)
         , m_translate(translate)
@@ -111,11 +111,11 @@ TransformCmd::TransformCmd(KisToolTransform *tool, KisNodeSP node, double scaleX
 {
 }
 
-TransformCmd::~TransformCmd()
+TransformCmdData::~TransformCmdData()
 {
 }
 
-void TransformCmd::transformArgs(double &sx, double &sy, QPointF &translate, double &a) const
+void TransformCmdData::transformArgs(double &sx, double &sy, QPointF &translate, double &a) const
 {
     sx = m_scaleX;
     sy = m_scaleY;
@@ -123,31 +123,45 @@ void TransformCmd::transformArgs(double &sx, double &sy, QPointF &translate, dou
     a = m_a;
 }
 
-KisSelectionSP TransformCmd::origSelection(QPoint &originalTopLeft, QPoint &originalBottomRight) const
+KisSelectionSP TransformCmdData::origSelection(QPoint &originalTopLeft, QPoint &originalBottomRight) const
 {
     originalTopLeft = m_originalTopLeft;
     originalBottomRight = m_originalBottomRight;
     return m_origSelection;
 }
 
-void TransformCmd::redo()
+void TransformCmdData::redo()
 {
-    KisSelectedTransaction::redo();
+    KisSelectedTransactionData::redo();
     layer()->paintDevice()->move(m_newPosition);
 }
 
-void TransformCmd::undo()
+void TransformCmdData::undo()
 {
-    KisSelectedTransaction::undo();
+    KisSelectedTransactionData::undo();
     layer()->paintDevice()->move(m_originalTopLeft);
 }
 
-void TransformCmd::setNewPosition(int x, int y)
+void TransformCmdData::setNewPosition(int x, int y)
 {
     m_newPosition.setX(x);
     m_newPosition.setY(y);
 }
 
+class TransformCmd : public KisTransaction
+{
+public:
+    TransformCmd(KisToolTransform *tool, KisNodeSP node,
+                 double scaleX, double scaleY,
+                 QPointF translate, double a, KisSelectionSP origSel,
+                 QPoint originalTopLeft, QPoint originalBottomRight)
+    {
+        m_transactionData =
+            new TransformCmdData(tool, node, scaleX, scaleY, translate,
+                                 a, origSel, originalTopLeft, originalBottomRight);
+    }
+};
+
 }
 
 KisToolTransform::KisToolTransform(KoCanvasBase * canvas)
@@ -193,10 +207,10 @@ void KisToolTransform::activate(ToolActivation toolActivation, const QSet<KoShap
     if (currentNode() && currentNode()->paintDevice()) {
         image()->undoAdapter()->setCommandHistoryListener(this);
 
-        const TransformCmd * cmd = 0;
+        const TransformCmdData * cmd = 0;
 
         if (image()->undoAdapter()->presentCommand())
-            cmd = dynamic_cast<const TransformCmd*>(image()->undoAdapter()->presentCommand());
+            cmd = dynamic_cast<const TransformCmdData*>(image()->undoAdapter()->presentCommand());
 
         if (cmd == 0) {
             initHandles();
@@ -656,8 +670,9 @@ void KisToolTransform::transform()
     KoUpdaterPtr progress = updater->startSubtask();
 
     // This mementoes the current state of the active device.
-    TransformCmd * transaction = new TransformCmd(this, currentNode(), m_scaleX,
-            m_scaleY, m_translate, m_a, m_origSelection, m_originalTopLeft, m_originalBottomRight);
+    TransformCmd transaction(this, currentNode(), m_scaleX,
+                             m_scaleY, m_translate, m_a, m_origSelection,
+                             m_originalTopLeft, m_originalBottomRight);
 
 
     //Copy the original state back.
@@ -720,7 +735,7 @@ void KisToolTransform::transform()
                 m_oldMatrixList << shape->transformation();
                 m_newMatrixList << shape->transformation()*matrix;
             }
-            KoShapeTransformCommand* cmd = new KoShapeTransformCommand(shapes, m_oldMatrixList, m_newMatrixList, transaction);
+            KoShapeTransformCommand* cmd = new KoShapeTransformCommand(shapes, m_oldMatrixList, m_newMatrixList, transaction.undoCommand());
             cmd->redo();
         }
 
@@ -737,8 +752,7 @@ void KisToolTransform::transform()
 //     // If canceled, go back to the memento
 //     if(worker.isCanceled())
 //     {
-//         transaction->undo();
-//         delete transaction;
+//         transaction.revert();
 //         return;
 //     }
 
@@ -751,20 +765,16 @@ void KisToolTransform::transform()
     // Else add the command -- this will have the memento from the previous state,
     // and the transformed state from the original device we cached in our activated()
     // method.
-    if (transaction) {
-        transaction->setNewPosition(currentNode()->paintDevice()->x(), currentNode()->paintDevice()->y());
-        if (image()->undo())
-            image()->undoAdapter()->addCommand(transaction);
-        else
-            delete transaction;
-    }
-    updater->deleteLater();
+    TransformCmdData* undoCommand = static_cast<TransformCmdData*>(transaction.undoCommand());
+    undoCommand->setNewPosition(currentNode()->paintDevice()->x(), currentNode()->paintDevice()->y());
+    transaction.commit(image()->undoAdapter());
 
+    updater->deleteLater();
 }
 
 void KisToolTransform::notifyCommandAdded(const QUndoCommand * command)
 {
-    const TransformCmd * cmd = dynamic_cast<const TransformCmd*>(command);
+    const TransformCmdData * cmd = dynamic_cast<const TransformCmdData*>(command);
     if (cmd == 0) {
         // The last added command wasn't one of ours;
         // we should reset to the new state of the canvas.
@@ -776,10 +786,10 @@ void KisToolTransform::notifyCommandAdded(const QUndoCommand * command)
 void KisToolTransform::notifyCommandExecuted(const QUndoCommand * command)
 {
     Q_UNUSED(command);
-    const TransformCmd * cmd = 0;
+    const TransformCmdData * cmd = 0;
 
     if (image()->undoAdapter()->presentCommand())
-        cmd = dynamic_cast<const TransformCmd*>(image()->undoAdapter()->presentCommand());
+        cmd = dynamic_cast<const TransformCmdData*>(image()->undoAdapter()->presentCommand());
 
     if (cmd == 0) {
         // The command now on the top of the stack isn't one of ours
diff --git a/krita/sdk/tests/filestest.h b/krita/sdk/tests/filestest.h
index a533dd6..310e03e 100644
--- a/krita/sdk/tests/filestest.h
+++ b/krita/sdk/tests/filestest.h
@@ -77,7 +77,7 @@ void testFiles(const QString& _dirname, const QStringList& exclusions)
             QString id = doc.image()->colorSpace()->id();
             if (id != "GRAYA" && id != "GRAYA16" && id != "RGBA" && id != "RGBA16") {
                 dbgKrita << "Images need conversion";
-                doc.image()->convertTo(KoColorSpaceRegistry::instance()->rgb8());
+                doc.image()->convertImageColorSpace(KoColorSpaceRegistry::instance()->rgb8());
             }
 
             KTemporaryFile tmpFile;
diff --git a/krita/ui/kis_doc2.cc b/krita/ui/kis_doc2.cc
index 63cadb8..5638682 100644
--- a/krita/ui/kis_doc2.cc
+++ b/krita/ui/kis_doc2.cc
@@ -175,20 +175,16 @@ void KisDoc2::slotLoadingFinished() {
 
 void KisDoc2::openExistingFile(const KUrl& url)
 {
-    setUndo(false);
     qApp->setOverrideCursor(Qt::BusyCursor);
     KoDocument::openExistingFile(url);
     qApp->restoreOverrideCursor();
-    setUndo(true);
 }
 
 void KisDoc2::openTemplate(const KUrl& url)
 {
-    setUndo(false);
     qApp->setOverrideCursor(Qt::BusyCursor);
     KoDocument::openTemplate(url);
     qApp->restoreOverrideCursor();
-    setUndo(true);
 }
 
 bool KisDoc2::init()
@@ -207,8 +203,6 @@ bool KisDoc2::init()
     connect(undoStack(), SIGNAL(indexChanged(int)), SLOT(undoIndexChanged(int)));
     Q_CHECK_PTR(m_d->undoAdapter);
 
-    setUndo(true);
-
     m_d->nserver = new KisNameServer(1);
     Q_CHECK_PTR(m_d->nserver);
 
@@ -271,7 +265,6 @@ bool KisDoc2::loadXML(const KoXmlDocument& doc, KoStore *)
         return false;
     }
 
-    setUndo(false);
     Q_ASSERT(m_d->kraLoader == 0);
     m_d->kraLoader = new KisKraLoader(this, syntaxVersion);
 
@@ -321,7 +314,6 @@ bool KisDoc2::completeLoading(KoStore *store)
     m_d->kraLoader = 0;
 
     setModified(false);
-    setUndo(true);
     m_d->image->setUndoAdapter(m_d->undoAdapter);
     m_d->shapeController->setImage(m_d->image);
     m_d->nodeModel->setImage(m_d->image);
@@ -389,15 +381,13 @@ bool KisDoc2::newImage(const QString& name,
 
     qApp->setOverrideCursor(Qt::BusyCursor);
 
-    setUndo(false);
-
     image = new KisImage(m_d->undoAdapter, width, height, cs, name);
     Q_CHECK_PTR(image);
     image->lock();
 
     connect(image.data(), SIGNAL(sigImageModified()), this, SLOT(setModified()));
     image->setResolution(imageResolution, imageResolution);
-    image->setProfile(cs->profile());
+    image->assignImageProfile(cs->profile());
     documentInfo()->setAboutInfo("title", name);
     documentInfo()->setAboutInfo("comments", description);
 
@@ -414,7 +404,6 @@ bool KisDoc2::newImage(const QString& name,
     cfg.defImageHeight(height);
     cfg.defImageResolution(imageResolution);
 
-    setUndo(true);
 
     qApp->restoreOverrideCursor();
     return true;
@@ -480,16 +469,6 @@ QPixmap KisDoc2::generatePreview(const QSize& size)
     return QPixmap(size);
 }
 
-void KisDoc2::setUndo(bool undo)
-{
-    m_d->undoAdapter->setUndo(undo);
-}
-
-bool KisDoc2::undo() const
-{
-    return m_d->undoAdapter->undo();
-}
-
 KoShapeControllerBase * KisDoc2::shapeController() const
 {
     return m_d->shapeController;
@@ -516,7 +495,6 @@ void KisDoc2::prepareForImport()
 {
     if (m_d->nserver == 0)
         init();
-    setUndo(false);
 }
 
 KisImageWSP KisDoc2::image() const
@@ -536,7 +514,6 @@ void KisDoc2::setCurrentImage(KisImageWSP image)
     m_d->shapeController->setImage(image);
     m_d->nodeModel->setImage(image);
 
-    setUndo(true);
     setModified(false);
 
     connect(m_d->image, SIGNAL(sigImageModified()), this, SLOT(setModified()));
diff --git a/krita/ui/kis_doc2.h b/krita/ui/kis_doc2.h
index 1e2cd8c..dac0952 100644
--- a/krita/ui/kis_doc2.h
+++ b/krita/ui/kis_doc2.h
@@ -93,9 +93,6 @@ public:
     /// Generate a scaled-down pixmap of the image projection that fits in size
     virtual QPixmap generatePreview(const QSize& size);
 
-    virtual void setUndo(bool undo);
-    virtual bool undo() const;
-
 public slots:
 
     /**
diff --git a/krita/ui/kis_filter_handler.cc b/krita/ui/kis_filter_handler.cc
index 78c5147..fa33673 100644
--- a/krita/ui/kis_filter_handler.cc
+++ b/krita/ui/kis_filter_handler.cc
@@ -76,7 +76,7 @@ struct KisFilterHandler::Private {
     KisPaintDeviceSP dev;
     KoProgressUpdater* updater;
     KisThreadedApplicator* applicator;
-    KisTransaction* cmd;
+    KisTransaction* transaction;
     KisSystemLocker* locker;
 };
 
@@ -91,7 +91,7 @@ KisFilterHandler::KisFilterHandler(KisFilterManager* parent, KisFilterSP f, KisV
     m_d->lastConfiguration = 0;
     m_d->updater = 0;
     m_d->applicator = 0;
-    m_d->cmd = 0;
+    m_d->transaction = 0;
     m_d->locker = 0;
 }
 
@@ -169,9 +169,7 @@ void KisFilterHandler::apply(KisNodeSP layer, KisFilterConfiguration* config)
     // also deletes all old updaters
     m_d->updater->start(100, m_d->currentFilter->name());
 
-    if (m_d->view->image()->undo()) {
-        m_d->cmd = new KisTransaction(m_d->currentFilter->name(), m_d->dev);
-    }
+    m_d->transaction = new KisTransaction(m_d->currentFilter->name(), m_d->dev);
 
     KisProcessingInformation src(m_d->dev, rect.topLeft(), selection);
     KisProcessingInformation dst(m_d->dev, rect.topLeft(), selection);
@@ -206,15 +204,13 @@ void KisFilterHandler::areaDone(const QRect & rc)
 void KisFilterHandler::filterDone(bool interrupted)
 {
     if (interrupted) {
-        if (m_d->cmd) {
-            m_d->cmd->undo();
-            delete m_d->cmd;
-        }
-
+        m_d->transaction->revert();
+        delete m_d->transaction;
     } else  {
-        if (m_d->cmd) {
-            m_d->view->document()->addCommand(m_d->cmd);
-        }
+        KisUndoAdapter *undoAdapter = m_d->view->image()->undoAdapter();
+        m_d->transaction->commit(undoAdapter);
+        delete m_d->transaction;
+
         if (m_d->filter->bookmarkManager()) {
             m_d->filter->bookmarkManager()->save(KisBookmarkedConfigurationManager::ConfigLastUsed.id(),
                                                  m_d->currentConfiguration);
diff --git a/krita/ui/kis_image_manager.cc b/krita/ui/kis_image_manager.cc
index 45d9b59..c73be6c 100644
--- a/krita/ui/kis_image_manager.cc
+++ b/krita/ui/kis_image_manager.cc
@@ -112,8 +112,6 @@ void KisImageManager::resizeCurrentImage(qint32 w, qint32 h, bool cropLayers)
     if (!m_view->image()) return;
 
     m_view->image()->resize(w, h, cropLayers);
-    m_view->image()->setModified();
-    m_view->layerManager()->layersUpdated();
 }
 
 void KisImageManager::resizeCurrentImage(qint32 w, qint32 h, qint32 xOffset, qint32 yOffset)
@@ -121,8 +119,6 @@ void KisImageManager::resizeCurrentImage(qint32 w, qint32 h, qint32 xOffset, qin
     if (!m_view->image()) return;
 
     m_view->image()->resizeWithOffset(w, h, xOffset, yOffset);
-    m_view->image()->setModified();
-    m_view->layerManager()->layersUpdated();
 }
 
 void KisImageManager::scaleCurrentImage(double sx, double sy, KisFilterStrategy *filterStrategy)
@@ -134,8 +130,6 @@ void KisImageManager::scaleCurrentImage(double sx, double sy, KisFilterStrategy
     KoUpdaterPtr up = updater->startSubtask();
 
     m_view->image()->scale(sx, sy, up, filterStrategy);
-    m_view->image()->setModified();
-    m_view->layerManager()->layersUpdated();
     updater->deleteLater();
 }
 
@@ -148,8 +142,6 @@ void KisImageManager::rotateCurrentImage(double radians)
     KoUpdaterPtr up = updater->startSubtask();
 
     m_view->image()->rotate(radians, up);
-    m_view->image()->setModified();
-    m_view->layerManager()->layersUpdated();
 
     m_view->statusBar()->progress()->detachUpdater(updater);
     updater->deleteLater();
@@ -164,8 +156,6 @@ void KisImageManager::shearCurrentImage(double angleX, double angleY)
     KoUpdaterPtr up = updater->startSubtask();
 
     m_view->image()->shear(angleX, angleY, up);
-    m_view->image()->setModified();
-    m_view->layerManager()->layersUpdated();
 
     m_view->statusBar()->progress()->detachUpdater(updater);
     updater->deleteLater();
@@ -181,8 +171,7 @@ void KisImageManager::slotImageProperties()
     KisDlgImageProperties dlg(image, m_view);
 
     if (dlg.exec() == QDialog::Accepted) {
-        QUndoCommand* cmd = new KisImagePropsCommand(image, dlg.colorSpace());
-        m_view->document()->addCommand(cmd);
+        image->convertProjectionColorSpace(dlg.colorSpace());
     }
 }
 
diff --git a/krita/ui/kis_layer_manager.cc b/krita/ui/kis_layer_manager.cc
index 52d0b92..246832e 100644
--- a/krita/ui/kis_layer_manager.cc
+++ b/krita/ui/kis_layer_manager.cc
@@ -53,7 +53,7 @@
 #include <kis_layer.h>
 #include <kis_paint_device.h>
 #include <kis_paint_layer.h>
-#include <kis_selected_transaction.h>
+#include <kis_transaction.h>
 #include <kis_selection.h>
 #include <flake/kis_shape_layer.h>
 #include <kis_shear_visitor.h>
@@ -196,20 +196,9 @@ void KisLayerManager::imageResizeToActiveLayer()
 
     if (image && (layer = activeLayer())) {
 
-        if (undoAdapter && undoAdapter->undo()) {
-            undoAdapter->beginMacro(i18n("Resize Image to Size of Current Layer"));
-        }
-
-        image->lock();
-
-        QRect r = layer->exactBounds();
-        image->resize(r.width(), r.height(), r.x(), r.y(), true);
-
-        image->unlock();
-
-        if (undoAdapter && undoAdapter->undo()) {
-            undoAdapter->endMacro();
-        }
+        undoAdapter->beginMacro(i18n("Resize Image to Size of Current Layer"));
+        image->resize(layer->exactBounds(), true);
+        undoAdapter->endMacro();
     }
 }
 
@@ -655,16 +644,12 @@ void KisLayerManager::mirrorLayerX()
     KisPaintDeviceSP dev = activeDevice();
     if (!dev) return;
 
-    KisTransaction * t = 0;
-    if (m_view->undoAdapter() && m_view->undoAdapter()->undo()) {
-        t = new KisTransaction(i18n("Mirror Layer X"), dev);
-        Q_CHECK_PTR(t);
-    }
+    KisTransaction transaction(i18n("Mirror Layer X"), dev);
 
     QRect dirty = KisTransformWorker::mirrorX(dev, m_view->selection());
     m_activeLayer->setDirty(dirty);
 
-    if (t) m_view->undoAdapter()->addCommand(t);
+    transaction.commit(m_view->image()->undoAdapter());
 
     m_doc->setModified(true);
     layersUpdated();
@@ -676,16 +661,12 @@ void KisLayerManager::mirrorLayerY()
     KisPaintDeviceSP dev = activeDevice();
     if (!dev) return;
 
-    KisTransaction * t = 0;
-    if (m_view->undoAdapter() && m_view->undoAdapter()->undo()) {
-        t = new KisTransaction(i18n("Mirror Layer Y"), dev);
-        Q_CHECK_PTR(t);
-    }
+    KisTransaction transaction(i18n("Mirror Layer Y"), dev);
 
     QRect dirty = KisTransformWorker::mirrorY(dev, m_view->selection());
     m_activeLayer->setDirty(dirty);
 
-    if (t) m_view->undoAdapter()->addCommand(t);
+    transaction.commit(m_view->image()->undoAdapter());
 
     m_doc->setModified(true);
     layersUpdated();
@@ -699,11 +680,7 @@ void KisLayerManager::scaleLayer(double sx, double sy, KisFilterStrategy *filter
     KisLayerSP layer = activeLayer();
     if (!layer) return;
 
-    KisSelectedTransaction * t = 0;
-    if (m_view->undoAdapter() && m_view->undoAdapter()->undo()) {
-        t = new KisSelectedTransaction(i18n("Scale Layer"), layer);
-        Q_CHECK_PTR(t);
-    }
+    KisSelectedTransaction transaction(i18n("Scale Layer"), layer);
 
     KoProgressUpdater* updater = m_view->createProgressUpdater();
     KoUpdaterPtr u = updater->startSubtask();
@@ -711,7 +688,8 @@ void KisLayerManager::scaleLayer(double sx, double sy, KisFilterStrategy *filter
     KisTransformWorker worker(layer->paintDevice(), sx, sy, 0, 0, 0.0, 0, 0, u, filterStrategy);
     worker.run();
 
-    if (t) m_view->undoAdapter()->addCommand(t);
+    transaction.commit(m_view->image()->undoAdapter());
+
     m_doc->setModified(true);
     layersUpdated();
     m_view->canvas()->update();
@@ -726,9 +704,8 @@ void KisLayerManager::rotateLayer(double radians)
     KisLayerSP layer = activeLayer();
     if (!layer) return;
 
-    if (m_view->undoAdapter() && m_view->undoAdapter()->undo()) {
-        m_view->undoAdapter()->beginMacro(i18n("Rotate Layer"));
-    }
+    KisUndoAdapter * undoAdapter = m_view->image()->undoAdapter();
+    undoAdapter->beginMacro(i18n("Rotate Layer"));
 
     KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value("Triangle");
     QRect r;
@@ -744,8 +721,7 @@ void KisLayerManager::rotateLayer(double radians)
     KisTransformVisitor visitor(m_view->image(), 1.0, 1.0, 0, 0, radians, -tx, -ty, 0, filter);
     layer->accept(visitor);
 
-    if (m_view->undoAdapter() && m_view->undoAdapter()->undo())
-        m_view->undoAdapter()->endMacro();
+    undoAdapter->endMacro();
 
     m_doc->setModified(true);
     layersUpdated();
@@ -759,20 +735,18 @@ void KisLayerManager::shearLayer(double angleX, double angleY)
     KisLayerSP layer = activeLayer();
     if (!layer) return;
 
-    KisUndoAdapter * undo = 0;
-    if ((undo = m_view->image()->undoAdapter())) {
-        undo->beginMacro(i18n("Shear layer"));
-    }
+    KisUndoAdapter * undoAdapter = m_view->image()->undoAdapter();
+    undoAdapter->beginMacro(i18n("Shear layer"));
 
     KoProgressUpdater* updater = m_view->statusBar()->progress()->createUpdater();
     updater->start(100, i18n("Shear layer"));
     KoUpdaterPtr up = updater->startSubtask();
 
     KisShearVisitor v(angleX, angleY, up);
-    v.setUndoAdapter(undo);
+    v.setUndoAdapter(undoAdapter);
     layer->accept(v);
 
-    if (undo) undo->endMacro();
+    undoAdapter->endMacro();
 
     m_doc->setModified(true);
     layersUpdated();
diff --git a/krita/ui/kis_mask_manager.cc b/krita/ui/kis_mask_manager.cc
index be4cdd7..4b5e576 100644
--- a/krita/ui/kis_mask_manager.cc
+++ b/krita/ui/kis_mask_manager.cc
@@ -358,16 +358,12 @@ void KisMaskManager::mirrorMaskX()
     KisPaintDeviceSP dev = m_activeMask->selection()->getOrCreatePixelSelection();
     if (!dev) return;
 
-    KisTransaction * t = 0;
-    if (m_view->undoAdapter() && m_view->undoAdapter()->undo()) {
-        t = new KisTransaction(i18n("Mirror Mask X"), dev);
-        Q_CHECK_PTR(t);
-    }
+    KisTransaction transaction(i18n("Mirror Mask X"), dev);
 
     QRect dirty = KisTransformWorker::mirrorX(dev, m_view->selection());
     m_activeMask->setDirty(dirty);
 
-    if (t) m_view->undoAdapter()->addCommand(t);
+    transaction.commit(m_view->image()->undoAdapter());
 
     m_view->document()->setModified(true);
     m_activeMask->selection()->updateProjection();
@@ -384,17 +380,12 @@ void KisMaskManager::mirrorMaskY()
     KisPaintDeviceSP dev = m_activeMask->selection()->getOrCreatePixelSelection();
     if (!dev) return;
 
-    KisTransaction * t = 0;
-    if (m_view->undoAdapter() && m_view->undoAdapter()->undo()) {
-        t = new KisTransaction(i18n("Mirror Layer Y"), dev);
-        Q_CHECK_PTR(t);
-    }
+    KisTransaction transaction(i18n("Mirror Layer Y"), dev);
 
     QRect dirty = KisTransformWorker::mirrorY(dev, m_view->selection());
     m_activeMask->setDirty(dirty);
 
-
-    if (t) m_view->undoAdapter()->addCommand(t);
+    transaction.commit(m_view->image()->undoAdapter());
 
     m_view->document()->setModified(true);
     m_activeMask->selection()->updateProjection();
diff --git a/krita/ui/kis_selection_manager.cc b/krita/ui/kis_selection_manager.cc
index b3ec1c7..cf495a7 100644
--- a/krita/ui/kis_selection_manager.cc
+++ b/krita/ui/kis_selection_manager.cc
@@ -63,16 +63,14 @@
 #include "kis_paint_device.h"
 #include "kis_paint_layer.h"
 #include "kis_painter.h"
-#include "kis_selected_transaction.h"
-#include "kis_selection.h"
 #include "kis_transaction.h"
+#include "kis_selection.h"
 #include "kis_types.h"
 #include "kis_canvas_resource_provider.h"
 #include "kis_undo_adapter.h"
 #include "kis_pixel_selection.h"
 #include "flake/kis_shape_selection.h"
 #include "commands/kis_selection_commands.h"
-#include "kis_selection_transaction.h"
 #include "kis_selection_mask.h"
 #include "flake/kis_shape_layer.h"
 #include "kis_selection_decoration.h"
@@ -374,14 +372,14 @@ void KisSelectionManager::cut()
 
     copy();
 
-    KisSelectedTransaction *t = new KisSelectedTransaction(i18n("Cut"), layer);
-    Q_CHECK_PTR(t);
+    KisSelectedTransaction transaction(i18n("Cut"), layer);
 
     layer->paintDevice()->clearSelection(m_view->selection());
     QRect rect = m_view->selection()->selectedRect();
     deselect();
 
-    m_view->document()->addCommand(t);
+    transaction.commit(m_view->image()->undoAdapter());
+
     layer->setDirty(rect);
 }
 
@@ -507,7 +505,6 @@ void KisSelectionManager::pasteNew()
     if (!doc) return;
 
     Q_ASSERT(doc->undoAdapter() != 0);
-    doc->undoAdapter()->setUndo(false);
 
     KisImageWSP image = new KisImage(doc->undoAdapter(), r.width(), r.height(),
                                    KoColorSpaceRegistry::instance()->colorSpace(clip->colorSpace()->colorModelId().id(), clip->colorSpace()->colorDepthId().id(), clip->colorSpace()->profile()), "Pasted");    // TODO should be translated ?
@@ -521,8 +518,6 @@ void KisSelectionManager::pasteNew()
     image->addNode(layer.data(), image->rootLayer());
     doc->setCurrentImage(image);
 
-    doc->undoAdapter()->setUndo(true);
-
     KoMainWindow *win = new KoMainWindow(doc->componentData());
     win->show();
     win->setRootDocument(doc);
@@ -533,18 +528,25 @@ void KisSelectionManager::selectAll()
     KisImageWSP image = m_view->image();
     if (!image) return;
 
-    QUndoCommand* selectionCmd = new QUndoCommand(i18n("Select All"));
+    KisUndoAdapter *undoAdapter = m_view->image()->undoAdapter();
+    undoAdapter->beginMacro(i18n("Select All"));
 
-    if (!image->globalSelection())
-        new KisSetGlobalSelectionCommand(image, selectionCmd);
-    KisSelectionSP selection = image->globalSelection();
+    if (!image->globalSelection()) {
+        QUndoCommand *globalSelectionCommand =
+            new KisSetGlobalSelectionCommand(image, 0, 0);
 
-    new KisSelectionTransaction(QString(), image, selection, selectionCmd);
+        undoAdapter->addCommand(globalSelectionCommand);
+    }
+
+    KisSelectionSP selection = image->globalSelection();
 
+    KisSelectionTransaction transaction(QString(), image, selection);
     selection->getOrCreatePixelSelection()->select(image->bounds());
+    transaction.commit(undoAdapter);
+
+    undoAdapter->endMacro();
 
     m_view->selectionManager()->selectionChanged();
-    m_view->document()->addCommand(selectionCmd);
 }
 
 void KisSelectionManager::deselect()
@@ -575,7 +577,7 @@ void KisSelectionManager::clear()
 
     KisSelectionSP sel = m_view->selection();
 
-    KisTransaction * t = new KisTransaction(i18n("Clear"), dev);
+    KisTransaction transaction(i18n("Clear"), dev);
 
     if (sel)
         dev->clearSelection(sel);
@@ -584,8 +586,9 @@ void KisSelectionManager::clear()
         dev->setDirty();
     }
 
+    transaction.commit(image->undoAdapter());
+
     dev->setDirty(image->bounds());
-    image->undoAdapter()->addCommand(t);
 }
 
 void KisSelectionManager::deleteSelection()
@@ -620,15 +623,11 @@ void KisSelectionManager::fill(const KoColor& color, bool fillWithPattern, const
 
     KisPainter painter2(dev, selection);
 
-    if (image->undo()) painter2.beginTransaction(transactionText);
-
+    painter2.beginTransaction(transactionText);
     painter2.bitBlt(0, 0, filled, 0, 0, image->width(), image->height());
+    painter2.endTransaction(image->undoAdapter());
 
     dev->setDirty();
-
-    if (image->undo()) {
-        image->undoAdapter()->addCommand(painter2.endTransaction());
-    }
 }
 
 void KisSelectionManager::fillForegroundColor()
@@ -656,7 +655,7 @@ void KisSelectionManager::reselect()
 
     if (image->globalSelection()) {
         KisReselectGlobalSelectionCommand* cmd = new KisReselectGlobalSelectionCommand(image);
-        m_view->document()->addCommand(cmd);
+        image->undoAdapter()->addCommand(cmd);
     }
 }
 
@@ -669,16 +668,14 @@ void KisSelectionManager::invert()
     KisSelectionSP selection = m_view->selection();
     if (!selection) return;
 
-    KisPixelSelectionSP s = selection->getOrCreatePixelSelection();
-
-    KisSelectionTransaction * t = new KisSelectionTransaction(i18n("Invert"), image, selection);
-    Q_CHECK_PTR(t);
+    KisPixelSelectionSP pixelSelection = selection->getOrCreatePixelSelection();
 
-    s->invert();
-    s->setDirty(image->bounds());
+    KisSelectionTransaction transaction(i18n("Invert"), image, selection);
+    pixelSelection->invert();
+    transaction.commit(image->undoAdapter());
 
+    pixelSelection->setDirty(image->bounds());
     selectionChanged();
-    m_view->document()->addCommand(t);
 }
 
 void KisSelectionManager::copySelectionToNewLayer()
@@ -741,7 +738,7 @@ void KisSelectionManager::grow(qint32 xradius, qint32 yradius)
     if (xradius <= 0 || yradius <= 0)
         return;
 
-    KisSelectionTransaction *t = new KisSelectionTransaction(i18n("Grow Selection"), image, m_view->selection());
+    KisSelectionTransaction transaction(i18n("Grow Selection"), image, m_view->selection());
 
     max = new quint8* [layerSize.width() + 2 * xradius];
     buf = new quint8* [yradius + 1];
@@ -839,7 +836,8 @@ void KisSelectionManager::grow(qint32 xradius, qint32 yradius)
     delete[] buf;
     delete[] out;
 
-    m_view->document()->addCommand(t);
+    transaction.commit(image->undoAdapter());
+
     m_view->selection()->setDirty(image->bounds());
     selectionChanged();
 }
@@ -853,8 +851,7 @@ void KisSelectionManager::shrink(qint32 xradius, qint32 yradius, bool edge_lock)
     if (!m_view->selection()) return;
     KisPixelSelectionSP selection = m_view->selection()->getOrCreatePixelSelection();
 
-    KisSelectionTransaction *t = new KisSelectionTransaction(i18n("Shrink Selection"), image, m_view->selection());
-    Q_CHECK_PTR(t);
+    KisSelectionTransaction transaction(i18n("Shrink Selection"), image, m_view->selection());
 
     //determine the layerSize
     QRect layerSize = image->bounds();
@@ -989,7 +986,8 @@ void KisSelectionManager::shrink(qint32 xradius, qint32 yradius, bool edge_lock)
     delete[] buf;
     delete[] out;
 
-    m_view->document()->addCommand(t);
+    transaction.commit(image->undoAdapter());
+
     m_view->selection()->setDirty(image->bounds());
     selectionChanged();
 }
@@ -1202,8 +1200,7 @@ void KisSelectionManager::border(qint32 xradius, qint32 yradius)
     //determine the layerSize
     QRect layerSize = image->bounds();
 
-    KisSelectionTransaction *t = new KisSelectionTransaction(i18n("Border Selection"), image, m_view->selection());
-    Q_CHECK_PTR(t);
+    KisSelectionTransaction transaction(i18n("Border Selection"), image, m_view->selection());
 
     quint8  *buf[3];
     quint8 **density;
@@ -1241,7 +1238,8 @@ void KisSelectionManager::border(qint32 xradius, qint32 yradius)
             delete[] source[i];
         delete[] transition;
 
-        m_view->document()->addCommand(t);
+        transaction.commit(image->undoAdapter());
+
         m_view->selection()->setDirty(image->bounds());
         selectionChanged();
         return;
@@ -1406,8 +1404,8 @@ void KisSelectionManager::border(qint32 xradius, qint32 yradius)
     density -= xradius;
     delete[] density;
 
+    transaction.commit(image->undoAdapter());
 
-    m_view->document()->addCommand(t);
     m_view->selection()->setDirty(image->bounds());
     selectionChanged();
 }
@@ -1420,8 +1418,7 @@ void KisSelectionManager::feather(qint32 radius)
         return;
 
     KisPixelSelectionSP selection = m_view->selection()->getOrCreatePixelSelection();
-    KisSelectionTransaction * t = new KisSelectionTransaction(i18n("Feather Selection"), image, m_view->selection());
-    Q_CHECK_PTR(t);
+    KisSelectionTransaction transaction(i18n("Feather Selection"), image, m_view->selection());
 
     // compute horizontal kernel
     const uint kernelSize = radius * 2 + 1;
@@ -1455,7 +1452,8 @@ void KisSelectionManager::feather(qint32 radius)
     verticalPainter.applyMatrix(kernelVertical, interm, rect.topLeft(), rect.topLeft(), rect.size(), BORDER_AVOID);
     verticalPainter.end();
 
-    m_view->document()->addCommand(t);
+    transaction.commit(image->undoAdapter());
+
     m_view->selection()->setDirty(image->bounds());
     selectionChanged();
 }
diff --git a/krita/ui/kis_view2.cpp b/krita/ui/kis_view2.cpp
index c310d70..85c8f34 100644
--- a/krita/ui/kis_view2.cpp
+++ b/krita/ui/kis_view2.cpp
@@ -620,7 +620,7 @@ void KisView2::connectCurrentImage()
     if (image()) {
         if (m_d->statusBar) {
             connect(image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace *)), m_d->statusBar, SLOT(updateStatusBarProfileLabel()));
-            connect(image(), SIGNAL(sigProfileChanged(KoColorProfile *)), m_d->statusBar, SLOT(updateStatusBarProfileLabel()));
+            connect(image(), SIGNAL(sigProfileChanged(const KoColorProfile *)), m_d->statusBar, SLOT(updateStatusBarProfileLabel()));
             connect(image(), SIGNAL(sigSizeChanged(qint32, qint32)), m_d->statusBar, SLOT(imageSizeChanged(qint32, qint32)));
 
         }
diff --git a/krita/ui/kra/kis_kra_loader.cpp b/krita/ui/kra/kis_kra_loader.cpp
index 2f1085c..372a687 100644
--- a/krita/ui/kra/kis_kra_loader.cpp
+++ b/krita/ui/kra/kis_kra_loader.cpp
@@ -201,7 +201,7 @@ void KisKraLoader::loadBinaryData(KoStore * store, KisImageWSP image, const QStr
         QByteArray data; data.resize(store->size());
         store->read(data.data(), store->size());
         store->close();
-        image->setProfile(KoColorSpaceRegistry::instance()->createColorProfile(image->colorSpace()->colorModelId().id(), image->colorSpace()->colorDepthId().id(), data));
+        image->assignImageProfile(KoColorSpaceRegistry::instance()->createColorProfile(image->colorSpace()->colorModelId().id(), image->colorSpace()->colorDepthId().id(), data));
     }
 
 
diff --git a/krita/ui/tool/kis_selection_tool_helper.cpp b/krita/ui/tool/kis_selection_tool_helper.cpp
index 2920fd5..7d6eca4 100644
--- a/krita/ui/tool/kis_selection_tool_helper.cpp
+++ b/krita/ui/tool/kis_selection_tool_helper.cpp
@@ -31,7 +31,7 @@
 #include "canvas/kis_canvas2.h"
 #include "kis_view2.h"
 #include "kis_selection_manager.h"
-#include "kis_selection_transaction.h"
+#include "kis_transaction.h"
 #include "commands/kis_selection_commands.h"
 #include "kis_shape_controller.h"
 
@@ -52,52 +52,52 @@ KisSelectionToolHelper::~KisSelectionToolHelper()
 {
 }
 
-QUndoCommand* KisSelectionToolHelper::selectPixelSelection(KisPixelSelectionSP selection, selectionAction action)
+void KisSelectionToolHelper::selectPixelSelection(KisPixelSelectionSP selection, selectionAction action)
 {
-    bool hasSelection = m_layer->selection();
+    KisUndoAdapter *undoAdapter = m_layer->image()->undoAdapter();
+    undoAdapter->beginMacro(m_name);
 
-    QUndoCommand* selectionCmd = new QUndoCommand(m_name);
+    bool hasSelection = m_layer->selection();
 
     if (!hasSelection)
-        new KisSetGlobalSelectionCommand(m_image, selectionCmd);
+        undoAdapter->addCommand(new KisSetGlobalSelectionCommand(m_image));
 
-    new KisSelectionTransaction(m_name, m_image, m_layer->selection(), selectionCmd);
+    KisSelectionTransaction transaction(m_name, m_image, m_layer->selection());
 
-    KisPixelSelectionSP getOrCreatePixelSelection = m_layer->selection()->getOrCreatePixelSelection();
+    KisPixelSelectionSP pixelSelection = m_layer->selection()->getOrCreatePixelSelection();
 
     if (! hasSelection || action == SELECTION_REPLACE) {
-        getOrCreatePixelSelection->clear();
+        pixelSelection->clear();
         if (action == SELECTION_SUBTRACT)
-            getOrCreatePixelSelection->invert();
+            pixelSelection->invert();
     }
-    getOrCreatePixelSelection->applySelection(selection, action);
+    pixelSelection->applySelection(selection, action);
 
+    QRect dirtyRect = m_image->bounds();
     if (hasSelection && action != SELECTION_REPLACE && action != SELECTION_INTERSECT) {
-        QRect rc = selection->selectedRect();
-        getOrCreatePixelSelection->setDirty(rc);
-        m_layer->selection()->updateProjection(rc);
-        m_canvas->view()->selectionManager()->selectionChanged();
-    } else {
-        getOrCreatePixelSelection->setDirty(m_image->bounds());
-        m_layer->selection()->updateProjection(m_image->bounds());
-        m_canvas->view()->selectionManager()->selectionChanged();
+        dirtyRect = selection->selectedRect();
     }
-    return selectionCmd;
+    m_layer->selection()->updateProjection(dirtyRect);
+
+    transaction.commit(undoAdapter);
+    undoAdapter->endMacro();
+
+    pixelSelection->setDirty(dirtyRect);
+    m_canvas->view()->selectionManager()->selectionChanged();
 }
 
 void KisSelectionToolHelper::addSelectionShape(KoShape* shape)
 {
-    bool hasSelection = m_layer->selection();
+    KisUndoAdapter *undoAdapter = m_layer->image()->undoAdapter();
+    undoAdapter->beginMacro(m_name);
 
-    m_canvas->startMacro(m_name);
+    bool hasSelection = m_layer->selection();
 
     if (!hasSelection)
-        m_canvas->addCommand(new KisSetGlobalSelectionCommand(m_image, 0));
+        undoAdapter->addCommand(new KisSetGlobalSelectionCommand(m_image, 0));
 
     KisSelectionSP selection = m_layer->selection();
-
-    if (selection->isDeselected())
-        new KisSelectionTransaction(m_name, m_image, m_layer->selection());
+    KisSelectionTransaction transaction(m_name, m_image, m_layer->selection());
 
     KisShapeSelection* shapeSelection;
     if (!selection->hasShapeSelection()) {
@@ -111,9 +111,10 @@ void KisSelectionToolHelper::addSelectionShape(KoShape* shape)
     if (kiscontroller)
         kiscontroller->prepareAddingSelectionShape();
 
-    QUndoCommand * cmd = m_canvas->shapeController()->addShape(shape);
-    m_canvas->addCommand(cmd);
+    transaction.commit(undoAdapter);
 
-    m_canvas->stopMacro();
+    QUndoCommand *cmd = m_canvas->shapeController()->addShape(shape);
+    undoAdapter->addCommand(cmd);
+    undoAdapter->endMacro();
 }
 
diff --git a/krita/ui/tool/kis_selection_tool_helper.h b/krita/ui/tool/kis_selection_tool_helper.h
index 21e671e..5a29863 100644
--- a/krita/ui/tool/kis_selection_tool_helper.h
+++ b/krita/ui/tool/kis_selection_tool_helper.h
@@ -37,7 +37,7 @@ public:
     KisSelectionToolHelper(KisCanvas2* canvas, KisNodeSP node, const QString& name);
     virtual ~KisSelectionToolHelper();
 
-    QUndoCommand* selectPixelSelection(KisPixelSelectionSP selection, selectionAction action);
+    void selectPixelSelection(KisPixelSelectionSP selection, selectionAction action);
     void addSelectionShape(KoShape* shape);
 
 private:
diff --git a/krita/ui/tool/kis_tool_freehand.cc b/krita/ui/tool/kis_tool_freehand.cc
index 4180544..88dabb0 100644
--- a/krita/ui/tool/kis_tool_freehand.cc
+++ b/krita/ui/tool/kis_tool_freehand.cc
@@ -450,8 +450,7 @@ void KisToolFreehand::endPaint()
         KisLayerSP layer = dynamic_cast<KisLayer*>(currentNode().data());
 
         if (layer && !m_paintIncremental) {
-            KisTransaction *incrementalTransaction =
-                    dynamic_cast<KisTransaction*>(m_painter->endTransaction());
+            m_painter->deleteTransaction();
 
             KisPainter painter(m_source, currentSelection());
             painter.setCompositeOp(m_compositeOp);
@@ -475,12 +474,12 @@ void KisToolFreehand::endPaint()
                 indirect->setTemporaryTarget(0);
             }
             m_source->setDirty(painter.dirtyRegion());
-            delete incrementalTransaction;
 
             m_incrementalDirtyRegion = QRegion();
-            canvas()->addCommand(painter.endTransaction());
+
+            painter.endTransaction(image()->undoAdapter());
         } else {
-            canvas()->addCommand(m_painter->endTransaction());
+            m_painter->endTransaction(image()->undoAdapter());
         }
     }
     delete m_painter;
diff --git a/krita/ui/widgets/kis_custom_image_widget.cc b/krita/ui/widgets/kis_custom_image_widget.cc
index 21309af..f976bb0 100644
--- a/krita/ui/widgets/kis_custom_image_widget.cc
+++ b/krita/ui/widgets/kis_custom_image_widget.cc
@@ -193,9 +193,10 @@ void KisCustomImageWidget::buttonClicked()
         if (layer && backgroundOpacity() < OPACITY_OPAQUE_U8) {
             KisFillPainter painter;
             painter.begin(layer->paintDevice());
+#warning "Why transaction here? FIXME: remove it!"
             painter.beginTransaction("");
             painter.fillRect(0, 0, width, height, bgColor, OPACITY_OPAQUE_U8);
-            delete painter.endTransaction();
+            painter.deleteTransaction();
 
         }
         if (chkFromClipboard->isChecked()) {
