GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-tree-model-owner.c
1/*
2 * gnc-tree-model-owner.c -- GtkTreeModel implementation to
3 * display owners in a GtkTreeView.
4 *
5 * Copyright (C) 2011 Geert Janssens <geert@kobaltwit.be>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, contact:
19 *
20 * Free Software Foundation Voice: +1-617-542-5942
21 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
22 * Boston, MA 02110-1301, USA gnu@gnu.org
23 */
24
25#include <config.h>
26
27#include <gtk/gtk.h>
28#include <glib/gi18n.h>
29#include <string.h>
30
32#include "gnc-component-manager.h"
33#include "gncOwner.h"
34#include "gnc-commodity.h"
35#include "gnc-prefs.h"
36#include "gnc-engine.h"
37#include "gnc-event.h"
38#include "gnc-gobject-utils.h"
39#include "gnc-ui-balances.h"
40#include "gnc-ui-util.h"
41
42#define TREE_MODEL_OWNER_CM_CLASS "tree-model-owner"
43
45static QofLogModule log_module = GNC_MOD_GUI;
46
48static void gnc_tree_model_owner_finalize (GObject *object);
49static void gnc_tree_model_owner_dispose (GObject *object);
50
52static void gnc_tree_model_owner_tree_model_init (GtkTreeModelIface *iface);
53static GtkTreeModelFlags gnc_tree_model_owner_get_flags (GtkTreeModel *tree_model);
54static int gnc_tree_model_owner_get_n_columns (GtkTreeModel *tree_model);
55static GType gnc_tree_model_owner_get_column_type (GtkTreeModel *tree_model,
56 int index);
57static gboolean gnc_tree_model_owner_get_iter (GtkTreeModel *tree_model,
58 GtkTreeIter *iter,
59 GtkTreePath *path);
60static GtkTreePath *gnc_tree_model_owner_get_path (GtkTreeModel *tree_model,
61 GtkTreeIter *iter);
62static void gnc_tree_model_owner_get_value (GtkTreeModel *tree_model,
63 GtkTreeIter *iter,
64 int column,
65 GValue *value);
66static gboolean gnc_tree_model_owner_iter_next (GtkTreeModel *tree_model,
67 GtkTreeIter *iter);
68static gboolean gnc_tree_model_owner_iter_children (GtkTreeModel *tree_model,
69 GtkTreeIter *iter,
70 GtkTreeIter *parent);
71static gboolean gnc_tree_model_owner_iter_has_child (GtkTreeModel *tree_model,
72 GtkTreeIter *iter);
73static int gnc_tree_model_owner_iter_n_children (GtkTreeModel *tree_model,
74 GtkTreeIter *iter);
75static gboolean gnc_tree_model_owner_iter_nth_child (GtkTreeModel *tree_model,
76 GtkTreeIter *iter,
77 GtkTreeIter *parent,
78 int n);
79static gboolean gnc_tree_model_owner_iter_parent (GtkTreeModel *tree_model,
80 GtkTreeIter *iter,
81 GtkTreeIter *child);
82
84static void gnc_tree_model_owner_event_handler (QofInstance *entity,
85 QofEventId event_type,
86 GncTreeModelOwner *model,
87 GncEventData *ed);
88
91{
92 GncTreeModel gnc_tree_model;
93 int stamp;
96 QofBook *book;
97 GncOwnerType owner_type;
98 OwnerList *owner_list;
99 gint event_handler_id;
100 const gchar *negative_color;
101};
102
103G_DEFINE_TYPE_WITH_CODE(GncTreeModelOwner, gnc_tree_model_owner,
104 GNC_TYPE_TREE_MODEL,
105 G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL,
106 gnc_tree_model_owner_tree_model_init))
107
108/************************************************************/
109/* Owner Tree Model - Misc Functions */
110/************************************************************/
111
112
118static void
119gnc_tree_model_owner_update_color (gpointer gsettings, gchar *key, gpointer user_data)
120{
121 GncTreeModelOwner *model;
122 gboolean use_red;
123
124 g_return_if_fail(GNC_IS_TREE_MODEL_OWNER(user_data));
125 model = user_data;
126 use_red = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
127 model->negative_color = use_red ? "red" : NULL;
128}
129/************************************************************/
130/* g_object required functions */
131/************************************************************/
132
133static void
134gnc_tree_model_owner_class_init (GncTreeModelOwnerClass *klass)
135{
136 GObjectClass *o_class;
137
138 o_class = G_OBJECT_CLASS (klass);
139
140 /* GObject signals */
141 o_class->finalize = gnc_tree_model_owner_finalize;
142 o_class->dispose = gnc_tree_model_owner_dispose;
143}
144
145static void
146gnc_tree_model_owner_init (GncTreeModelOwner *model)
147{
148 gboolean red;
149
150 ENTER("model %p", model);
151 while (model->stamp == 0)
152 {
153 model->stamp = g_random_int ();
154 }
155
156 red = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
157
158 model->book = NULL;
159 model->owner_list = NULL;
160 model->owner_type = GNC_OWNER_NONE;
161 model->negative_color = red ? "red" : NULL;
162
163 gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED,
164 gnc_tree_model_owner_update_color,
165 model);
166
167 LEAVE(" ");
168}
169
170static void
171gnc_tree_model_owner_finalize (GObject *object)
172{
173 GncTreeModelOwner *model;
174
175 g_return_if_fail (object != NULL);
176 g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (object));
177
178 ENTER("model %p", object);
179
180 model = GNC_TREE_MODEL_OWNER (object);
181
182 if (model->owner_list)
183 g_list_free_full (model->owner_list, (GDestroyNotify) gncOwnerFree);
184
185 model->book = NULL;
186 model->owner_list = NULL;
187
188 G_OBJECT_CLASS(gnc_tree_model_owner_parent_class)->finalize (object);
189 LEAVE(" ");
190}
191
192static void
193gnc_tree_model_owner_dispose (GObject *object)
194{
195 GncTreeModelOwner *model;
196
197 g_return_if_fail (object != NULL);
198 g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (object));
199
200 ENTER("model %p", object);
201
202 model = GNC_TREE_MODEL_OWNER (object);
203
204 if (model->event_handler_id)
205 {
206 qof_event_unregister_handler (model->event_handler_id);
207 model->event_handler_id = 0;
208 }
209
210 gnc_prefs_remove_cb_by_func(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED,
211 gnc_tree_model_owner_update_color,
212 model);
213
214 G_OBJECT_CLASS (gnc_tree_model_owner_parent_class)->dispose (object);
215 LEAVE(" ");
216}
217
218
219/************************************************************/
220/* New Model Creation */
221/************************************************************/
222
223GtkTreeModel *
224gnc_tree_model_owner_new (GncOwnerType owner_type)
225{
226 GncTreeModelOwner *model;
227 const GList *item;
228
229 ENTER("owner_type %d", owner_type);
230 item = gnc_gobject_tracking_get_list(GNC_TREE_MODEL_OWNER_NAME);
231 for ( ; item; item = g_list_next(item))
232 {
233 model = (GncTreeModelOwner *)item->data;
234 if (model->owner_type == owner_type)
235 {
236 g_object_ref(G_OBJECT(model));
237 LEAVE("returning existing model %p", model);
238 return GTK_TREE_MODEL(model);
239 }
240 }
241
242 model = g_object_new (GNC_TYPE_TREE_MODEL_OWNER,
243 NULL);
244
245 model->book = gnc_get_current_book();
246 model->owner_type = owner_type;
247 model->owner_list = gncBusinessGetOwnerList (model->book, gncOwnerTypeToQofIdType(owner_type), TRUE);
248
249 model->event_handler_id = qof_event_register_handler
250 ((QofEventHandler)gnc_tree_model_owner_event_handler, model);
251
252 LEAVE("model %p", model);
253 return GTK_TREE_MODEL (model);
254}
255
256
257/************************************************************/
258/* Gnc Tree Model Debugging Utility Function */
259/************************************************************/
260
261#define ITER_STRING_LEN 128
262
263static const gchar *
264iter_to_string (GtkTreeIter *iter)
265{
266#ifdef G_THREADS_ENABLED
267 static GPrivate gtmits_buffer_key = G_PRIVATE_INIT(g_free);
268 gchar *string;
269
270 string = g_private_get (&gtmits_buffer_key);
271 if (string == NULL)
272 {
273 string = g_malloc(ITER_STRING_LEN + 1);
274 g_private_set (&gtmits_buffer_key, string);
275 }
276#else
277 static char string[ITER_STRING_LEN + 1];
278#endif
279
280 if (iter)
281 snprintf(string, ITER_STRING_LEN,
282 "[stamp:%x data:%p (%s), %p, %d]",
283 iter->stamp, iter->user_data,
284 gncOwnerGetName ((GncOwner *) iter->user_data),
285 iter->user_data2, GPOINTER_TO_INT(iter->user_data3));
286 else
287 strcpy(string, "(null)");
288 return string;
289}
290
291
292/************************************************************/
293/* Gtk Tree Model Required Interface Functions */
294/************************************************************/
295
296static void
297gnc_tree_model_owner_tree_model_init (GtkTreeModelIface *iface)
298{
299 iface->get_flags = gnc_tree_model_owner_get_flags;
300 iface->get_n_columns = gnc_tree_model_owner_get_n_columns;
301 iface->get_column_type = gnc_tree_model_owner_get_column_type;
302 iface->get_iter = gnc_tree_model_owner_get_iter;
303 iface->get_path = gnc_tree_model_owner_get_path;
304 iface->get_value = gnc_tree_model_owner_get_value;
305 iface->iter_next = gnc_tree_model_owner_iter_next;
306 iface->iter_children = gnc_tree_model_owner_iter_children;
307 iface->iter_has_child = gnc_tree_model_owner_iter_has_child;
308 iface->iter_n_children = gnc_tree_model_owner_iter_n_children;
309 iface->iter_nth_child = gnc_tree_model_owner_iter_nth_child;
310 iface->iter_parent = gnc_tree_model_owner_iter_parent;
311}
312
313static GtkTreeModelFlags
314gnc_tree_model_owner_get_flags (GtkTreeModel *tree_model)
315{
316 return 0;
317}
318
319static int
320gnc_tree_model_owner_get_n_columns (GtkTreeModel *tree_model)
321{
322 g_return_val_if_fail(GNC_IS_TREE_MODEL_OWNER(tree_model), -1);
323
324 return GNC_TREE_MODEL_OWNER_NUM_COLUMNS;
325}
326
327static GType
328gnc_tree_model_owner_get_column_type (GtkTreeModel *tree_model,
329 int index)
330{
331 g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), G_TYPE_INVALID);
332 g_return_val_if_fail ((index < GNC_TREE_MODEL_OWNER_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
333
334 switch (index)
335 {
336 case GNC_TREE_MODEL_OWNER_COL_NAME:
337 case GNC_TREE_MODEL_OWNER_COL_TYPE:
338 case GNC_TREE_MODEL_OWNER_COL_CURRENCY:
339 case GNC_TREE_MODEL_OWNER_COL_ID:
340 case GNC_TREE_MODEL_OWNER_COL_ADDRESS_NAME:
341 case GNC_TREE_MODEL_OWNER_COL_ADDRESS_1:
342 case GNC_TREE_MODEL_OWNER_COL_ADDRESS_2:
343 case GNC_TREE_MODEL_OWNER_COL_ADDRESS_3:
344 case GNC_TREE_MODEL_OWNER_COL_ADDRESS_4:
345 case GNC_TREE_MODEL_OWNER_COL_PHONE:
346 case GNC_TREE_MODEL_OWNER_COL_FAX:
347 case GNC_TREE_MODEL_OWNER_COL_EMAIL:
348 case GNC_TREE_MODEL_OWNER_COL_BALANCE:
349 case GNC_TREE_MODEL_OWNER_COL_BALANCE_REPORT:
350 case GNC_TREE_MODEL_OWNER_COL_NOTES:
351
352 case GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE:
353 return G_TYPE_STRING;
354
355 case GNC_TREE_MODEL_OWNER_COL_ACTIVE:
356 return G_TYPE_BOOLEAN;
357
358 default:
359 g_assert_not_reached ();
360 return G_TYPE_INVALID;
361 }
362}
363
364static gboolean
365gnc_tree_model_owner_get_iter (GtkTreeModel *tree_model,
366 GtkTreeIter *iter,
367 GtkTreePath *path)
368{
369 GncTreeModelOwner *model;
370 GncOwner *owner;
371 gint *indices;
372
373 g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
374
375 {
376 gchar *path_string = gtk_tree_path_to_string(path);
377 ENTER("model %p, iter %p, path %s", tree_model, iter, path_string);
378 g_free(path_string);
379 }
380
381 model = GNC_TREE_MODEL_OWNER (tree_model);
382
383 /* We keep a simple list of owners, not a tree, so only depth 1 is valid */
384 if (gtk_tree_path_get_depth (path) != 1)
385 {
386 LEAVE("bad depth");
387 return FALSE;
388 }
389
390 indices = gtk_tree_path_get_indices (path);
391
392 owner = g_list_nth_data (model->owner_list, indices[0]);
393 if (owner == NULL)
394 {
395 iter->stamp = 0;
396 LEAVE("bad index");
397 return FALSE;
398 }
399
400 iter->stamp = model->stamp;
401 iter->user_data = owner;
402 iter->user_data2 = GINT_TO_POINTER (indices[0]);
403 iter->user_data3 = NULL;
404
405 LEAVE("iter %s", iter_to_string (iter));
406 return TRUE;
407}
408
409static GtkTreePath *
410gnc_tree_model_owner_get_path (GtkTreeModel *tree_model,
411 GtkTreeIter *iter)
412{
413 GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
414 GncOwner *owner;
415 GtkTreePath *path;
416 gint i;
417
418 g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
419 g_return_val_if_fail (iter != NULL, NULL);
420 g_return_val_if_fail (iter->user_data != NULL, NULL);
421 g_return_val_if_fail (iter->stamp == model->stamp, NULL);
422
423 ENTER("model %p, iter %s", model, iter_to_string(iter));
424
425 if (model->owner_list == NULL)
426 {
427 LEAVE("failed (1)");
428 return NULL;
429 }
430
431 owner = (GncOwner *) iter->user_data;
432
433 path = gtk_tree_path_new ();
434 i = g_list_index (model->owner_list, owner);
435 if (i == -1)
436 {
437 gtk_tree_path_free (path);
438 LEAVE("failed (3)");
439 return NULL;
440 }
441 gtk_tree_path_prepend_index (path, i);
442
443 {
444 gchar *path_string = gtk_tree_path_to_string(path);
445 LEAVE("path (4) %s", path_string);
446 g_free(path_string);
447 }
448 return path;
449}
450
451static void
452gnc_tree_model_owner_set_color(GncTreeModelOwner *model,
453 gboolean negative,
454 GValue *value)
455{
456 if (negative)
457 g_value_set_static_string (value, model->negative_color);
458 else
459 g_value_set_static_string (value, NULL);
460}
461
462static void
463gnc_tree_model_owner_get_value (GtkTreeModel *tree_model,
464 GtkTreeIter *iter,
465 int column,
466 GValue *value)
467{
468 GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
469 GncOwner *owner;
470 gboolean negative; /* used to set "deficit style" also known as red numbers */
471 gchar *string = NULL;
472
473 g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (model));
474 g_return_if_fail (iter != NULL);
475 g_return_if_fail (iter->user_data != NULL);
476 g_return_if_fail (iter->stamp == model->stamp);
477
478 ENTER("model %p, iter %s, col %d", tree_model,
479 iter_to_string(iter), column);
480
481 owner = (GncOwner *) iter->user_data;
482
483 switch (column)
484 {
485 case GNC_TREE_MODEL_OWNER_COL_NAME:
486 g_value_init (value, G_TYPE_STRING);
487 g_value_set_string (value, gncOwnerGetName (owner));
488 break;
489 case GNC_TREE_MODEL_OWNER_COL_TYPE:
490 g_value_init (value, G_TYPE_STRING);
491 g_value_set_string (value,
493 break;
494 case GNC_TREE_MODEL_OWNER_COL_ID:
495 g_value_init (value, G_TYPE_STRING);
496 g_value_set_string (value, gncOwnerGetID (owner));
497 break;
498 case GNC_TREE_MODEL_OWNER_COL_CURRENCY:
499 g_value_init (value, G_TYPE_STRING);
500 g_value_set_string (value,
501 gnc_commodity_get_fullname(gncOwnerGetCurrency (owner)));
502 break;
503 case GNC_TREE_MODEL_OWNER_COL_ADDRESS_NAME:
504 g_value_init (value, G_TYPE_STRING);
505 string = g_strdup (gncAddressGetName (gncOwnerGetAddr (owner)));
506 if (string)
507 g_value_take_string (value, string);
508 else
509 g_value_set_static_string (value, "");
510 break;
511 case GNC_TREE_MODEL_OWNER_COL_ADDRESS_1:
512 g_value_init (value, G_TYPE_STRING);
513 string = g_strdup (gncAddressGetAddr1 (gncOwnerGetAddr (owner)));
514 if (string)
515 g_value_take_string (value, string);
516 else
517 g_value_set_static_string (value, "");
518 break;
519 case GNC_TREE_MODEL_OWNER_COL_ADDRESS_2:
520 g_value_init (value, G_TYPE_STRING);
521 string = g_strdup (gncAddressGetAddr2 (gncOwnerGetAddr (owner)));
522 if (string)
523 g_value_take_string (value, string);
524 else
525 g_value_set_static_string (value, "");
526 break;
527 case GNC_TREE_MODEL_OWNER_COL_ADDRESS_3:
528 g_value_init (value, G_TYPE_STRING);
529 string = g_strdup (gncAddressGetAddr3 (gncOwnerGetAddr (owner)));
530 if (string)
531 g_value_take_string (value, string);
532 else
533 g_value_set_static_string (value, "");
534 break;
535 case GNC_TREE_MODEL_OWNER_COL_ADDRESS_4:
536 g_value_init (value, G_TYPE_STRING);
537 string = g_strdup (gncAddressGetAddr4 (gncOwnerGetAddr (owner)));
538 if (string)
539 g_value_take_string (value, string);
540 else
541 g_value_set_static_string (value, "");
542 break;
543 case GNC_TREE_MODEL_OWNER_COL_PHONE:
544 g_value_init (value, G_TYPE_STRING);
545 string = g_strdup (gncAddressGetPhone (gncOwnerGetAddr (owner)));
546 if (string)
547 g_value_take_string (value, string);
548 else
549 g_value_set_static_string (value, "");
550 break;
551 case GNC_TREE_MODEL_OWNER_COL_FAX:
552 g_value_init (value, G_TYPE_STRING);
553 string = g_strdup (gncAddressGetFax (gncOwnerGetAddr (owner)));
554 if (string)
555 g_value_take_string (value, string);
556 else
557 g_value_set_static_string (value, "");
558 break;
559 case GNC_TREE_MODEL_OWNER_COL_EMAIL:
560 g_value_init (value, G_TYPE_STRING);
561 string = g_strdup (gncAddressGetEmail (gncOwnerGetAddr (owner)));
562 if (string)
563 g_value_take_string (value, string);
564 else
565 g_value_set_static_string (value, "");
566 break;
567
568 case GNC_TREE_MODEL_OWNER_COL_BALANCE:
569 g_value_init (value, G_TYPE_STRING);
570 string = gnc_ui_owner_get_print_balance(owner, &negative);
571 g_value_take_string (value, string);
572 break;
573
574 case GNC_TREE_MODEL_OWNER_COL_BALANCE_REPORT:
575 g_value_init (value, G_TYPE_STRING);
576 string = gnc_ui_owner_get_print_report_balance(owner, &negative);
577 g_value_take_string (value, string);
578 break;
579 case GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE:
580 g_value_init (value, G_TYPE_STRING);
581 string = gnc_ui_owner_get_print_balance(owner, &negative);
582 gnc_tree_model_owner_set_color(model, negative, value);
583 g_free(string);
584 break;
585
586 case GNC_TREE_MODEL_OWNER_COL_NOTES:
587 g_value_init (value, G_TYPE_STRING);
588 switch (gncOwnerGetType (owner))
589 {
590 case GNC_OWNER_NONE:
591 case GNC_OWNER_UNDEFINED:
592 case GNC_OWNER_EMPLOYEE:
593 case GNC_OWNER_JOB:
594 default:
595 g_value_set_static_string (value, "");
596 break;
597 case GNC_OWNER_VENDOR:
598 g_value_set_string (value, gncVendorGetNotes (gncOwnerGetVendor (owner)));
599 break;
600 case GNC_OWNER_CUSTOMER:
601 g_value_set_string (value, gncCustomerGetNotes (gncOwnerGetCustomer (owner)));
602 break;
603 }
604 break;
605
606 case GNC_TREE_MODEL_OWNER_COL_ACTIVE:
607 g_value_init (value, G_TYPE_BOOLEAN);
608 g_value_set_boolean (value, gncOwnerGetActive (owner));
609 break;
610
611 default:
612 g_assert_not_reached ();
613 }
614 LEAVE(" ");
615}
616
617static gboolean
618gnc_tree_model_owner_iter_next (GtkTreeModel *tree_model,
619 GtkTreeIter *iter)
620{
621 GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
622 GncOwner *owner;
623 gint i;
624
625 g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), FALSE);
626 g_return_val_if_fail (iter != NULL, FALSE);
627 g_return_val_if_fail (iter->user_data != NULL, FALSE);
628 g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
629
630 ENTER("model %p, iter %s", tree_model, iter_to_string (iter));
631
632 /* Get the *next* sibling owner. */
633 i = GPOINTER_TO_INT (iter->user_data2);
634 owner = g_list_nth_data (model->owner_list, i + 1);
635 if (owner == NULL)
636 {
637 iter->stamp = 0;
638 LEAVE("failed (3)");
639 return FALSE;
640 }
641
642 iter->user_data = owner;
643 iter->user_data2 = GINT_TO_POINTER (i + 1);
644 iter->user_data3 = NULL;
645
646 LEAVE("iter %s", iter_to_string(iter));
647 return TRUE;
648}
649
650static gboolean
651gnc_tree_model_owner_iter_children (GtkTreeModel *tree_model,
652 GtkTreeIter *iter,
653 GtkTreeIter *parent_iter)
654{
655 GncTreeModelOwner *model;
656
657 g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
658 ENTER("model %p, iter %p (to be filed in), parent %s",
659 tree_model, iter, (parent_iter ? iter_to_string(parent_iter) : "(null)"));
660
661 model = GNC_TREE_MODEL_OWNER (tree_model);
662
663 /* Owner lists don't have children, so this function call only
664 * makes sense if no parent_iter was supplied. In that case,
665 * return the first owner in the list */
666 if (!parent_iter)
667 {
668 iter->user_data = g_list_nth_data (model->owner_list, 0);
669 iter->user_data2 = GINT_TO_POINTER (0);
670 iter->user_data3 = NULL;
671 iter->stamp = model->stamp;
672 LEAVE("iter (2) %s", iter_to_string(iter));
673 return TRUE;
674 }
675 else
676 {
677 iter->stamp = 0;
678 LEAVE("failed (owners don't have children)");
679 return FALSE;
680 }
681}
682
683static gboolean
684gnc_tree_model_owner_iter_has_child (GtkTreeModel *tree_model,
685 GtkTreeIter *iter)
686{
687 /* Owner lists don't have children, so always return false */
688 return FALSE;
689}
690
691static int
692gnc_tree_model_owner_iter_n_children (GtkTreeModel *tree_model,
693 GtkTreeIter *iter)
694{
695 GncTreeModelOwner *model;
696
697 g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), -1);
698
699 model = GNC_TREE_MODEL_OWNER (tree_model);
700
701 /* Owner lists don't have children, so always return 0, except for
702 * the special case this request comes for the special "root" iter
703 * (NULL). For that exception we return the size of the owner list.
704 */
705 if (iter == NULL)
706 return (gint) g_list_length (model->owner_list);
707
708 g_return_val_if_fail (
709 GNC_TREE_MODEL_OWNER (tree_model)->stamp == iter->stamp, -1);
710
711 return 0;
712}
713
714static gboolean
715gnc_tree_model_owner_iter_nth_child (GtkTreeModel *tree_model,
716 GtkTreeIter *iter,
717 GtkTreeIter *parent_iter,
718 int n)
719{
720 GncTreeModelOwner *model;
721
722 if (parent_iter)
723 {
724 gchar *parent_string;
725 parent_string = g_strdup(iter_to_string(parent_iter));
726 ENTER("model %p, iter %s, parent_iter %s, n %d",
727 tree_model, iter_to_string(iter),
728 parent_string, n);
729 g_free(parent_string);
730 }
731 else
732 {
733 ENTER("model %p, iter %s, parent_iter (null), n %d",
734 tree_model, iter_to_string(iter), n);
735 }
736 gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
737
738 model = GNC_TREE_MODEL_OWNER (tree_model);
739
740 /* Owner lists don't have children, so this function call only
741 * makes sense if no parent_iter was supplied. In that case,
742 * return the first owner in the list */
743 if (!parent_iter)
744 {
745 iter->user_data = g_list_nth_data (model->owner_list, n);
746 iter->user_data2 = GINT_TO_POINTER (n);
747 iter->user_data3 = NULL;
748 iter->stamp = model->stamp;
749 LEAVE("iter (2) %s", iter_to_string(iter));
750 return TRUE;
751 }
752 else
753 {
754 iter->stamp = 0;
755 LEAVE("failed (owners don't have children)");
756 return FALSE;
757 }
758}
759
760static gboolean
761gnc_tree_model_owner_iter_parent (GtkTreeModel *tree_model,
762 GtkTreeIter *iter,
763 GtkTreeIter *child)
764{
765 /* Owner lists don't have children, so always return false */
766 iter->stamp = 0;
767 return FALSE;
768}
769
770
771/************************************************************/
772/* Owner Tree View Filter Functions */
773/************************************************************/
774
775/*
776 * Convert a model/iter pair to a gnucash owner. This routine should
777 * only be called from an owner tree view filter function.
778 */
779GncOwner *
780gnc_tree_model_owner_get_owner (GncTreeModelOwner *model,
781 GtkTreeIter *iter)
782{
783 g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
784 g_return_val_if_fail (iter != NULL, NULL);
785 g_return_val_if_fail (iter->user_data != NULL, NULL);
786 g_return_val_if_fail (iter->stamp == model->stamp, NULL);
787
788 return (GncOwner *) iter->user_data;
789}
790
791/*
792 * Convert a model/owner pair into a gtk_tree_model_iter. This
793 * routine should only be called from the file
794 * gnc-tree-view-owner.c.
795 */
796gboolean
798 GncOwner *owner,
799 GtkTreeIter *iter)
800{
801 GList *owner_in_list;
802
803 ENTER("model %p, owner %p, iter %p", model, owner, iter);
804 gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), FALSE);
805 gnc_leave_return_val_if_fail ((owner != NULL), FALSE);
806 gnc_leave_return_val_if_fail ((iter != NULL), FALSE);
807
808 owner_in_list = g_list_find_custom (model->owner_list, (gconstpointer)owner, (GCompareFunc)gncOwnerGCompareFunc);
809 if (owner_in_list)
810 {
811 iter->stamp = model->stamp;
812 iter->user_data = owner_in_list->data;
813 iter->user_data2 = GINT_TO_POINTER (g_list_position (model->owner_list, owner_in_list));
814 iter->user_data3 = NULL;
815 LEAVE("iter %s", iter_to_string (iter));
816 return TRUE;
817 }
818 else
819 {
820 iter->stamp = 0;
821 iter->user_data = NULL;
822 LEAVE("Owner not found in list");
823 return FALSE;
824 }
825}
826
827/*
828 * Convert a model/owner pair into a gtk_tree_model_path. This
829 * routine should only be called from the file
830 * gnc-tree-view-owner.c.
831 */
832GtkTreePath *
834 GncOwner *owner)
835{
836 GtkTreeIter tree_iter;
837 GtkTreePath *tree_path;
838
839 ENTER("model %p, owner %p", model, owner);
840 gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
841 gnc_leave_return_val_if_fail (owner != NULL, NULL);
842
844 &tree_iter))
845 {
846 LEAVE("no iter");
847 return NULL;
848 }
849
850 tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &tree_iter);
851 if (tree_path)
852 {
853 gchar *path_string = gtk_tree_path_to_string(tree_path);
854 LEAVE("path (2) %s", path_string);
855 g_free(path_string);
856 }
857 else
858 {
859 LEAVE("no path");
860 }
861 return tree_path;
862}
863
864/************************************************************/
865/* Owner Tree Model - Engine Event Handling Functions */
866/************************************************************/
867
868static void
869increment_stamp(GncTreeModelOwner *model)
870{
871 do model->stamp++;
872 while (!model->stamp);
873}
874
903static void
904gnc_tree_model_owner_event_handler (QofInstance *entity,
905 QofEventId event_type,
906 GncTreeModelOwner *model,
907 GncEventData *ed)
908{
909 GtkTreePath *path = NULL;
910 GtkTreeIter iter;
911 GncOwner owner;
912
913 g_return_if_fail(model); /* Required */
914
915 if (!GNC_IS_OWNER(entity))
916 return;
917
918 ENTER("entity %p of type %d, model %p, event_data %p",
919 entity, event_type, model, ed);
920
921 qofOwnerSetEntity (&owner, entity);
922 if (gncOwnerGetType(&owner) != model->owner_type)
923 {
924 LEAVE("model type and owner type differ");
925 return;
926 }
927
928 if (qof_instance_get_book (entity) != model->book)
929 {
930 LEAVE("not in this book");
931 return;
932 }
933
934 /* What to do, that to do. */
935 switch (event_type)
936 {
937 case QOF_EVENT_ADD:
938 /* Tell the filters/views where the new owner was added. */
939 DEBUG("add owner %p (%s)", &owner, gncOwnerGetName(&owner));
940 /* First update our copy of the owner list. This isn't done automatically */
941 if (model->owner_list)
942 g_list_free_full (model->owner_list, (GDestroyNotify) gncOwnerFree);
943
944 model->owner_list = gncBusinessGetOwnerList (model->book,
945 gncOwnerTypeToQofIdType(model->owner_type), TRUE);
946 increment_stamp(model);
947 if (!gnc_tree_model_owner_get_iter_from_owner (model, &owner, &iter))
948 {
949 LEAVE("can't generate iter");
950 break;
951 }
952 path = gnc_tree_model_owner_get_path(GTK_TREE_MODEL(model), &iter);
953 if (!path)
954 {
955 DEBUG("can't generate path");
956 break;
957 }
958 gtk_tree_model_row_inserted (GTK_TREE_MODEL(model), path, &iter);
959 break;
960
961 case QOF_EVENT_REMOVE:
962 if (!ed) /* Required for a remove. */
963 break;
964 DEBUG("remove owner %d (%s) from owner_list %p", ed->idx,
965 gncOwnerGetName(&owner), model->owner_list);
966 path = gtk_tree_path_new();
967 if (!path)
968 {
969 DEBUG("can't generate path");
970 break;
971 }
972 increment_stamp(model);
973 gtk_tree_path_append_index (path, ed->idx);
974 gtk_tree_model_row_deleted (GTK_TREE_MODEL(model), path);
975 break;
976
977 case QOF_EVENT_MODIFY:
978 DEBUG("modify owner %p (%s)", &owner, gncOwnerGetName(&owner));
979 if (!gnc_tree_model_owner_get_iter_from_owner (model, &owner, &iter))
980 {
981 LEAVE("can't generate iter");
982 return;
983 }
984 path = gnc_tree_model_owner_get_path(GTK_TREE_MODEL(model), &iter);
985 if (!path)
986 {
987 DEBUG("can't generate path");
988 break;
989 }
990 gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter);
991 break;
992
993 default:
994 LEAVE("unknown event type");
995 return;
996 }
997
998 if (path)
999 gtk_tree_path_free(path);
1000 LEAVE(" ");
1001 return;
1002}
Commodity handling public routines.
All type declarations for the whole Gnucash engine.
Additional event handling code.
Gobject helper routines.
Generic api to store and retrieve preferences.
GtkTreeModel implementation for gnucash owner tree.
utility functions for the GnuCash UI
GList OwnerList
For SWIG: A GList containing GncOwner.
Business Interface: Object OWNERs.
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
Retrieve the full name for the specified commodity.
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
Definition qofevent.cpp:103
void(* QofEventHandler)(QofInstance *ent, QofEventId event_type, gpointer handler_data, gpointer event_data)
Handler invoked when an event is generated.
Definition qofevent.h:89
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition qofevent.cpp:73
gint QofEventId
Define the type of events allowed.
Definition qofevent.h:45
const GList * gnc_gobject_tracking_get_list(const gchar *name)
Get a list of all known objects of a specified type.
gboolean gnc_tree_model_owner_get_iter_from_owner(GncTreeModelOwner *model, GncOwner *owner, GtkTreeIter *iter)
Convert a model/owner pair into a gtk_tree_model_iter.
GtkTreeModel * gnc_tree_model_owner_new(GncOwnerType owner_type)
Create a new GtkTreeModel for manipulating gnucash owners.
GtkTreePath * gnc_tree_model_owner_get_path_from_owner(GncTreeModelOwner *model, GncOwner *owner)
Convert a model/owner pair into a gtk_tree_model_path.
GncOwner * gnc_tree_model_owner_get_owner(GncTreeModelOwner *model, GtkTreeIter *iter)
Convert a model/iter pair to a gnucash owner.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
#define gnc_leave_return_val_if_fail(test, val)
Replacement for g_return_val_if_fail, but calls LEAVE if the test fails.
Definition qoflog.h:294
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
GncCustomer * gncOwnerGetCustomer(const GncOwner *owner)
If the given owner is of type GNC_OWNER_CUSTOMER, returns the pointer to the customer object.
Definition gncOwner.c:369
gboolean GNC_IS_OWNER(QofInstance *ent)
Check if entity is an owner kind.
Definition gncOwner.c:352
GncVendor * gncOwnerGetVendor(const GncOwner *owner)
If the given owner is of type GNC_OWNER_VENDOR, returns the pointer to the vendor object.
Definition gncOwner.c:383
int gncOwnerGCompareFunc(const GncOwner *a, const GncOwner *b)
Same as gncOwnerEqual, but returns 0 if equal to be used as a GList custom compare function.
Definition gncOwner.c:411
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Returns the GncOwnerType of this owner.
Definition gncOwner.c:200
QofIdTypeConst gncOwnerTypeToQofIdType(GncOwnerType t)
Returns the QofIdType of the given GncOwnerType, or NULL if no suitable one exists.
Definition gncOwner.c:235
void qofOwnerSetEntity(GncOwner *owner, QofInstance *ent)
set the owner from the entity.
Definition gncOwner.c:319
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Register a callback that gets triggered when the given preference changes.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
QofBook reference.
Definition qofbook-p.hpp:47
The instance data structure for an owner tree model.
GncTreeModel gnc_tree_model
The parent object data.
int stamp
The state of the model.