GnuCash 2.4.99
gnc-budget.c
00001 /********************************************************************\
00002  * gnc-budget.c -- Implementation of the top level Budgeting API.   *
00003  * Copyright (C) 04 sep 2003    Darin Willits <darin@willits.ca>    *
00004  * Copyright (C) 2005-2006 Chris Shoemaker <c.shoemaker@cox.net>    *
00005  *                                                                  *
00006  * This program is free software; you can redistribute it and/or    *
00007  * modify it under the terms of the GNU General Public License as   *
00008  * published by the Free Software Foundation; either version 2 of   *
00009  * the License, or (at your option) any later version.              *
00010  *                                                                  *
00011  * This program is distributed in the hope that it will be useful,  *
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00014  * GNU General Public License for more details.                     *
00015  *                                                                  *
00016  * You should have received a copy of the GNU General Public License*
00017  * along with this program; if not, contact:                        *
00018  *                                                                  *
00019  * Free Software Foundation           Voice:  +1-617-542-5942       *
00020  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00021  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00022  *                                                                  *
00023 \********************************************************************/
00024 
00025 #include "config.h"
00026 #include <glib.h>
00027 #include <glib/gprintf.h>
00028 #include <glib/gi18n.h>
00029 #include <time.h>
00030 #include "qof.h"
00031 #include "qofbookslots.h"
00032 
00033 #include "Account.h"
00034 
00035 #include "gnc-budget.h"
00036 #include "gnc-commodity.h"
00037 #include "gnc-gdate-utils.h"
00038 
00039 static QofLogModule log_module = GNC_MOD_ENGINE;
00040 
00041 enum
00042 {
00043     PROP_0,
00044     PROP_NAME,
00045     PROP_DESCRIPTION,
00046     PROP_NUM_PERIODS,
00047     PROP_RECURRENCE,
00048 };
00049 
00050 struct budget_s
00051 {
00052     QofInstance inst;
00053 };
00054 
00055 typedef struct
00056 {
00057     QofInstanceClass parent_class;
00058 } BudgetClass;
00059 
00060 typedef struct BudgetPrivate
00061 {
00062     /* The name is an arbitrary string assigned by the user. */
00063     gchar* name;
00064 
00065     /* The description is an arbitrary string assigned by the user. */
00066     gchar* description;
00067 
00068     /* Recurrence (period info) for the budget */
00069     Recurrence recurrence;
00070 
00071     /* Number of periods */
00072     guint  num_periods;
00073 } BudgetPrivate;
00074 
00075 #define GET_PRIVATE(o) \
00076   (G_TYPE_INSTANCE_GET_PRIVATE((o), GNC_TYPE_BUDGET, BudgetPrivate))
00077 
00078 struct _GncBudgetClass
00079 {
00080     QofInstanceClass parent_class;
00081 };
00082 
00083 /* GObject Initialization */
00084 G_DEFINE_TYPE(GncBudget, gnc_budget, QOF_TYPE_INSTANCE)
00085 
00086 static void
00087 gnc_budget_init(GncBudget* budget)
00088 {
00089     BudgetPrivate* priv;
00090     GDate date;
00091 
00092     priv = GET_PRIVATE(budget);
00093     priv->name = CACHE_INSERT(_("Unnamed Budget"));
00094     priv->description = CACHE_INSERT("");
00095 
00096     priv->num_periods = 12;
00097     g_date_set_time_t(&date, time(NULL));
00098     g_date_subtract_days(&date, g_date_get_day(&date) - 1);
00099     recurrenceSet(&priv->recurrence, 1, PERIOD_MONTH, &date, WEEKEND_ADJ_NONE);
00100 }
00101 
00102 static void
00103 gnc_budget_dispose (GObject *budgetp)
00104 {
00105     G_OBJECT_CLASS(gnc_budget_parent_class)->dispose(budgetp);
00106 }
00107 
00108 static void
00109 gnc_budget_finalize(GObject* budgetp)
00110 {
00111     G_OBJECT_CLASS(gnc_budget_parent_class)->finalize(budgetp);
00112 }
00113 
00114 static void
00115 gnc_budget_get_property( GObject* object,
00116                          guint prop_id,
00117                          GValue* value,
00118                          GParamSpec* pspec)
00119 {
00120     GncBudget* budget;
00121     BudgetPrivate* priv;
00122 
00123     g_return_if_fail(GNC_IS_BUDGET(object));
00124 
00125     budget = GNC_BUDGET(object);
00126     priv = GET_PRIVATE(budget);
00127     switch ( prop_id )
00128     {
00129     case PROP_NAME:
00130         g_value_set_string(value, priv->name);
00131         break;
00132     case PROP_DESCRIPTION:
00133         g_value_set_string(value, priv->description);
00134         break;
00135     case PROP_NUM_PERIODS:
00136         g_value_set_uint(value, priv->num_periods);
00137         break;
00138     case PROP_RECURRENCE:
00139         /* TODO: Make this a BOXED type */
00140         g_value_set_pointer(value, &priv->recurrence);
00141         break;
00142     default:
00143         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
00144         break;
00145     }
00146 }
00147 
00148 static void
00149 gnc_budget_set_property( GObject* object,
00150                          guint prop_id,
00151                          const GValue* value,
00152                          GParamSpec* pspec)
00153 {
00154     GncBudget* budget;
00155 
00156     g_return_if_fail(GNC_IS_BUDGET(object));
00157 
00158     budget = GNC_BUDGET(object);
00159     switch ( prop_id )
00160     {
00161     case PROP_NAME:
00162         gnc_budget_set_name(budget, g_value_get_string(value));
00163         break;
00164     case PROP_DESCRIPTION:
00165         gnc_budget_set_description(budget, g_value_get_string(value));
00166         break;
00167     case PROP_NUM_PERIODS:
00168         gnc_budget_set_num_periods(budget, g_value_get_uint(value));
00169         break;
00170     case PROP_RECURRENCE:
00171         gnc_budget_set_recurrence(budget, g_value_get_pointer(value));
00172         break;
00173     default:
00174         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
00175         break;
00176     }
00177 }
00178 
00179 static void
00180 gnc_budget_class_init(GncBudgetClass* klass)
00181 {
00182     GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
00183 
00184     gobject_class->dispose = gnc_budget_dispose;
00185     gobject_class->finalize = gnc_budget_finalize;
00186     gobject_class->get_property = gnc_budget_get_property;
00187     gobject_class->set_property = gnc_budget_set_property;
00188 
00189     g_type_class_add_private(klass, sizeof(BudgetPrivate));
00190 
00191     g_object_class_install_property(
00192         gobject_class,
00193         PROP_NAME,
00194         g_param_spec_string( "name",
00195                              "Budget Name",
00196                              "The name is an arbitrary string "
00197                              "assigned by the user.  It is intended "
00198                              "to be a short, 5 to 30 character long string "
00199                              "that is displayed by the GUI as the "
00200                              "budget mnemonic",
00201                              NULL,
00202                              G_PARAM_READWRITE));
00203 
00204     g_object_class_install_property(
00205         gobject_class,
00206         PROP_DESCRIPTION,
00207         g_param_spec_string( "description",
00208                              "Budget Description",
00209                              "The description is an arbitrary string "
00210                              "assigned by the user.  It is intended "
00211                              "to be a longer, 1-5 sentence description of "
00212                              "what the budget is all about.",
00213                              NULL,
00214                              G_PARAM_READWRITE));
00215 
00216     g_object_class_install_property(
00217         gobject_class,
00218         PROP_NUM_PERIODS,
00219         g_param_spec_uint( "num-periods",
00220                            "Number of Periods",
00221                            "The number of periods for this budget.",
00222                            0,
00223                            G_MAXUINT32,
00224                            12,
00225                            G_PARAM_READWRITE));
00226 
00227     g_object_class_install_property(
00228         gobject_class,
00229         PROP_RECURRENCE,
00230         g_param_spec_pointer( "recurrence",
00231                               "Budget Recurrence",
00232                               "about.",
00233                               G_PARAM_READWRITE));
00234 }
00235 
00236 static void commit_err (QofInstance *inst, QofBackendError errcode)
00237 {
00238     PERR ("Failed to commit: %d", errcode);
00239     gnc_engine_signal_commit_error( errcode );
00240 }
00241 
00242 static void
00243 gnc_budget_free(QofInstance *inst)
00244 {
00245     GncBudget *budget;
00246     BudgetPrivate* priv;
00247 
00248     if (inst == NULL)
00249         return;
00250     g_return_if_fail(GNC_IS_BUDGET(inst));
00251 
00252     budget = GNC_BUDGET(inst);
00253     priv = GET_PRIVATE(budget);
00254 
00255     /* We first send the message that this object is about to be
00256      * destroyed so that any GUI elements can remove it before it is
00257      * actually gone. */
00258     qof_event_gen( &budget->inst, QOF_EVENT_DESTROY, NULL);
00259 
00260     CACHE_REMOVE(priv->name);
00261     CACHE_REMOVE(priv->description);
00262 
00263     /* qof_instance_release (&budget->inst); */
00264     g_object_unref(budget);
00265 }
00266 
00267 static void noop (QofInstance *inst) {}
00268 
00269 void
00270 gnc_budget_begin_edit(GncBudget *bgt)
00271 {
00272     qof_begin_edit(QOF_INSTANCE(bgt));
00273 }
00274 
00275 void
00276 gnc_budget_commit_edit(GncBudget *bgt)
00277 {
00278     if (!qof_commit_edit(QOF_INSTANCE(bgt))) return;
00279     qof_commit_edit_part2(QOF_INSTANCE(bgt), commit_err,
00280                           noop, gnc_budget_free);
00281 }
00282 
00283 GncBudget*
00284 gnc_budget_new(QofBook *book)
00285 {
00286     GncBudget* budget;
00287 
00288     g_return_val_if_fail(book, NULL);
00289 
00290     ENTER(" ");
00291     budget = g_object_new(GNC_TYPE_BUDGET, NULL);
00292     qof_instance_init_data (&budget->inst, GNC_ID_BUDGET, book);
00293 
00294     qof_event_gen( &budget->inst, QOF_EVENT_CREATE , NULL);
00295 
00296     LEAVE(" ");
00297     return budget;
00298 }
00299 
00300 void
00301 gnc_budget_destroy(GncBudget *budget)
00302 {
00303     g_return_if_fail(GNC_IS_BUDGET(budget));
00304     gnc_budget_begin_edit(budget);
00305     qof_instance_set_dirty(&budget->inst);
00306     qof_instance_set_destroying(budget, TRUE);
00307     gnc_budget_commit_edit(budget);
00308 }
00309 
00311 typedef struct
00312 {
00313     const GncBudget* old_b;
00314     GncBudget* new_b;
00315     guint num_periods;
00316 } CloneBudgetData_t;
00317 
00318 static void
00319 clone_budget_values_cb(Account* a, gpointer user_data)
00320 {
00321     CloneBudgetData_t* data = (CloneBudgetData_t*)user_data;
00322     guint i;
00323 
00324     for ( i = 0; i < data->num_periods; ++i )
00325     {
00326         if ( gnc_budget_is_account_period_value_set(data->old_b, a, i) )
00327         {
00328             gnc_budget_set_account_period_value(data->new_b, a, i,
00329                                                 gnc_budget_get_account_period_value(data->old_b, a, i));
00330         }
00331     }
00332 }
00333 
00334 GncBudget*
00335 gnc_budget_clone(const GncBudget* old_b)
00336 {
00337     GncBudget* new_b;
00338     Account* root;
00339     CloneBudgetData_t clone_data;
00340 
00341     g_return_val_if_fail(old_b != NULL, NULL);
00342 
00343     ENTER(" ");
00344 
00345     new_b = gnc_budget_new(qof_instance_get_book(old_b));
00346     gnc_budget_begin_edit(new_b);
00347     gnc_budget_set_name(new_b, gnc_budget_get_name(old_b));
00348     gnc_budget_set_description(new_b, gnc_budget_get_description(old_b));
00349     gnc_budget_set_recurrence(new_b, gnc_budget_get_recurrence(old_b));
00350     gnc_budget_set_num_periods(new_b, gnc_budget_get_num_periods(old_b));
00351 
00352     root = gnc_book_get_root_account(qof_instance_get_book(old_b));
00353     clone_data.old_b = old_b;
00354     clone_data.new_b = new_b;
00355     clone_data.num_periods = gnc_budget_get_num_periods(new_b);
00356     gnc_account_foreach_descendant(root, clone_budget_values_cb, &clone_data);
00357 
00358     gnc_budget_commit_edit(new_b);
00359 
00360     LEAVE(" ");
00361 
00362     return new_b;
00363 }
00364 
00365 void
00366 gnc_budget_set_name(GncBudget* budget, const gchar* name)
00367 {
00368     BudgetPrivate* priv;
00369 
00370     g_return_if_fail(GNC_IS_BUDGET(budget) && name);
00371 
00372     priv = GET_PRIVATE(budget);
00373     if ( name == priv->name ) return;
00374 
00375     gnc_budget_begin_edit(budget);
00376     CACHE_REPLACE(priv->name, name);
00377     qof_instance_set_dirty(&budget->inst);
00378     gnc_budget_commit_edit(budget);
00379 
00380     qof_event_gen( &budget->inst, QOF_EVENT_MODIFY, NULL);
00381 }
00382 
00383 const gchar*
00384 gnc_budget_get_name(const GncBudget* budget)
00385 {
00386     g_return_val_if_fail(GNC_IS_BUDGET(budget), NULL);
00387     return GET_PRIVATE(budget)->name;
00388 }
00389 
00390 void
00391 gnc_budget_set_description(GncBudget* budget, const gchar* description)
00392 {
00393     BudgetPrivate* priv;
00394 
00395     g_return_if_fail(GNC_IS_BUDGET(budget));
00396     g_return_if_fail(description);
00397 
00398     priv = GET_PRIVATE(budget);
00399     if ( description == priv->description ) return;
00400     gnc_budget_begin_edit(budget);
00401     CACHE_REPLACE(priv->description, description);
00402     qof_instance_set_dirty(&budget->inst);
00403     gnc_budget_commit_edit(budget);
00404 
00405     qof_event_gen( &budget->inst, QOF_EVENT_MODIFY, NULL);
00406 }
00407 
00408 const gchar*
00409 gnc_budget_get_description(const GncBudget* budget)
00410 {
00411     g_return_val_if_fail(GNC_IS_BUDGET(budget), NULL);
00412     return GET_PRIVATE(budget)->description;
00413 }
00414 
00415 void
00416 gnc_budget_set_recurrence(GncBudget *budget, const Recurrence *r)
00417 {
00418     BudgetPrivate* priv;
00419 
00420     g_return_if_fail(budget && r);
00421     priv = GET_PRIVATE(budget);
00422 
00423     gnc_budget_begin_edit(budget);
00424     priv->recurrence = *r;
00425     qof_instance_set_dirty(&budget->inst);
00426     gnc_budget_commit_edit(budget);
00427 
00428     qof_event_gen(&budget->inst, QOF_EVENT_MODIFY, NULL);
00429 }
00430 
00431 const Recurrence *
00432 gnc_budget_get_recurrence(const GncBudget *budget)
00433 {
00434     g_return_val_if_fail(budget, NULL);
00435     return (&GET_PRIVATE(budget)->recurrence);
00436 }
00437 
00438 const GncGUID*
00439 gnc_budget_get_guid(const GncBudget* budget)
00440 {
00441     g_return_val_if_fail(budget, NULL);
00442     g_return_val_if_fail(GNC_IS_BUDGET(budget), NULL);
00443     return qof_instance_get_guid(QOF_INSTANCE(budget));
00444 }
00445 
00446 void
00447 gnc_budget_set_num_periods(GncBudget* budget, guint num_periods)
00448 {
00449     BudgetPrivate* priv;
00450 
00451     g_return_if_fail(GNC_IS_BUDGET(budget));
00452 
00453     priv = GET_PRIVATE(budget);
00454     if ( priv->num_periods == num_periods ) return;
00455 
00456     gnc_budget_begin_edit(budget);
00457     priv->num_periods = num_periods;
00458     qof_instance_set_dirty(&budget->inst);
00459     gnc_budget_commit_edit(budget);
00460 
00461     qof_event_gen( &budget->inst, QOF_EVENT_MODIFY, NULL);
00462 }
00463 
00464 guint
00465 gnc_budget_get_num_periods(const GncBudget* budget)
00466 {
00467     g_return_val_if_fail(GNC_IS_BUDGET(budget), 0);
00468     return GET_PRIVATE(budget)->num_periods;
00469 }
00470 
00471 #define BUF_SIZE (10 + GUID_ENCODING_LENGTH + \
00472    GNC_BUDGET_MAX_NUM_PERIODS_DIGITS)
00473 
00474 /* period_num is zero-based */
00475 /* What happens when account is deleted, after we have an entry for it? */
00476 void
00477 gnc_budget_unset_account_period_value(GncBudget *budget, const Account *account,
00478                                       guint period_num)
00479 {
00480     const GncGUID *guid;
00481     KvpFrame *frame;
00482     gchar path[BUF_SIZE];
00483     gchar *bufend;
00484 
00485     gnc_budget_begin_edit(budget);
00486     frame = qof_instance_get_slots(QOF_INSTANCE(budget));
00487     guid = xaccAccountGetGUID(account);
00488     bufend = guid_to_string_buff(guid, path);
00489     g_sprintf(bufend, "/%d", period_num);
00490 
00491     kvp_frame_set_value(frame, path, NULL);
00492     qof_instance_set_dirty(&budget->inst);
00493     gnc_budget_commit_edit(budget);
00494 
00495     qof_event_gen( &budget->inst, QOF_EVENT_MODIFY, NULL);
00496 
00497 }
00498 
00499 /* period_num is zero-based */
00500 /* What happens when account is deleted, after we have an entry for it? */
00501 void
00502 gnc_budget_set_account_period_value(GncBudget *budget, const Account *account,
00503                                     guint period_num, gnc_numeric val)
00504 {
00505     const GncGUID *guid;
00506     KvpFrame *frame;
00507     gchar path[BUF_SIZE];
00508     gchar *bufend;
00509 
00510     gnc_budget_begin_edit(budget);
00511     frame = qof_instance_get_slots(QOF_INSTANCE(budget));
00512     guid = xaccAccountGetGUID(account);
00513     bufend = guid_to_string_buff(guid, path);
00514     g_sprintf(bufend, "/%d", period_num);
00515 
00516     if (gnc_numeric_check(val))
00517         kvp_frame_set_value(frame, path, NULL);
00518     else
00519         kvp_frame_set_numeric(frame, path, val);
00520     qof_instance_set_dirty(&budget->inst);
00521     gnc_budget_commit_edit(budget);
00522 
00523     qof_event_gen( &budget->inst, QOF_EVENT_MODIFY, NULL);
00524 
00525 }
00526 
00527 /* We don't need these here, but maybe they're useful somewhere else?
00528    Maybe this should move to Account.h */
00529 
00530 gboolean
00531 gnc_budget_is_account_period_value_set(const GncBudget *budget, const Account *account,
00532                                        guint period_num)
00533 {
00534     gchar path[BUF_SIZE];
00535     gchar *bufend;
00536     KvpFrame *frame;
00537 
00538     g_return_val_if_fail(GNC_IS_BUDGET(budget), FALSE);
00539     g_return_val_if_fail(account, FALSE);
00540 
00541     frame = qof_instance_get_slots(QOF_INSTANCE(budget));
00542     bufend = guid_to_string_buff(xaccAccountGetGUID(account), path);
00543     g_sprintf(bufend, "/%d", period_num);
00544     return (kvp_frame_get_value(frame, path) != NULL);
00545 }
00546 
00547 gnc_numeric
00548 gnc_budget_get_account_period_value(const GncBudget *budget, const Account *account,
00549                                     guint period_num)
00550 {
00551     gnc_numeric numeric;
00552     gchar path[BUF_SIZE];
00553     gchar *bufend;
00554     KvpFrame *frame;
00555 
00556     numeric = gnc_numeric_zero();
00557     g_return_val_if_fail(GNC_IS_BUDGET(budget), numeric);
00558     g_return_val_if_fail(account, numeric);
00559 
00560     frame = qof_instance_get_slots(QOF_INSTANCE(budget));
00561     bufend = guid_to_string_buff(xaccAccountGetGUID(account), path);
00562     g_sprintf(bufend, "/%d", period_num);
00563 
00564     numeric = kvp_frame_get_numeric(frame, path);
00565     /* This still returns zero if unset, but callers can check for that. */
00566     return numeric;
00567 }
00568 
00569 
00570 Timespec
00571 gnc_budget_get_period_start_date(const GncBudget *budget, guint period_num)
00572 {
00573     Timespec ts;
00574     timespecFromTime_t(
00575         &ts,  recurrenceGetPeriodTime(&GET_PRIVATE(budget)->recurrence, period_num, FALSE));
00576     return ts;
00577 }
00578 
00579 Timespec
00580 gnc_budget_get_period_end_date(const GncBudget *budget, guint period_num)
00581 {
00582     Timespec ts;
00583     timespecFromTime_t(
00584         &ts,  recurrenceGetPeriodTime(&GET_PRIVATE(budget)->recurrence, period_num, TRUE));
00585     return ts;
00586 }
00587 
00588 gnc_numeric
00589 gnc_budget_get_account_period_actual_value(
00590     const GncBudget *budget, Account *acc, guint period_num)
00591 {
00592     // FIXME: maybe zero is not best error return val.
00593     g_return_val_if_fail(GNC_IS_BUDGET(budget) && acc, gnc_numeric_zero());
00594     return recurrenceGetAccountPeriodValue(&GET_PRIVATE(budget)->recurrence,
00595                                            acc, period_num);
00596 }
00597 
00598 GncBudget*
00599 gnc_budget_lookup (const GncGUID *guid, const QofBook *book)
00600 {
00601     QofCollection *col;
00602 
00603     g_return_val_if_fail(guid, NULL);
00604     g_return_val_if_fail(book, NULL);
00605     col = qof_book_get_collection (book, GNC_ID_BUDGET);
00606     return GNC_BUDGET(qof_collection_lookup_entity (col, guid));
00607 }
00608 
00609 static void just_get_one(QofInstance *ent, gpointer data)
00610 {
00611     GncBudget **bgt = (GncBudget**)data;
00612     if (bgt && !*bgt) *bgt = GNC_BUDGET(ent);
00613 }
00614 
00615 GncBudget*
00616 gnc_budget_get_default (QofBook *book)
00617 {
00618     QofCollection *col;
00619     GncBudget *bgt = NULL;
00620     kvp_value *kvp_default_budget;
00621     const GncGUID *default_budget_guid;
00622 
00623     g_return_val_if_fail(book, NULL);
00624 
00625     /* See if there is a budget selected in the KVP perferences */
00626 
00627     kvp_default_budget = kvp_frame_get_slot_path(qof_book_get_slots (book),
00628                          KVP_OPTION_PATH,
00629                          OPTION_SECTION_BUDGETING,
00630                          OPTION_NAME_DEFAULT_BUDGET,
00631                          NULL);
00632 
00633     if (kvp_default_budget != NULL )
00634     {
00635         default_budget_guid = kvp_value_get_guid(kvp_default_budget);
00636         if (default_budget_guid != NULL)
00637         {
00638             col = qof_book_get_collection(book, GNC_ID_BUDGET);
00639             bgt = (GncBudget *) qof_collection_lookup_entity(col,
00640                     default_budget_guid);
00641         }
00642     }
00643 
00644     /* Revert to 2.2.x behavior if there is no defined budget in KVP */
00645 
00646     if ( bgt == NULL )
00647     {
00648         col = qof_book_get_collection(book, GNC_ID_BUDGET);
00649         if (qof_collection_count(col) > 0)
00650         {
00651             qof_collection_foreach(col, just_get_one, &bgt);
00652         }
00653     }
00654 
00655     return bgt;
00656 }
00657 
00658 static void
00659 destroy_budget_on_book_close(QofInstance *ent, gpointer data)
00660 {
00661     GncBudget* bgt = GNC_BUDGET(ent);
00662 
00663     gnc_budget_destroy(bgt);
00664 }
00665 
00670 static void
00671 gnc_budget_book_end(QofBook* book)
00672 {
00673     QofCollection *col;
00674 
00675     col = qof_book_get_collection(book, GNC_ID_BUDGET);
00676     qof_collection_foreach(col, destroy_budget_on_book_close, NULL);
00677 }
00678 
00679 #ifdef _MSC_VER
00680 /* MSVC compiler doesn't have C99 "designated initializers"
00681  * so we wrap them in a macro that is empty on MSVC. */
00682 # define DI(x) /* */
00683 #else
00684 # define DI(x) x
00685 #endif
00686 
00687 /* Define the QofObject. */
00688 static QofObject budget_object_def =
00689 {
00690     DI(.interface_version = ) QOF_OBJECT_VERSION,
00691     DI(.e_type            = ) GNC_ID_BUDGET,
00692     DI(.type_label        = ) "Budget",
00693     DI(.create            = ) (gpointer)gnc_budget_new,
00694     DI(.book_begin        = ) NULL,
00695     DI(.book_end          = ) gnc_budget_book_end,
00696     DI(.is_dirty          = ) qof_collection_is_dirty,
00697     DI(.mark_clean        = ) qof_collection_mark_clean,
00698     DI(.foreach           = ) qof_collection_foreach,
00699     DI(.printable         = ) (const char * (*)(gpointer)) gnc_budget_get_name,
00700     DI(.version_cmp       = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
00701 };
00702 
00703 
00704 /* Static wrapper getters for the recurrence params */
00705 static PeriodType gnc_budget_get_rec_pt(const GncBudget *bgt)
00706 {
00707     return recurrenceGetPeriodType(&(GET_PRIVATE(bgt)->recurrence));
00708 }
00709 static guint gnc_budget_get_rec_mult(const GncBudget *bgt)
00710 {
00711     return recurrenceGetMultiplier(&(GET_PRIVATE(bgt)->recurrence));
00712 }
00713 static GDate gnc_budget_get_rec_date(const GncBudget *bgt)
00714 {
00715     return recurrenceGetDate(&(GET_PRIVATE(bgt)->recurrence));
00716 }
00717 
00718 /* Register ourselves with the engine. */
00719 gboolean gnc_budget_register (void)
00720 {
00721     static QofParam params[] =
00722     {
00723         {
00724             "name", QOF_TYPE_STRING,
00725             (QofAccessFunc) gnc_budget_get_name,
00726             (QofSetterFunc) gnc_budget_set_name
00727         },
00728         {
00729             "description", QOF_TYPE_STRING,
00730             (QofAccessFunc) gnc_budget_get_description,
00731             (QofSetterFunc) gnc_budget_set_description
00732         },
00733         {
00734             "recurrence_period_type", QOF_TYPE_INT32,
00735             (QofAccessFunc) gnc_budget_get_rec_pt, NULL
00736         },
00737         /* Signedness problem: Should be unsigned. */
00738         {
00739             "recurrence_multiplier", QOF_TYPE_INT32,
00740             (QofAccessFunc) gnc_budget_get_rec_mult, NULL
00741         },
00742         /* This is the same way that SchedXaction.c uses QOF_TYPE_DATE
00743            but I don't think QOF actually supports a GDate, so I think
00744            this is wrong. */
00745         {
00746             "recurrence_date", QOF_TYPE_DATE,
00747             (QofAccessFunc) gnc_budget_get_rec_date, NULL
00748         },
00749         /* Signedness problem: Should be unsigned. */
00750         {
00751             "num_periods", QOF_TYPE_INT32,
00752             (QofAccessFunc) gnc_budget_get_num_periods,
00753             (QofSetterFunc) gnc_budget_set_num_periods
00754         },
00755         {
00756             QOF_PARAM_BOOK, QOF_ID_BOOK,
00757             (QofAccessFunc) qof_instance_get_book, NULL
00758         },
00759         {
00760             QOF_PARAM_GUID, QOF_TYPE_GUID,
00761             (QofAccessFunc) qof_instance_get_guid, NULL
00762         },
00763         { NULL },
00764     };
00765 
00766     qof_class_register(GNC_ID_BUDGET, (QofSortFunc) NULL, params);
00767     return qof_object_register(&budget_object_def);
00768 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines