Neil Williams linux at
Thu Jul 7 06:43:54 EDT 2005

On Wednesday 06 July 2005 10:11 pm, Derek Atkins wrote:

(bear with me, this is a long one).

> > I used QofCollection because of the tight control of 1 type per
> > collection. It makes it easy to handle multiple entities. A GList of
> > entities of more than one type is much more difficult to handle. Even if
> > each instance only contains one entity, the fact that the one parameter
> > can access entities of more than one type makes it very difficult to
> > handle generically.
> But that's not actually correct.  The "collection" can be any of Job,
> Employee, Vendor, or Customer... So you kind of need to know ahead of time
> what it is.

I was handling that inside the object - it would only use objects it knew in 
advance. It's fine for an object to know about other objects that it 
references. Doesn't matter now.

> > The current backend knows about these things in advance, QOF cannot.
> Why not?

Turns out it probably can.

> Why can't there be a QOF_CHOICE object which is sort of like a C++
> template.. QOF_CHOICE doesn't really exist by itself, it's a
> QOF_CHOICE<QOF_X, QOF_Y, QOF_Z> and holds a single entity of type X, Y, or
> Z for the pursposes of QOF/QSF..  But for querying the object it queries as
> if it's an X, Y, or Z.

Eeek! Sounds great but I must admit I haven't any experience of templates.

How's this for starters?

Each choice type would need it's own definition of the allowable objects - 
each of which would need to be registered as normal. Objects would declare 
themselves to be one option of a particular choice. That could be a new 
component of QofObject, "choice". If GncOwner declared itself as 
choice: QOF_CHOICE, 
GncCustomer could set:
choice: GNC_ID_OWNER
in it's QofObject definition, declaring gncCustomer as an option for 

(maybe choice_parent: instead). That should be easily extensible.

As for the order in which objects are registered, QOF will either create a new 
key and an empty hash value if GncOwner is registered first or it will create 
the GNC_ID_OWNER key and it's first value if GncCustomer is registered first.

So GncOwner would end up with a QofObject description but could set a NULL 
foreach:. Queries would use the original QofAccessFuncs to obtain the 
GncCustomer etc..

The GncInvoice would have a GNC_ID_OWNER parameter (as before) and QOF would 
lookup a new static table (alongside the existing GList* in qofobject.c) that 
identifies the allowable choices for that object as it is identified as a 
choice. A simple gboolean qof_object_is_choice(QofIdType) and GList* 
qof_object_get_choices(QofIdType) that each refer to a static GHashTable 

The table would be populated by the same qof_object_register() function - it 
would also be v.small.

QOF could use the original GNC_ID_OWNER type parameter to retrieve the 
owner.customer etc. instance (this keeps existing queries happy). QOF would 
look up the param_type and if it's a QOF_CHOICE, handle it as a simple 
QofEntity instead of using the param_type that is set to GNC_ID_OWNER.

QOF now has a QofEntity and therefore a ent->e_type, belonging to the current 
invoice object, using the GNC_ID_OWNER QofParam. That is sufficient for QSF 
to write out a QofEntityReference and export it. This would also allow 
recursion as the invoice entity would contain an owner that would provide the 
entity that can be copied to the export book.

This would be done in QSF for all QOF_CHOICE objects - an extra conditional. 
The QSF would then contain:
<object type="gncInvoice">
  <guid type="guid">invoice_guid_as_string</guid>
  <guid type="gncCustomer">customer_guid_as_string</guid>

On importing/merging, QOF would create the GncCustomer etc. from it's object 
tag block in the same file. When populating the invoice, QOF would come 
across the GNC_ID_OWNER QofParam and lookup GNC_ID_OWNER in the choice table. 
QOF would need to create an owner object to pass to the QofSetterFunc for the 
invoice. GncOwner, as a choice object, would look up it's registered choices 
and accept the entity using the QofSetterFunc for that type. The invoice for 
it's part would use the param_setfcn to receive the owner. 

Would that work?

(Phew! That took two hours to work out!)
(and it'll take a few minutes to read and understand too!)

> Well, I was kind of thinking that it might be easier to have an "Export
> Book" 

Next on my list ...

> The downside is that this requires extra work outside of QOF; each object
> would need to know all the references to other objects and be able to add
> them to the Export Book.

i.e. the export routine in GnuCash is hard-coded with the list of objects that 
comprise the book.

Not if QOF_CHOICE works - it should allow the recursion needed to find the 
references within QOF with no explicit help from the export routine - just 
the objects concerned.

> Well, it would work just fine IFF you added an API that would allow QOF to
> ask the invoice to return all the sub-objects so that QOF could export
> them.

That's what should happen. The Choice will allow the invoice to tell QOF about 
a GncCustomer (as opposed to a vendor etc.). The Collect will allow the 
invoice to tell QOF about the list of GncEntry entities. As you recommended, 
two is better than one.


Neil Williams

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url :

More information about the gnucash-devel mailing list