GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 <[email protected]>
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 [email protected]
23  */
24 
25 #include "config.h"
26 
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 #include <string.h>
30 
31 #include "gnc-tree-model-owner.h"
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 
45 static QofLogModule log_module = GNC_MOD_GUI;
46 
48 static void gnc_tree_model_owner_class_init (GncTreeModelOwnerClass *klass);
49 static void gnc_tree_model_owner_init (GncTreeModelOwner *model);
50 static void gnc_tree_model_owner_finalize (GObject *object);
51 static void gnc_tree_model_owner_dispose (GObject *object);
52 
54 static void gnc_tree_model_owner_tree_model_init (GtkTreeModelIface *iface);
55 static GtkTreeModelFlags gnc_tree_model_owner_get_flags (GtkTreeModel *tree_model);
56 static int gnc_tree_model_owner_get_n_columns (GtkTreeModel *tree_model);
57 static GType gnc_tree_model_owner_get_column_type (GtkTreeModel *tree_model,
58  int index);
59 static gboolean gnc_tree_model_owner_get_iter (GtkTreeModel *tree_model,
60  GtkTreeIter *iter,
61  GtkTreePath *path);
62 static GtkTreePath *gnc_tree_model_owner_get_path (GtkTreeModel *tree_model,
63  GtkTreeIter *iter);
64 static void gnc_tree_model_owner_get_value (GtkTreeModel *tree_model,
65  GtkTreeIter *iter,
66  int column,
67  GValue *value);
68 static gboolean gnc_tree_model_owner_iter_next (GtkTreeModel *tree_model,
69  GtkTreeIter *iter);
70 static gboolean gnc_tree_model_owner_iter_children (GtkTreeModel *tree_model,
71  GtkTreeIter *iter,
72  GtkTreeIter *parent);
73 static gboolean gnc_tree_model_owner_iter_has_child (GtkTreeModel *tree_model,
74  GtkTreeIter *iter);
75 static int gnc_tree_model_owner_iter_n_children (GtkTreeModel *tree_model,
76  GtkTreeIter *iter);
77 static gboolean gnc_tree_model_owner_iter_nth_child (GtkTreeModel *tree_model,
78  GtkTreeIter *iter,
79  GtkTreeIter *parent,
80  int n);
81 static gboolean gnc_tree_model_owner_iter_parent (GtkTreeModel *tree_model,
82  GtkTreeIter *iter,
83  GtkTreeIter *child);
84 
86 static void gnc_tree_model_owner_event_handler (QofInstance *entity,
87  QofEventId event_type,
88  GncTreeModelOwner *model,
89  GncEventData *ed);
90 
93 {
94  QofBook *book;
95  GncOwnerType owner_type;
96  OwnerList *owner_list;
97  gint event_handler_id;
98  const gchar *negative_color;
100 
101 #define GNC_TREE_MODEL_OWNER_GET_PRIVATE(o) \
102  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_TREE_MODEL_OWNER, GncTreeModelOwnerPrivate))
103 
104 
105 /************************************************************/
106 /* Owner Tree Model - Misc Functions */
107 /************************************************************/
108 
115 static void
116 gnc_tree_model_owner_update_color (gpointer gsettings, gchar *key, gpointer user_data)
117 {
119  GncTreeModelOwner *model;
120  gboolean use_red;
121 
122  g_return_if_fail(GNC_IS_TREE_MODEL_OWNER(user_data));
123  model = user_data;
124  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
125  use_red = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
126  priv->negative_color = use_red ? "red" : NULL;
127 }
128 /************************************************************/
129 /* g_object required functions */
130 /************************************************************/
131 
133 static GtkObjectClass *parent_class = NULL;
134 
135 GType
137 {
138  static GType gnc_tree_model_owner_type = 0;
139 
140  if (gnc_tree_model_owner_type == 0)
141  {
142  static const GTypeInfo our_info =
143  {
144  sizeof (GncTreeModelOwnerClass), /* class_size */
145  NULL, /* base_init */
146  NULL, /* base_finalize */
147  (GClassInitFunc) gnc_tree_model_owner_class_init,
148  NULL, /* class_finalize */
149  NULL, /* class_data */
150  sizeof (GncTreeModelOwner), /* */
151  0, /* n_preallocs */
152  (GInstanceInitFunc) gnc_tree_model_owner_init
153  };
154 
155  static const GInterfaceInfo tree_model_info =
156  {
157  (GInterfaceInitFunc) gnc_tree_model_owner_tree_model_init,
158  NULL,
159  NULL
160  };
161 
162  gnc_tree_model_owner_type = g_type_register_static (GNC_TYPE_TREE_MODEL,
163  GNC_TREE_MODEL_OWNER_NAME,
164  &our_info, 0);
165 
166  g_type_add_interface_static (gnc_tree_model_owner_type,
167  GTK_TYPE_TREE_MODEL,
168  &tree_model_info);
169  }
170 
171  return gnc_tree_model_owner_type;
172 }
173 
174 static void
175 gnc_tree_model_owner_class_init (GncTreeModelOwnerClass *klass)
176 {
177  GObjectClass *o_class;
178 
179  parent_class = g_type_class_peek_parent (klass);
180 
181  o_class = G_OBJECT_CLASS (klass);
182 
183  /* GObject signals */
184  o_class->finalize = gnc_tree_model_owner_finalize;
185  o_class->dispose = gnc_tree_model_owner_dispose;
186 
187  g_type_class_add_private(klass, sizeof(GncTreeModelOwnerPrivate));
188 }
189 
190 static void
191 gnc_tree_model_owner_init (GncTreeModelOwner *model)
192 {
194  gboolean red;
195 
196  ENTER("model %p", model);
197  while (model->stamp == 0)
198  {
199  model->stamp = g_random_int ();
200  }
201 
202  red = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
203 
204  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
205  priv->book = NULL;
206  priv->owner_list = NULL;
207  priv->owner_type = GNC_OWNER_NONE;
208  priv->negative_color = red ? "red" : NULL;
209 
210  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED,
211  gnc_tree_model_owner_update_color,
212  model);
213 
214  LEAVE(" ");
215 }
216 
217 static void
218 gnc_tree_model_owner_finalize (GObject *object)
219 {
221  GncTreeModelOwner *model;
222 
223  g_return_if_fail (object != NULL);
224  g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (object));
225 
226  ENTER("model %p", object);
227 
228  model = GNC_TREE_MODEL_OWNER (object);
229  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
230 
231  priv->book = NULL;
232  priv->owner_list = NULL;
233 
234  if (G_OBJECT_CLASS (parent_class)->finalize)
235  G_OBJECT_CLASS(parent_class)->finalize (object);
236  LEAVE(" ");
237 }
238 
239 static void
240 gnc_tree_model_owner_dispose (GObject *object)
241 {
243  GncTreeModelOwner *model;
244 
245  g_return_if_fail (object != NULL);
246  g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (object));
247 
248  ENTER("model %p", object);
249 
250  model = GNC_TREE_MODEL_OWNER (object);
251  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
252 
253  if (priv->event_handler_id)
254  {
255  qof_event_unregister_handler (priv->event_handler_id);
256  priv->event_handler_id = 0;
257  }
258 
259  gnc_prefs_remove_cb_by_func(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED,
260  gnc_tree_model_owner_update_color,
261  model);
262 
263  if (G_OBJECT_CLASS (parent_class)->dispose)
264  G_OBJECT_CLASS (parent_class)->dispose (object);
265  LEAVE(" ");
266 }
267 
268 
269 /************************************************************/
270 /* New Model Creation */
271 /************************************************************/
272 
273 GtkTreeModel *
274 gnc_tree_model_owner_new (GncOwnerType owner_type)
275 {
276  GncTreeModelOwner *model;
278  const GList *item;
279 
280  ENTER("owner_type %d", owner_type);
281  item = gnc_gobject_tracking_get_list(GNC_TREE_MODEL_OWNER_NAME);
282  for ( ; item; item = g_list_next(item))
283  {
284  model = (GncTreeModelOwner *)item->data;
285  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
286  if (priv->owner_type == owner_type)
287  {
288  g_object_ref(G_OBJECT(model));
289  LEAVE("returning existing model %p", model);
290  return GTK_TREE_MODEL(model);
291  }
292  }
293 
294  model = g_object_new (GNC_TYPE_TREE_MODEL_OWNER,
295  NULL);
296 
297  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
298  priv->book = gnc_get_current_book();
299  priv->owner_type = owner_type;
300  priv->owner_list = gncBusinessGetOwnerList (priv->book, gncOwnerTypeToQofIdType(owner_type), TRUE);
301 
302  priv->event_handler_id = qof_event_register_handler
303  ((QofEventHandler)gnc_tree_model_owner_event_handler, model);
304 
305  LEAVE("model %p", model);
306  return GTK_TREE_MODEL (model);
307 }
308 
309 
310 /************************************************************/
311 /* Gnc Tree Model Debugging Utility Function */
312 /************************************************************/
313 
314 #define ITER_STRING_LEN 128
315 
316 static const gchar *
317 iter_to_string (GtkTreeIter *iter)
318 {
319 #ifdef G_THREADS_ENABLED
320 #ifndef HAVE_GLIB_2_32
321  static GStaticPrivate gtmits_buffer_key = G_STATIC_PRIVATE_INIT;
322  gchar *string;
323 
324  string = g_static_private_get (&gtmits_buffer_key);
325  if (string == NULL)
326  {
327  string = g_malloc(ITER_STRING_LEN + 1);
328  g_static_private_set (&gtmits_buffer_key, string, g_free);
329  }
330 #else
331  static GPrivate gtmits_buffer_key = G_PRIVATE_INIT(g_free);
332  gchar *string;
333 
334  string = g_private_get (&gtmits_buffer_key);
335  if (string == NULL)
336  {
337  string = g_malloc(ITER_STRING_LEN + 1);
338  g_private_set (&gtmits_buffer_key, string);
339  }
340 #endif
341 #else
342  static char string[ITER_STRING_LEN + 1];
343 #endif
344 
345  if (iter)
346  snprintf(string, ITER_STRING_LEN,
347  "[stamp:%x data:%p (%s), %p, %d]",
348  iter->stamp, iter->user_data,
349  gncOwnerGetName ((GncOwner *) iter->user_data),
350  iter->user_data2, GPOINTER_TO_INT(iter->user_data3));
351  else
352  strcpy(string, "(null)");
353  return string;
354 }
355 
356 
357 /************************************************************/
358 /* Gtk Tree Model Required Interface Functions */
359 /************************************************************/
360 
361 static void
362 gnc_tree_model_owner_tree_model_init (GtkTreeModelIface *iface)
363 {
364  iface->get_flags = gnc_tree_model_owner_get_flags;
365  iface->get_n_columns = gnc_tree_model_owner_get_n_columns;
366  iface->get_column_type = gnc_tree_model_owner_get_column_type;
367  iface->get_iter = gnc_tree_model_owner_get_iter;
368  iface->get_path = gnc_tree_model_owner_get_path;
369  iface->get_value = gnc_tree_model_owner_get_value;
370  iface->iter_next = gnc_tree_model_owner_iter_next;
371  iface->iter_children = gnc_tree_model_owner_iter_children;
372  iface->iter_has_child = gnc_tree_model_owner_iter_has_child;
373  iface->iter_n_children = gnc_tree_model_owner_iter_n_children;
374  iface->iter_nth_child = gnc_tree_model_owner_iter_nth_child;
375  iface->iter_parent = gnc_tree_model_owner_iter_parent;
376 }
377 
378 static GtkTreeModelFlags
379 gnc_tree_model_owner_get_flags (GtkTreeModel *tree_model)
380 {
381  return 0;
382 }
383 
384 static int
385 gnc_tree_model_owner_get_n_columns (GtkTreeModel *tree_model)
386 {
387  g_return_val_if_fail(GNC_IS_TREE_MODEL_OWNER(tree_model), -1);
388 
389  return GNC_TREE_MODEL_OWNER_NUM_COLUMNS;
390 }
391 
392 static GType
393 gnc_tree_model_owner_get_column_type (GtkTreeModel *tree_model,
394  int index)
395 {
396  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), G_TYPE_INVALID);
397  g_return_val_if_fail ((index < GNC_TREE_MODEL_OWNER_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
398 
399  switch (index)
400  {
401  case GNC_TREE_MODEL_OWNER_COL_NAME:
402  case GNC_TREE_MODEL_OWNER_COL_TYPE:
403  case GNC_TREE_MODEL_OWNER_COL_CURRENCY:
404  case GNC_TREE_MODEL_OWNER_COL_ID:
405  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_NAME:
406  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_1:
407  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_2:
408  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_3:
409  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_4:
410  case GNC_TREE_MODEL_OWNER_COL_PHONE:
411  case GNC_TREE_MODEL_OWNER_COL_FAX:
412  case GNC_TREE_MODEL_OWNER_COL_EMAIL:
413  case GNC_TREE_MODEL_OWNER_COL_BALANCE:
414  case GNC_TREE_MODEL_OWNER_COL_BALANCE_REPORT:
415  case GNC_TREE_MODEL_OWNER_COL_NOTES:
416 
417  case GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE:
418  return G_TYPE_STRING;
419 
420  case GNC_TREE_MODEL_OWNER_COL_ACTIVE:
421  return G_TYPE_BOOLEAN;
422 
423  default:
424  g_assert_not_reached ();
425  return G_TYPE_INVALID;
426  }
427 }
428 
429 static gboolean
430 gnc_tree_model_owner_get_iter (GtkTreeModel *tree_model,
431  GtkTreeIter *iter,
432  GtkTreePath *path)
433 {
435  GncTreeModelOwner *model;
436  GncOwner *owner;
437  gint *indices;
438 
439  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
440 
441  {
442  gchar *path_string = gtk_tree_path_to_string(path);
443  ENTER("model %p, iter %p, path %s", tree_model, iter, path_string);
444  g_free(path_string);
445  }
446 
447  model = GNC_TREE_MODEL_OWNER (tree_model);
448  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
449 
450  /* We keep a simple list of owners, not a tree, so only depth 1 is valid */
451  if (gtk_tree_path_get_depth (path) != 1)
452  {
453  LEAVE("bad depth");
454  return FALSE;
455  }
456 
457  indices = gtk_tree_path_get_indices (path);
458 
459  owner = g_list_nth_data (priv->owner_list, indices[0]);
460  if (owner == NULL)
461  {
462  iter->stamp = 0;
463  LEAVE("bad index");
464  return FALSE;
465  }
466 
467  iter->stamp = model->stamp;
468  iter->user_data = owner;
469  iter->user_data2 = GINT_TO_POINTER (indices[0]);
470  iter->user_data3 = NULL;
471 
472  LEAVE("iter %s", iter_to_string (iter));
473  return TRUE;
474 }
475 
476 static GtkTreePath *
477 gnc_tree_model_owner_get_path (GtkTreeModel *tree_model,
478  GtkTreeIter *iter)
479 {
480  GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
482  GncOwner *owner;
483  GtkTreePath *path;
484  gint i;
485 
486  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
487  g_return_val_if_fail (iter != NULL, NULL);
488  g_return_val_if_fail (iter->user_data != NULL, NULL);
489  g_return_val_if_fail (iter->stamp == model->stamp, NULL);
490 
491  ENTER("model %p, iter %s", model, iter_to_string(iter));
492 
493  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
494  if (priv->owner_list == NULL)
495  {
496  LEAVE("failed (1)");
497  return NULL;
498  }
499 
500  owner = (GncOwner *) iter->user_data;
501 
502  path = gtk_tree_path_new ();
503  i = g_list_index (priv->owner_list, owner);
504  if (i == -1)
505  {
506  gtk_tree_path_free (path);
507  LEAVE("failed (3)");
508  return NULL;
509  }
510  gtk_tree_path_prepend_index (path, i);
511 
512  {
513  gchar *path_string = gtk_tree_path_to_string(path);
514  LEAVE("path (4) %s", path_string);
515  g_free(path_string);
516  }
517  return path;
518 }
519 
520 static void
521 gnc_tree_model_owner_set_color(GncTreeModelOwner *model,
522  gboolean negative,
523  GValue *value)
524 {
526 
527  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
528  if (negative)
529  g_value_set_static_string (value, priv->negative_color);
530  else
531  g_value_set_static_string (value, NULL);
532 }
533 
534 static void
535 gnc_tree_model_owner_get_value (GtkTreeModel *tree_model,
536  GtkTreeIter *iter,
537  int column,
538  GValue *value)
539 {
540  GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
541  GncOwner *owner;
542  gboolean negative; /* used to set "deficit style" also known as red numbers */
543  gchar *string = NULL;
544 
545  g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (model));
546  g_return_if_fail (iter != NULL);
547  g_return_if_fail (iter->user_data != NULL);
548  g_return_if_fail (iter->stamp == model->stamp);
549 
550  ENTER("model %p, iter %s, col %d", tree_model,
551  iter_to_string(iter), column);
552 
553  owner = (GncOwner *) iter->user_data;
554 
555  switch (column)
556  {
557  case GNC_TREE_MODEL_OWNER_COL_NAME:
558  g_value_init (value, G_TYPE_STRING);
559  g_value_set_string (value, gncOwnerGetName (owner));
560  break;
561  case GNC_TREE_MODEL_OWNER_COL_TYPE:
562  g_value_init (value, G_TYPE_STRING);
563  g_value_set_string (value,
565  break;
566  case GNC_TREE_MODEL_OWNER_COL_ID:
567  g_value_init (value, G_TYPE_STRING);
568  g_value_set_string (value, gncOwnerGetID (owner));
569  break;
570  case GNC_TREE_MODEL_OWNER_COL_CURRENCY:
571  g_value_init (value, G_TYPE_STRING);
572  g_value_set_string (value,
573  gnc_commodity_get_fullname(gncOwnerGetCurrency (owner)));
574  break;
575  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_NAME:
576  g_value_init (value, G_TYPE_STRING);
577  string = g_strdup (gncAddressGetName (gncOwnerGetAddr (owner)));
578  if (string)
579  g_value_take_string (value, string);
580  else
581  g_value_set_static_string (value, "");
582  break;
583  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_1:
584  g_value_init (value, G_TYPE_STRING);
585  string = g_strdup (gncAddressGetAddr1 (gncOwnerGetAddr (owner)));
586  if (string)
587  g_value_take_string (value, string);
588  else
589  g_value_set_static_string (value, "");
590  break;
591  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_2:
592  g_value_init (value, G_TYPE_STRING);
593  string = g_strdup (gncAddressGetAddr2 (gncOwnerGetAddr (owner)));
594  if (string)
595  g_value_take_string (value, string);
596  else
597  g_value_set_static_string (value, "");
598  break;
599  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_3:
600  g_value_init (value, G_TYPE_STRING);
601  string = g_strdup (gncAddressGetAddr3 (gncOwnerGetAddr (owner)));
602  if (string)
603  g_value_take_string (value, string);
604  else
605  g_value_set_static_string (value, "");
606  break;
607  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_4:
608  g_value_init (value, G_TYPE_STRING);
609  string = g_strdup (gncAddressGetAddr4 (gncOwnerGetAddr (owner)));
610  if (string)
611  g_value_take_string (value, string);
612  else
613  g_value_set_static_string (value, "");
614  break;
615  case GNC_TREE_MODEL_OWNER_COL_PHONE:
616  g_value_init (value, G_TYPE_STRING);
617  string = g_strdup (gncAddressGetPhone (gncOwnerGetAddr (owner)));
618  if (string)
619  g_value_take_string (value, string);
620  else
621  g_value_set_static_string (value, "");
622  break;
623  case GNC_TREE_MODEL_OWNER_COL_FAX:
624  g_value_init (value, G_TYPE_STRING);
625  string = g_strdup (gncAddressGetFax (gncOwnerGetAddr (owner)));
626  if (string)
627  g_value_take_string (value, string);
628  else
629  g_value_set_static_string (value, "");
630  break;
631  case GNC_TREE_MODEL_OWNER_COL_EMAIL:
632  g_value_init (value, G_TYPE_STRING);
633  string = g_strdup (gncAddressGetEmail (gncOwnerGetAddr (owner)));
634  if (string)
635  g_value_take_string (value, string);
636  else
637  g_value_set_static_string (value, "");
638  break;
639 
640  case GNC_TREE_MODEL_OWNER_COL_BALANCE:
641  g_value_init (value, G_TYPE_STRING);
642  string = gnc_ui_owner_get_print_balance(owner, &negative);
643  g_value_take_string (value, string);
644  break;
645 
646  case GNC_TREE_MODEL_OWNER_COL_BALANCE_REPORT:
647  g_value_init (value, G_TYPE_STRING);
648  string = gnc_ui_owner_get_print_report_balance(owner, &negative);
649  g_value_take_string (value, string);
650  break;
651  case GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE:
652  g_value_init (value, G_TYPE_STRING);
653  string = gnc_ui_owner_get_print_balance(owner, &negative);
654  gnc_tree_model_owner_set_color(model, negative, value);
655  g_free(string);
656  break;
657 
658  case GNC_TREE_MODEL_OWNER_COL_NOTES:
659  g_value_init (value, G_TYPE_STRING);
660  switch (gncOwnerGetType (owner))
661  {
662  case GNC_OWNER_NONE:
663  case GNC_OWNER_UNDEFINED:
664  case GNC_OWNER_EMPLOYEE:
665  case GNC_OWNER_JOB:
666  default:
667  g_value_set_static_string (value, "");
668  break;
669  case GNC_OWNER_VENDOR:
670  g_value_set_string (value, gncVendorGetNotes (gncOwnerGetVendor (owner)));
671  break;
672  case GNC_OWNER_CUSTOMER:
673  g_value_set_string (value, gncCustomerGetNotes (gncOwnerGetCustomer (owner)));
674  break;
675  }
676  break;
677 
678  case GNC_TREE_MODEL_OWNER_COL_ACTIVE:
679  g_value_init (value, G_TYPE_BOOLEAN);
680  g_value_set_boolean (value, gncOwnerGetActive (owner));
681  break;
682 
683  default:
684  g_assert_not_reached ();
685  }
686  LEAVE(" ");
687 }
688 
689 static gboolean
690 gnc_tree_model_owner_iter_next (GtkTreeModel *tree_model,
691  GtkTreeIter *iter)
692 {
693  GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
695  GncOwner *owner;
696  gint i;
697 
698  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), FALSE);
699  g_return_val_if_fail (iter != NULL, FALSE);
700  g_return_val_if_fail (iter->user_data != NULL, FALSE);
701  g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
702 
703  ENTER("model %p, iter %s", tree_model, iter_to_string (iter));
704 
705  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
706 
707  /* Get the *next* sibling owner. */
708  i = GPOINTER_TO_INT (iter->user_data2);
709  owner = g_list_nth_data (priv->owner_list, i + 1);
710  if (owner == NULL)
711  {
712  iter->stamp = 0;
713  LEAVE("failed (3)");
714  return FALSE;
715  }
716 
717  iter->user_data = owner;
718  iter->user_data2 = GINT_TO_POINTER (i + 1);
719  iter->user_data3 = NULL;
720 
721  LEAVE("iter %s", iter_to_string(iter));
722  return TRUE;
723 }
724 
725 static gboolean
726 gnc_tree_model_owner_iter_children (GtkTreeModel *tree_model,
727  GtkTreeIter *iter,
728  GtkTreeIter *parent_iter)
729 {
731  GncTreeModelOwner *model;
732 
733  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
734  ENTER("model %p, iter %p (to be filed in), parent %s",
735  tree_model, iter, (parent_iter ? iter_to_string(parent_iter) : "(null)"));
736 
737  model = GNC_TREE_MODEL_OWNER (tree_model);
738  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(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 (priv->owner_list, 0);
746  iter->user_data2 = GINT_TO_POINTER (0);
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 
760 static gboolean
761 gnc_tree_model_owner_iter_has_child (GtkTreeModel *tree_model,
762  GtkTreeIter *iter)
763 {
764  /* Owner lists don't have children, so always return false */
765  return FALSE;
766 }
767 
768 static int
769 gnc_tree_model_owner_iter_n_children (GtkTreeModel *tree_model,
770  GtkTreeIter *iter)
771 {
772  GncTreeModelOwner *model;
774 
775  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), -1);
776 
777  model = GNC_TREE_MODEL_OWNER (tree_model);
778  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE (model);
779 
780  /* Owner lists don't have children, so always return 0, except for
781  * the special case this request comes for the special "root" iter
782  * (NULL). For that exception we return the size of the ower list.
783  */
784  if (iter == NULL)
785  return (gint) g_list_length (priv->owner_list);
786 
787  g_return_val_if_fail (
788  GNC_TREE_MODEL_OWNER (tree_model)->stamp == iter->stamp, -1);
789 
790  return 0;
791 }
792 
793 static gboolean
794 gnc_tree_model_owner_iter_nth_child (GtkTreeModel *tree_model,
795  GtkTreeIter *iter,
796  GtkTreeIter *parent_iter,
797  int n)
798 {
799  GncTreeModelOwner *model;
801 
802  if (parent_iter)
803  {
804  gchar *parent_string;
805  parent_string = g_strdup(iter_to_string(parent_iter));
806  ENTER("model %p, iter %s, parent_iter %s, n %d",
807  tree_model, iter_to_string(iter),
808  parent_string, n);
809  g_free(parent_string);
810  }
811  else
812  {
813  ENTER("model %p, iter %s, parent_iter (null), n %d",
814  tree_model, iter_to_string(iter), n);
815  }
816  gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
817 
818  model = GNC_TREE_MODEL_OWNER (tree_model);
819  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
820 
821  /* Owner lists don't have children, so this function call only
822  * makes sense if no parent_iter was supplied. In that case,
823  * return the first owner in the list */
824  if (!parent_iter)
825  {
826  iter->user_data = g_list_nth_data (priv->owner_list, n);
827  iter->user_data2 = GINT_TO_POINTER (n);
828  iter->user_data3 = NULL;
829  iter->stamp = model->stamp;
830  LEAVE("iter (2) %s", iter_to_string(iter));
831  return TRUE;
832  }
833  else
834  {
835  iter->stamp = 0;
836  LEAVE("failed (owners don't have children)");
837  return FALSE;
838  }
839 }
840 
841 static gboolean
842 gnc_tree_model_owner_iter_parent (GtkTreeModel *tree_model,
843  GtkTreeIter *iter,
844  GtkTreeIter *child)
845 {
846  /* Owner lists don't have children, so always return false */
847  iter->stamp = 0;
848  return FALSE;
849 }
850 
851 
852 /************************************************************/
853 /* Owner Tree View Filter Functions */
854 /************************************************************/
855 
856 /*
857  * Convert a model/iter pair to a gnucash owner. This routine should
858  * only be called from an owner tree view filter function.
859  */
860 GncOwner *
862  GtkTreeIter *iter)
863 {
864  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
865  g_return_val_if_fail (iter != NULL, NULL);
866  g_return_val_if_fail (iter->user_data != NULL, NULL);
867  g_return_val_if_fail (iter->stamp == model->stamp, NULL);
868 
869  return (GncOwner *) iter->user_data;
870 }
871 
872 /*
873  * Convert a model/owner pair into a gtk_tree_model_iter. This
874  * routine should only be called from the file
875  * gnc-tree-view-owner.c.
876  */
877 gboolean
879  GncOwner *owner,
880  GtkTreeIter *iter)
881 {
883  GList *owner_in_list;
884 
885  ENTER("model %p, owner %p, iter %p", model, owner, iter);
886  gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), FALSE);
887  gnc_leave_return_val_if_fail ((owner != NULL), FALSE);
888  gnc_leave_return_val_if_fail ((iter != NULL), FALSE);
889 
890 
891  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
892  owner_in_list = g_list_find_custom (priv->owner_list, (gconstpointer)owner, (GCompareFunc)gncOwnerGCompareFunc);
893  if (owner_in_list)
894  {
895  iter->stamp = model->stamp;
896  iter->user_data = owner_in_list->data;
897  iter->user_data2 = GINT_TO_POINTER (g_list_position (priv->owner_list, owner_in_list));
898  iter->user_data3 = NULL;
899  LEAVE("iter %s", iter_to_string (iter));
900  return TRUE;
901  }
902  else
903  {
904  iter->stamp = 0;
905  iter->user_data = NULL;
906  LEAVE("Owner not found in list");
907  return FALSE;
908  }
909 }
910 
911 /*
912  * Convert a model/owner pair into a gtk_tree_model_path. This
913  * routine should only be called from the file
914  * gnc-tree-view-owner.c.
915  */
916 GtkTreePath *
918  GncOwner *owner)
919 {
920  GtkTreeIter tree_iter;
921  GtkTreePath *tree_path;
922 
923  ENTER("model %p, owner %p", model, owner);
924  gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
925  gnc_leave_return_val_if_fail (owner != NULL, NULL);
926 
927  if (!gnc_tree_model_owner_get_iter_from_owner (model, owner,
928  &tree_iter))
929  {
930  LEAVE("no iter");
931  return NULL;
932  }
933 
934  tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &tree_iter);
935  if (tree_path)
936  {
937  gchar *path_string = gtk_tree_path_to_string(tree_path);
938  LEAVE("path (2) %s", path_string);
939  g_free(path_string);
940  }
941  else
942  {
943  LEAVE("no path");
944  }
945  return tree_path;
946 }
947 
948 /************************************************************/
949 /* Owner Tree Model - Engine Event Handling Functions */
950 /************************************************************/
951 
952 static void
953 increment_stamp(GncTreeModelOwner *model)
954 {
955  do model->stamp++;
956  while (!model->stamp);
957 }
958 
987 static void
988 gnc_tree_model_owner_event_handler (QofInstance *entity,
989  QofEventId event_type,
990  GncTreeModelOwner *model,
991  GncEventData *ed)
992 {
994  GtkTreePath *path = NULL;
995  GtkTreeIter iter;
996  GncOwner owner;
997 
998  g_return_if_fail(model); /* Required */
999 
1000  if (!GNC_IS_OWNER(entity))
1001  return;
1002 
1003  ENTER("entity %p of type %d, model %p, event_data %p",
1004  entity, event_type, model, ed);
1005  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
1006 
1007  qofOwnerSetEntity (&owner, entity);
1008  if (gncOwnerGetType(&owner) != priv->owner_type)
1009  {
1010  LEAVE("model type and owner type differ");
1011  return;
1012  }
1013 
1014  if (qof_instance_get_book (entity) != priv->book)
1015  {
1016  LEAVE("not in this book");
1017  return;
1018  }
1019 
1020  /* What to do, that to do. */
1021  switch (event_type)
1022  {
1023  case QOF_EVENT_ADD:
1024  /* Tell the filters/views where the new owner was added. */
1025  DEBUG("add owner %p (%s)", &owner, gncOwnerGetName(&owner));
1026  /* First update our copy of the owner list. This isn't done automatically */
1027  priv->owner_list = gncBusinessGetOwnerList (priv->book,
1028  gncOwnerTypeToQofIdType(priv->owner_type), TRUE);
1029  increment_stamp(model);
1030  if (!gnc_tree_model_owner_get_iter_from_owner (model, &owner, &iter))
1031  {
1032  LEAVE("can't generate iter");
1033  break;
1034  }
1035  path = gnc_tree_model_owner_get_path(GTK_TREE_MODEL(model), &iter);
1036  if (!path)
1037  {
1038  DEBUG("can't generate path");
1039  break;
1040  }
1041  gtk_tree_model_row_inserted (GTK_TREE_MODEL(model), path, &iter);
1042  break;
1043 
1044  case QOF_EVENT_REMOVE:
1045  if (!ed) /* Required for a remove. */
1046  break;
1047  DEBUG("remove owner %d (%s) from owner_list %p", ed->idx,
1048  gncOwnerGetName(&owner), priv->owner_list);
1049  path = gtk_tree_path_new();
1050  if (!path)
1051  {
1052  DEBUG("can't generate path");
1053  break;
1054  }
1055  increment_stamp(model);
1056  gtk_tree_path_append_index (path, ed->idx);
1057  gtk_tree_model_row_deleted (GTK_TREE_MODEL(model), path);
1058  break;
1059 
1060  case QOF_EVENT_MODIFY:
1061  DEBUG("modify owner %p (%s)", &owner, gncOwnerGetName(&owner));
1062  if (!gnc_tree_model_owner_get_iter_from_owner (model, &owner, &iter))
1063  {
1064  LEAVE("can't generate iter");
1065  return;
1066  }
1067  path = gnc_tree_model_owner_get_path(GTK_TREE_MODEL(model), &iter);
1068  if (!path)
1069  {
1070  DEBUG("can't generate path");
1071  break;
1072  }
1073  gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter);
1074  break;
1075 
1076  default:
1077  LEAVE("unknown event type");
1078  return;
1079  }
1080 
1081  if (path)
1082  gtk_tree_path_free(path);
1083  LEAVE(" ");
1084  return;
1085 }
OwnerList * gncBusinessGetOwnerList(QofBook *book, QofIdTypeConst type_name, gboolean all_including_inactive)
Business Interface: Object OWNERs.
const GList * gnc_gobject_tracking_get_list(const gchar *name)
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Definition: gnc-prefs.c:128
GtkTreeModel implementation for gnucash owner tree.
QofBook * qof_instance_get_book(gconstpointer)
utility functions for the GnuCash UI
#define DEBUG(format, args...)
Definition: qoflog.h:255
void(* QofEventHandler)(QofInstance *ent, QofEventId event_type, gpointer handler_data, gpointer event_data)
Handler invoked when an event is generated.
Definition: qofevent.h:89
#define ENTER(format, args...)
Definition: qoflog.h:261
#define gnc_leave_return_val_if_fail(test, val)
Definition: qoflog.h:283
gint qof_event_register_handler(QofEventHandler handler, gpointer handler_data)
Register a handler for events.
int gncOwnerGCompareFunc(const GncOwner *a, const GncOwner *b)
Definition: gncOwner.c:389
GType gnc_tree_model_owner_get_type(void)
GtkTreeModel * gnc_tree_model_owner_new(GncOwnerType owner_type)
gint QofEventId
Definition: qofevent.h:45
Gobject helper routines.
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
void qofOwnerSetEntity(GncOwner *owner, QofInstance *ent)
Definition: gncOwner.c:297
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
QofIdTypeConst gncOwnerTypeToQofIdType(GncOwnerType t)
Definition: gncOwner.c:213
GtkTreePath * gnc_tree_model_owner_get_path_from_owner(GncTreeModelOwner *model, GncOwner *owner)
GncOwner * gnc_tree_model_owner_get_owner(GncTreeModelOwner *model, GtkTreeIter *iter)
Additional event handling code.
All type declarations for the whole Gnucash engine.
Generic api to store and retrieve preferences.
gboolean GNC_IS_OWNER(QofInstance *ent)
Definition: gncOwner.c:330
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Definition: gncOwner.c:201
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
gboolean gnc_tree_model_owner_get_iter_from_owner(GncTreeModelOwner *model, GncOwner *owner, GtkTreeIter *iter)
#define LEAVE(format, args...)
Definition: qoflog.h:271
GncVendor * gncOwnerGetVendor(const GncOwner *owner)
Definition: gncOwner.c:361
GncCustomer * gncOwnerGetCustomer(const GncOwner *owner)
Definition: gncOwner.c:347
Commodity handling public routines.
const gchar * QofLogModule
Definition: qofid.h:89
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Definition: gnc-prefs.c:148
GList OwnerList
Definition: gncBusiness.h:77