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