CLI undo edit?

Neil Williams linux at codehelp.co.uk
Wed Aug 10 07:44:18 EDT 2005


On Wednesday 10 August 2005 8:49 am, Derek Atkins wrote:
> Also, I think the right way to go about it is not a list of changed
> entities, but a list of events/operations.

So each event would generate a list of the parameter values of each affected 
entity as they existed prior to the event.

Undo List 
	-> List of affected entities (just the type and GUID) per event.
		-> list of affected parameter values before the event.

In order to do redo properly, the undo operation needs to add itself to the 
list as an event that includes the state of affected parameter values before 
the user clicked undo because the *current* state of any entity would not 
exist in the list, only the previous state.

I'd like to check my logic of how this would work - when a user clicks 
"undo" / presses Ctrl-Z 3 times and then restarts editing, the last two 
positions in the list need to be freed - but only if the next event is NOT a 
redo. Yes?

I'd use modified begin_edit/commit_edit calls that pass the char* 
param->parameter_name to identify the entity changes and use the type of 
event to determine how the values are stored and reset.

Values would need to be obtained at the begin edit stage and added to the undo 
list (or what is becoming more of a tree) only when an event was received - 
making storing the undo data into a two stage process, invisible to the 
application concerned. If there is no event before commit_edit, the undo data 
is freed (or should that if no event is received before the NEXT begin_edit?)

Changes that don't use BOTH a begin_edit/commit_edit pair AND generate an 
event won't be available for undo or redo. What happens in the numerous 
places where engine events are suspended?

Outline so far:

/** @brief The parameter changes, >=1 per affected entity 

One per parameter change - the bottom level of any undo. A single click of 
Undo could use the data from one or many parameter changes - as determined by 
the event. Each parameter change can be for any entity of any registered type 
in the book and parameter changes can be repeated for the multiple changes to 
different parameters of the same entity. The combination of param, guid and 
type will be unique per event. (i.e. no event will ever set the same 
parameter of the same entity twice (with or without different data) in one 
undo operation.)
*/
typedef struct qof_undo_entity_t
{
        QofParam *param; /**< static anyway so only store a pointer */
/* or maybe just use the param_name */
        const GUID *guid; /**< or use a cached guid_as_string? */
        QofIdType type; /**< ditto param, static. */
        char *value; /**< cached string? */
}qof_undo_entity;

/** @brief The affected entities, >=1 per event 

The top level of any undo. Contains a GList that keeps the type of event and 
the GList of qof_undo_entity* instances relating to that event. Some form of 
index / counter probably too in order to speed up freeing unwanted events and 
undo data upon resumption of editing and in controlling the total number of 
events that can be undone.

Each qof_undo_event.entity_list can contain data about >1 type of entity.
*/
typedef struct qof_undo_event_t
{
	GNCEngineEventType type;
        Timespec ts;
	gint index_position;
	GList *entity_list; /**< GList of qof_undo_entity* */
}qof_undo_event;

/** @brief the undo list itself */
// definition within the QofBook opaque struct
	GList *book_undo; /**< GList of qof_undo_event* */

Also in qofbook.c:
#define MAX_UNDO_LENGTH     300

The Timespec would probably be better in this top level struct and it would be 
the earliest valid Timespec from all qof_undo instances in the list for that 
event.

The book would report the first valid Timespec in the undo list as the time of 
the first change of the book data.

The entire undo list would have to be accessible only from a single book - 
multiple books, multiple undo lists.

With such a structure, an undo list that could hold data for all parameters of 
all entities affected by up to 300 individual events should be more than 
adequate. I plucked 300 from examples of other applications - there's no 
particular reason behind it - we could use 100 or 500. I doubt there's much 
point in going beyond 500 and, personally, I'd see much less than 100 as a 
wasted opportunity.

A simple #define should suffice for extensibility.

We can look at configuration options for reducing it from the default later.

> Then you can undo/redo per 
> operation.

OK.

> Each operation can have a list of changed entities. 
> Therefore, an "import" is a single operation (so it's a single
> undo/redo entry in the undo/list) but it can have as many entries as
> necessary in the changed-entries list.

Agreed. Other edits may also affect values of more than one parameter so there 
may be a lot of these sub-lists around. e.g. entity deletion.

It would need begin_edit() to pass the name of the parameter that is about to 
be edited - not a big problem. (To save storing the entire entity everytime.)

> Please don't feel inadiquate; you've done a tremendous amount of work.

Thank you, Derek. Overwhelmed is more the feeling! There's simply so much left 
to do! I admit, I do feel swamped by it at times.

Your encouragement and support is much appreciated. It's a vital component of 
the development process - volunteer projects cannot survive without 
motivation and nothing saps morale more than a lack of leadership and 
encouragement. It can't be easy to keep GnuCash on track when you are a 
volunteer yourself.

It's just a shame that Linas isn't around to be hands-on with QOF. It takes 
time for new developers to be able to contribute and an experienced lead 
developer is so important.

> Undo/Redo is a HARD problem in general unless we have the framework in
> place to support it.  Unfortunately I suspect that framework will
> require changes to QOF, but we'll have to see.

No more than the changes needed for book merging or QSF, I suspect.

> I don't expect this anytime soon; I'd much rather see g2 get done and
> out the door first ;)

Definitely. I will use some low-level form of this in the CLI - a single 
entity undo list in a CLI sub-shell that should form the basis of the full 
QOF version. Probably just an implementation of qof_undo_entity that bypasses 
the event system and works solely within the CLI shell code.

-- 

Neil Williams
=============
http://www.data-freedom.org/
http://www.nosoftwarepatents.com/
http://www.linux.codehelp.co.uk/

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.gnucash.org/pipermail/gnucash-devel/attachments/20050810/73efa4da/attachment.bin


More information about the gnucash-devel mailing list