Logic ideas - 5 levels.

Neil Williams linux at codehelp.co.uk
Wed Sep 28 11:35:12 EDT 2005

On Wednesday 28 September 2005 3:06 pm, Derek Atkins wrote:
> Quoting Neil Williams <linux at codehelp.co.uk>:
> > A bit like QSF and qof_book_merge and indeed cashutil itself. To keep
> > things small and simple(r) I copy current sources into a new tree for
> > testing. It's much like creating a branch. I work with only the files I
> > need for the current critical area, making development faster.
> >
> >> I'd like
> >> to see an existing dialog of moderate complexity in terms of these
> >> rules.
> >
> > Nothing yet, I've got other things to solve first. I'll post when I've
> > got some real code.
> I still don't understand how this helps with User Input problem...  You
> don't want to have to build a "test object" and then test it.. 

?? Uh?? I haven't built any code yet, I'm not into test objects at runtime, 
I'm creating a separate tree to write the logic code in the first place!

No way will it "build" anything to check the logic, that's daft. I have to 
build the code first though. PLEASE read the message, Derek!

I'll be building a test application that will help me develop the rules and 
the code that runs the rules. It's only the rules and the logic apparatus 
that gets into the main tree and that is ALL runtime stuff.

The logic layer itself is a bit of a gopher. It gets requests from user 
interface inputs via the handler, it passes results back to the user 
interface handler. It gets it's rules from the objects and other structs in 
the layer itself (for the higher level logic) and uses those to decide on the 
result. Once the dialog can enable the OK button, the data is committed to 
the book upon clicking OK. In the CLI, it will work differently, that is an 
incremental model where the entity is created BEFORE any parameters are 
entered. The entity is then logically checked as each parameter is edited and 
cashutil will free the entity if the user aborts.

That's why I don't like talking in terms of what happens with specific 
widgets, the layer is widget neutral, it only cares about the logic, the data 
and the objects. It's intended to fit behind the UI going to and fro to 
provide answers about what to do with the user input in realtime.

The one layer will support an API that will be flexible enough to be used in a 
variety of UI's. If you can provide the data, the objects and logical rules, 
the logic layer will work.

If you want to create the entity first (as with the CLI), you can.
If you want to check all the data before creating the entity, you can do that 

Which way you do it will determine in which order the rules are called but it 
won't affect the logical result because all the critical rules will still 
have to be satisfied whichever way around.

> I want to 
> be able to test the inputs before I translate them into an object and use
> all the object setters.

You will. That's exactly the point. But before you can do that I've got to 
have a test tree that allows me to build the code. There IS no code yet.

Off the top of my head, it might go something like this:

Dialog input -> dialog_handler -> logic_layer (unchanged and untested).

logic_layer -> looks up rules for the object and parameter, does ALL the 
logical checks required for that combination and sets GncLogicResult. 

If == 0, calls the param->param_setfcn before returning. Only those parameters 
that are suitable for a setfcn call would allow a zero result, if an object 
needs >1 parameter to be logically intact, then that will be enforced. This 
is the whole point, cashutil cannot know this because the logic that dictates 
how parameters interrelate is hidden in the GUI. So currently, cashutil 
blindly sets parameters independently of any other parameter. That's why it's 
not ready for use!!!!!

Dialog receives the logic result and proceeds:
1. If 0, check if OK should be enabled by calling a summary function in the 
logic layer, maybe gboolean gnc_logic_complete() or gint 
gnc_logic_remaining() which returns the number of inputs that are still 
required before the dialog can enable OK, again zero would mean go ahead.
2. If <>0, read the reason from the logic layer and decide how to complain 
to / help the user.

The logic layer will completely replace any logic currently in the dialog that 
determines if the user input is logically intact. Depending on the type of 
data, this could involve one or more of the 5 logic levels - the rules being 
modelled on exactly what happens now.

> It sounds like I need to modify the object, test the modification, and if
> there's a failure back out the modifications...

No. You read the input from the user, pass that back to the object with the 
parameter that is meant to accept it and get back a logical result. If  
successful, the data will have been committed in the same stage. If it fails, 
you'll get back a reason for the refusal which you pass on to the user. 
Failure just means the parameter remains unchanged and the dialog asks the 
user to try again, explaining what needs to be done. Exactly as now. If the 
input is OK but more inputs are required (essential fields etc.), then the 
parameter can be set but the log_result is still non-zero. Again, the dialog 
asks the logic layer why and passes that on to the user.

Maybe something like (off the top of my head)
gnc_logic_test(QofIdType object_type, gpointer data, QofParam param)

Whereas now in QOF you'd call qof_class_get_parameter and then 
param->param_setfcn(), that would be called behind the scenes IF the rules 
specify that the data can be committed.
Alternatively, other parts of the code use the objects directly with some 
xaccObjectSetParam type. Instead of doing the logic in the dialog and THEN 
calling the setter, you call the logic test with the UNCHECKED input data and 
either report back on error or carry on to the next element. If there are no 
more elements that are essential for the current object definition, the logic 
layer reports that it is acceptable to commit the data and the dialog enables 
the OK / the CLI exits the edit sub-shell.

Dialogs that use >1 object will be able to test one against another because of 
the higher level rules - 4 and 5. The dialog won't have to do any of that 
itself. The objects declare their rules at registration and higher rules are 
added at application startup.

I'm taking the logic out of the dialog - the dialog reads the input data in 
realtime, it delegates the job of checking it logically to the logic layer 
and doesn't have to bother setting the data itself.

The current step(s) in the dialog handler that actually check the incoming 
data would be moved into the logic test so that the CLI could use the same 

You get a result immediately that you read the data from the dialog input, the 
whole point is that the dialog doesn't wait until OK is clicked, it checks 
everything as it comes in, by passing the incoming data to the logic layer.

The rules specify which of the 5 levels get checked for which parameters and 
which objects.

> It also means I can't do 
> real-time testing (e.g. enable the OK button) on user inputs because I'm
> contantly having to create test objects...

Uh??? There are NO TEST OBJECTS! There will be a test tree for me to develop 
the code but you'll never see any of that, let alone use it to create 

In fact, the dialog may not actually be creating anything itself, the dialog 
just passes the data to the logic layer and if all the correct data is 
available for a new entity, it would be created and populated.

New Account could simply check each input against the logic layer and then 
leave the logic to create the actual account - but only when the logic layer 
is satisfied that the rules have been met.

> Short of creating a UI-Widget-Independent input layer, which is...
> painful.. I
> just don't see how to solve this problem in a UI-independent way, and
> your five
> levels still don't help with this problem.

Might that be because you're still reading them as file level tests?

This is a layer, it's a runtime layer, it involves no test objects or building 
anything at runtime. It simply moves the logic from the dialog to the logic 
layer so that the same logic can be used by a non-GUI, specifically, 

It simply replaces the logic in the dialog with a single call to the logic 
layer for each data input that both checks the data AND actions the changes 
IF the logic is good.

The logic is a mix of QofObject and QofClass rules. i.e. some rules operate 
solely on the object definition (static data) and don't need a real entity. 
Others would create the entity if lower logic levels are OK and use that to 
check against other entities. The entity would remain unless the user cancels 
the entire dialog. So where the current GUI creates one entity, the GUI will 
delegate that role to the logic layer which will create just the one entity. 
No spurious entities, subject to undo and user cancel.


Neil Williams

-------------- 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/20050928/2042cf51/attachment.bin

More information about the gnucash-devel mailing list