protux-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Protux-devel] Mustux MUE - Mustux Undo Engine - First formal approach


From: Luciano Giordana
Subject: [Protux-devel] Mustux MUE - Mustux Undo Engine - First formal approach
Date: Thu, 13 May 2004 16:09:02 -0300

The Mustux Undo Engine - MUE


This brief text aims to provide a conceptual explanation on a proposed
Action/Anti-action Strategy Based Undo Service Engine, supposed to be the
main target on this phase of  Mustux (particularly Protux) project.

Known cases as Blender (www.blender.org) had serious problems to implement
undo engine because they decided to adopt a robust engine in advanced stages
of development, which caused enourmous back-fixes. Thus, it is important to
start implement such an engine as soon as possible in our project.

After some emails, we kind of agreed on the strategy matter. The proposed
strategy for MUE is the Action/Antiaction strategy, with some kind of
persistence ability.
Here follows a basic approach for such engine, using A/AA tecnique.


1 - The Action Stack (the Mue STACK)

We can initially think that everything performed by user should be some way
registered so it can be "undone". This is almost correct, if we think that
there are few things that should not be undone (like Quit, or Help, or Show
Bus Monitor, and other simple and not-undoable things) . That leads us to 2
things

- An action (an JMB action) must have a boolean flag "undoable", because
some actions won't be undoable.
- Undoable actions must be registered somewhere. A Stack (LIFO) must be
implemented,
and actions are stacked someway (more later) so they can be retrived in case
of an undo (of course, the very undo action is NOT undoable)

2 - The superclass MustuxObject and the PerformedAction class

An action to be undone must restore the data structures it modified. It can
be a simple cursor position or a entire list of clips. We never know what
data structure should be stacked (together the action), neither the size of
it. Thus, we must deal with abstract objects. Every data structure that is
supposed to be stacked for undo purposes in the application  must derive
from a common super class MustuxObject
Also, the stacked action must KNOW what data struct or what collection of
data structures it affcted. Thus, the performed actions must retaing
pointers to mustux objects, without worrying about their nature. This will
lead us to the conclusion that we must stack not only the JMBAction
performed, but a class that holds it and the circumstances on what it
happened, including any aditional data that the data struct affected could
depend, as the context of it was removed, for example.


3 - The PerformedAction

When performing actions, will be essentially pushing jmbactions into the MUE
stack. When undoing, we will retrieve the antiaction by poping the last
action up and discovering what is the antiaction related to it. One could
think: this could be stored in a table. Actually it will be, but the
"circumstances" won't. For example,
we can store in a static table the Delete Clip has Insert Clip as
antiaction, but think of "delete clip B from song 4 in project X ". We can
just store the pure idea the delete clip has insert clip as antiaction, but
not the whole scenario on when and how it happens. All these things must be
part of PerformedAction class, which will be stacked . The PerformedAction
class must then have proper atributes to hold this scenario, in the most
abstract way possible.

So, we would have a PerformedAction class like

PerformedAction in pseudo-definition
{
JmbAction* performedJmbAction;
MustuxObject* affectedObject;
JmbContext* contextWhenPerforming;
JmbMode* modeWhenPerforming;
ProjectState* stateWhenDoing;
}

And the MUE engine would make something like

PerformedAction a = MueStack.pop();
Antiaction a = ActionAntiActionTable.getAntiaction(a); // a brings all
// scenarios which must be restored from action
Jmb::broadcast(a);

Of course, Some static (see examples below) table would map actions to their
respective anti-actions.

The new thing here is the ProjectState. I think this could be kind of a
property table for each application which holds the very basic information
for a mustux project (which itself, should be promoted to libmustux as a
superclass facility).
In this object one can store things like current cursor position, snap mode
status, and so on... It is up to us to decide if a undo should restore
previous project state (sometimes it is not interesting). Anyway, Mue could
exist without it.

Now lets see an example of the static table that would map actions to
antiactions.

Action          AntiAction
Delete Clip     Insert Clip
Move Node       Move Node
Delete node     add node
mute track      unmute track
split clip      glue clip
Move Edge       Move Edge
Delete Track    Insert Track (*)

I call the attention to the last example : When you delete a track the
affected objects are a list of audioclips, which will be treat as a
MustuxObject* pointer. When performing the antiaction ("insert track") we
should call a serie of insert clips. This is provided by the MustuxObject*
pointer in the stacked action. The inserttrack could be overloaded to
receibe a list of clips to be automatcally inserted. So, when performing the
antiaction, we should upcast MustuxObject* to (AudioClip*) list, and pass it
it to insert_track(AudioClip*), and we get our clips back ! That is the
importance of storing in a abstract form the data affected by an action.


4 - The persistence

The more information we store in the Performed action, more reliable will be
the antiaction.  And since are have a single structure to hold all our
previous actions, it is just a matter of serialize it and persist it to the
HD in order to get a persistable behavior, just like we would have if we
used the memory-image approach (when you store all your data structure every
time you perform an action). The big difference here, is that you just
persist once, when you are about to quit the application. Also, you dont
need to persist a big number of levels (user could select how many previous
action it should persist after a quit).



5 - Conclusions

This is a first formal approach for Mustux MUE. Of course, many things here
must be discussed and improved, specially regarding the abstraction level
necessary to implement the getAntiAction with proper scenario. Anyway, the
final architeture should not differ too much from this initial approach,
exaclty because I am concerned in explaining in a higher level the concepts
involved here, and kind of show that the current
JmbMode+JmbContext+JmbSlots, just implemented, is a very proper moment to
start the Undo Engine coding (that's why I annouced this change before start
the undo engine, last September-2003). I hope that we can get it further
discussed ASAP so we can start real coding on this matter. Thanks

Luciano Giordana



________________________________________________
Horizon Serviços Digitais
Assine já! - 0300 789 70 90





reply via email to

[Prev in Thread] Current Thread [Next in Thread]