GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-schedxaction-xml-v2.cpp
1/********************************************************************
2 * gnc-schedxactions-xml-v2.c -- xml routines for transactions *
3 * Copyright (C) 2001,2007 Joshua Sled <jsled@asynchronous.org> *
4 * *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License as *
7 * published by the Free Software Foundation; either version 2 of *
8 * the License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License*
16 * along with this program; if not, contact: *
17 * *
18 * Free Software Foundation Voice: +1-617-542-5942 *
19 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20 * Boston, MA 02110-1301, USA gnu@gnu.org *
21 * *
22 *******************************************************************/
23#include <glib.h>
24
25#include <config.h>
26#include <string.h>
27
28#include "SX-book.h"
29
30#include "gnc-xml-helper.h"
31#include "sixtp.h"
32#include "sixtp-utils.h"
33#include "sixtp-parsers.h"
34#include "sixtp-utils.h"
35#include "sixtp-dom-parsers.h"
36#include "sixtp-dom-generators.h"
37
38#include "gnc-xml.h"
39
40#include "io-gncxml-v2.h"
41#include "io-gncxml-gen.h"
42
43#include "sixtp-dom-parsers.h"
44
45#undef G_LOG_DOMAIN
46#define G_LOG_DOMAIN "gnc.backend.file.sx"
47static const QofLogModule log_module = G_LOG_DOMAIN;
48
49#define SX_ID "sx:id"
50#define SX_NAME "sx:name"
51#define SX_ENABLED "sx:enabled"
52#define SX_AUTOCREATE "sx:autoCreate"
53#define SX_AUTOCREATE_NOTIFY "sx:autoCreateNotify"
54#define SX_ADVANCE_CREATE_DAYS "sx:advanceCreateDays"
55#define SX_ADVANCE_REMIND_DAYS "sx:advanceRemindDays"
56#define SX_INSTANCE_COUNT "sx:instanceCount"
57#define SX_START "sx:start"
58#define SX_LAST "sx:last"
59#define SX_NUM_OCCUR "sx:num-occur"
60#define SX_REM_OCCUR "sx:rem-occur"
61#define SX_END "sx:end"
62#define SX_TEMPL_ACCT "sx:templ-acct"
63#define SX_FREQSPEC "sx:freqspec"
64#define SX_SCHEDULE "sx:schedule"
65#define SX_SLOTS "sx:slots"
66#define SX_DEFER_INSTANCE "sx:deferredInstance"
67
68/*
69 * FIXME: These should be defined in a header somewhere
70 */
71
72#define GNC_ACCOUNT_TAG "gnc:account"
73#define GNC_TRANSACTION_TAG "gnc:transaction"
74#define GNC_SCHEDXACTION_TAG "gnc:schedxaction"
75
76const gchar* schedxaction_version_string = "1.0.0";
77const gchar* schedxaction_version2_string = "2.0.0";
78
79xmlNodePtr
80gnc_schedXaction_dom_tree_create (SchedXaction* sx)
81{
82 xmlNodePtr ret;
83 const GDate* date;
84 gint instCount;
85 const GncGUID* templ_acc_guid;
86 gboolean allow_2_2_incompat = TRUE;
87 gchar* name = g_strdup (xaccSchedXactionGetName (sx));
88
89 templ_acc_guid = xaccAccountGetGUID (sx->template_acct);
90
91 /* FIXME: this should be the same as the def in io-gncxml-v2.c */
92 ret = xmlNewNode (NULL, BAD_CAST GNC_SCHEDXACTION_TAG);
93
94 if (allow_2_2_incompat)
95 xmlSetProp (ret, BAD_CAST "version", BAD_CAST schedxaction_version2_string);
96 else
97 xmlSetProp (ret, BAD_CAST "version", BAD_CAST schedxaction_version_string);
98
99 xmlAddChild (ret,
100 guid_to_dom_tree (SX_ID,
102
103 xmlNewTextChild (ret, NULL, BAD_CAST SX_NAME, checked_char_cast (name));
104 g_free (name);
105
106 if (allow_2_2_incompat)
107 {
108 xmlNewTextChild (ret, NULL, BAD_CAST SX_ENABLED,
109 BAD_CAST (sx->enabled ? "y" : "n"));
110 }
111
112 xmlNewTextChild (ret, NULL, BAD_CAST SX_AUTOCREATE,
113 BAD_CAST (sx->autoCreateOption ? "y" : "n"));
114 xmlNewTextChild (ret, NULL, BAD_CAST SX_AUTOCREATE_NOTIFY,
115 BAD_CAST (sx->autoCreateNotify ? "y" : "n"));
116 xmlAddChild (ret, int_to_dom_tree (SX_ADVANCE_CREATE_DAYS,
117 sx->advanceCreateDays));
118 xmlAddChild (ret, int_to_dom_tree (SX_ADVANCE_REMIND_DAYS,
119 sx->advanceRemindDays));
120
121 instCount = gnc_sx_get_instance_count (sx, NULL);
122 xmlAddChild (ret, int_to_dom_tree (SX_INSTANCE_COUNT,
123 instCount));
124
125 xmlAddChild (ret,
126 gdate_to_dom_tree (SX_START,
127 xaccSchedXactionGetStartDate (sx)));
128
129 date = xaccSchedXactionGetLastOccurDate (sx);
130 if (g_date_valid (date))
131 {
132 xmlAddChild (ret, gdate_to_dom_tree (SX_LAST, date));
133 }
134
136 {
137
138 xmlAddChild (ret, int_to_dom_tree (SX_NUM_OCCUR,
139 xaccSchedXactionGetNumOccur (sx)));
140 xmlAddChild (ret, int_to_dom_tree (SX_REM_OCCUR,
141 xaccSchedXactionGetRemOccur (sx)));
142
143 }
144 else if (xaccSchedXactionHasEndDate (sx))
145 {
146 xmlAddChild (ret,
147 gdate_to_dom_tree (SX_END,
149 }
150
151 /* output template account GncGUID */
152 xmlAddChild (ret,
153 guid_to_dom_tree (SX_TEMPL_ACCT,
154 templ_acc_guid));
155
156 if (allow_2_2_incompat)
157 {
158 xmlNodePtr schedule_node = xmlNewNode (NULL,
159 BAD_CAST "sx:schedule");
160 GList* schedule = gnc_sx_get_schedule (sx);
161 for (; schedule != NULL; schedule = schedule->next)
162 {
163 xmlAddChild (schedule_node, recurrence_to_dom_tree ("gnc:recurrence",
164 (Recurrence*)schedule->data));
165 }
166 xmlAddChild (ret, schedule_node);
167 }
168
169 /* Output deferred-instance list. */
170 {
171 xmlNodePtr instNode;
172 SXTmpStateData* tsd;
173 GList* l;
174
175 for (l = gnc_sx_get_defer_instances (sx); l; l = l->next)
176 {
177 tsd = (SXTmpStateData*)l->data;
178
179 instNode = xmlNewNode (NULL, BAD_CAST SX_DEFER_INSTANCE);
180 if (g_date_valid (&tsd->last_date))
181 {
182 xmlAddChild (instNode, gdate_to_dom_tree (SX_LAST,
183 &tsd->last_date));
184 }
185 xmlAddChild (instNode, int_to_dom_tree (SX_REM_OCCUR,
186 tsd->num_occur_rem));
187 xmlAddChild (instNode, int_to_dom_tree (SX_INSTANCE_COUNT,
188 tsd->num_inst));
189 xmlAddChild (ret, instNode);
190 }
191 }
192
193 /* xmlAddChild won't do anything with a NULL, so tests are superfluous. */
194 xmlAddChild (ret, qof_instance_slots_to_dom_tree (SX_SLOTS,
195 QOF_INSTANCE (sx)));
196 return ret;
197}
198
200{
201 SchedXaction* sx;
202 QofBook* book;
203 gboolean saw_freqspec;
204 gboolean saw_recurrence;
205};
206
207static
208gboolean
209sx_id_handler (xmlNodePtr node, gpointer sx_pdata)
210{
211 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
212 SchedXaction* sx = pdata->sx;
213 auto tmp = dom_tree_to_guid (node);
214
215 g_return_val_if_fail (tmp, FALSE);
216 xaccSchedXactionSetGUID (sx, &*tmp);
217
218 return TRUE;
219}
220
221static
222gboolean
223sx_name_handler (xmlNodePtr node, gpointer sx_pdata)
224{
225 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
226 return apply_xmlnode_text (xaccSchedXactionSetName, pdata->sx, node);
227}
228
229static gboolean
230sx_enabled_handler (xmlNodePtr node, gpointer sx_pdata)
231{
232 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
233 auto set_enabled = [](SchedXaction* sx, const char* txt)
234 {
235 sx->enabled = !g_strcmp0 (txt, "y");
236 };
237 return apply_xmlnode_text (set_enabled, pdata->sx, node);
238}
239
240static gboolean
241sx_autoCreate_handler (xmlNodePtr node, gpointer sx_pdata)
242{
243 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
244 auto set_autocreate = [](SchedXaction* sx, const char* txt)
245 {
246 sx->autoCreateOption = !g_strcmp0 (txt, "y");
247 };
248 return apply_xmlnode_text (set_autocreate, pdata->sx, node);
249}
250
251static gboolean
252sx_notify_handler (xmlNodePtr node, gpointer sx_pdata)
253{
254 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
255 auto set_notify = [](SchedXaction* sx, const char* txt)
256 {
257 sx->autoCreateNotify = !g_strcmp0 (txt, "y");
258 };
259 return apply_xmlnode_text (set_notify, pdata->sx, node);
260}
261
262static gboolean
263sx_advCreate_handler (xmlNodePtr node, gpointer sx_pdata)
264{
265 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
266 SchedXaction* sx = pdata->sx;
267 gint64 advCreate;
268
269 if (! dom_tree_to_integer (node, &advCreate))
270 {
271 return FALSE;
272 }
273
274 xaccSchedXactionSetAdvanceCreation (sx, advCreate);
275 return TRUE;
276}
277
278static gboolean
279sx_advRemind_handler (xmlNodePtr node, gpointer sx_pdata)
280{
281 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
282 SchedXaction* sx = pdata->sx;
283 gint64 advRemind;
284
285 if (! dom_tree_to_integer (node, &advRemind))
286 {
287 return FALSE;
288 }
289
290 xaccSchedXactionSetAdvanceReminder (sx, advRemind);
291 return TRUE;
292}
293
294static
295gboolean
296sx_set_date (xmlNodePtr node, SchedXaction* sx,
297 void (*settor) (SchedXaction* sx, const GDate* d))
298{
299 GDate* date;
300 date = dom_tree_to_gdate (node);
301 g_return_val_if_fail (date, FALSE);
302 (*settor) (sx, date);
303 g_date_free (date);
304
305 return TRUE;
306}
307
308static
309gboolean
310sx_instcount_handler (xmlNodePtr node, gpointer sx_pdata)
311{
312 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
313 SchedXaction* sx = pdata->sx;
314 gint64 instanceNum;
315
316 if (! dom_tree_to_integer (node, &instanceNum))
317 {
318 return FALSE;
319 }
320
321 gnc_sx_set_instance_count (sx, instanceNum);
322 return TRUE;
323}
324
325static
326gboolean
327sx_start_handler (xmlNodePtr node, gpointer sx_pdata)
328{
329 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
330 SchedXaction* sx = pdata->sx;
331
332 return sx_set_date (node, sx, xaccSchedXactionSetStartDate);
333}
334
335static
336gboolean
337sx_last_handler (xmlNodePtr node, gpointer sx_pdata)
338{
339 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
340 SchedXaction* sx = pdata->sx;
341
342 return sx_set_date (node, sx, xaccSchedXactionSetLastOccurDate);
343}
344
345static
346gboolean
347sx_end_handler (xmlNodePtr node, gpointer sx_pdata)
348{
349 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
350 SchedXaction* sx = pdata->sx;
351
352 return sx_set_date (node, sx, xaccSchedXactionSetEndDate);
353}
354
355static void
356_fixup_recurrence_start_dates (const GDate* sx_start_date, GList* schedule)
357{
358 GList* iter;
359 for (iter = schedule; iter != NULL; iter = iter->next)
360 {
361 Recurrence* r;
362 GDate start, next;
363
364 r = (Recurrence*)iter->data;
365
366 start = *sx_start_date;
367 g_date_subtract_days (&start, 1);
368
369 g_date_clear (&next, 1);
370
371 recurrenceNextInstance (r, &start, &next);
372 g_return_if_fail (g_date_valid (&next));
373
374 {
375 gchar date_str[128];
376 gchar* sched_str;
377
378 g_date_strftime (date_str, 127, "%x", &next);
379 sched_str = recurrenceToString (r);
380 DEBUG ("setting recurrence [%s] start date to [%s]",
381 sched_str, date_str);
382 g_free (sched_str);
383 }
384
385 recurrenceSet (r,
386 recurrenceGetMultiplier (r),
387 recurrenceGetPeriodType (r),
388 &next,
389 recurrenceGetWeekendAdjust (r));
390 }
391
392 if (g_list_length (schedule) == 1
393 && recurrenceGetPeriodType ((Recurrence*)g_list_nth_data (schedule,
394 0)) == PERIOD_ONCE)
395 {
396 char date_buf[128];
397 Recurrence* fixup = (Recurrence*)g_list_nth_data (schedule, 0);
398 g_date_strftime (date_buf, 127, "%x", sx_start_date);
399 recurrenceSet (fixup, 1, PERIOD_ONCE, sx_start_date, WEEKEND_ADJ_NONE);
400 DEBUG ("fixed up period=ONCE Recurrence to date [%s]", date_buf);
401 }
402}
403
404static gboolean
405sx_freqspec_handler (xmlNodePtr node, gpointer sx_pdata)
406{
407 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
408 SchedXaction* sx = pdata->sx;
409 GList* schedule;
410 gchar* debug_str;
411
412 g_return_val_if_fail (node, FALSE);
413
414 schedule = dom_tree_freqSpec_to_recurrences (node, pdata->book);
415 gnc_sx_set_schedule (sx, schedule);
416 debug_str = recurrenceListToString (schedule);
417 DEBUG ("parsed from freqspec [%s]", debug_str);
418 g_free (debug_str);
419
420 _fixup_recurrence_start_dates (xaccSchedXactionGetStartDate (sx), schedule);
421 pdata->saw_freqspec = TRUE;
422
423 return TRUE;
424}
425
426static gboolean
427sx_schedule_recurrence_handler (xmlNodePtr node, gpointer parsing_data)
428{
429 GList** schedule = (GList**)parsing_data;
430 gchar* sched_str;
431 Recurrence* r = dom_tree_to_recurrence (node);
432 g_return_val_if_fail (r, FALSE);
433 sched_str = recurrenceToString (r);
434 DEBUG ("parsed recurrence [%s]", sched_str);
435 g_free (sched_str);
436 *schedule = g_list_append (*schedule, r);
437 return TRUE;
438}
439
440struct dom_tree_handler sx_recurrence_list_handlers[] =
441{
442 { "gnc:recurrence", sx_schedule_recurrence_handler, 0, 0 },
443 { NULL, NULL, 0, 0 }
444};
445
446static gboolean
447sx_recurrence_handler (xmlNodePtr node, gpointer _pdata)
448{
449 struct sx_pdata* parsing_data = static_cast<decltype (parsing_data)> (_pdata);
450 GList* schedule = NULL;
451 gchar* debug_str;
452
453 g_return_val_if_fail (node, FALSE);
454
455 if (!dom_tree_generic_parse (node, sx_recurrence_list_handlers, &schedule))
456 return FALSE;
457 // g_return_val_if_fail(schedule, FALSE);
458 debug_str = recurrenceListToString (schedule);
459 DEBUG ("setting freshly-parsed schedule: [%s]", debug_str);
460 g_free (debug_str);
461 gnc_sx_set_schedule (parsing_data->sx, schedule);
462 parsing_data->saw_recurrence = TRUE;
463 return TRUE;
464}
465
466static
467gboolean
468sx_defer_last_handler (xmlNodePtr node, gpointer gpTSD)
469{
470 GDate* gd;
471 SXTmpStateData* tsd = (SXTmpStateData*)gpTSD;
472
473 g_return_val_if_fail (node, FALSE);
474 gd = dom_tree_to_gdate (node);
475 g_return_val_if_fail (gd, FALSE);
476 tsd->last_date = *gd;
477 g_date_free (gd);
478 return TRUE;
479}
480
481static
482gboolean
483sx_defer_rem_occur_handler (xmlNodePtr node, gpointer gpTSD)
484{
485 gint64 remOccur;
486 SXTmpStateData* tsd = (SXTmpStateData*)gpTSD;
487 g_return_val_if_fail (node, FALSE);
488
489 if (! dom_tree_to_integer (node, &remOccur))
490 {
491 return FALSE;
492 }
493 tsd->num_occur_rem = remOccur;
494 return TRUE;
495}
496
497static
498gboolean
499sx_defer_inst_count_handler (xmlNodePtr node, gpointer gpTSD)
500{
501 gint64 instCount;
502 SXTmpStateData* tsd = (SXTmpStateData*)gpTSD;
503 g_return_val_if_fail (node, FALSE);
504
505 if (! dom_tree_to_integer (node, &instCount))
506 {
507 return FALSE;
508 }
509 tsd->num_inst = instCount;
510 return TRUE;
511}
512
513struct dom_tree_handler sx_defer_dom_handlers[] =
514{
515 /* tag name, handler, opt, ? */
516 { SX_LAST, sx_defer_last_handler, 1, 0 },
517 { SX_REM_OCCUR, sx_defer_rem_occur_handler, 1, 0 },
518 { SX_INSTANCE_COUNT, sx_defer_inst_count_handler, 1, 0 },
519 { NULL, NULL, 0, 0 }
520};
521
522static
523gboolean
524sx_defer_inst_handler (xmlNodePtr node, gpointer sx_pdata)
525{
526 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
527 SchedXaction* sx = pdata->sx;
528 SXTmpStateData* tsd;
529
530 g_return_val_if_fail (node, FALSE);
531
532 tsd = g_new0 (SXTmpStateData, 1);
533 g_assert (sx_defer_dom_handlers != NULL);
534 if (!dom_tree_generic_parse (node,
535 sx_defer_dom_handlers,
536 tsd))
537 {
538 xmlElemDump (stdout, NULL, node);
539 g_free (tsd);
540 tsd = NULL;
541 return FALSE;
542 }
543
544 /* We assume they were serialized in sorted order, here. */
545 sx->deferredList = g_list_append (sx->deferredList, tsd);
546 return TRUE;
547}
548
549static
550gboolean
551sx_numOccur_handler (xmlNodePtr node, gpointer sx_pdata)
552{
553 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
554 SchedXaction* sx = pdata->sx;
555 gint64 numOccur;
556
557 if (! dom_tree_to_integer (node, &numOccur))
558 {
559 return FALSE;
560 }
561
562 xaccSchedXactionSetNumOccur (sx, numOccur);
563
564 return TRUE;
565}
566
567
568static
569gboolean
570sx_templ_acct_handler (xmlNodePtr node, gpointer sx_pdata)
571{
572 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
573 SchedXaction* sx = pdata->sx;
574 auto templ_acct_guid = dom_tree_to_guid (node);
575 Account* account;
576
577 if (!templ_acct_guid)
578 {
579 return FALSE;
580 }
581
582 account = xaccAccountLookup (&*templ_acct_guid, pdata->book);
583 sx_set_template_account (sx, account);
584
585 return TRUE;
586}
587
588
589static
590gboolean
591sx_remOccur_handler (xmlNodePtr node, gpointer sx_pdata)
592{
593 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
594 SchedXaction* sx = pdata->sx;
595 gint64 remOccur;
596
597 if (! dom_tree_to_integer (node, &remOccur))
598 {
599 return FALSE;
600 }
601
602 xaccSchedXactionSetRemOccur (sx, remOccur);
603
604 return TRUE;
605}
606
607static
608gboolean
609sx_slots_handler (xmlNodePtr node, gpointer sx_pdata)
610{
611 struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
612 SchedXaction* sx = pdata->sx;
613
614 return dom_tree_create_instance_slots (node, QOF_INSTANCE (sx));
615}
616
617struct dom_tree_handler sx_dom_handlers[] =
618{
619 { SX_ID, sx_id_handler, 1, 0 },
620 { SX_NAME, sx_name_handler, 1, 0 },
621 { SX_ENABLED, sx_enabled_handler, 0, 0 },
622 { SX_AUTOCREATE, sx_autoCreate_handler, 1, 0 },
623 { SX_AUTOCREATE_NOTIFY, sx_notify_handler, 1, 0 },
624 { SX_ADVANCE_CREATE_DAYS, sx_advCreate_handler, 1, 0 },
625 { SX_ADVANCE_REMIND_DAYS, sx_advRemind_handler, 1, 0 },
626 { SX_INSTANCE_COUNT, sx_instcount_handler, 0, 0 },
627 { SX_START, sx_start_handler, 1, 0 },
628 { SX_LAST, sx_last_handler, 0, 0 },
629 { SX_NUM_OCCUR, sx_numOccur_handler, 0, 0 },
630 { SX_REM_OCCUR, sx_remOccur_handler, 0, 0 },
631 { SX_END, sx_end_handler, 0, 0 },
632 { SX_TEMPL_ACCT, sx_templ_acct_handler, 0, 0 },
633 { SX_FREQSPEC, sx_freqspec_handler, 0, 0 },
634 { SX_SCHEDULE, sx_recurrence_handler, 0, 0 },
635 { SX_DEFER_INSTANCE, sx_defer_inst_handler, 0, 0 },
636 { SX_SLOTS, sx_slots_handler, 0, 0 },
637 { NULL, NULL, 0, 0 }
638};
639
640static gboolean
641gnc_schedXaction_end_handler (gpointer data_for_children,
642 GSList* data_from_children, GSList* sibling_data,
643 gpointer parent_data, gpointer global_data,
644 gpointer* result, const gchar* tag)
645{
646 SchedXaction* sx;
647 gboolean successful = FALSE;
648 xmlNodePtr tree = (xmlNodePtr)data_for_children;
649 gxpf_data* gdata = (gxpf_data*)global_data;
650 struct sx_pdata sx_pdata;
651
652 if (parent_data)
653 {
654 return TRUE;
655 }
656
657 if (!tag)
658 {
659 return TRUE;
660 }
661
662 g_return_val_if_fail (tree, FALSE);
663
664 sx = xaccSchedXactionMalloc (static_cast<QofBook*> (gdata->bookdata));
665
666 memset (&sx_pdata, 0, sizeof (sx_pdata));
667 sx_pdata.sx = sx;
668 sx_pdata.book = static_cast<decltype (sx_pdata.book)> (gdata->bookdata);
669
670 g_assert (sx_dom_handlers != NULL);
671
672 successful = dom_tree_generic_parse (tree, sx_dom_handlers, &sx_pdata);
673 if (!successful)
674 {
675 g_critical ("failed to parse scheduled xaction");
676 xmlElemDump (stdout, NULL, tree);
677 gnc_sx_begin_edit (sx);
679 goto done;
680 }
681
682 if (tree->properties)
683 {
684 gchar* sx_name = xaccSchedXactionGetName (sx);
685 xmlAttr* attr;
686 for (attr = tree->properties; attr != NULL; attr = attr->next)
687 {
688 xmlChar* attr_value = attr->children->content;
689 DEBUG ("sx attribute name[%s] value[%s]", attr->name, attr_value);
690 if (strcmp ((const char*)attr->name, "version") != 0)
691 {
692 g_warning ("unknown sx attribute [%s]", attr->name);
693 continue;
694 }
695
696 // if version == 1.0.0: ensure freqspec, no recurrence
697 // if version == 2.0.0: ensure recurrence, no freqspec.
698 if (strcmp ((const char*)attr_value,
699 schedxaction_version_string) == 0)
700 {
701 if (!sx_pdata.saw_freqspec)
702 g_critical ("did not see freqspec in version 1 sx [%s]", sx_name);
703 if (sx_pdata.saw_recurrence)
704 g_warning ("saw recurrence in supposedly version 1 sx [%s]", sx_name);
705 }
706
707 if (strcmp ((const char*)attr_value,
708 schedxaction_version2_string) == 0)
709 {
710 if (sx_pdata.saw_freqspec)
711 g_warning ("saw freqspec in version 2 sx [%s]", sx_name);
712 if (!sx_pdata.saw_recurrence)
713 g_critical ("did not find recurrence in version 2 sx [%s]", sx_name);
714 }
715 }
716 }
717
718 // generic_callback -> book_callback: insert the SX in the book
719 gdata->cb (tag, gdata->parsedata, sx);
720
721 /* FIXME: this should be removed somewhere near 1.8 release time. */
722 if (sx->template_acct == NULL)
723 {
724 Account* ra = NULL;
725 Account* acct = NULL;
726 sixtp_gdv2* sixdata = static_cast<decltype (sixdata)> (gdata->parsedata);
727 QofBook* book;
728 gchar guidstr[GUID_ENCODING_LENGTH + 1];
729
730 book = sixdata->book;
731
732 /* We're dealing with a pre-200107<near-end-of-month> rgmerk
733 change re: storing template accounts. */
734 /* Fix: get account with name of our GncGUID from the template
735 accounts. Make that our template_acct pointer. */
737 ra = gnc_book_get_template_root (book);
738 if (ra == NULL)
739 {
740 g_warning ("Error getting template root account from being-parsed Book.");
741 xmlFreeNode (tree);
742 return FALSE;
743 }
744 acct = gnc_account_lookup_by_name (ra, guidstr);
745 if (acct == NULL)
746 {
747 g_warning ("no template account with name [%s]", guidstr);
748 xmlFreeNode (tree);
749 return FALSE;
750 }
751 DEBUG ("template account name [%s] for SX with GncGUID [%s]",
752 xaccAccountGetName (acct), guidstr);
753
754 /* FIXME: free existing template account.
755 * HUH????? We only execute this if there isn't
756 * currently an existing template account, don't we?
757 * <rgmerk>
758 */
759
760 sx->template_acct = acct;
761 }
762
763done:
764 xmlFreeNode (tree);
765
766 return successful;
767}
768
769sixtp*
770gnc_schedXaction_sixtp_parser_create (void)
771{
772 return sixtp_dom_parser_new (gnc_schedXaction_end_handler, NULL, NULL);
773}
774
775static
776gboolean
777tt_act_handler (xmlNodePtr node, gpointer data)
778{
779 gnc_template_xaction_data* txd = static_cast<decltype (txd)> (data);
780 Account* acc;
781 gnc_commodity* com;
782
783 acc = dom_tree_to_account (node, txd->book);
784
785 if (acc == NULL)
786 {
787 return FALSE;
788 }
789 else
790 {
792
793 /* Check for the lack of a commodity [signifying that the
794 pre-7/11/2001-CIT-change SX template Account was parsed [but
795 incorrectly]. */
796 if (xaccAccountGetCommodity (acc) == NULL)
797 {
798#if 1
799 gnc_commodity_table* table;
800
802 com = gnc_commodity_table_lookup (table,
803 GNC_COMMODITY_NS_TEMPLATE, "template");
804#else
805 /* FIXME: This should first look in the table of the
806 book, maybe? The right thing happens [WRT file
807 load/save] if we just _new all the time, but it
808 doesn't seem right. This whole block should go
809 away at some point, but the same concern still
810 applies for
811 SchedXaction.c:xaccSchedXactionInit... */
812 com = gnc_commodity_new (txd->book,
813 "template", GNC_COMMODITY_NS_TEMPLATE,
814 "template", "template",
815 1);
816#endif
817 xaccAccountSetCommodity (acc, com);
818 }
819
820 txd->accts = g_list_append (txd->accts, acc);
821 }
822
823 return TRUE;
824}
825
826static
827gboolean
828tt_trn_handler (xmlNodePtr node, gpointer data)
829{
830 gnc_template_xaction_data* txd = static_cast<decltype (txd)> (data);
831 Transaction* trn;
832
833 trn = dom_tree_to_transaction (node, txd->book);
834
835 if (trn == NULL)
836 {
837 return FALSE;
838 }
839 else
840 {
841 txd->transactions = g_list_append (txd->transactions, trn);
842 }
843
844 return TRUE;
845}
846
847struct dom_tree_handler tt_dom_handlers[] =
848{
849 { GNC_ACCOUNT_TAG, tt_act_handler, 0, 0 },
850 { GNC_TRANSACTION_TAG, tt_trn_handler, 0, 0 },
851 { NULL, NULL, 0, 0 },
852};
853
854static gboolean
855gnc_template_transaction_end_handler (gpointer data_for_children,
856 GSList* data_from_children,
857 GSList* sibling_data,
858 gpointer parent_data,
859 gpointer global_data,
860 gpointer* result,
861 const gchar* tag)
862{
863 gboolean successful = FALSE;
864 xmlNodePtr tree = static_cast<decltype (tree)> (data_for_children);
865 gxpf_data* gdata = static_cast<decltype (gdata)> (global_data);
866 QofBook* book = static_cast<decltype (book)> (gdata->bookdata);
867 GList* n;
868 gnc_template_xaction_data txd;
869
870 txd.book = book;
871 txd.accts = NULL;
872 txd.transactions = NULL;
873
874 /* the DOM tree will have an account tree [the template
875 accounts] and a list of transactions [which will be members
876 of the template account].
877
878 we want to parse through the dom trees for each, placing
879 the null-parent account in the book's template-group slot,
880 the others under it, and the transactions as normal. */
881
882 if (parent_data)
883 {
884 return TRUE;
885 }
886
887 if (!tag)
888 {
889 return TRUE;
890 }
891
892 g_return_val_if_fail (tree, FALSE);
893
894 successful = dom_tree_generic_parse (tree, tt_dom_handlers, &txd);
895
896 if (successful)
897 {
898 gdata->cb (tag, gdata->parsedata, &txd);
899 }
900 else
901 {
902 g_warning ("failed to parse template transaction");
903 xmlElemDump (stdout, NULL, tree);
904 }
905
906 /* cleanup */
907 for (n = txd.accts; n; n = n->next)
908 {
909 n->data = NULL;
910 }
911 for (n = txd.transactions; n; n = n->next)
912 {
913 n->data = NULL;
914 }
915 g_list_free (txd.accts);
916 g_list_free (txd.transactions);
917
918 xmlFreeNode (tree);
919
920 return successful;
921}
922
923sixtp*
924gnc_template_transaction_sixtp_parser_create (void)
925{
926 return sixtp_dom_parser_new (gnc_template_transaction_end_handler,
927 NULL, NULL);
928}
Anchor Scheduled Transaction info in a book.
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition Account.cpp:3289
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition Account.cpp:1475
#define xaccAccountGetGUID(X)
Definition Account.h:252
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Definition Account.cpp:3408
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Set the account's commodity.
Definition Account.cpp:2678
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id,...
Definition Account.cpp:2050
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
Create a new commodity.
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
The gnc_account_lookup_by_name() subroutine fetches the account by name from the descendants of the s...
Definition Account.cpp:3093
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition guid.h:84
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition guid.cpp:208
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define xaccSchedXactionGetGUID(X)
GList * gnc_sx_get_defer_instances(SchedXaction *sx)
Returns the defer list from the SX; this is a (date-)sorted temporal-state-data instance list.
gint gnc_sx_get_instance_count(const SchedXaction *sx, SXTmpStateData *stateData)
Get the instance count.
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
Account * gnc_book_get_template_root(const QofBook *book)
Returns the template group from the book.
Definition SX-book.cpp:65
gboolean xaccSchedXactionHasOccurDef(const SchedXaction *sx)
Returns true if the scheduled transaction has a defined number of occurrences, false if not.
const GDate * xaccSchedXactionGetEndDate(const SchedXaction *sx)
Returns invalid date when there is no end-date specified.
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
Creates and initializes a scheduled transaction.
GList * gnc_sx_get_schedule(const SchedXaction *sx)
void xaccSchedXactionSetName(SchedXaction *sx, const gchar *newName)
A copy of the name is made.
void xaccSchedXactionSetEndDate(SchedXaction *sx, const GDate *newEnd)
Set to an invalid GDate to turn off 'end-date' definition.
void xaccSchedXactionDestroy(SchedXaction *sx)
Cleans up and frees a SchedXaction and its associated data.
void xaccSchedXactionSetNumOccur(SchedXaction *sx, gint new_num)
Set to '0' to turn off number-of-occurrences definition.
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
Sets the instance count to something other than the default.
api for GnuCash version 2 XML-based file format
STRUCTS.
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47
Just the variable temporal bits from the SX structure.
Definition sixtp.h:130