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