business-gnome-utils.c

00001 /*
00002  * business-gnome-utils.c -- General GUI Utilities for GNC Business Objects
00003  *
00004  * Written By: Derek Atkins <warlord@MIT.EDU>
00005  * Copyright (C) 2001,2002,2006 Derek Atkins
00006  * Copyright (c) 2006 David Hampton <hampton@employees.org>
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License as
00010  * published by the Free Software Foundation; either version 2 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, contact:
00020  *
00021  * Free Software Foundation           Voice:  +1-617-542-5942
00022  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00023  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00024  */
00025 
00026 #include "config.h"
00027 
00028 #include <gtk/gtk.h>
00029 #include <glib/gi18n.h>
00030 
00031 #include "Account.h"
00032 #include "gnc-ui-util.h"
00033 #include "qof.h"
00034 #include "gnc-component-manager.h"
00035 #include "gnc-gtk-utils.h"
00036 
00037 #include "gncCustomer.h"
00038 #include "gncJob.h"
00039 #include "gncVendor.h"
00040 #include "gncOwner.h"
00041 #include "gncInvoice.h"
00042 
00043 #include "gnc-general-search.h"
00044 #include "gncObject.h"
00045 #include "business-gnome-utils.h"
00046 #include "dialog-customer.h"
00047 #include "dialog-job.h"
00048 #include "dialog-vendor.h"
00049 #include "dialog-employee.h"
00050 #include "dialog-invoice.h"
00051 
00052 typedef enum {
00053   GNCSEARCH_TYPE_SELECT,
00054   GNCSEARCH_TYPE_EDIT
00055 } GNCSearchType;
00056 
00057 static GtkWidget * gnc_owner_new (GtkWidget *label, GtkWidget *hbox,
00058                                   GNCBook *book, GncOwner *owner,
00059                                   GNCSearchType type)
00060 {
00061   GtkWidget *edit;
00062   GNCSearchCB search_cb = NULL;
00063   const char *type_name = NULL;
00064   const char *text = NULL;
00065 
00066   switch (type) {
00067   case GNCSEARCH_TYPE_SELECT:
00068     text = _("Select...");
00069     break;
00070   case GNCSEARCH_TYPE_EDIT:
00071     text = _("Edit...");
00072   };
00073 
00074   switch (owner->type) {
00075   case GNC_OWNER_NONE:
00076   case GNC_OWNER_UNDEFINED:
00077     return NULL;
00078 
00079   case GNC_OWNER_CUSTOMER:
00080     if (type == GNCSEARCH_TYPE_SELECT)
00081       search_cb = gnc_customer_search_select;
00082     else
00083       search_cb = gnc_customer_search_edit;
00084     type_name = GNC_CUSTOMER_MODULE_NAME;
00085     break;
00086 
00087   case GNC_OWNER_JOB:
00088     if (type == GNCSEARCH_TYPE_SELECT)
00089       search_cb = gnc_job_search_select;
00090     else
00091       search_cb = gnc_job_search_edit;
00092     type_name = GNC_JOB_MODULE_NAME;
00093     break;
00094 
00095   case GNC_OWNER_VENDOR:
00096     if (type == GNCSEARCH_TYPE_SELECT)
00097       search_cb = gnc_vendor_search_select;
00098     else
00099       search_cb = gnc_vendor_search_edit;
00100     type_name = GNC_VENDOR_MODULE_NAME;
00101     break;
00102 
00103   case GNC_OWNER_EMPLOYEE:
00104     if (type == GNCSEARCH_TYPE_SELECT)
00105       search_cb = gnc_employee_search_select;
00106     else
00107       search_cb = gnc_employee_search_edit;
00108     type_name = GNC_EMPLOYEE_MODULE_NAME;
00109     break;
00110 
00111   default:
00112     g_warning ("Unknown type");
00113     return NULL;
00114   }
00115 
00116   edit = gnc_general_search_new (type_name, text, search_cb, book);
00117   if (!edit)
00118     return NULL;
00119 
00120   gnc_general_search_set_selected (GNC_GENERAL_SEARCH (edit),
00121                                    owner->owner.undefined);
00122   gtk_box_pack_start (GTK_BOX (hbox), edit, FALSE, FALSE, 0);
00123   if (label)
00124     gtk_label_set_text (GTK_LABEL (label), _(gncObjectGetTypeLabel (type_name)));
00125 
00126   return edit;
00127 }
00128 
00129 GtkWidget * gnc_owner_select_create (GtkWidget *label, GtkWidget *hbox,
00130                                      GNCBook *book, GncOwner *owner)
00131 {
00132   g_return_val_if_fail (hbox != NULL, NULL);
00133   g_return_val_if_fail (book != NULL, NULL);
00134   g_return_val_if_fail (owner != NULL, NULL);
00135 
00136   return gnc_owner_new (label, hbox, book, owner, GNCSEARCH_TYPE_SELECT);
00137 }
00138 
00139 GtkWidget * gnc_owner_edit_create (GtkWidget *label, GtkWidget *hbox,
00140                                    GNCBook *book, GncOwner *owner)
00141 {
00142   g_return_val_if_fail (hbox != NULL, NULL);
00143   g_return_val_if_fail (book != NULL, NULL);
00144   g_return_val_if_fail (owner != NULL, NULL);
00145 
00146   return gnc_owner_new (label, hbox, book, owner, GNCSEARCH_TYPE_EDIT);
00147 }
00148 
00149 void gnc_owner_get_owner (GtkWidget *widget, GncOwner *owner)
00150 {
00151   g_return_if_fail (widget != NULL);
00152   g_return_if_fail (owner != NULL);
00153 
00154   /* We'll assume that the owner has the proper 'type' because we
00155    * can't change it here.  Hopefully the caller has it set properly
00156    */
00157   owner->owner.undefined =
00158     gnc_general_search_get_selected (GNC_GENERAL_SEARCH (widget));
00159 }
00160 
00161 void gnc_owner_set_owner (GtkWidget *widget, GncOwner *owner)
00162 {
00163   g_return_if_fail (widget != NULL);
00164   g_return_if_fail (owner != NULL);
00165 
00166   /* We'll assume that the owner has the proper 'type' because we
00167    * can't change it here.  Hopefully the caller has it set properly
00168    */
00169 
00170   gnc_general_search_set_selected (GNC_GENERAL_SEARCH (widget),
00171                                    owner->owner.undefined);
00172 }
00173 
00174 typedef struct _invoice_select_info {
00175   GtkWidget *label;
00176   GNCBook *book;
00177   GncOwner owner;
00178   gboolean have_owner;
00179 } GncISI;
00180 
00181 static GNCSearchWindow *
00182 gnc_invoice_select_search_cb (gpointer start, gpointer isip)
00183 {
00184   GncISI *isi = isip;
00185 
00186   if (!isi) return NULL;
00187   g_assert(isi->book);
00188 
00189   return gnc_invoice_search (start,
00190                              isi->have_owner ? &isi->owner : NULL,
00191                              isi->book);
00192 }
00193 
00194 static void
00195 gnc_invoice_select_search_set_label(GncISI* isi)
00196 {
00197   GncOwnerType owner_type;
00198   GncOwner *tmp;
00199   char *label;
00200 
00201   g_assert(isi);
00202   if (!isi->label) return;
00203 
00204   tmp = &isi->owner;
00205   owner_type = gncOwnerGetType(tmp);
00206   while (owner_type == GNC_OWNER_JOB) {
00207     tmp = gncOwnerGetEndOwner(tmp);
00208     owner_type = gncOwnerGetType(tmp);
00209   }
00210 
00211   /* Translators:  See comments in dialog-invoice.c:gnc_invoice_search() */
00212   switch (owner_type) {
00213   case GNC_OWNER_VENDOR:
00214     label = _("Bill");
00215     break;
00216   case GNC_OWNER_EMPLOYEE:
00217     label = _("Voucher");
00218     break;
00219   default:
00220     label = _("Invoice");
00221   }
00222 
00223   gtk_label_set_text(GTK_LABEL(isi->label), label);
00224 }
00225 
00226 GtkWidget * gnc_invoice_select_create (GtkWidget *hbox, GNCBook *book,
00227                                        const GncOwner *owner,
00228                                        GncInvoice *invoice,
00229                                        GtkWidget *label)
00230 {
00231   GtkWidget *edit;
00232   GncISI *isi;
00233 
00234   g_return_val_if_fail (hbox != NULL, NULL);
00235   g_return_val_if_fail (book != NULL, NULL);
00236   /* Note: it is legal to have no owner or invoice */
00237 
00238   isi = g_new0(GncISI, 1);
00239   if (!isi)
00240     return NULL;
00241 
00242   if (owner) {
00243     gncOwnerCopy(owner, &isi->owner);
00244     isi->have_owner = TRUE;
00245   } else {
00246     gncOwnerInitCustomer(&isi->owner, NULL);
00247   }
00248   isi->book = book;
00249   isi->label = label;
00250 
00251   edit = gnc_general_search_new (GNC_INVOICE_MODULE_NAME, _("Select..."),
00252                                  gnc_invoice_select_search_cb, isi);
00253   if (!edit) {
00254     g_free(isi);
00255     return NULL;
00256   }
00257 
00258   gnc_general_search_set_selected (GNC_GENERAL_SEARCH (edit), invoice);
00259   gtk_box_pack_start (GTK_BOX (hbox), edit, FALSE, FALSE, 0);
00260   g_object_set_data_full(G_OBJECT(edit), "isi-state", isi, g_free);
00261 
00262   /* Set the label */
00263   gnc_invoice_select_search_set_label(isi);
00264 
00265   return edit;
00266 }
00267 
00268 GncInvoice * gnc_invoice_get_invoice (GtkWidget *widget)
00269 {
00270   g_return_val_if_fail (widget != NULL, NULL);
00271 
00272   return gnc_general_search_get_selected (GNC_GENERAL_SEARCH (widget));
00273 }
00274 
00275 void gnc_invoice_set_invoice (GtkWidget *widget, GncInvoice *invoice)
00276 {
00277   g_return_if_fail (widget != NULL);
00278   g_return_if_fail (invoice != NULL);
00279 
00280   gnc_general_search_set_selected (GNC_GENERAL_SEARCH (widget), invoice);
00281 }
00282 
00283 void gnc_invoice_set_owner (GtkWidget *widget, GncOwner *owner)
00284 {
00285   GncISI *isi;
00286 
00287   g_return_if_fail (widget != NULL);
00288   g_return_if_fail (owner != NULL);
00289 
00290   isi = g_object_get_data(G_OBJECT(widget), "isi-state");
00291   g_assert(isi);
00292 
00293   if (isi->owner.owner.undefined == owner->owner.undefined)
00294     return;
00295 
00296   gncOwnerCopy(owner, &isi->owner);
00297   isi->have_owner = TRUE;
00298   gnc_general_search_set_selected(GNC_GENERAL_SEARCH(widget), NULL);
00299 
00300   /* Reset the label */
00301   gnc_invoice_select_search_set_label(isi);
00302 }
00303 
00304 void
00305 gnc_fill_account_select_combo (GtkWidget *combo, GNCBook *book,
00306                                GList *acct_types)
00307 {
00308   GtkListStore *store;
00309   GtkEntry *entry;
00310   GList *list, *node;
00311   char *text;
00312 
00313   g_return_if_fail (combo && GTK_IS_COMBO_BOX_ENTRY(combo));
00314   g_return_if_fail (book);
00315   g_return_if_fail (acct_types);
00316 
00317   /* Figure out if anything is set in the combo */
00318   text = gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo));
00319 
00320   list = gnc_account_get_descendants (gnc_book_get_root_account (book));
00321 
00322   /* Clear the existing list */
00323   entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(combo)));
00324   gtk_entry_set_text(entry, "");
00325   store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo)));
00326   gtk_list_store_clear(store);
00327 
00328  /* Add the account names to the combo box */
00329   for (node = list; node; node = node->next) {
00330     Account *account = node->data;
00331     char *name;
00332 
00333     /* Only present accounts of the appropriate type */
00334     if (g_list_index (acct_types, (gpointer)xaccAccountGetType (account))
00335         == -1)
00336       continue;
00337 
00338     name = xaccAccountGetFullName (account);
00339     gtk_combo_box_append_text(GTK_COMBO_BOX(combo), name);
00340     g_free(name);
00341   }
00342   gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
00343 
00344   g_list_free (list);
00345 
00346   gnc_cbe_set_by_string(GTK_COMBO_BOX_ENTRY(combo), text);
00347 
00348   if (text)
00349     g_free (text);
00350 }
00351 
00352 GList *
00353 gnc_business_account_types (GncOwner *owner)
00354 {
00355   g_return_val_if_fail (owner, NULL);
00356 
00357   switch (gncOwnerGetType (owner)) {
00358   case GNC_OWNER_CUSTOMER:
00359     return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_RECEIVABLE));
00360   case GNC_OWNER_VENDOR:
00361   case GNC_OWNER_EMPLOYEE:
00362     return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_PAYABLE));
00363     break;
00364   default:
00365     return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_NONE));
00366   }
00367 }
00368 
00369 /*********************************************************************/
00370 /* Option Menu creation                                              */
00371 
00372 typedef const char * (*GenericLookup_t)(gpointer);
00373 
00374 typedef struct {
00375   gint          component_id;
00376   GtkWidget *   omenu;
00377   GNCBook *     book;
00378   gboolean      none_ok;
00379   const char *  (*get_name)(gpointer);
00380   GList *       (*get_list)(GNCBook*);
00381 
00382   gboolean      building_menu;
00383   gpointer      result;
00384   gpointer *    result_p;
00385   
00386   void          (*changed_cb)(GtkWidget*, gpointer);
00387   gpointer      cb_arg;
00388 } OpMenuData;
00389 
00390 #define DO_ADD_ITEM(s,o) { \
00391         add_menu_item (menu, (s), omd, (o)); \
00392         if (omd->result == (o)) current = index; \
00393         index++; \
00394 }
00395 
00396 static void
00397 business_option_changed (GtkWidget *widget, gpointer data)
00398 {
00399   OpMenuData *omd = data;
00400 
00401   g_return_if_fail (omd);
00402   omd->result = g_object_get_data (G_OBJECT (widget), "this_item");
00403 
00404   if (!omd->building_menu) {
00405     if (omd->result_p)
00406       *(omd->result_p) = omd->result;
00407 
00408     if (omd->changed_cb)
00409       (omd->changed_cb)(omd->omenu, omd->cb_arg);
00410   }
00411 }
00412 
00413 static void
00414 add_menu_item (GtkWidget *menu, const char *label, OpMenuData *omd,
00415                gpointer this_item)
00416 {
00417   GtkWidget *item = gtk_menu_item_new_with_label (label);
00418   g_object_set_data (G_OBJECT (item), "this_item", this_item);
00419   g_signal_connect (G_OBJECT (item), "activate",
00420                     G_CALLBACK (business_option_changed), omd);
00421   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
00422   gtk_widget_show (item);
00423 }
00424 
00425 static void
00426 generic_omenu_destroy_cb (GtkWidget *widget, gpointer data)
00427 {
00428   OpMenuData *omd = data;
00429 
00430   gnc_unregister_gui_component (omd->component_id);
00431   g_free (omd);
00432 }
00433 
00434 static void
00435 build_generic_optionmenu (OpMenuData *omd)
00436 {
00437   GList *items;
00438   GtkWidget *menu;
00439   int current = 0, index = 0;
00440 
00441   /* Make sure we can "get_list" */
00442   if (omd->get_list == NULL)
00443     return;
00444 
00445   /* Get the list of items */
00446   items = (omd->get_list)(omd->book);
00447 
00448   /* Make a menu */
00449   menu = gtk_menu_new ();
00450   
00451   omd->building_menu = TRUE;
00452 
00453   if (omd->none_ok || items == NULL)
00454     DO_ADD_ITEM (_("None"), NULL);
00455 
00456   for ( ; items; items = items->next)
00457     DO_ADD_ITEM ((omd->get_name)(items->data), items->data);
00458 
00459   gtk_option_menu_set_menu (GTK_OPTION_MENU (omd->omenu), menu);
00460   gtk_option_menu_set_history (GTK_OPTION_MENU (omd->omenu), current);
00461   gtk_widget_show (menu);
00462 
00463   omd->building_menu = FALSE;
00464 }
00465 
00466 static void
00467 generic_omenu_refresh_handler (GHashTable *changes, gpointer user_data)
00468 {
00469   OpMenuData *omd = user_data;
00470   build_generic_optionmenu (omd);
00471 }
00472 
00473 static OpMenuData *
00474 make_generic_optionmenu (GtkWidget *omenu, GNCBook *book,
00475                          gboolean none_ok, GNCIdType type_name,
00476                          GList * (*get_list)(GNCBook*),
00477                          GenericLookup_t get_name,
00478                          gpointer *result)
00479 {
00480   OpMenuData *omd;
00481 
00482   omd = g_object_get_data (G_OBJECT (omenu), "menu-data");
00483 
00484   /* If this is the first time we've been called, then build the
00485    * Option Menu Data object, register with the component manager, and
00486    * watch for changed items.  Then register for deletion, so we can
00487    * unregister and free the data when this menu is destroyed.
00488    */
00489   if (!omd) {
00490     omd = g_new0 (OpMenuData, 1);
00491     omd->omenu = omenu;
00492     omd->book = book;
00493     omd->result_p = result;
00494     omd->none_ok = none_ok;
00495     omd->get_name = get_name;
00496     omd->get_list = get_list;
00497     g_object_set_data (G_OBJECT (omenu), "menu-data", omd);
00498 
00499     if (result)
00500       omd->result = *result;
00501 
00502     omd->component_id =
00503       gnc_register_gui_component ("generic-omenu-refresh-hook",
00504                                   generic_omenu_refresh_handler,
00505                                   NULL, omd);
00506 
00507 
00508     if (type_name)
00509       gnc_gui_component_watch_entity_type (omd->component_id,
00510                                            type_name,
00511                                            QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
00512     
00513     g_signal_connect (G_OBJECT (omenu), "destroy",
00514                       G_CALLBACK (generic_omenu_destroy_cb), omd);
00515 
00516   }
00517 
00518   build_generic_optionmenu (omd);
00519 
00520   return omd;
00521 }
00522 
00523 void
00524 gnc_ui_optionmenu_set_changed_callback (GtkWidget *omenu,
00525                                         void (*changed_cb)(GtkWidget*,gpointer),
00526                                         gpointer cb_arg)
00527 {
00528   OpMenuData *omd;
00529 
00530   if (!omenu) return;
00531 
00532   omd = g_object_get_data (G_OBJECT (omenu), "menu-data");
00533   g_return_if_fail (omd);
00534 
00535   omd->changed_cb = changed_cb;
00536   omd->cb_arg = cb_arg;
00537 }
00538 
00539 gpointer
00540 gnc_ui_optionmenu_get_value (GtkWidget *omenu)
00541 {
00542   OpMenuData *omd;
00543 
00544   if (!omenu) return NULL;
00545 
00546   omd = g_object_get_data (G_OBJECT (omenu), "menu-data");
00547   g_return_val_if_fail (omd, NULL);
00548 
00549   return omd->result;
00550 }
00551 
00552 void
00553 gnc_ui_optionmenu_set_value (GtkWidget *omenu, gpointer data)
00554 {
00555   OpMenuData *omd;
00556   GtkWidget *menu;
00557   GList *node;
00558   gint counter;
00559 
00560   if (!omenu) return;
00561 
00562   omd = g_object_get_data (G_OBJECT (omenu), "menu-data");
00563   g_return_if_fail (omd);
00564 
00565   menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (omenu));
00566   g_return_if_fail (menu);
00567 
00568   /* now walk all the children until we find our object */
00569   for (counter = 0, node = ((GTK_MENU_SHELL (menu))->children);
00570        node;
00571        node = node->next, counter++)
00572   {
00573     GObject *menuitem = node->data;
00574     gpointer this_object = g_object_get_data (menuitem, "this_item");
00575 
00576     if (this_object == data) {
00577       gtk_option_menu_set_history (GTK_OPTION_MENU (omd->omenu), counter);
00578       return;
00579     }
00580   }
00581 }
00582 
00583 /* Create an optionmenu of available billing terms and attach it to
00584  * the menu passed in.  If none_ok is true, then add "none" as a
00585  * choice (with data set to NULL).  Any time the menu changes,
00586  * 'choice' will be set to the chosen option.  If *choice is non-NULL,
00587  * then that will be the default option setting when the menu is
00588  * created.
00589  */
00590 void
00591 gnc_ui_billterms_optionmenu (GtkWidget *omenu, GNCBook *book,
00592                              gboolean none_ok, GncBillTerm **choice)
00593 {
00594   if (!omenu || !book) return;
00595 
00596   make_generic_optionmenu (omenu, book, none_ok, GNC_BILLTERM_MODULE_NAME,
00597                            gncBillTermGetTerms,
00598                            (GenericLookup_t)gncBillTermGetName,
00599                            (gpointer *)choice);
00600 }
00601 
00602 void
00603 gnc_ui_taxtables_optionmenu (GtkWidget *omenu, GNCBook *book,
00604                              gboolean none_ok, GncTaxTable **choice)
00605 {
00606   if (!omenu || !book) return;
00607 
00608   make_generic_optionmenu (omenu, book, none_ok, GNC_TAXTABLE_MODULE_NAME,
00609                            gncTaxTableGetTables,
00610                            (GenericLookup_t)gncTaxTableGetName,
00611                            (gpointer *)choice);
00612 }
00613 
00614 void
00615 gnc_ui_taxincluded_optionmenu (GtkWidget *omenu, GncTaxIncluded *choice)
00616 {
00617   GtkWidget *menu;
00618   OpMenuData *omd;
00619   int current = 0, index = 0;
00620 
00621   if (!omenu) return;
00622 
00623   omd = make_generic_optionmenu (omenu, NULL, FALSE, NULL, NULL, NULL,
00624                                  (gpointer *)choice);
00625 
00626   g_return_if_fail (omd);
00627 
00628   menu = gtk_menu_new ();
00629   
00630   add_menu_item (menu, _("Yes"), omd,
00631                  GINT_TO_POINTER (GNC_TAXINCLUDED_YES));
00632   if (*choice == GNC_TAXINCLUDED_YES) current = index;
00633   index++;
00634 
00635   add_menu_item (menu, _("No"), omd,
00636                  GINT_TO_POINTER (GNC_TAXINCLUDED_NO));
00637   if (*choice == GNC_TAXINCLUDED_NO) current = index;
00638   index++;
00639 
00640   add_menu_item (menu, _("Use Global"), omd,
00641                  GINT_TO_POINTER (GNC_TAXINCLUDED_USEGLOBAL));
00642   if (*choice == GNC_TAXINCLUDED_USEGLOBAL) current = index;
00643   index++;
00644 
00645   gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
00646   gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), current);
00647   gtk_widget_show (menu);
00648 }

Generated on Thu Jul 3 05:06:28 2008 for GnuCash by  doxygen 1.5.2