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 
64 struct _job_select_window
65 {
66     QofBook  *book;
67     GncOwner *owner;
68     QofQuery *q;
69     GncOwner  owner_def;
70 };
71 
72 struct _job_window
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 *
jw_get_job(JobWindow * jw)93 jw_get_job (JobWindow *jw)
94 {
95     if (!jw)
96         return NULL;
97 
98     return gncJobLookup (jw->book, &jw->job_guid);
99 }
100 
gnc_ui_to_job(JobWindow * jw,GncJob * job)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_editable_get_chars (GTK_EDITABLE (jw->id_entry),
109                  0, -1));
110     gncJobSetName (job, gtk_editable_get_chars (GTK_EDITABLE (jw->name_entry),
111                    0, -1));
112     gncJobSetReference (job, gtk_editable_get_chars
113                         (GTK_EDITABLE (jw->desc_entry), 0, -1));
114     gncJobSetRate (job, gnc_amount_edit_get_amount
115                         (GNC_AMOUNT_EDIT (jw->rate_entry)));
116     gncJobSetActive (job, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
117                      (jw->active_check)));
118     {
119         GncOwner * old = gncJobGetOwner (job);
120         gnc_owner_get_owner (jw->cust_edit, &(jw->owner));
121         if (! gncOwnerEqual (old, &(jw->owner)))
122             gncJobSetOwner (job, &(jw->owner));
123     }
124 
125     gncJobCommitEdit (job);
126     gnc_resume_gui_refresh ();
127 }
128 
129 static gboolean
gnc_job_verify_ok(JobWindow * jw)130 gnc_job_verify_ok (JobWindow *jw)
131 {
132     const char *res;
133     gchar *string;
134 
135     /* Check for valid name */
136     res = gtk_entry_get_text (GTK_ENTRY (jw->name_entry));
137     if (g_strcmp0 (res, "") == 0)
138     {
139         const char *message = _("The Job must be given a name.");
140         gnc_error_dialog (GTK_WINDOW (jw->dialog), "%s", message);
141         return FALSE;
142     }
143 
144     /* Check for owner */
145     gnc_owner_get_owner (jw->cust_edit, &(jw->owner));
146     res = gncOwnerGetName (&(jw->owner));
147     if (res == NULL || g_strcmp0 (res, "") == 0)
148     {
149         const char *message = _("You must choose an owner for this job.");
150         gnc_error_dialog (GTK_WINDOW (jw->dialog), "%s", message);
151         return FALSE;
152     }
153 
154     /* Check for valid rate */
155     if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT(jw->rate_entry), NULL))
156     {
157         const char *message = _("The rate amount must be valid or you must leave it blank.");
158         gnc_error_dialog (GTK_WINDOW (jw->dialog), "%s", message);
159         return FALSE;
160     }
161 
162     /* Set a valid id if one was not created */
163     res = gtk_entry_get_text (GTK_ENTRY (jw->id_entry));
164     if (g_strcmp0 (res, "") == 0)
165     {
166         string = gncJobNextID(jw->book);
167         gtk_entry_set_text (GTK_ENTRY (jw->id_entry), string);
168         g_free(string);
169     }
170 
171     /* Now save it off */
172     {
173         GncJob *job = jw_get_job (jw);
174         if (job)
175         {
176             gnc_ui_to_job (jw, job);
177         }
178     }
179 
180     /* Ok, it's been saved... Change to an editor.. */
181     jw->dialog_type = EDIT_JOB;
182 
183     return TRUE;
184 }
185 
186 void
gnc_job_window_ok_cb(GtkWidget * widget,gpointer data)187 gnc_job_window_ok_cb (GtkWidget *widget, gpointer data)
188 {
189     JobWindow *jw = data;
190 
191     /* Make sure this is ok */
192     if (!gnc_job_verify_ok (jw))
193         return;
194 
195     /* Now save off the job so we can return it */
196     jw->created_job = jw_get_job (jw);
197     jw->job_guid = *guid_null ();
198 
199     gnc_close_gui_component (jw->component_id);
200 }
201 
202 void
gnc_job_window_cancel_cb(GtkWidget * widget,gpointer data)203 gnc_job_window_cancel_cb (GtkWidget *widget, gpointer data)
204 {
205     JobWindow *jw = data;
206 
207     gnc_close_gui_component (jw->component_id);
208 }
209 
210 void
gnc_job_window_help_cb(GtkWidget * widget,gpointer data)211 gnc_job_window_help_cb (GtkWidget *widget, gpointer data)
212 {
213     JobWindow *jw = data;
214     gnc_gnome_help (GTK_WINDOW(jw->dialog), HF_HELP, HL_USAGE_JOB);
215 }
216 
217 
218 void
gnc_job_window_destroy_cb(GtkWidget * widget,gpointer data)219 gnc_job_window_destroy_cb (GtkWidget *widget, gpointer data)
220 {
221     JobWindow *jw = data;
222     GncJob *job = jw_get_job (jw);
223 
224     gnc_suspend_gui_refresh ();
225 
226     if (jw->dialog_type == NEW_JOB && job != NULL)
227     {
228         gncJobBeginEdit (job);
229         gncJobDestroy (job);
230         jw->job_guid = *guid_null ();
231     }
232 
233     gnc_unregister_gui_component (jw->component_id);
234     gnc_resume_gui_refresh ();
235 
236     g_free (jw);
237 }
238 
239 void
gnc_job_name_changed_cb(GtkWidget * widget,gpointer data)240 gnc_job_name_changed_cb (GtkWidget *widget, gpointer data)
241 {
242     JobWindow *jw = data;
243     char *fullname, *title;
244     const char *name, *id;
245 
246     if (!jw)
247         return;
248 
249     name = gtk_entry_get_text (GTK_ENTRY (jw->name_entry));
250     if (!name || *name == '\0')
251         name = _("<No name>");
252 
253     id = gtk_entry_get_text (GTK_ENTRY (jw->id_entry));
254 
255     fullname = g_strconcat (name, " (", id, ")", (char *)NULL);
256 
257     if (jw->dialog_type == EDIT_JOB)
258         title = g_strconcat (_("Edit Job"), " - ", fullname, (char *)NULL);
259     else
260         title = g_strconcat (_("New Job"), " - ", fullname, (char *)NULL);
261 
262     gtk_window_set_title (GTK_WINDOW (jw->dialog), title);
263 
264     g_free (fullname);
265     g_free (title);
266 }
267 
268 static void
gnc_job_window_close_handler(gpointer user_data)269 gnc_job_window_close_handler (gpointer user_data)
270 {
271     JobWindow *jw = user_data;
272 
273     gtk_widget_destroy (jw->dialog);
274     /* jw is already freed at this point
275     jw->dialog = NULL; */
276 }
277 
278 static void
gnc_job_window_refresh_handler(GHashTable * changes,gpointer user_data)279 gnc_job_window_refresh_handler (GHashTable *changes, gpointer user_data)
280 {
281     JobWindow *jw = user_data;
282     const EventInfo *info;
283     GncJob *job = jw_get_job (jw);
284 
285     /* If there isn't a job behind us, close down */
286     if (!job)
287     {
288         gnc_close_gui_component (jw->component_id);
289         return;
290     }
291 
292     /* Next, close if this is a destroy event */
293     if (changes)
294     {
295         info = gnc_gui_get_entity_events (changes, &jw->job_guid);
296         if (info && (info->event_mask & QOF_EVENT_DESTROY))
297         {
298             gnc_close_gui_component (jw->component_id);
299             return;
300         }
301     }
302 }
303 
304 static gboolean
find_handler(gpointer find_data,gpointer user_data)305 find_handler (gpointer find_data, gpointer user_data)
306 {
307     const GncGUID *job_guid = find_data;
308     JobWindow *jw = user_data;
309 
310     return(jw && guid_equal(&jw->job_guid, job_guid));
311 }
312 
313 static JobWindow *
gnc_job_new_window(GtkWindow * parent,QofBook * bookp,GncOwner * owner,GncJob * job)314 gnc_job_new_window (GtkWindow *parent, QofBook *bookp, GncOwner *owner, GncJob *job)
315 {
316     JobWindow *jw;
317     GtkBuilder *builder;
318     GtkWidget *owner_box, *owner_label, *edit, *hbox;
319 
320     /*
321      * Find an existing window for this job.  If found, bring it to
322      * the front.
323      */
324     if (job)
325     {
326         GncGUID job_guid;
327 
328         job_guid = *gncJobGetGUID (job);
329         jw = gnc_find_first_gui_component (DIALOG_EDIT_JOB_CM_CLASS,
330                                            find_handler, &job_guid);
331         if (jw)
332         {
333             gtk_window_set_transient_for (GTK_WINDOW(jw->dialog), parent);
334             gtk_window_present (GTK_WINDOW(jw->dialog));
335             return(jw);
336         }
337     }
338 
339     /*
340      * No existing job window found.  Build a new one.
341      */
342     jw = g_new0 (JobWindow, 1);
343     jw->book = bookp;
344     gncOwnerCopy (owner, &(jw->owner)); /* save it off now, we know it's valid */
345 
346     /* Load the Glade File */
347     builder = gtk_builder_new();
348     gnc_builder_add_from_file (builder, "dialog-job.glade", "job_dialog");
349 
350     /* Find the dialog */
351     jw->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "job_dialog"));
352     gtk_window_set_transient_for (GTK_WINDOW(jw->dialog), parent);
353 
354     // Set the name for this dialog so it can be easily manipulated with css
355     gtk_widget_set_name (GTK_WIDGET(jw->dialog), "gnc-id-job");
356     gnc_widget_style_context_add_class (GTK_WIDGET(jw->dialog), "gnc-class-jobs");
357 
358     /* Get entry points */
359     jw->id_entry  = GTK_WIDGET(gtk_builder_get_object (builder, "id_entry"));
360     jw->name_entry = GTK_WIDGET(gtk_builder_get_object (builder, "name_entry"));
361     jw->desc_entry = GTK_WIDGET(gtk_builder_get_object (builder, "desc_entry"));
362     jw->active_check = GTK_WIDGET(gtk_builder_get_object (builder, "active_check"));
363 
364     owner_box = GTK_WIDGET(gtk_builder_get_object (builder, "customer_hbox"));
365     owner_label = GTK_WIDGET(gtk_builder_get_object (builder, "owner_label"));
366 
367     edit = gnc_amount_edit_new();
368     gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (edit), TRUE);
369 
370     jw->rate_entry = edit;
371     gtk_widget_show (edit);
372 
373     hbox = GTK_WIDGET(gtk_builder_get_object (builder, "rate_entry"));
374     gtk_box_pack_start (GTK_BOX (hbox), edit, TRUE, TRUE, 0);
375 
376     /* Setup signals */
377     gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, jw);
378 
379 
380     /* Set initial entries */
381     if (job != NULL)
382     {
383         jw->job_guid = *gncJobGetGUID (job);
384 
385         jw->dialog_type = EDIT_JOB;
386         jw->cust_edit = gnc_owner_edit_create (owner_label, owner_box,
387                                                bookp, owner);
388 
389         gtk_entry_set_text (GTK_ENTRY (jw->id_entry), gncJobGetID (job));
390         gtk_entry_set_text (GTK_ENTRY (jw->name_entry), gncJobGetName (job));
391         gtk_entry_set_text (GTK_ENTRY (jw->desc_entry), gncJobGetReference (job));
392         gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (jw->rate_entry),
393                                       gncJobGetRate (job));
394         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (jw->active_check),
395                                       gncJobGetActive (job));
396 
397         jw->component_id = gnc_register_gui_component (DIALOG_EDIT_JOB_CM_CLASS,
398                            gnc_job_window_refresh_handler,
399                            gnc_job_window_close_handler,
400                            jw);
401     }
402     else
403     {
404         job = gncJobCreate (bookp);
405         gncJobSetOwner (job, owner);
406         jw->job_guid = *gncJobGetGUID (job);
407 
408         jw->dialog_type = NEW_JOB;
409 
410         /* If we are passed a real owner, don't allow the user to change it */
411         if (owner->owner.undefined)
412         {
413             jw->cust_edit = gnc_owner_edit_create (owner_label, owner_box,
414                                                    bookp, owner);
415         }
416         else
417         {
418             jw->cust_edit = gnc_owner_select_create (owner_label, owner_box,
419                             bookp, owner);
420         }
421 
422         jw->component_id = gnc_register_gui_component (DIALOG_NEW_JOB_CM_CLASS,
423                            gnc_job_window_refresh_handler,
424                            gnc_job_window_close_handler,
425                            jw);
426     }
427 
428     gnc_job_name_changed_cb (NULL, jw);
429     gnc_gui_component_watch_entity_type (jw->component_id,
430                                          GNC_JOB_MODULE_NAME,
431                                          QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
432 
433     gtk_widget_show_all (jw->dialog);
434 
435     // The job name should have keyboard focus
436     gtk_widget_grab_focus(jw->name_entry);
437     // Or should the owner field have focus?
438 //    if (GNC_IS_GENERAL_SEARCH(jw->cust_edit))
439 //    {
440 //        gnc_general_search_grab_focus(GNC_GENERAL_SEARCH(jw->cust_edit));
441 //    }
442 
443     g_object_unref(G_OBJECT(builder));
444 
445     return jw;
446 }
447 
448 JobWindow *
gnc_ui_job_new(GtkWindow * parent,GncOwner * ownerp,QofBook * bookp)449 gnc_ui_job_new (GtkWindow *parent, GncOwner *ownerp, QofBook *bookp)
450 {
451     JobWindow *jw;
452     GncOwner owner;
453 
454     /* Make sure required options exist */
455     if (!bookp) return NULL;
456 
457     if (ownerp)
458     {
459         g_return_val_if_fail ((gncOwnerGetType (ownerp) == GNC_OWNER_CUSTOMER) ||
460                               (gncOwnerGetType (ownerp) == GNC_OWNER_VENDOR),
461                               NULL);
462         gncOwnerCopy (ownerp, &owner);
463     }
464     else
465         gncOwnerInitCustomer (&owner, NULL); /* XXX */
466 
467     jw = gnc_job_new_window (parent, bookp, &owner, NULL);
468     return jw;
469 }
470 
471 JobWindow *
gnc_ui_job_edit(GtkWindow * parent,GncJob * job)472 gnc_ui_job_edit (GtkWindow *parent, GncJob *job)
473 {
474     JobWindow *jw;
475 
476     if (!job) return NULL;
477 
478     jw = gnc_job_new_window (parent, gncJobGetBook(job), gncJobGetOwner(job), job);
479     return jw;
480 }
481 
482 /* Search functionality */
483 
484 static void
edit_job_cb(GtkWindow * dialog,gpointer * job_p,gpointer user_data)485 edit_job_cb (GtkWindow *dialog, gpointer *job_p, gpointer user_data)
486 {
487     GncJob *job;
488 
489     g_return_if_fail (job_p && user_data);
490 
491     job = *job_p;
492 
493     if (!job)
494         return;
495 
496     gnc_ui_job_edit (dialog, job);
497 }
498 
499 static void
invoice_job_cb(GtkWindow * dialog,gpointer * job_p,gpointer user_data)500 invoice_job_cb (GtkWindow *dialog, gpointer *job_p, gpointer user_data)
501 {
502     struct _job_select_window * sw = user_data;
503     GncJob *job;
504     GncOwner owner;
505 
506     g_return_if_fail (job_p && user_data);
507 
508     job = *job_p;
509     if (!job)
510         return;
511 
512     gncOwnerInitJob (&owner, job);
513     gnc_invoice_search (dialog, NULL, &owner, sw->book);
514 }
515 
516 static void
payment_job_cb(GtkWindow * dialog,gpointer * job_p,gpointer user_data)517 payment_job_cb (GtkWindow *dialog, gpointer *job_p, gpointer user_data)
518 {
519     struct _job_select_window *sw = user_data;
520     GncOwner owner;
521     GncJob *job;
522 
523     g_return_if_fail (job_p && user_data);
524 
525     job = *job_p;
526 
527     if (!job)
528         return;
529 
530     gncOwnerInitJob (&owner, job);
531     gnc_ui_payment_new (dialog, &owner, sw->book);
532     return;
533 }
534 
535 static gpointer
new_job_cb(GtkWindow * dialog,gpointer user_data)536 new_job_cb (GtkWindow *dialog, gpointer user_data)
537 {
538     struct _job_select_window *sw = user_data;
539     JobWindow *jw;
540 
541     g_return_val_if_fail (user_data, NULL);
542 
543     jw = gnc_ui_job_new (dialog, sw->owner, sw->book);
544     return jw_get_job (jw);
545 }
546 
547 static void
free_userdata_cb(gpointer user_data)548 free_userdata_cb (gpointer user_data)
549 {
550     struct _job_select_window *sw = user_data;
551 
552     g_return_if_fail (sw);
553 
554     qof_query_destroy (sw->q);
555     g_free (sw);
556 }
557 
558 GNCSearchWindow *
gnc_job_search(GtkWindow * parent,GncJob * start,GncOwner * owner,QofBook * book)559 gnc_job_search (GtkWindow *parent, GncJob *start, GncOwner *owner, QofBook *book)
560 {
561     QofQuery *q, *q2 = NULL;
562     QofIdType type = GNC_JOB_MODULE_NAME;
563     struct _job_select_window *sw;
564     static GList *params = NULL;
565     static GList *columns = NULL;
566     static GNCSearchCallbackButton buttons[] =
567     {
568         { N_("View/Edit Job"), edit_job_cb, NULL, TRUE},
569         { N_("View Invoices"), invoice_job_cb, NULL, TRUE},
570         { N_("Process Payment"), payment_job_cb, NULL, FALSE},
571         { NULL },
572     };
573 
574     g_return_val_if_fail (book, NULL);
575 
576     /* Build parameter list in reverse order */
577     if (params == NULL)
578     {
579         params = gnc_search_param_prepend (params, _("Owner's Name"), NULL, type,
580                                            JOB_OWNER, OWNER_NAME, NULL);
581         params = gnc_search_param_prepend (params, _("Only Active?"), NULL, type,
582                                            JOB_ACTIVE, NULL);
583         params = gnc_search_param_prepend (params, _("Billing ID"), NULL, type,
584                                            JOB_REFERENCE, NULL);
585         params = gnc_search_param_prepend (params, _("Rate"), NULL, type,
586                                            JOB_RATE, NULL);
587         params = gnc_search_param_prepend (params, _("Job Number"), NULL, type,
588                                            JOB_ID, NULL);
589         params = gnc_search_param_prepend (params, _("Job Name"), NULL, type,
590                                            JOB_NAME, NULL);
591     }
592 
593     /* Build the column list in reverse order */
594     if (columns == NULL)
595     {
596         columns = gnc_search_param_prepend (columns, _("Billing ID"), NULL, type,
597                                             JOB_REFERENCE, NULL);
598         columns = gnc_search_param_prepend (columns, _("Rate"), NULL, type,
599                                             JOB_RATE, NULL);
600         columns = gnc_search_param_prepend (columns, _("Company"), NULL, type,
601                                             JOB_OWNER, OWNER_NAME, NULL);
602         columns = gnc_search_param_prepend (columns, _("Job Name"), NULL, type,
603                                             JOB_NAME, NULL);
604         columns = gnc_search_param_prepend (columns, _("ID #"), NULL, type,
605                                             JOB_ID, NULL);
606     }
607 
608     /* Build the queries */
609     q = qof_query_create_for (type);
610     qof_query_set_book (q, book);
611 
612     /* If we have a start job but, for some reason, not an owner -- grab
613      * the owner from the starting job.
614      */
615     if ((!owner || !gncOwnerGetGUID (owner)) && start)
616         owner = gncJobGetOwner (start);
617 
618     /* If owner is supplied, limit all searches to invoices who's owner
619      * is the supplied owner!  Show all invoices by this owner.
620      */
621     if (owner && gncOwnerGetGUID (owner))
622     {
623         qof_query_add_guid_match (q, g_slist_prepend
624                                   (g_slist_prepend (NULL, QOF_PARAM_GUID),
625                                    JOB_OWNER),
626                                   gncOwnerGetGUID (owner), QOF_QUERY_AND);
627 
628         q2 = qof_query_copy (q);
629     }
630 
631 #if 0
632     if (start)
633     {
634         if (q2 == NULL)
635             q2 = qof_query_copy (q);
636 
637         qof_query_add_guid_match (q2, g_slist_prepend (NULL, QOF_PARAM_GUID),
638                                   gncJobGetGUID (start), QOF_QUERY_AND);
639     }
640 #endif
641 
642     /* launch select dialog and return the result */
643     sw = g_new0 (struct _job_select_window, 1);
644 
645     if (owner)
646     {
647         gncOwnerCopy (owner, &(sw->owner_def));
648         sw->owner = &(sw->owner_def);
649     }
650     sw->book = book;
651     sw->q = q;
652 
653     return gnc_search_dialog_create (parent, type, _("Find Job"),
654                                      params, columns, q, q2, buttons, NULL,
655                                      new_job_cb, sw, free_userdata_cb,
656                                      GNC_PREFS_GROUP_SEARCH, NULL,
657                                      "gnc-class-jobs");
658 }
659 
660 /* Functions for widgets for job selection */
661 
662 GNCSearchWindow *
gnc_job_search_select(GtkWindow * parent,gpointer start,gpointer book)663 gnc_job_search_select (GtkWindow *parent, gpointer start, gpointer book)
664 {
665     GncJob *j = start;
666     GncOwner owner, *ownerp;
667 
668     if (!book) return NULL;
669 
670     if (j)
671     {
672         ownerp = gncJobGetOwner (j);
673         gncOwnerCopy (ownerp, &owner);
674     }
675     else
676         gncOwnerInitCustomer (&owner, NULL); /* XXX */
677 
678     return gnc_job_search (parent, start, &owner, book);
679 }
680 
681 GNCSearchWindow *
gnc_job_search_edit(GtkWindow * parent,gpointer start,gpointer book)682 gnc_job_search_edit (GtkWindow *parent, gpointer start, gpointer book)
683 {
684     if (start)
685         gnc_ui_job_edit (parent, start);
686 
687     return NULL;
688 }
689