1 /********************************************************************\
2 * SX-book.c -- scheduled transaction dataset access *
3 * *
4 * This program is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU General Public License as *
6 * published by the Free Software Foundation; either version 2 of *
7 * the License, or (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License*
15 * along with this program; if not, contact: *
16 * *
17 * Free Software Foundation Voice: +1-617-542-5942 *
18 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19 * Boston, MA 02110-1301, USA gnu@gnu.org *
20 \********************************************************************/
21
22 /*
23 * FILE:
24 * SX-book.c
25 *
26 * FUNCTION:
27 * Anchor Scheduled Transaction Info into the book.
28 * See src/doc/books.txt for design overview.
29 *
30 * HISTORY:
31 * Copyright (c) 2003 Linas Vepstas <linas@linas.org>
32 */
33
34 #include <config.h>
35
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include <glib.h>
40
41 #include "gnc-engine.h"
42 #include "Account.h"
43 #include "Split.h"
44 #include "SchedXaction.h"
45 #include "SX-book.h"
46 #include "SX-book-p.h"
47 #include "gnc-event.h"
48 #include <qofinstance-p.h>
49
50 #undef G_LOG_DOMAIN
51 #define G_LOG_DOMAIN "gnc.engine.sx"
52
53 /* XXX this whole file is crufty, it doesn't really use entities
54 * in the most efficient/best way */
55
56 /* ====================================================================== */
57
58 static Account *
gnc_collection_get_template_root(const QofCollection * col)59 gnc_collection_get_template_root( const QofCollection *col )
60 {
61 return qof_collection_get_data (col);
62 }
63
64 Account *
gnc_book_get_template_root(const QofBook * book)65 gnc_book_get_template_root( const QofBook *book )
66 {
67 QofCollection *col;
68 if (!book) return NULL;
69 col = qof_book_get_collection (book, GNC_ID_SXTG);
70 return gnc_collection_get_template_root (col);
71 }
72
73 static void
gnc_collection_set_template_root(QofCollection * col,Account * templateRoot)74 gnc_collection_set_template_root (QofCollection *col,
75 Account *templateRoot)
76 {
77 Account *old_root;
78 if (!col) return;
79
80 old_root = gnc_collection_get_template_root (col);
81 if (old_root == templateRoot) return;
82
83 qof_collection_set_data (col, templateRoot);
84
85 if (old_root)
86 {
87 xaccAccountBeginEdit (old_root);
88 xaccAccountDestroy (old_root);
89 }
90 }
91
92
93 void
gnc_book_set_template_root(QofBook * book,Account * templateRoot)94 gnc_book_set_template_root (QofBook *book, Account *templateRoot)
95 {
96 QofCollection *col;
97 if (!book) return;
98
99 if (templateRoot && gnc_account_get_book(templateRoot) != book)
100 {
101 g_critical("cannot mix and match books freely!");
102 return;
103 }
104
105 col = qof_book_get_collection (book, GNC_ID_SXTG);
106 gnc_collection_set_template_root (col, templateRoot);
107 }
108
109
110 /* ====================================================================== */
111 /* gncObject function implementation and registration */
112
113 static void
sxtg_book_begin(QofBook * book)114 sxtg_book_begin (QofBook *book)
115 {
116 Account *root;
117
118 root = xaccMallocAccount(book);
119 xaccAccountBeginEdit(root);
120 xaccAccountSetType(root, ACCT_TYPE_ROOT);
121 xaccAccountSetName(root, "Template Root");
122 qof_instance_set_dirty (QOF_INSTANCE (root));
123 xaccAccountCommitEdit(root);
124 gnc_book_set_template_root (book, root);
125 }
126
127 static void
sxtg_book_end(QofBook * book)128 sxtg_book_end (QofBook *book)
129 {
130 gnc_book_set_template_root (book, NULL);
131 }
132
133 static gboolean
sxtg_is_dirty(const QofCollection * col)134 sxtg_is_dirty(const QofCollection *col)
135 {
136 Account *root;
137 GList *descendants, *node;
138 gboolean dirty = FALSE;
139
140 root = gnc_collection_get_template_root(col);
141 descendants = gnc_account_get_descendants(root);
142 for (node = descendants; node; node = g_list_next(node))
143 {
144 if (qof_instance_is_dirty(node->data))
145 {
146 dirty = TRUE;
147 break;
148 }
149 }
150 g_list_free(descendants);
151
152 return dirty;
153 }
154
155 /* EFFECTIVE FRIEND FUNCTION declared in qofinstance-p.h */
156 extern void qof_instance_mark_clean (QofInstance *);
157
158 static void
sxtg_mark_clean(QofCollection * col)159 sxtg_mark_clean(QofCollection *col)
160 {
161 Account *root;
162 GList *descendants;
163
164 root = gnc_collection_get_template_root(col);
165 qof_collection_mark_clean(col);
166
167 descendants = gnc_account_get_descendants(root);
168 g_list_foreach(descendants, (GFunc)qof_instance_mark_clean, NULL);
169 g_list_free(descendants);
170 }
171
172 #ifdef _MSC_VER
173 /* MSVC compiler doesn't have C99 "designated initializers"
174 * so we wrap them in a macro that is empty on MSVC. */
175 # define DI(x) /* */
176 #else
177 # define DI(x) x
178 #endif
179 static QofObject sxtg_object_def =
180 {
181 DI(.interface_version = ) QOF_OBJECT_VERSION,
182 DI(.e_type = ) GNC_ID_SXTG,
183 DI(.type_label = ) "Scheduled Transaction Templates",
184 DI(.create = ) NULL,
185 DI(.book_begin = ) sxtg_book_begin,
186 DI(.book_end = ) sxtg_book_end,
187 DI(.is_dirty = ) sxtg_is_dirty,
188 DI(.mark_clean = ) sxtg_mark_clean,
189 DI(.foreach = ) NULL,
190 DI(.printable = ) NULL,
191 };
192
193 /* ====================================================================== */
194
195 SchedXactions*
gnc_collection_get_schedxactions(const QofCollection * col)196 gnc_collection_get_schedxactions(const QofCollection *col)
197 {
198 SchedXactions *rtn = qof_collection_get_data(col);
199 // @@assert(rtn != null);
200 return rtn;
201 }
202
203 SchedXactions*
gnc_book_get_schedxactions(QofBook * book)204 gnc_book_get_schedxactions(QofBook *book)
205 {
206 QofCollection *col;
207 col = qof_book_get_collection(book, GNC_ID_SCHEDXACTION);
208 return gnc_collection_get_schedxactions(col);
209 }
210
211 void
gnc_sxes_add_sx(SchedXactions * sxes,SchedXaction * sx)212 gnc_sxes_add_sx(SchedXactions *sxes, SchedXaction *sx)
213 {
214 if (g_list_find(sxes->sx_list, sx) != NULL)
215 return;
216 sxes->sx_list = g_list_append(sxes->sx_list, sx);
217 qof_event_gen(&sxes->inst, GNC_EVENT_ITEM_ADDED, (gpointer)sx);
218 }
219
220 void
gnc_sxes_del_sx(SchedXactions * sxes,SchedXaction * sx)221 gnc_sxes_del_sx(SchedXactions *sxes, SchedXaction *sx)
222 {
223 GList *to_remove;
224 to_remove = g_list_find(sxes->sx_list, sx);
225 if (to_remove == NULL)
226 return;
227 sxes->sx_list = g_list_delete_link(sxes->sx_list, to_remove);
228 qof_event_gen(&sxes->inst, GNC_EVENT_ITEM_REMOVED, (gpointer)sx);
229 }
230
231 /* ====================================================================== */
232 /* SX-trans stuff */
233
234 /* GObject initialization */
235 QOF_GOBJECT_IMPL(gnc_schedxactions, SchedXactions, QOF_TYPE_INSTANCE);
236
237 static void
gnc_schedxactions_init(SchedXactions * sxs)238 gnc_schedxactions_init(SchedXactions* sxs)
239 {
240 }
241
242 static void
gnc_schedxactions_dispose_real(GObject * sxsp)243 gnc_schedxactions_dispose_real (GObject *sxsp)
244 {
245 }
246
247 static void
gnc_schedxactions_finalize_real(GObject * sxsp)248 gnc_schedxactions_finalize_real(GObject* sxsp)
249 {
250 }
251
252 static void
mark_sx_clean(gpointer data,gpointer user_data)253 mark_sx_clean(gpointer data, gpointer user_data)
254 {
255 SchedXaction *sx = (SchedXaction *) data;
256 qof_instance_mark_clean (QOF_INSTANCE(sx));
257 }
258
259 static void
book_sxes_setup(QofBook * book)260 book_sxes_setup(QofBook *book)
261 {
262 QofCollection *col;
263 SchedXactions *sxes;
264
265 col = qof_book_get_collection(book, GNC_ID_SCHEDXACTION);
266 sxes = g_object_new (GNC_TYPE_SCHEDXACTIONS, NULL);
267 g_assert(sxes);
268 qof_instance_init_data(&sxes->inst, GNC_ID_SXES, book);
269 sxes->sx_list = NULL;
270 sxes->sx_notsaved = TRUE;
271 qof_collection_set_data(col, sxes);
272 }
273
274 static void
book_sxes_end(QofBook * book)275 book_sxes_end(QofBook* book)
276 {
277 QofCollection *col;
278 SchedXactions *sxes;
279
280 col = qof_book_get_collection(book, GNC_ID_SCHEDXACTION);
281 sxes = qof_collection_get_data(col);
282 if (sxes != NULL)
283 {
284 g_object_unref(sxes);
285 qof_collection_set_data(col, NULL);
286 }
287 }
288
289 static void
book_sxns_mark_saved(QofCollection * col)290 book_sxns_mark_saved(QofCollection *col)
291 {
292 SchedXactions *sxl;
293 sxl = gnc_collection_get_schedxactions(col);
294 if (!sxl)
295 return;
296 sxl->sx_notsaved = FALSE;
297 g_list_foreach(sxl->sx_list,
298 mark_sx_clean,
299 NULL);
300 }
301
302 static gboolean
book_sxlist_notsaved(const QofCollection * col)303 book_sxlist_notsaved(const QofCollection *col)
304 {
305 GList *sxlist;
306 SchedXactions *sxl;
307
308 sxl = gnc_collection_get_schedxactions(col);
309 if (!sxl) return FALSE;
310 if (sxl->sx_notsaved) return TRUE;
311
312 for (sxlist = sxl->sx_list;
313 sxlist != NULL;
314 sxlist = g_list_next(sxlist))
315 {
316 SchedXaction *sx;
317 sx = (SchedXaction *) (sxlist->data);
318 if (xaccSchedXactionIsDirty( sx ))
319 return TRUE;
320 }
321
322 return FALSE;
323 }
324
325 static QofObject sxes_object_def =
326 {
327 DI(.interface_version = ) QOF_OBJECT_VERSION,
328 DI(.e_type = ) GNC_ID_SXES,
329 DI(.type_label = ) "Scheduled Transactions List",
330 DI(.create = ) NULL,
331 DI(.book_begin = ) book_sxes_setup,
332 DI(.book_end = ) book_sxes_end,
333 DI(.is_dirty = ) book_sxlist_notsaved,
334 DI(.mark_clean = ) book_sxns_mark_saved,
335 DI(.foreach = ) NULL,
336 DI(.printable = ) NULL,
337 DI(.version_cmp = ) NULL
338 };
339
340 static QofObject sxtt_object_def =
341 {
342 DI(.interface_version = ) QOF_OBJECT_VERSION,
343 DI(.e_type = ) GNC_ID_SXTT,
344 DI(.type_label = ) "Scheduled Transaction Templates",
345 DI(.create = ) NULL,
346 DI(.book_begin = ) NULL,
347 DI(.book_end = ) NULL,
348 DI(.is_dirty = ) NULL,
349 DI(.mark_clean = ) NULL,
350 DI(.foreach = ) NULL,
351 DI(.printable = ) NULL,
352 DI(.version_cmp = ) NULL,
353 };
354
355 gboolean
gnc_sxtt_register(void)356 gnc_sxtt_register (void)
357 {
358 if (!qof_object_register(&sxes_object_def))
359 return FALSE;
360 if (!qof_object_register(&sxtg_object_def))
361 return FALSE;
362 return qof_object_register(&sxtt_object_def);
363 }
364
365 GList*
gnc_sx_get_sxes_referencing_account(QofBook * book,Account * acct)366 gnc_sx_get_sxes_referencing_account(QofBook *book, Account *acct)
367 {
368 GList *rtn = NULL;
369 const GncGUID *acct_guid = qof_entity_get_guid(QOF_INSTANCE(acct));
370 GList *sx_list;
371 SchedXactions *sxactions = gnc_book_get_schedxactions(book);
372 g_return_val_if_fail( sxactions != NULL, rtn);
373 for (sx_list = sxactions->sx_list; sx_list != NULL; sx_list = sx_list->next)
374 {
375 SchedXaction *sx = (SchedXaction*)sx_list->data;
376 GList *splits = xaccSchedXactionGetSplits(sx);
377 for (; splits != NULL; splits = splits->next)
378 {
379 Split *s = (Split*)splits->data;
380 GncGUID *guid = NULL;
381 qof_instance_get (QOF_INSTANCE (s), "sx-account", &guid, NULL);
382 if (guid_equal(acct_guid, guid))
383 rtn = g_list_prepend (rtn, sx);
384
385 guid_free (guid);
386 }
387 }
388 return g_list_reverse (rtn);
389 }
390
391 /* ========================== END OF FILE =============================== */
392