CLI undo edit?

Neil Williams linux at codehelp.co.uk
Sat Aug 6 19:04:30 EDT 2005


On Saturday 06 August 2005 9:36 pm, Derek Atkins wrote:
> If QOF supported a native "undo" that would be REALLY COOL..  In fact,
> supported a "list" of undo operations would be even cooler!
>
> :)

(well, I did ask!)

My ideas on how that might be best achieved: (as expected, quite long!)

If it's limited to one undo operation per entity then a hashtable indexed on 
the GUID could work. That's the first option, not perfect but probably quite 
fast. A second change in the same entity would overwrite any previous and 
undoing changes would need to be done as a block. That's more of a confirm 
and commit model - like the merge, keep all changes back until a commit is 
executed. Not particularly good for undo, me thinks.

A list would be more flexible - undo lists have to be sequential so a generic 
qof_undo() would need a single GList of all changes and rolling such a list 
in strict sequential order back and forth (i.e. a redo as well as undo) is 
far faster than iterating / searching.

I'm presuming the list would be freed only when the book is saved? Therefore a 
job for the backend? I think QSF could do that, not sure about the GnuCash 
XML v2. (What happens with a SQL backend?)

The question is whether to store the entire entity or just parameter values. 
If only changes, is the overhead of identifying which bits have changed more 
than the overhead of storing the entity itself? 

Isn't this tying back into the whole SQL identification_of_changes idea? Can 
those be combined? QOF creates the undo list via the instance dirty routines 
and the SQL backend reads that to identify what changes need to be committed? 
(and then clears it at some point or keeps a configurable number of events on 
the list - more like a stack?)

It may be handy to only store changes, but that means passing the parameter 
name into the instance_dirty routines (which will retrieve the value as a 
string).

void qof_instance_make_dirty(QofInstance *inst, const char *param_name);

(QOF can't undo / redo anything unless the data is accessible as a parameter 
with a QofAccessFunc *and* a QofSetterFunc so passing the value as a string 
is pointless. The combination of param_name and the object e_type from the 
instance do the rest.)

I could do a qof_undo struct that contains the QofParam and a gpointer of the 
previous value of that parameter along with the type and GUID of the entity 
concerned?

struct qof_undo
{
	QofParam *param; /**< static anyway so only store a pointer */
	gpointer value  /**< Duplicated? (and freed later) */
	GUID guid;
	QofIdType type; /**< ditto param, static. */
};

Then make a GList of qof_undo* 's.

The gpointer value might just as easily be a string as QOF is already used to 
converting each type to and from strings. The guid may be more easily stored 
as a string too. So then the entire undo list consists of repeated structs 
consisting only of two pointers and two strings. Would those go into the 
cache?

A Timespec in qof_undo would solve David's request for a time since first 
change too. Simply read the first value in the GList and return ts or 
ts.tv_sec.

/** @brief Built into a GList for qof_undo() and qof_redo() */
typedef struct qof_undo_t
{
	QofParam *param; /**< static anyway so only store a pointer */
	char *value; /**< cached string? */
	char *guid_as_string; /**< cached string? */
	QofIdType type; /**< ditto param, static. */
	Timespec ts;
}qof_undo;

/** @brief rolls back one change at a time */
void qof_undo(void);
/** @brief re-does one undo at a time */
void qof_redo(void);

Each would return silently if the end of the list is reached in the 
appropriate direction. Maybe they should return gboolean so that the UI can 
tell if more steps are available? Or should that be a separate function:
gboolean qof_can_undo(); gboolean qof_can_redo();
Both would return FALSE after a save operation.

What about created / deleted entities? Some kind of enum as to the state of 
the entity perhaps, store each value and then store a value which denotes 
that the entity must be recreated. This would be read before the parameter 
values and would be interpreted as CREATE for undo (later in the list so read 
first) and DELETE for redo (reverse direction, parameters stored first then 
delete). Dirty instance calls would simply append their data to the list. Too 
much overhead? (ISTR prepend is faster so maybe those would be reversed.)

qof_undo would interpret a CREATE as a special case that re-instated the 
entity plus all it's parameters in one undo operation - maybe by using the 
Timespec to identify how far back to roll the list, all parameter values of 
the entity to be deleted being given the same Timespec.

Currently, replaying the logs is used for a crash situation (amongst others) - 
are we looking for some form of storage for the undo list? That, AFAICT, 
would be unusual for an application - most accept a loss of data upon a crash 
- and would be a worthy feather in the cap for GnuCash data integrity. Would 
the logs simply use the qof_undo data as well as / instead of their current 
data source, essentially providing an offline storage for the qof_undo data 
(written in the same as-we-go-until-we-crash manner as the current logs)? By 
using only strings, the log procedure could be relatively simple and possibly 
easier to implement as a data recovery method.

(I said it was non-trivial!)

Oh, and for this to work, gncCommodity is really going to have to be made 
available to QOF! (along with all other data sources that users may need to 
use in undo - if it isn't a QofObject with QofClass set and get parameters, 
it cannot be in a QOF undo/redo list).

This is well beyond what can be achieved (and tested) before G2 is released. 
Something for QOF 0.7 & G2.1 perhaps.

-- 

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/20050807/d4cb6833/attachment.bin


More information about the gnucash-devel mailing list