GnuCash  5.6-150-g038405b370+
dialog-job.c
1 /*
2  * dialog-job.c -- Dialog for Job entry
3  * Copyright (C) 2001, 2002 Derek Atkins
4  * Author: Derek Atkins <warlord@MIT.EDU>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, contact:
18  *
19  * Free Software Foundation Voice: +1-617-542-5942
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
21  * Boston, MA 02110-1301, USA gnu@gnu.org
22  */
23 
24 #include <config.h>
25 
26 #include <gtk/gtk.h>
27 #include <glib/gi18n.h>
28 
29 #include "dialog-utils.h"
30 #include "gnc-amount-edit.h"
31 #include "gnc-component-manager.h"
32 #include "gnc-ui.h"
33 #include "gnc-gui-query.h"
34 #include "qof.h"
35 #include "dialog-search.h"
36 #include "search-param.h"
37 
38 #include "gncBusiness.h"
39 #include "gncJob.h"
40 #include "gncJobP.h"
41 
42 #include "business-gnome-utils.h"
43 #include "dialog-job.h"
44 #include "dialog-invoice.h"
45 #include "dialog-payment.h"
46 
47 #define DIALOG_NEW_JOB_CM_CLASS "dialog-new-job"
48 #define DIALOG_EDIT_JOB_CM_CLASS "dialog-edit-job"
49 
50 #define GNC_PREFS_GROUP_SEARCH "dialogs.business.job-search"
51 
52 void gnc_job_window_ok_cb (GtkWidget *widget, gpointer data);
53 void gnc_job_window_cancel_cb (GtkWidget *widget, gpointer data);
54 void gnc_job_window_help_cb (GtkWidget *widget, gpointer data);
55 void gnc_job_window_destroy_cb (GtkWidget *widget, gpointer data);
56 void gnc_job_name_changed_cb (GtkWidget *widget, gpointer data);
57 
58 typedef enum
59 {
60  NEW_JOB,
61  EDIT_JOB
62 } JobDialogType;
63 
65 {
66  QofBook *book;
67  GncOwner *owner;
68  QofQuery *q;
69  GncOwner owner_def;
70 };
71 
73 {
74  GtkWidget * dialog;
75  GtkWidget * id_entry;
76  GtkWidget * cust_edit;
77  GtkWidget * name_entry;
78  GtkWidget * desc_entry;
79  GtkWidget * rate_entry;
80  GtkWidget * active_check;
81 
82  JobDialogType dialog_type;
83  GncGUID job_guid;
84  gint component_id;
85  QofBook * book;
86  GncJob * created_job;
87 
88  GncOwner owner;
89 
90 };
91 
92 static GncJob *
93 jw_get_job (JobWindow *jw)
94 {
95  if (!jw)
96  return NULL;
97 
98  return gncJobLookup (jw->book, &jw->job_guid);
99 }
100 
101 static void gnc_ui_to_job (JobWindow *jw, GncJob *job)
102 {
103  gnc_suspend_gui_refresh ();
104  gncJobBeginEdit (job);
105 
106  qof_event_gen(QOF_INSTANCE(job), QOF_EVENT_ADD, NULL);
107 
108  gncJobSetID (job, gtk_entry_get_text (GTK_ENTRY (jw->id_entry)));
109  gncJobSetName (job, gtk_entry_get_text (GTK_ENTRY (jw->name_entry)));
110  gncJobSetReference (job, gtk_entry_get_text (GTK_ENTRY (jw->desc_entry)));
111  gncJobSetRate (job, gnc_amount_edit_get_amount
112  (GNC_AMOUNT_EDIT (jw->rate_entry)));
113  gncJobSetActive (job, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
114  (jw->active_check)));
115  {
116  GncOwner * old = gncJobGetOwner (job);
117  gnc_owner_get_owner (jw->cust_edit, &(jw->owner));
118  if (! gncOwnerEqual (old, &(jw->owner)))
119  gncJobSetOwner (job, &(jw->owner));
120  }
121 
122  gncJobCommitEdit (job);
123  gnc_resume_gui_refresh ();
124 }
125 
126 static gboolean
127 gnc_job_verify_ok (JobWindow *jw)
128 {
129  const char *res;
130  gchar *string;
131 
132  /* Check for valid name */
133  res = gtk_entry_get_text (GTK_ENTRY (jw->name_entry));
134  if (g_strcmp0 (res, "") == 0)
135  {
136  const char *message = _("The Job must be given a name.");
137  gnc_error_dialog (GTK_WINDOW (jw->dialog), "%s", message);
138  return FALSE;
139  }
140 
141  /* Check for owner */
142  gnc_owner_get_owner (jw->cust_edit, &(jw->owner));
143  res = gncOwnerGetName (&(jw->owner));
144  if (res == NULL || g_strcmp0 (res, "") == 0)
145  {
146  const char *message = _("You must choose an owner for this job.");
147  gnc_error_dialog (GTK_WINDOW (jw->dialog), "%s", message);
148  return FALSE;
149  }
150 
151  /* Check for valid rate */
152  if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT(jw->rate_entry), NULL))
153  {
154  const char *message = _("The rate amount must be valid or you must leave it blank.");
155  gnc_error_dialog (GTK_WINDOW (jw->dialog), "%s", message);
156  return FALSE;
157  }
158 
159  /* Set a valid id if one was not created */
160  res = gtk_entry_get_text (GTK_ENTRY (jw->id_entry));
161  if (g_strcmp0 (res, "") == 0)
162  {
163  string = gncJobNextID(jw->book);
164  gtk_entry_set_text (GTK_ENTRY (jw->id_entry), string);
165  g_free(string);
166  }
167 
168  /* Now save it off */
169  {
170  GncJob *job = jw_get_job (jw);
171  if (job)
172  {
173  gnc_ui_to_job (jw, job);
174  }
175  }
176 
177  /* Ok, it's been saved... Change to an editor.. */
178  jw->dialog_type = EDIT_JOB;
179 
180  return TRUE;
181 }
182 
183 void
184 gnc_job_window_ok_cb (GtkWidget *widget, gpointer data)
185 {
186  JobWindow *jw = data;
187 
188  /* Make sure this is ok */
189  if (!gnc_job_verify_ok (jw))
190  return;
191 
192  /* Now save off the job so we can return it */
193  jw->created_job = jw_get_job (jw);
194  jw->job_guid = *guid_null ();
195 
196  gnc_close_gui_component (jw->component_id);
197 }
198 
199 void
200 gnc_job_window_cancel_cb (GtkWidget *widget, gpointer data)
201 {
202  JobWindow *jw = data;
203 
204  gnc_close_gui_component (jw->component_id);
205 }
206 
207 void
208 gnc_job_window_help_cb (GtkWidget *widget, gpointer data)
209 {
210  JobWindow *jw = data;
211  gnc_gnome_help (GTK_WINDOW(jw->dialog), DF_MANUAL, DL_USAGE_JOB);
212 }
213 
214 
215 void
216 gnc_job_window_destroy_cb (GtkWidget *widget, gpointer data)
217 {
218  JobWindow *jw = data;
219  GncJob *job = jw_get_job (jw);
220 
221  gnc_suspend_gui_refresh ();
222 
223  if (jw->dialog_type == NEW_JOB && job != NULL)
224  {
225  gncJobBeginEdit (job);
226  gncJobDestroy (job);
227  jw->job_guid = *guid_null ();
228  }
229 
230  gnc_unregister_gui_component (jw->component_id);
231  gnc_resume_gui_refresh ();
232 
233  g_free (jw);
234 }
235 
236 void
237 gnc_job_name_changed_cb (GtkWidget *widget, gpointer data)
238 {
239  JobWindow *jw = data;
240  if (!jw)
241  return;
242 
243  gnc_owner_window_set_title (GTK_WINDOW (jw->dialog),
244  (jw->dialog_type == EDIT_JOB) ?
245  _("Edit Job") : _("New Job"),
246  jw->name_entry, jw->id_entry);
247 }
248 
249 static void
250 gnc_job_window_close_handler (gpointer user_data)
251 {
252  JobWindow *jw = user_data;
253 
254  gtk_widget_destroy (jw->dialog);
255  /* jw is already freed at this point
256  jw->dialog = NULL; */
257 }
258 
259 static void
260 gnc_job_window_refresh_handler (GHashTable *changes, gpointer user_data)
261 {
262  JobWindow *jw = user_data;
263  const EventInfo *info;
264  GncJob *job = jw_get_job (jw);
265 
266  /* If there isn't a job behind us, close down */
267  if (!job)
268  {
269  gnc_close_gui_component (jw->component_id);
270  return;
271  }
272 
273  /* Next, close if this is a destroy event */
274  if (changes)
275  {
276  info = gnc_gui_get_entity_events (changes, &jw->job_guid);
277  if (info && (info->event_mask & QOF_EVENT_DESTROY))
278  {
279  gnc_close_gui_component (jw->component_id);
280  return;
281  }
282  }
283 }
284 
285 static gboolean
286 find_handler (gpointer find_data, gpointer user_data)
287 {
288  const GncGUID *job_guid = find_data;
289  JobWindow *jw = user_data;
290 
291  return(jw && guid_equal(&jw->job_guid, job_guid));
292 }
293 
294 static JobWindow *
295 gnc_job_new_window (GtkWindow *parent, QofBook *bookp, GncOwner *owner, GncJob *job)
296 {
297  JobWindow *jw;
298  GtkBuilder *builder;
299  GtkWidget *owner_box, *owner_label, *edit, *hbox;
300 
301  /*
302  * Find an existing window for this job. If found, bring it to
303  * the front.
304  */
305  if (job)
306  {
307  GncGUID job_guid;
308 
309  job_guid = *gncJobGetGUID (job);
310  jw = gnc_find_first_gui_component (DIALOG_EDIT_JOB_CM_CLASS,
311  find_handler, &job_guid);
312  if (jw)
313  {
314  gtk_window_set_transient_for (GTK_WINDOW(jw->dialog), parent);
315  gtk_window_present (GTK_WINDOW(jw->dialog));
316  return(jw);
317  }
318  }
319 
320  /*
321  * No existing job window found. Build a new one.
322  */
323  jw = g_new0 (JobWindow, 1);
324  jw->book = bookp;
325  gncOwnerCopy (owner, &(jw->owner)); /* save it off now, we know it's valid */
326 
327  /* Load the Glade File */
328  builder = gtk_builder_new();
329  gnc_builder_add_from_file (builder, "dialog-job.glade", "job_dialog");
330 
331  /* Find the dialog */
332  jw->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "job_dialog"));
333  gtk_window_set_transient_for (GTK_WINDOW(jw->dialog), parent);
334 
335  // Set the name for this dialog so it can be easily manipulated with css
336  gtk_widget_set_name (GTK_WIDGET(jw->dialog), "gnc-id-job");
337  gnc_widget_style_context_add_class (GTK_WIDGET(jw->dialog), "gnc-class-jobs");
338 
339  /* Get entry points */
340  jw->id_entry = GTK_WIDGET(gtk_builder_get_object (builder, "id_entry"));
341  jw->name_entry = GTK_WIDGET(gtk_builder_get_object (builder, "name_entry"));
342  jw->desc_entry = GTK_WIDGET(gtk_builder_get_object (builder, "desc_entry"));
343  jw->active_check = GTK_WIDGET(gtk_builder_get_object (builder, "active_check"));
344 
345  owner_box = GTK_WIDGET(gtk_builder_get_object (builder, "customer_hbox"));
346  owner_label = GTK_WIDGET(gtk_builder_get_object (builder, "owner_label"));
347 
348  edit = gnc_amount_edit_new();
349  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (edit), TRUE);
350 
351  jw->rate_entry = edit;
352  gtk_widget_show (edit);
353 
354  hbox = GTK_WIDGET(gtk_builder_get_object (builder, "rate_entry"));
355  gtk_box_pack_start (GTK_BOX (hbox), edit, TRUE, TRUE, 0);
356 
357  /* Setup signals */
358  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, jw);
359 
360 
361  /* Set initial entries */
362  if (job != NULL)
363  {
364  jw->job_guid = *gncJobGetGUID (job);
365 
366  jw->dialog_type = EDIT_JOB;
367  jw->cust_edit = gnc_owner_edit_create (owner_label, owner_box,
368  bookp, owner);
369 
370  gtk_entry_set_text (GTK_ENTRY (jw->id_entry), gncJobGetID (job));
371  gtk_entry_set_text (GTK_ENTRY (jw->name_entry), gncJobGetName (job));
372  gtk_entry_set_text (GTK_ENTRY (jw->desc_entry), gncJobGetReference (job));
373  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (jw->rate_entry),
374  gncJobGetRate (job));
375  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (jw->active_check),
376  gncJobGetActive (job));
377 
378  jw->component_id = gnc_register_gui_component (DIALOG_EDIT_JOB_CM_CLASS,
379  gnc_job_window_refresh_handler,
380  gnc_job_window_close_handler,
381  jw);
382  }
383  else
384  {
385  job = gncJobCreate (bookp);
386  gncJobSetOwner (job, owner);
387  jw->job_guid = *gncJobGetGUID (job);
388 
389  jw->dialog_type = NEW_JOB;
390 
391  /* If we are passed a real owner, don't allow the user to change it */
392  if (owner->owner.undefined)
393  {
394  jw->cust_edit = gnc_owner_edit_create (owner_label, owner_box,
395  bookp, owner);
396  }
397  else
398  {
399  jw->cust_edit = gnc_owner_select_create (owner_label, owner_box,
400  bookp, owner);
401  }
402 
403  jw->component_id = gnc_register_gui_component (DIALOG_NEW_JOB_CM_CLASS,
404  gnc_job_window_refresh_handler,
405  gnc_job_window_close_handler,
406  jw);
407  }
408 
409  gnc_job_name_changed_cb (NULL, jw);
410  gnc_gui_component_watch_entity_type (jw->component_id,
411  GNC_JOB_MODULE_NAME,
412  QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
413 
414  gtk_widget_show_all (jw->dialog);
415 
416  // The job name should have keyboard focus
417  gtk_widget_grab_focus(jw->name_entry);
418  // Or should the owner field have focus?
419 // if (GNC_IS_GENERAL_SEARCH(jw->cust_edit))
420 // {
421 // gnc_general_search_grab_focus(GNC_GENERAL_SEARCH(jw->cust_edit));
422 // }
423 
424  g_object_unref(G_OBJECT(builder));
425 
426  return jw;
427 }
428 
429 JobWindow *
430 gnc_ui_job_new (GtkWindow *parent, GncOwner *ownerp, QofBook *bookp)
431 {
432  JobWindow *jw;
433  GncOwner owner;
434 
435  /* Make sure required options exist */
436  if (!bookp) return NULL;
437 
438  if (ownerp)
439  {
440  g_return_val_if_fail ((gncOwnerGetType (ownerp) == GNC_OWNER_CUSTOMER) ||
441  (gncOwnerGetType (ownerp) == GNC_OWNER_VENDOR),
442  NULL);
443  gncOwnerCopy (ownerp, &owner);
444  }
445  else
446  gncOwnerInitCustomer (&owner, NULL); /* XXX */
447 
448  jw = gnc_job_new_window (parent, bookp, &owner, NULL);
449  return jw;
450 }
451 
452 JobWindow *
453 gnc_ui_job_edit (GtkWindow *parent, GncJob *job)
454 {
455  JobWindow *jw;
456 
457  if (!job) return NULL;
458 
459  jw = gnc_job_new_window (parent, gncJobGetBook(job), gncJobGetOwner(job), job);
460  return jw;
461 }
462 
463 /* Search functionality */
464 
465 static void
466 edit_job_cb (GtkWindow *dialog, gpointer *job_p, gpointer user_data)
467 {
468  GncJob *job;
469 
470  g_return_if_fail (job_p && user_data);
471 
472  job = *job_p;
473 
474  if (!job)
475  return;
476 
477  gnc_ui_job_edit (dialog, job);
478 }
479 
480 static void
481 invoice_job_cb (GtkWindow *dialog, gpointer *job_p, gpointer user_data)
482 {
483  struct _job_select_window * sw = user_data;
484  GncJob *job;
485  GncOwner owner;
486 
487  g_return_if_fail (job_p && user_data);
488 
489  job = *job_p;
490  if (!job)
491  return;
492 
493  gncOwnerInitJob (&owner, job);
494  gnc_invoice_search (dialog, NULL, &owner, sw->book);
495 }
496 
497 static void
498 payment_job_cb (GtkWindow *dialog, gpointer *job_p, gpointer user_data)
499 {
500  struct _job_select_window *sw = user_data;
501  GncOwner owner;
502  GncJob *job;
503 
504  g_return_if_fail (job_p && user_data);
505 
506  job = *job_p;
507 
508  if (!job)
509  return;
510 
511  gncOwnerInitJob (&owner, job);
512  gnc_ui_payment_new (dialog, &owner, sw->book);
513  return;
514 }
515 
516 static gpointer
517 new_job_cb (GtkWindow *dialog, gpointer user_data)
518 {
519  struct _job_select_window *sw = user_data;
520  JobWindow *jw;
521 
522  g_return_val_if_fail (user_data, NULL);
523 
524  jw = gnc_ui_job_new (dialog, sw->owner, sw->book);
525  return jw_get_job (jw);
526 }
527 
528 static void
529 free_userdata_cb (gpointer user_data)
530 {
531  struct _job_select_window *sw = user_data;
532 
533  g_return_if_fail (sw);
534 
535  qof_query_destroy (sw->q);
536  g_free (sw);
537 }
538 
539 GNCSearchWindow *
540 gnc_job_search (GtkWindow *parent, GncJob *start, GncOwner *owner, QofBook *book)
541 {
542  QofQuery *q, *q2 = NULL;
543  QofIdType type = GNC_JOB_MODULE_NAME;
544  struct _job_select_window *sw;
545  static GList *params = NULL;
546  static GList *columns = NULL;
547  static GNCSearchCallbackButton buttons[] =
548  {
549  { N_("View/Edit Job"), edit_job_cb, NULL, TRUE},
550  { N_("View Invoices"), invoice_job_cb, NULL, TRUE},
551  { N_("Process Payment"), payment_job_cb, NULL, FALSE},
552  { NULL },
553  };
554 
555  g_return_val_if_fail (book, NULL);
556 
557  /* Build parameter list in reverse order */
558  if (params == NULL)
559  {
560  params = gnc_search_param_prepend (params, _("Owner's Name"), NULL, type,
561  JOB_OWNER, OWNER_NAME, NULL);
562  params = gnc_search_param_prepend (params, _("Only Active?"), NULL, type,
563  JOB_ACTIVE, NULL);
564  params = gnc_search_param_prepend (params, _("Billing ID"), NULL, type,
565  JOB_REFERENCE, NULL);
566  params = gnc_search_param_prepend (params, _("Rate"), NULL, type,
567  JOB_RATE, NULL);
568  params = gnc_search_param_prepend (params, _("Job Number"), NULL, type,
569  JOB_ID, NULL);
570  params = gnc_search_param_prepend (params, _("Job Name"), NULL, type,
571  JOB_NAME, NULL);
572  }
573 
574  /* Build the column list in reverse order */
575  if (columns == NULL)
576  {
577  columns = gnc_search_param_prepend (columns, _("Billing ID"), NULL, type,
578  JOB_REFERENCE, NULL);
579  columns = gnc_search_param_prepend (columns, _("Rate"), NULL, type,
580  JOB_RATE, NULL);
581  columns = gnc_search_param_prepend (columns, _("Company"), NULL, type,
582  JOB_OWNER, OWNER_NAME, NULL);
583  columns = gnc_search_param_prepend (columns, _("Job Name"), NULL, type,
584  JOB_NAME, NULL);
585  columns = gnc_search_param_prepend (columns, _("ID #"), NULL, type,
586  JOB_ID, NULL);
587  }
588 
589  /* Build the queries */
590  q = qof_query_create_for (type);
591  qof_query_set_book (q, book);
592 
593  /* If we have a start job but, for some reason, not an owner -- grab
594  * the owner from the starting job.
595  */
596  if ((!owner || !gncOwnerGetGUID (owner)) && start)
597  owner = gncJobGetOwner (start);
598 
599  /* If owner is supplied, limit all searches to invoices who's owner
600  * is the supplied owner! Show all invoices by this owner.
601  */
602  if (owner && gncOwnerGetGUID (owner))
603  {
604  qof_query_add_guid_match (q, g_slist_prepend
605  (g_slist_prepend (NULL, QOF_PARAM_GUID),
606  JOB_OWNER),
607  gncOwnerGetGUID (owner), QOF_QUERY_AND);
608 
609  q2 = qof_query_copy (q);
610  }
611 
612 #if 0
613  if (start)
614  {
615  if (q2 == NULL)
616  q2 = qof_query_copy (q);
617 
618  qof_query_add_guid_match (q2, g_slist_prepend (NULL, QOF_PARAM_GUID),
619  gncJobGetGUID (start), QOF_QUERY_AND);
620  }
621 #endif
622 
623  /* launch select dialog and return the result */
624  sw = g_new0 (struct _job_select_window, 1);
625 
626  if (owner)
627  {
628  gncOwnerCopy (owner, &(sw->owner_def));
629  sw->owner = &(sw->owner_def);
630  }
631  sw->book = book;
632  sw->q = q;
633 
634  return gnc_search_dialog_create (parent, type, _("Find Job"),
635  params, columns, q, q2, buttons, NULL,
636  new_job_cb, sw, free_userdata_cb,
637  GNC_PREFS_GROUP_SEARCH, NULL,
638  "gnc-class-jobs");
639 }
640 
641 /* Functions for widgets for job selection */
642 
643 GNCSearchWindow *
644 gnc_job_search_select (GtkWindow *parent, gpointer start, gpointer book)
645 {
646  GncJob *j = start;
647  GncOwner owner, *ownerp;
648 
649  if (!book) return NULL;
650 
651  if (j)
652  {
653  ownerp = gncJobGetOwner (j);
654  gncOwnerCopy (ownerp, &owner);
655  }
656  else
657  gncOwnerInitCustomer (&owner, NULL); /* XXX */
658 
659  return gnc_job_search (parent, start, &owner, book);
660 }
661 
662 GNCSearchWindow *
663 gnc_job_search_edit (GtkWindow *parent, gpointer start, gpointer book)
664 {
665  if (start)
666  gnc_ui_job_edit (parent, start);
667 
668  return NULL;
669 }
const GncGUID * gncOwnerGetGUID(const GncOwner *owner)
Get the GncGUID of the immediate owner.
Definition: gncOwner.c:518
gboolean gncOwnerEqual(const GncOwner *a, const GncOwner *b)
Assess equality by checking.
Definition: gncOwner.c:404
QofQuery * qof_query_copy(QofQuery *q)
Make a copy of the indicated query.
Definition: qofquery.cpp:1018
const gchar * QofIdType
QofIdType declaration.
Definition: qofid.h:80
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
void gnc_gnome_help(GtkWindow *parent, const char *file_name, const char *anchor)
Launch the systems default help browser, gnome&#39;s yelp for linux, and open to a given link within a gi...
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
Given two GUIDs, return TRUE if they are non-NULL and equal.
Definition: guid.cpp:204
void qof_query_set_book(QofQuery *query, QofBook *book)
Set the book to be searched.
– Business Helper Functions
void qof_query_add_guid_match(QofQuery *q, QofQueryParamList *param_list, const GncGUID *guid, QofQueryOp op)
DOCUMENT ME !!
Definition: qofquery.cpp:1310
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Returns the GncOwnerType of this owner.
Definition: gncOwner.c:200
Job Interface.
#define gncJobGetBook(x)
deprecated functions
Definition: gncJob.h:117
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.cpp:231
The type used to store guids in C.
Definition: guid.h:75
A Query.
Definition: qofquery.cpp:74