27 #include <qofbookslots.h> 28 #include <qofinstance-p.h> 29 #include <unordered_map> 39 static QofLogModule log_module = GNC_MOD_ENGINE;
58 QofInstanceClass parent_class;
67 PeriodData (
const char* note,
bool value_is_set, gnc_numeric value)
69 , value_is_set (value_is_set)
73 using PeriodDataVec = std::vector<PeriodData>;
74 using AcctMap = std::unordered_map<const Account*, PeriodDataVec>;
75 using StringVec = std::vector<std::string>;
83 const gchar *description;
88 std::unique_ptr<AcctMap> acct_map;
94 #define GET_PRIVATE(o) \ 95 ((GncBudgetPrivate*)gnc_budget_get_instance_private((GncBudget*)o)) 99 QofInstanceClass parent_class;
103 G_DEFINE_TYPE_WITH_PRIVATE(GncBudget, gnc_budget, QOF_TYPE_INSTANCE)
106 gnc_budget_init(GncBudget* budget)
111 priv = GET_PRIVATE(budget);
112 priv->name = CACHE_INSERT(_(
"Unnamed Budget"));
113 priv->description = CACHE_INSERT(
"");
114 priv->acct_map = std::make_unique<AcctMap>();
116 priv->num_periods = 12;
118 g_date_subtract_days(date, g_date_get_day(date) - 1);
119 recurrenceSet(&priv->recurrence, 1, PERIOD_MONTH, date, WEEKEND_ADJ_NONE);
124 gnc_budget_dispose (GObject *budgetp)
126 G_OBJECT_CLASS(gnc_budget_parent_class)->dispose(budgetp);
130 gnc_budget_finalize(GObject* budgetp)
132 G_OBJECT_CLASS(gnc_budget_parent_class)->finalize(budgetp);
136 gnc_budget_get_property( GObject*
object,
144 g_return_if_fail(GNC_IS_BUDGET(
object));
146 budget = GNC_BUDGET(
object);
147 priv = GET_PRIVATE(budget);
151 g_value_set_string(value, priv->name);
153 case PROP_DESCRIPTION:
154 g_value_set_string(value, priv->description);
156 case PROP_NUM_PERIODS:
157 g_value_set_uint(value, priv->num_periods);
159 case PROP_RECURRENCE:
161 g_value_set_pointer(value, &priv->recurrence);
164 G_OBJECT_WARN_INVALID_PROPERTY_ID(
object, prop_id, pspec);
170 gnc_budget_set_property( GObject*
object,
177 g_return_if_fail(GNC_IS_BUDGET(
object));
179 budget = GNC_BUDGET(
object);
180 if (prop_id < PROP_RUNTIME_0)
181 g_assert (qof_instance_get_editlevel(budget));
188 case PROP_DESCRIPTION:
191 case PROP_NUM_PERIODS:
194 case PROP_RECURRENCE:
195 gnc_budget_set_recurrence (budget, static_cast<Recurrence*>(g_value_get_pointer(value)));
198 G_OBJECT_WARN_INVALID_PROPERTY_ID(
object, prop_id, pspec);
204 gnc_budget_class_init(GncBudgetClass* klass)
206 GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
208 gobject_class->dispose = gnc_budget_dispose;
209 gobject_class->finalize = gnc_budget_finalize;
210 gobject_class->get_property = gnc_budget_get_property;
211 gobject_class->set_property = gnc_budget_set_property;
213 g_object_class_install_property(
216 g_param_spec_string(
"name",
218 "The name is an arbitrary string " 219 "assigned by the user. It is intended " 220 "to be a short, 5 to 30 character long string " 221 "that is displayed by the GUI as the " 226 g_object_class_install_property(
229 g_param_spec_string(
"description",
230 "Budget Description",
231 "The description is an arbitrary string " 232 "assigned by the user. It is intended " 233 "to be a longer, 1-5 sentence description of " 234 "what the budget is all about.",
238 g_object_class_install_property(
241 g_param_spec_uint(
"num-periods",
243 "The number of periods for this budget.",
249 g_object_class_install_property(
252 g_param_spec_pointer(
"recurrence",
260 PERR (
"Failed to commit: %d", errcode);
261 gnc_engine_signal_commit_error( errcode );
272 g_return_if_fail(GNC_IS_BUDGET(inst));
274 budget = GNC_BUDGET(inst);
275 priv = GET_PRIVATE(budget);
282 CACHE_REMOVE(priv->name);
283 CACHE_REMOVE(priv->description);
284 priv->acct_map =
nullptr;
287 g_object_unref(budget);
293 gnc_budget_begin_edit(GncBudget *bgt)
299 gnc_budget_commit_edit(GncBudget *bgt)
303 noop, gnc_budget_free);
309 g_return_val_if_fail(book, NULL);
313 auto budget {
static_cast<GncBudget*
>(g_object_new(GNC_TYPE_BUDGET,
nullptr)) };
325 g_return_if_fail(GNC_IS_BUDGET(budget));
326 gnc_budget_begin_edit(budget);
327 qof_instance_set_dirty(&budget->inst);
328 qof_instance_set_destroying(budget, TRUE);
329 gnc_budget_commit_edit(budget);
335 const GncBudget* old_b;
341 clone_budget_values_cb(
Account* a, gpointer user_data)
346 for ( i = 0; i < data->num_periods; ++i )
348 if ( gnc_budget_is_account_period_value_set(data->old_b, a, i) )
350 gnc_budget_set_account_period_value(data->new_b, a, i,
351 gnc_budget_get_account_period_value(data->old_b, a, i));
363 g_return_val_if_fail(old_b != NULL, NULL);
368 gnc_budget_begin_edit(new_b);
371 gnc_budget_set_recurrence(new_b, gnc_budget_get_recurrence(old_b));
375 clone_data.old_b = old_b;
376 clone_data.new_b = new_b;
377 clone_data.num_periods = gnc_budget_get_num_periods(new_b);
380 gnc_budget_commit_edit(new_b);
392 g_return_if_fail(GNC_IS_BUDGET(budget) && name);
394 priv = GET_PRIVATE(budget);
395 if ( name == priv->name )
return;
397 gnc_budget_begin_edit(budget);
398 CACHE_REPLACE(priv->name, name);
399 qof_instance_set_dirty(&budget->inst);
400 gnc_budget_commit_edit(budget);
406 gnc_budget_get_name(
const GncBudget* budget)
408 g_return_val_if_fail(GNC_IS_BUDGET(budget), NULL);
409 return GET_PRIVATE(budget)->name;
417 g_return_if_fail(GNC_IS_BUDGET(budget));
418 g_return_if_fail(description);
420 priv = GET_PRIVATE(budget);
421 if ( description == priv->description )
return;
422 gnc_budget_begin_edit(budget);
423 CACHE_REPLACE(priv->description, description);
424 qof_instance_set_dirty(&budget->inst);
425 gnc_budget_commit_edit(budget);
431 gnc_budget_get_description(
const GncBudget* budget)
433 g_return_val_if_fail(GNC_IS_BUDGET(budget), NULL);
434 return GET_PRIVATE(budget)->description;
438 gnc_budget_set_recurrence(GncBudget *budget,
const Recurrence *r)
442 g_return_if_fail(budget && r);
443 priv = GET_PRIVATE(budget);
445 gnc_budget_begin_edit(budget);
446 priv->recurrence = *r;
447 qof_instance_set_dirty(&budget->inst);
448 gnc_budget_commit_edit(budget);
454 gnc_budget_get_recurrence(
const GncBudget *budget)
456 g_return_val_if_fail(budget, NULL);
457 return (&GET_PRIVATE(budget)->recurrence);
461 gnc_budget_get_guid(
const GncBudget* budget)
463 g_return_val_if_fail(budget, NULL);
464 g_return_val_if_fail(GNC_IS_BUDGET(budget), NULL);
473 g_return_if_fail(GNC_IS_BUDGET(budget));
474 g_return_if_fail(num_periods > 0);
476 priv = GET_PRIVATE(budget);
477 if ( priv->num_periods == num_periods )
return;
479 gnc_budget_begin_edit(budget);
480 priv->num_periods = num_periods;
481 std::for_each (priv->acct_map->begin(),
482 priv->acct_map->end(),
483 [num_periods](
auto& it)
485 it.second.resize(num_periods);
487 qof_instance_set_dirty(&budget->inst);
488 gnc_budget_commit_edit(budget);
494 gnc_budget_get_num_periods(
const GncBudget* budget)
496 g_return_val_if_fail(GNC_IS_BUDGET(budget), 0);
497 return GET_PRIVATE(budget)->num_periods;
500 static inline StringVec
501 make_period_data_path (
const Account *account, guint period_num)
504 return { acct_guid.to_string(), std::to_string (period_num) };
507 static inline StringVec
508 make_period_note_path (
const Account *account, guint period_num)
510 StringVec path { GNC_BUDGET_NOTES_PATH };
511 StringVec data_path { make_period_data_path (account, period_num) };
512 std::move (data_path.begin(), data_path.end(), std::back_inserter (path));
516 static PeriodData& get_perioddata (
const GncBudget *budget,
523 gnc_budget_unset_account_period_value(GncBudget *budget,
const Account *account,
526 g_return_if_fail (budget != NULL);
527 g_return_if_fail (account != NULL);
528 g_return_if_fail (period_num < GET_PRIVATE(budget)->num_periods);
530 auto& data = get_perioddata (budget, account, period_num);
531 data.value_is_set =
false;
533 gnc_budget_begin_edit(budget);
534 auto path = make_period_data_path (account, period_num);
535 auto budget_kvp { QOF_INSTANCE (budget)->kvp_data };
536 delete budget_kvp->set_path (path,
nullptr);
537 qof_instance_set_dirty(&budget->inst);
538 gnc_budget_commit_edit(budget);
547 gnc_budget_set_account_period_value(GncBudget *budget,
const Account *account,
548 guint period_num, gnc_numeric val)
552 if (period_num >= GET_PRIVATE(budget)->num_periods)
554 PWARN(
"Period %i does not exist", period_num);
558 g_return_if_fail (budget != NULL);
559 g_return_if_fail (account != NULL);
561 auto& perioddata = get_perioddata (budget, account, period_num);
562 auto budget_kvp { QOF_INSTANCE (budget)->kvp_data };
563 auto path = make_period_data_path (account, period_num);
565 gnc_budget_begin_edit(budget);
568 delete budget_kvp->set_path (path,
nullptr);
569 perioddata.value_is_set =
false;
573 KvpValue* v =
new KvpValue (val);
574 delete budget_kvp->set_path (path, v);
575 perioddata.value_is_set =
true;
576 perioddata.value = val;
578 qof_instance_set_dirty(&budget->inst);
579 gnc_budget_commit_edit(budget);
586 gnc_budget_is_account_period_value_set (
const GncBudget *budget,
590 g_return_val_if_fail (period_num < GET_PRIVATE(budget)->num_periods,
false);
591 return get_perioddata (budget, account, period_num).value_is_set;
595 gnc_budget_get_account_period_value (
const GncBudget *budget,
599 g_return_val_if_fail (period_num < GET_PRIVATE(budget)->num_periods,
601 auto& data = get_perioddata (budget, account, period_num);
602 if (!data.value_is_set)
603 return gnc_numeric_zero();
609 gnc_budget_set_account_period_note(GncBudget *budget,
const Account *account,
610 guint period_num,
const gchar *note)
614 if (period_num >= GET_PRIVATE(budget)->num_periods)
616 PWARN(
"Period %i does not exist", period_num);
620 g_return_if_fail (budget != NULL);
621 g_return_if_fail (account != NULL);
623 auto& perioddata = get_perioddata (budget, account, period_num);
624 auto budget_kvp { QOF_INSTANCE (budget)->kvp_data };
625 auto path = make_period_note_path (account, period_num);
627 gnc_budget_begin_edit(budget);
630 delete budget_kvp->set_path (path,
nullptr);
631 perioddata.note.clear ();
635 KvpValue* v =
new KvpValue (g_strdup (note));
637 delete budget_kvp->set_path (path, v);
638 perioddata.note = note;
640 qof_instance_set_dirty(&budget->inst);
641 gnc_budget_commit_edit(budget);
648 gnc_budget_get_account_period_note (
const GncBudget *budget,
649 const Account *account, guint period_num)
651 g_return_val_if_fail (period_num < GET_PRIVATE(budget)->num_periods,
nullptr);
652 auto& data = get_perioddata (budget, account, period_num);
653 return data.note.empty () ? nullptr : data.note.c_str();
659 g_return_val_if_fail (GNC_IS_BUDGET(budget), 0);
660 return recurrenceGetPeriodTime(&GET_PRIVATE(budget)->recurrence, period_num, FALSE);
666 g_return_val_if_fail (GNC_IS_BUDGET(budget), 0);
667 return recurrenceGetPeriodTime(&GET_PRIVATE(budget)->recurrence, period_num, TRUE);
671 gnc_budget_get_account_period_actual_value(
672 const GncBudget *budget,
Account *acc, guint period_num)
675 g_return_val_if_fail(GNC_IS_BUDGET(budget) && acc, gnc_numeric_zero());
676 return recurrenceGetAccountPeriodValue(&GET_PRIVATE(budget)->recurrence,
681 get_perioddata (
const GncBudget *budget,
const Account *account, guint period_num)
685 if (period_num >= priv->num_periods)
686 throw std::out_of_range(
"period_num >= num_periods");
688 auto& vec = priv->acct_map->operator[](account);
692 auto budget_kvp { QOF_INSTANCE (budget)->kvp_data };
693 vec.reserve (priv->num_periods);
695 for (guint i = 0; i < priv->num_periods; i++)
697 auto kval1 { budget_kvp->get_slot (make_period_data_path (account, i)) };
698 auto kval2 { budget_kvp->get_slot (make_period_note_path (account, i)) };
700 auto is_set = kval1 && kval1->get_type() == KvpValue::Type::NUMERIC;
701 auto num = is_set ? kval1->get<gnc_numeric>() : gnc_numeric_zero ();
702 auto note = (kval2 && kval2->get_type() == KvpValue::Type::STRING) ?
703 kval2->get<
const char*>() :
"";
705 vec.emplace_back (note, is_set, num);
709 return vec.at(period_num);
713 gnc_budget_lookup (
const GncGUID *guid,
const QofBook *book)
717 g_return_val_if_fail(guid, NULL);
718 g_return_val_if_fail(book, NULL);
723 static void just_get_one(
QofInstance *ent, gpointer data)
725 GncBudget **bgt = (GncBudget**)data;
726 if (bgt && !*bgt) *bgt = GNC_BUDGET(ent);
730 gnc_budget_get_default (QofBook *book)
733 GncBudget *bgt = NULL;
734 GncGUID *default_budget_guid = NULL;
736 g_return_val_if_fail(book, NULL);
739 "default-budget", &default_budget_guid,
741 if (default_budget_guid)
745 default_budget_guid);
759 guid_free (default_budget_guid);
764 destroy_budget_on_book_close(
QofInstance *ent, gpointer data)
766 GncBudget* bgt = GNC_BUDGET(ent);
776 gnc_budget_book_end(QofBook* book)
793 static QofObject budget_object_def =
796 DI(.e_type = ) GNC_ID_BUDGET,
797 DI(.type_label = ) "Budget",
799 DI(.book_begin = ) NULL,
800 DI(.book_end = ) gnc_budget_book_end,
804 DI(.printable = ) (const
char * (*)(gpointer)) gnc_budget_get_name,
810 static PeriodType gnc_budget_get_rec_pt(const GncBudget *bgt)
812 return recurrenceGetPeriodType(&(GET_PRIVATE(bgt)->recurrence));
814 static guint gnc_budget_get_rec_mult(
const GncBudget *bgt)
816 return recurrenceGetMultiplier(&(GET_PRIVATE(bgt)->recurrence));
818 static time64 gnc_budget_get_rec_time(
const GncBudget *bgt)
820 return recurrenceGetTime(&(GET_PRIVATE(bgt)->recurrence));
824 gboolean gnc_budget_register (
void)
826 static QofParam params[] =
829 "name", QOF_TYPE_STRING,
834 "description", QOF_TYPE_STRING,
839 "recurrence_period_type", QOF_TYPE_INT32,
844 "recurrence_multiplier", QOF_TYPE_INT32,
851 "recurrence_date", QOF_TYPE_DATE,
856 "num_periods", QOF_TYPE_INT32,
865 QOF_PARAM_GUID, QOF_TYPE_GUID,
void gnc_budget_set_num_periods(GncBudget *budget, guint num_periods)
Set/Get the number of periods in the Budget.
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
void gnc_budget_destroy(GncBudget *budget)
Deletes the given budget object.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
This method will traverse all children of this accounts and their descendants, calling 'func' on each...
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of 'dirty' flag on collection.
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
QofBackendError
The errors that can be reported to the GUI & other front-end users.
GncBudget * gnc_budget_new(QofBook *book)
Creates and initializes a Budget.
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_function, const QofParam *params)
This function registers a new object class with the Qof subsystem.
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
#define PERR(format, args...)
Log a serious error.
#define ENTER(format, args...)
Print a function entry debugging message.
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Data structure for containing info while cloning budget values.
void qof_collection_foreach(const QofCollection *col, QofInstanceForeachCB cb_func, gpointer user_data)
Call the callback for each entity in the collection.
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
#define PWARN(format, args...)
Log a warning.
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
#define xaccAccountGetGUID(X)
Account handling public routines.
time64 gnc_budget_get_period_start_date(const GncBudget *budget, guint period_num)
Get the starting date of the Budget period.
GncBudget * gnc_budget_clone(const GncBudget *old_b)
Clones a budget creating a copy.
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
part2 – deal with the backend
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
void gnc_budget_set_name(GncBudget *budget, const gchar *name)
Set/Get the name of the Budget.
void gnc_budget_set_description(GncBudget *budget, const gchar *description)
Set/Get the description of the Budget.
#define LEAVE(format, args...)
Print a function exit debugging message.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
guint qof_collection_count(const QofCollection *col)
return the number of entities in the collection.
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
time64 gnc_budget_get_period_end_date(const GncBudget *budget, guint period_num)
Get the ending date of the Budget period.
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
The type used to store guids in C.
Commodity handling public routines.
GDate * gnc_g_date_new_today()
Returns a newly allocated date of the current clock time, taken from time(2).