GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
business-gnome-utils.c
1 /*
2  * business-gnome-utils.c -- General GUI Utilities for GNC Business Objects
3  *
4  * Written By: Derek Atkins <[email protected]>
5  * Copyright (C) 2001,2002,2006 Derek Atkins
6  * Copyright (c) 2006 David Hampton <[email protected]>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, contact:
20  *
21  * Free Software Foundation Voice: +1-617-542-5942
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
23  * Boston, MA 02110-1301, USA [email protected]
24  */
25 
26 #include "config.h"
27 
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30 
31 #include "Account.h"
32 #include "gnc-ui-util.h"
33 #include "qof.h"
34 #include "gnc-component-manager.h"
35 #include "gnc-gtk-utils.h"
36 
37 #include "gncCustomer.h"
38 #include "gncJob.h"
39 #include "gncVendor.h"
40 #include "gncOwner.h"
41 #include "gncInvoice.h"
42 
43 #include "gnc-general-search.h"
44 #include "qof.h"
45 #include "business-gnome-utils.h"
46 #include "dialog-customer.h"
47 #include "dialog-job.h"
48 #include "dialog-vendor.h"
49 #include "dialog-employee.h"
50 #include "dialog-invoice.h"
51 
52 #include "gnc-commodity.h"
53 
54 typedef enum
55 {
56  GNCSEARCH_TYPE_SELECT,
57  GNCSEARCH_TYPE_EDIT
58 } GNCSearchType;
59 
60 static GtkWidget * gnc_owner_new (GtkWidget *label, GtkWidget *hbox,
61  QofBook *book, GncOwner *owner,
62  GNCSearchType type)
63 {
64  GtkWidget *edit;
65  GNCSearchCB search_cb = NULL;
66  const char *type_name = NULL;
67  const char *text = NULL;
68  gboolean text_editable = FALSE;
69 
70  switch (type)
71  {
72  case GNCSEARCH_TYPE_SELECT:
73  text = _("Select...");
74  text_editable = TRUE;
75  break;
76  case GNCSEARCH_TYPE_EDIT:
77  text = _("Edit...");
78  text_editable = FALSE;
79  break;
80  };
81 
82  switch (owner->type)
83  {
84  case GNC_OWNER_NONE:
85  case GNC_OWNER_UNDEFINED:
86  return NULL;
87 
88  case GNC_OWNER_CUSTOMER:
89  if (type == GNCSEARCH_TYPE_SELECT)
90  search_cb = gnc_customer_search_select;
91  else
92  search_cb = gnc_customer_search_edit;
93  type_name = GNC_CUSTOMER_MODULE_NAME;
94  break;
95 
96  case GNC_OWNER_JOB:
97  if (type == GNCSEARCH_TYPE_SELECT)
98  search_cb = gnc_job_search_select;
99  else
100  search_cb = gnc_job_search_edit;
101  type_name = GNC_JOB_MODULE_NAME;
102  break;
103 
104  case GNC_OWNER_VENDOR:
105  if (type == GNCSEARCH_TYPE_SELECT)
106  search_cb = gnc_vendor_search_select;
107  else
108  search_cb = gnc_vendor_search_edit;
109  type_name = GNC_VENDOR_MODULE_NAME;
110  break;
111 
112  case GNC_OWNER_EMPLOYEE:
113  if (type == GNCSEARCH_TYPE_SELECT)
114  search_cb = gnc_employee_search_select;
115  else
116  search_cb = gnc_employee_search_edit;
117  type_name = GNC_EMPLOYEE_MODULE_NAME;
118  break;
119 
120  default:
121  g_warning ("Unknown type");
122  return NULL;
123  }
124 
125  edit = gnc_general_search_new (type_name, text, text_editable, search_cb, book, book);
126  if (!edit)
127  return NULL;
128 
129  gnc_general_search_set_selected (GNC_GENERAL_SEARCH (edit),
130  owner->owner.undefined);
131  gtk_box_pack_start (GTK_BOX (hbox), edit, TRUE, TRUE, 0);
132  if (label)
133  gtk_label_set_text (GTK_LABEL (label), _(qof_object_get_type_label (type_name)));
134 
135  return edit;
136 }
137 
138 GtkWidget * gnc_owner_select_create (GtkWidget *label, GtkWidget *hbox,
139  QofBook *book, GncOwner *owner)
140 {
141  g_return_val_if_fail (hbox != NULL, NULL);
142  g_return_val_if_fail (book != NULL, NULL);
143  g_return_val_if_fail (owner != NULL, NULL);
144 
145  return gnc_owner_new (label, hbox, book, owner, GNCSEARCH_TYPE_SELECT);
146 }
147 
148 GtkWidget * gnc_owner_edit_create (GtkWidget *label, GtkWidget *hbox,
149  QofBook *book, GncOwner *owner)
150 {
151  g_return_val_if_fail (hbox != NULL, NULL);
152  g_return_val_if_fail (book != NULL, NULL);
153  g_return_val_if_fail (owner != NULL, NULL);
154 
155  return gnc_owner_new (label, hbox, book, owner, GNCSEARCH_TYPE_EDIT);
156 }
157 
158 void gnc_owner_get_owner (GtkWidget *widget, GncOwner *owner)
159 {
160  g_return_if_fail (widget != NULL);
161  g_return_if_fail (owner != NULL);
162 
163  /* We'll assume that the owner has the proper 'type' because we
164  * can't change it here. Hopefully the caller has it set properly
165  */
166  owner->owner.undefined =
167  gnc_general_search_get_selected (GNC_GENERAL_SEARCH (widget));
168 }
169 
170 void gnc_owner_set_owner (GtkWidget *widget, GncOwner *owner)
171 {
172  g_return_if_fail (widget != NULL);
173  g_return_if_fail (owner != NULL);
174 
175  /* We'll assume that the owner has the proper 'type' because we
176  * can't change it here. Hopefully the caller has it set properly
177  */
178 
179  gnc_general_search_set_selected (GNC_GENERAL_SEARCH (widget),
180  owner->owner.undefined);
181 }
182 
183 typedef struct _invoice_select_info
184 {
185  GtkWidget *label;
186  QofBook *book;
187  GncOwner owner;
188  gboolean have_owner;
189 } GncISI;
190 
191 static GNCSearchWindow *
192 gnc_invoice_select_search_cb (gpointer start, gpointer isip)
193 {
194  GncISI *isi = isip;
195 
196  if (!isi) return NULL;
197  g_assert(isi->book);
198 
199  return gnc_invoice_search (start,
200  isi->have_owner ? &isi->owner : NULL,
201  isi->book);
202 }
203 
204 static void
205 gnc_invoice_select_search_set_label(GncISI* isi)
206 {
207  GncOwnerType owner_type;
208  char *label;
209 
210  g_assert(isi);
211  if (!isi->label) return;
212 
213  owner_type = gncOwnerGetType(gncOwnerGetEndOwner(&isi->owner));
214 
215  /* Translators: See comments in dialog-invoice.c:gnc_invoice_search() */
216  switch (owner_type)
217  {
218  case GNC_OWNER_VENDOR:
219  label = _("Bill");
220  break;
221  case GNC_OWNER_EMPLOYEE:
222  label = _("Voucher");
223  break;
224  default:
225  label = _("Invoice");
226  break;
227  }
228 
229  gtk_label_set_text(GTK_LABEL(isi->label), label);
230 }
231 
232 GtkWidget * gnc_invoice_select_create (GtkWidget *hbox, QofBook *book,
233  const GncOwner *owner,
234  GncInvoice *invoice,
235  GtkWidget *label)
236 {
237  GtkWidget *edit;
238  GncISI *isi;
239 
240  g_return_val_if_fail (hbox != NULL, NULL);
241  g_return_val_if_fail (book != NULL, NULL);
242  /* Note: it is legal to have no owner or invoice */
243 
244  isi = g_new0(GncISI, 1);
245  if (!isi)
246  return NULL;
247 
248  if (owner)
249  {
250  gncOwnerCopy(owner, &isi->owner);
251  isi->have_owner = TRUE;
252  }
253  else
254  {
255  gncOwnerInitCustomer(&isi->owner, NULL);
256  }
257  isi->book = book;
258  isi->label = label;
259 
260  edit = gnc_general_search_new (GNC_INVOICE_MODULE_NAME, _("Select..."),
261  TRUE, gnc_invoice_select_search_cb, isi, isi->book);
262  if (!edit)
263  {
264  g_free(isi);
265  return NULL;
266  }
267 
268  gnc_general_search_set_selected (GNC_GENERAL_SEARCH (edit), invoice);
269  gtk_box_pack_start (GTK_BOX (hbox), edit, FALSE, FALSE, 0);
270  g_object_set_data_full(G_OBJECT(edit), "isi-state", isi, g_free);
271 
272  /* Set the label */
273  gnc_invoice_select_search_set_label(isi);
274 
275  return edit;
276 }
277 
278 GncInvoice * gnc_invoice_get_invoice (GtkWidget *widget)
279 {
280  g_return_val_if_fail (widget != NULL, NULL);
281 
282  return gnc_general_search_get_selected (GNC_GENERAL_SEARCH (widget));
283 }
284 
285 void gnc_invoice_set_invoice (GtkWidget *widget, GncInvoice *invoice)
286 {
287  g_return_if_fail (widget != NULL);
288  g_return_if_fail (invoice != NULL);
289 
290  gnc_general_search_set_selected (GNC_GENERAL_SEARCH (widget), invoice);
291 }
292 
293 void gnc_invoice_set_owner (GtkWidget *widget, GncOwner *owner)
294 {
295  GncISI *isi;
296 
297  g_return_if_fail (widget != NULL);
298  g_return_if_fail (owner != NULL);
299 
300  isi = g_object_get_data(G_OBJECT(widget), "isi-state");
301  g_assert(isi);
302 
303  if (isi->owner.owner.undefined == owner->owner.undefined)
304  return;
305 
306  gncOwnerCopy(owner, &isi->owner);
307  isi->have_owner = TRUE;
308  gnc_general_search_set_selected(GNC_GENERAL_SEARCH(widget), NULL);
309 
310  /* Reset the label */
311  gnc_invoice_select_search_set_label(isi);
312 }
313 
314 Account *
315 gnc_account_select_combo_fill (GtkWidget *combo, QofBook *book,
316  GList *acct_types, GList *acct_commodities)
317 {
318  GtkListStore *store;
319  GtkTreeIter iter;
320  GList *list, *node;
321  const gchar *text;
322 
323  g_return_val_if_fail (combo && GTK_IS_COMBO_BOX(combo), NULL);
324  g_return_val_if_fail (book, NULL);
325  g_return_val_if_fail (acct_types, NULL);
326 
327  /* Figure out if anything is set in the combo */
328  text = gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (GTK_COMBO_BOX(combo)))));
329 
330  g_object_set_data (G_OBJECT(combo), "book", book);
331  list = gnc_account_get_descendants (gnc_book_get_root_account (book));
332 
333  /* Clear the existing list */
334  store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo)));
335  gtk_list_store_clear(store);
336 
337  /* Add the account names to the combo box */
338  for (node = list; node; node = node->next)
339  {
340  Account *account = node->data;
341  char *name;
342 
343  /* Only present accounts of the appropriate type */
344  if (g_list_index (acct_types, (gpointer)xaccAccountGetType (account))
345  == -1)
346  continue;
347 
348  /* Only present accounts with the right commodity, if that's a
349  restriction */
350  if (acct_commodities)
351  {
352  if ( g_list_find_custom( acct_commodities,
353  GINT_TO_POINTER(xaccAccountGetCommodity(account)),
354  gnc_commodity_compare_void) == NULL )
355  {
356  continue;
357  }
358  }
359 
360  name = gnc_account_get_full_name (account);
361  gtk_list_store_append(store, &iter);
362  gtk_list_store_set (store, &iter, 0, name, -1);
363 
364  /* Save the first account name in case no account name was set */
365  if (!text || g_strcmp0 (text, "") == 0)
366  {
367  text = g_strdup (name);
368  }
369  g_free(name);
370  }
371  gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
372 
373  g_list_free (list);
374 
375  gnc_cbwe_set_by_string(GTK_COMBO_BOX(combo), text);
376 
377  return gnc_account_select_combo_get_active (combo);
378 }
379 
380 Account *
381 gnc_account_select_combo_get_active (GtkWidget *combo)
382 {
383  const gchar *text;
384  QofBook *book;
385 
386  if (!combo || !GTK_IS_COMBO_BOX(combo))
387  return NULL;
388 
389  book = g_object_get_data (G_OBJECT(combo), "book");
390  if (!book)
391  return NULL;
392 
393  text = gtk_entry_get_text( GTK_ENTRY( gtk_bin_get_child( GTK_BIN( GTK_COMBO_BOX(combo)))));
394 
395  if (!text || g_strcmp0 (text, "") == 0)
396  return NULL;
397 
398  return gnc_account_lookup_by_full_name (gnc_book_get_root_account (book), text);
399 }
400 
401 /***********************************************************************
402  * gnc_simple_combo implementation functions
403  */
404 
405 typedef const char * (*GenericLookup_t)(gpointer);
406 typedef gboolean (*GenericEqual_t)(gpointer, gpointer);
407 
408 typedef struct
409 {
410  gint component_id;
411  GtkComboBox *cbox;
412  QofBook *book;
413  gboolean none_ok;
414  const char * (*get_name)(gpointer);
415  GList * (*get_list)(QofBook*);
416  gboolean (*is_equal)(gpointer, gpointer);
417 
418 } ListStoreData;
419 
420 static void
421 gnc_simple_combo_add_item (GtkListStore *liststore, const char *label, gpointer this_item)
422 {
423  GtkTreeIter iter;
424 
425  gtk_list_store_append (liststore, &iter);
426  gtk_list_store_set (liststore, &iter, 0, label, 1, this_item, -1);
427 }
428 
429 static void
430 gnc_simple_combo_generate_liststore (ListStoreData *lsd)
431 {
432  GList *items;
433  GtkListStore *liststore;
434 
435  if (!(lsd->get_list))
436  return;
437  if (!(lsd->get_name))
438  return;
439 
440  /* Get the list of items */
441  items = (lsd->get_list)(lsd->book);
442 
443  /* Reset the combobox' liststore */
444  liststore = GTK_LIST_STORE (gtk_combo_box_get_model (lsd->cbox));
445  gtk_list_store_clear (liststore);
446 
447  if (lsd->none_ok || !items)
448  gnc_simple_combo_add_item (liststore, _("None"), NULL);
449 
450  for ( ; items; items = items->next)
451  gnc_simple_combo_add_item (liststore, (lsd->get_name)(items->data), items->data);
452 }
453 
454 static void
455 gnc_simple_combo_refresh_handler (GHashTable *changes, gpointer user_data)
456 {
457  ListStoreData *lsd = user_data;
458  gnc_simple_combo_generate_liststore (lsd);
459 }
460 
461 static void
462 gnc_simple_combo_destroy_cb (GtkWidget *widget, gpointer data)
463 {
464  ListStoreData *lsd = data;
465 
466  gnc_unregister_gui_component (lsd->component_id);
467  g_free (lsd);
468 }
469 
470 static void
471 gnc_simple_combo_make (GtkComboBox *cbox, QofBook *book,
472  gboolean none_ok, QofIdType type_name,
473  GList * (*get_list)(QofBook*),
474  GenericLookup_t get_name,
475  GenericEqual_t is_equal,
476  gpointer initial_choice)
477 {
478  ListStoreData *lsd;
479 
480  lsd = g_object_get_data (G_OBJECT (cbox), "liststore-data");
481 
482  /* If this is the first time we've been called, then build the
483  * Option Menu Data object, register with the component manager, and
484  * watch for changed items. Then register for deletion, so we can
485  * unregister and free the data when this menu is destroyed.
486  */
487  if (!lsd)
488  {
489 
490  lsd = g_new0 (ListStoreData, 1);
491  lsd->cbox = cbox;
492  lsd->book = book;
493  lsd->none_ok = none_ok;
494  lsd->get_name = get_name;
495  lsd->get_list = get_list;
496  lsd->is_equal = is_equal;
497  g_object_set_data (G_OBJECT (cbox), "liststore-data", lsd);
498 
499  lsd->component_id =
500  gnc_register_gui_component ("gnc-simple-combo-refresh-hook",
501  gnc_simple_combo_refresh_handler,
502  NULL, lsd);
503 
504  if (type_name)
505  gnc_gui_component_watch_entity_type (lsd->component_id,
506  type_name,
507  QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
508 
509  g_signal_connect (G_OBJECT (cbox), "destroy",
510  G_CALLBACK (gnc_simple_combo_destroy_cb), lsd);
511  }
512 
513  gnc_simple_combo_generate_liststore (lsd);
514  gnc_simple_combo_set_value (cbox, initial_choice);
515 }
516 
517 /***********************************************************
518  * Specific invocations of the gnc_simple_combo widget
519  */
520 
521 /* Use a list available billing terms to fill the model of
522  * the combobox passed in. If none_ok is true, then add "none" as a
523  * choice (with data set to NULL).. If inital_choice is non-NULL,
524  * then that will be the default option setting when the menu is
525  * created.
526  */
527 void
528 gnc_billterms_combo (GtkComboBox *cbox, QofBook *book,
529  gboolean none_ok, GncBillTerm *initial_choice)
530 {
531  if (!cbox || !book) return;
532 
533  gnc_simple_combo_make (cbox, book, none_ok, GNC_BILLTERM_MODULE_NAME,
534  gncBillTermGetTerms,
535  (GenericLookup_t)gncBillTermGetName,
536  (GenericEqual_t)gncBillTermIsFamily,
537  (gpointer)initial_choice);
538 }
539 
540 void
541 gnc_taxtables_combo (GtkComboBox *cbox, QofBook *book,
542  gboolean none_ok, GncTaxTable *initial_choice)
543 {
544  if (!cbox || !book) return;
545 
546  gnc_simple_combo_make (cbox, book, none_ok, GNC_TAXTABLE_MODULE_NAME,
547  gncTaxTableGetTables,
548  (GenericLookup_t)gncTaxTableGetName,
549  NULL,
550  (gpointer)initial_choice);
551 }
552 
553 void
554 gnc_taxincluded_combo (GtkComboBox *cbox, GncTaxIncluded initial_choice)
555 {
556  GtkListStore *liststore;
557 
558  if (!cbox) return;
559 
560  gnc_simple_combo_make (cbox, NULL, FALSE, NULL, NULL, NULL, NULL,
561  GINT_TO_POINTER(initial_choice));
562  liststore = GTK_LIST_STORE (gtk_combo_box_get_model (cbox));
563 
564  gnc_simple_combo_add_item (liststore, _("Yes"),
565  GINT_TO_POINTER (GNC_TAXINCLUDED_YES));
566  gnc_simple_combo_add_item (liststore, _("No"),
567  GINT_TO_POINTER (GNC_TAXINCLUDED_NO));
568  gnc_simple_combo_add_item (liststore, _("Use Global"),
569  GINT_TO_POINTER (GNC_TAXINCLUDED_USEGLOBAL));
570 
571  gnc_simple_combo_set_value (cbox, GINT_TO_POINTER(initial_choice));
572 }
573 
574 /* Convenience functions for the above simple combo box types. */
575 
577 gpointer
578 gnc_simple_combo_get_value (GtkComboBox *cbox)
579 {
580  GtkTreeIter iter;
581  GtkTreeModel *model;
582  GValue value = { 0 };
583 
584  if (!cbox) return NULL;
585 
586  model = gtk_combo_box_get_model (cbox);
587  if (!gtk_combo_box_get_active_iter (cbox, &iter))
588  return NULL;
589  gtk_tree_model_get_value (model, &iter, 1, &value);
590  return g_value_get_pointer (&value);
591 }
592 
595 void
596 gnc_simple_combo_set_value (GtkComboBox *cbox, gpointer data)
597 {
598  GtkTreeIter iter;
599  GtkTreeModel *model;
600  gboolean valid_iter;
601  ListStoreData *lsd = g_object_get_data (G_OBJECT (cbox), "liststore-data");
602 
603  if (!cbox) return;
604 
605  model = gtk_combo_box_get_model (cbox);
606  valid_iter = gtk_tree_model_get_iter_first (model, &iter);
607 
608  while (valid_iter)
609  {
610  GValue value = { 0 };
611 
612  gtk_tree_model_get_value (model, &iter, 1, &value);
613  if (lsd && lsd->is_equal) // A specific comparator function was set
614  {
615  if ((lsd->is_equal)(g_value_get_pointer(&value), data))
616  {
617  gtk_combo_box_set_active_iter (cbox, &iter);
618  return;
619  }
620  }
621  else // No specific comparator function set, use generic pointer comparison instead
622  {
623  if (g_value_get_pointer(&value) == data)
624  {
625  gtk_combo_box_set_active_iter (cbox, &iter);
626  return;
627  }
628  }
629  valid_iter = gtk_tree_model_iter_next (model, &iter);
630  }
631 }
void gnc_cbwe_set_by_string(GtkComboBox *cbwe, const gchar *text)
Definition: gnc-gtk-utils.c:41
Core Customer Interface.
Business Interface: Object OWNERs.
const char * qof_object_get_type_label(QofIdTypeConst type_name)
utility functions for the GnuCash UI
GncTaxIncluded
Definition: gncTaxTable.h:100
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
gtk helper routines.
int gnc_commodity_compare_void(const void *a, const void *b)
gboolean gncBillTermIsFamily(const GncBillTerm *a, const GncBillTerm *b)
Definition: gncBillTerm.c:711
const gchar * QofIdType
Definition: qofid.h:85
gchar * gnc_account_get_full_name(const Account *account)
Definition: Account.c:3038
Account handling public routines.
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
Definition: Account.c:2915
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Definition: gncOwner.c:201
const GncOwner * gncOwnerGetEndOwner(const GncOwner *owner)
Definition: gncOwner.c:550
GList * gnc_account_get_descendants(const Account *account)
Definition: Account.c:2755
Business Invoice Interface.
Job Interface.
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
Vendor Interface.
Commodity handling public routines.