[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    Replacement for Qt's Undo Framework
From:       Alexander Potashev <aspotashev () gmail ! com>
Date:       2011-04-25 18:12:55
Message-ID: BANLkTinQY1TY2H4wRLNrQTQ6Yxht_v33xw () mail ! gmail ! com
[Download RAW message or body]

Hi,

The Qt's Undo Framework (QUndoCommand, QUndoStack, QUndoGroup,
QUndoView) has a few oddities:
1. The names of undo actions can only have a predefined prefix
(https://bugs.kde.org/show_bug.cgi?id=253459),
2. You can't use different strings for the name of undo action (Edit
-> Undo/Redo [some action]) and for the items in the undo history
(there is such panel, for example, in Step and Krita). The reason for
having different strings is to make grammatical cases of the names of
actions consistent with the context (in Russian and a few other
languages you should put %1 in accusative case in "Undo %1").


If I'm not mistaken, those problems can't be solved by just deriving
your own classes from QUndo*, because you need to override methods
like createUndoAction which are not "virtual" (sure, you can name
those methods differently, but then other problems may arise).

The solution is to fork QUndo* classes and fix the problems in the new
classes, so did I:
https://github.com/aspotashev/libkundo2
(the code looks like garbage, I only made it working, but didn't try
to clean it up)


At the first glance, the only way to use two strings for every
UndoCommand is to add yet another argument to the constructor of
UndoCommand. But then a huge amount of code would need changes, that's
not very good. Also, most languages don't really need different names
for undo actions and items in undo history.
I kept the arguments of UndoCommand() the same, but now if you put
something like "Create a document|-|creation of a document" as the
"text" into the constructor (or translate it with a similar string
with "|-|"), you'll get "Create a document" as the name of an item in
Undo History panel, and the "Undo ..." menu item will be called "Undo
creation of a document".

Screenshots:
http://ompldr.org/vOGYxaQ -- translation in Lokalize (into Russian)
http://ompldr.org/vOGYxag -- Step using different translations for
"Undo ..." command and undo history.

The patch I used for Step is attached.


What do you think about inclusion of KUndo*2 into kdelibs?


-- 
Alexander Potashev

["0001-use-libkundo2.patch" (text/x-patch)]

From aec3a9f2fa6c16d46a5de10bb29441007245c676 Mon Sep 17 00:00:00 2001
From: Alexander Potashev <aspotashev@gmail.com>
Date: Mon, 25 Apr 2011 19:46:51 +0400
Subject: [PATCH] use libkundo2

---
 step/CMakeLists.txt |    1 +
 step/mainwindow.cc  |    4 ++--
 step/undobrowser.cc |    4 ++--
 step/undobrowser.h  |    4 ++--
 step/worldmodel.cc  |   16 ++++++++--------
 step/worldmodel.h   |   10 +++++-----
 6 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/step/CMakeLists.txt b/step/CMakeLists.txt
index 4d571ea..e26dcd3 100644
--- a/step/CMakeLists.txt
+++ b/step/CMakeLists.txt
@@ -65,6 +65,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 kde4_add_executable(step ${step_SRCS})
 target_link_libraries(step
     stepcore
+    kundo2
     ${KDE4_KHTML_LIBS}
     ${KDE4_KNEWSTUFF3_LIBS}
     ${QT_QTOPENGL_LIBRARY}
diff --git a/step/mainwindow.cc b/step/mainwindow.cc
index fdc0e50..cdc5169 100644
--- a/step/mainwindow.cc
+++ b/step/mainwindow.cc
@@ -177,9 +177,9 @@ void MainWindow::setupActions()
     connect(worldModel->undoStack(), SIGNAL(canRedoChanged(bool)), actionRedo, \
                SLOT(setEnabled(bool)));
     connect(worldModel->undoStack(), SIGNAL(canUndoChanged(bool)), actionUndo, \
                SLOT(setEnabled(bool)));
     connect(worldModel->undoStack(), SIGNAL(cleanChanged(bool)), this, \
                SLOT(updateCaption()));
-    connect(worldModel->undoStack(), SIGNAL(undoTextChanged(const QString&)),
+    connect(worldModel->undoStack(), SIGNAL(undoActionTextChanged(const QString&)),
                                  this, SLOT(undoTextChanged(const QString&)));
-    connect(worldModel->undoStack(), SIGNAL(redoTextChanged(const QString&)),
+    connect(worldModel->undoStack(), SIGNAL(redoActionTextChanged(const QString&)),
                                  this, SLOT(redoTextChanged(const QString&)));
 
     actionDelete = actionCollection()->add<KAction>("edit_delete", worldModel, \
                SLOT(deleteSelectedItems()));
diff --git a/step/undobrowser.cc b/step/undobrowser.cc
index 05e6fdc..7979f44 100644
--- a/step/undobrowser.cc
+++ b/step/undobrowser.cc
@@ -20,7 +20,7 @@
 #include "undobrowser.moc"
 
 #include "worldmodel.h"
-#include <QUndoView>
+#include <kundoview2.h>
 #include <KUrl>
 #include <KIcon>
 #include <KLocale>
@@ -28,7 +28,7 @@
 UndoBrowser::UndoBrowser(WorldModel* worldModel, QWidget* parent, Qt::WindowFlags \
                flags)
     : QDockWidget(i18n("Undo history"), parent, flags), _worldModel(worldModel)
 {
-    _undoView = new QUndoView(_worldModel->undoStack(), this);
+    _undoView = new KUndoView2(_worldModel->undoStack(), this);
     setWidget(_undoView);
 }
 
diff --git a/step/undobrowser.h b/step/undobrowser.h
index a60d679..c05629d 100644
--- a/step/undobrowser.h
+++ b/step/undobrowser.h
@@ -22,7 +22,7 @@
 #include <QDockWidget>
 
 class WorldModel;
-class QUndoView;
+class KUndoView2;
 class KUrl;
 
 class UndoBrowser: public QDockWidget
@@ -39,7 +39,7 @@ public slots:
 
 protected:
     WorldModel* _worldModel;
-    QUndoView*  _undoView;
+    KUndoView2*  _undoView;
 };
 
 #endif
diff --git a/step/worldmodel.cc b/step/worldmodel.cc
index 513135b..85204ea 100644
--- a/step/worldmodel.cc
+++ b/step/worldmodel.cc
@@ -37,14 +37,14 @@
 #include <KIcon>
 #include <KLocale>
 
-class CommandEditProperty: public QUndoCommand
+class CommandEditProperty: public KUndoCommand2
 {
 public:
     CommandEditProperty(WorldModel* worldModel, StepCore::Object* object,
                 const StepCore::MetaProperty* property, const QVariant& newValue, \
bool merge);  
     int id() const { return _merge ? 1 : -1; }
-    bool mergeWith(const QUndoCommand* command);
+    bool mergeWith(const KUndoCommand2* command);
 
     void redo();
     void undo();
@@ -99,7 +99,7 @@ void CommandEditProperty::undo()
     //foreach(StepCore::Object* object, _objects) \
_worldModel->objectChanged(object);  }
 
-bool CommandEditProperty::mergeWith(const QUndoCommand* command)
+bool CommandEditProperty::mergeWith(const KUndoCommand2* command)
 {
     const CommandEditProperty* cmd = dynamic_cast<const \
CommandEditProperty*>(command);  Q_ASSERT(cmd != NULL);
@@ -118,7 +118,7 @@ bool CommandEditProperty::mergeWith(const QUndoCommand* command)
     return true;
 }
 
-class CommandNewItem: public QUndoCommand
+class CommandNewItem: public KUndoCommand2
 {
 public:
     CommandNewItem(WorldModel* worldModel, StepCore::Item* item, \
StepCore::ItemGroup* parent, bool create) @@ -190,7 +190,7 @@ void \
CommandNewItem::undo()  _shouldDelete = _create;
 }
 
-class CommandSetSolver: public QUndoCommand
+class CommandSetSolver: public KUndoCommand2
 {
 public:
     CommandSetSolver(WorldModel* worldModel, StepCore::Solver* solver)
@@ -204,7 +204,7 @@ protected:
     StepCore::Solver* _solver;
 };
 
-class CommandSimulate: public QUndoCommand
+class CommandSimulate: public KUndoCommand2
 {
 public:
     CommandSimulate(WorldModel* worldModel);
@@ -308,7 +308,7 @@ WorldModel::WorldModel(QObject* parent)
     : QAbstractItemModel(parent), _actions(0)
 {
     _selectionModel = new QItemSelectionModel(this, this);
-    _undoStack = new KUndoStack(this);
+    _undoStack = new KUndoStack2(this);
     _worldFactory = new WorldFactory();
     _world = new StepCore::World();
 
@@ -654,7 +654,7 @@ StepCore::Solver* WorldModel::swapSolver(StepCore::Solver* \
solver)  return oldSolver;
 }
 
-void WorldModel::pushCommand(QUndoCommand* command)
+void WorldModel::pushCommand(KUndoCommand2* command)
 {
     Q_ASSERT(!_simulationFrameWaiting || _simulationPaused);
     if(!isSimulationActive()) {
diff --git a/step/worldmodel.h b/step/worldmodel.h
index a441edd..5167a84 100644
--- a/step/worldmodel.h
+++ b/step/worldmodel.h
@@ -20,12 +20,11 @@
 #define STEP_WORLDMODEL_H
 
 #include <QAbstractItemModel>
-#include <QUndoCommand>
 #include <QVariant>
 #include <QTime>
 
 #include <stepcore/world.h>
-#include <kundostack.h>
+#include <kundostack2.h>
 
 namespace StepCore {
     class Object;
@@ -40,6 +39,7 @@ namespace StepCore {
 class QItemSelectionModel;
 class QTimer;
 class QMenu;
+class KActionCollection;
 class WorldFactory;
 class CommandSimulate;
 class SimulationThread;
@@ -122,8 +122,8 @@ public:
     StepCore::Solver* newSolver(const QString& name);
 
     // Undo/redo helpers
-    KUndoStack* undoStack() { return _undoStack; } ///< Get associated KUndoStack
-    void pushCommand(QUndoCommand* command); ///< Push new undo command
+    KUndoStack2* undoStack() { return _undoStack; } ///< Get associated KUndoStack2
+    void pushCommand(KUndoCommand2* command); ///< Push new undo command
     void beginMacro(const QString& text); ///< Begin undo macro
     void endMacro(); ///< End undo macro
 
@@ -240,7 +240,7 @@ protected:
 protected:
     StepCore::World* _world;
     QItemSelectionModel* _selectionModel;
-    KUndoStack* _undoStack;
+    KUndoStack2* _undoStack;
     const WorldFactory* _worldFactory;
     QString _errorString;
 
-- 
1.7.5.rc1



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic