GnuCash  4.11-148-gc20d717b33+
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 
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 G_DEFINE_TYPE_WITH_CODE(GncTreeModelOwner, gnc_tree_model_owner,
102  GNC_TYPE_TREE_MODEL,
103  G_ADD_PRIVATE(GncTreeModelOwner)
104  G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL,
105  gnc_tree_model_owner_tree_model_init))
106 
107 #define GNC_TREE_MODEL_OWNER_GET_PRIVATE(o) \
108  ((GncTreeModelOwnerPrivate*)gnc_tree_model_owner_get_instance_private((GncTreeModelOwner*)o))
109 
110 
111 /************************************************************/
112 /* Owner Tree Model - Misc Functions */
113 /************************************************************/
114 
121 static void
122 gnc_tree_model_owner_update_color (gpointer gsettings, gchar *key, gpointer user_data)
123 {
125  GncTreeModelOwner *model;
126  gboolean use_red;
127 
128  g_return_if_fail(GNC_IS_TREE_MODEL_OWNER(user_data));
129  model = user_data;
130  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
131  use_red = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
132  priv->negative_color = use_red ? "red" : NULL;
133 }
134 /************************************************************/
135 /* g_object required functions */
136 /************************************************************/
137 
139 static GObjectClass *parent_class = NULL;
140 
141 static void
142 gnc_tree_model_owner_class_init (GncTreeModelOwnerClass *klass)
143 {
144  GObjectClass *o_class;
145 
146  parent_class = g_type_class_peek_parent (klass);
147 
148  o_class = G_OBJECT_CLASS (klass);
149 
150  /* GObject signals */
151  o_class->finalize = gnc_tree_model_owner_finalize;
152  o_class->dispose = gnc_tree_model_owner_dispose;
153 }
154 
155 static void
156 gnc_tree_model_owner_init (GncTreeModelOwner *model)
157 {
159  gboolean red;
160 
161  ENTER("model %p", model);
162  while (model->stamp == 0)
163  {
164  model->stamp = g_random_int ();
165  }
166 
167  red = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
168 
169  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
170  priv->book = NULL;
171  priv->owner_list = NULL;
172  priv->owner_type = GNC_OWNER_NONE;
173  priv->negative_color = red ? "red" : NULL;
174 
175  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED,
176  gnc_tree_model_owner_update_color,
177  model);
178 
179  LEAVE(" ");
180 }
181 
182 static void
183 gnc_tree_model_owner_finalize (GObject *object)
184 {
186  GncTreeModelOwner *model;
187 
188  g_return_if_fail (object != NULL);
189  g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (object));
190 
191  ENTER("model %p", object);
192 
193  model = GNC_TREE_MODEL_OWNER (object);
194  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
195 
196  if (priv->owner_list)
197  g_list_free_full (priv->owner_list, (GDestroyNotify) gncOwnerFree);
198 
199  priv->book = NULL;
200  priv->owner_list = NULL;
201 
202  if (G_OBJECT_CLASS (parent_class)->finalize)
203  G_OBJECT_CLASS(parent_class)->finalize (object);
204  LEAVE(" ");
205 }
206 
207 static void
208 gnc_tree_model_owner_dispose (GObject *object)
209 {
211  GncTreeModelOwner *model;
212 
213  g_return_if_fail (object != NULL);
214  g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (object));
215 
216  ENTER("model %p", object);
217 
218  model = GNC_TREE_MODEL_OWNER (object);
219  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
220 
221  if (priv->event_handler_id)
222  {
223  qof_event_unregister_handler (priv->event_handler_id);
224  priv->event_handler_id = 0;
225  }
226 
227  gnc_prefs_remove_cb_by_func(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED,
228  gnc_tree_model_owner_update_color,
229  model);
230 
231  if (G_OBJECT_CLASS (parent_class)->dispose)
232  G_OBJECT_CLASS (parent_class)->dispose (object);
233  LEAVE(" ");
234 }
235 
236 
237 /************************************************************/
238 /* New Model Creation */
239 /************************************************************/
240 
241 GtkTreeModel *
242 gnc_tree_model_owner_new (GncOwnerType owner_type)
243 {
244  GncTreeModelOwner *model;
246  const GList *item;
247 
248  ENTER("owner_type %d", owner_type);
249  item = gnc_gobject_tracking_get_list(GNC_TREE_MODEL_OWNER_NAME);
250  for ( ; item; item = g_list_next(item))
251  {
252  model = (GncTreeModelOwner *)item->data;
253  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
254  if (priv->owner_type == owner_type)
255  {
256  g_object_ref(G_OBJECT(model));
257  LEAVE("returning existing model %p", model);
258  return GTK_TREE_MODEL(model);
259  }
260  }
261 
262  model = g_object_new (GNC_TYPE_TREE_MODEL_OWNER,
263  NULL);
264 
265  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
266  priv->book = gnc_get_current_book();
267  priv->owner_type = owner_type;
268  priv->owner_list = gncBusinessGetOwnerList (priv->book, gncOwnerTypeToQofIdType(owner_type), TRUE);
269 
270  priv->event_handler_id = qof_event_register_handler
271  ((QofEventHandler)gnc_tree_model_owner_event_handler, model);
272 
273  LEAVE("model %p", model);
274  return GTK_TREE_MODEL (model);
275 }
276 
277 
278 /************************************************************/
279 /* Gnc Tree Model Debugging Utility Function */
280 /************************************************************/
281 
282 #define ITER_STRING_LEN 128
283 
284 static const gchar *
285 iter_to_string (GtkTreeIter *iter)
286 {
287 #ifdef G_THREADS_ENABLED
288  static GPrivate gtmits_buffer_key = G_PRIVATE_INIT(g_free);
289  gchar *string;
290 
291  string = g_private_get (&gtmits_buffer_key);
292  if (string == NULL)
293  {
294  string = g_malloc(ITER_STRING_LEN + 1);
295  g_private_set (&gtmits_buffer_key, string);
296  }
297 #else
298  static char string[ITER_STRING_LEN + 1];
299 #endif
300 
301  if (iter)
302  snprintf(string, ITER_STRING_LEN,
303  "[stamp:%x data:%p (%s), %p, %d]",
304  iter->stamp, iter->user_data,
305  gncOwnerGetName ((GncOwner *) iter->user_data),
306  iter->user_data2, GPOINTER_TO_INT(iter->user_data3));
307  else
308  strcpy(string, "(null)");
309  return string;
310 }
311 
312 
313 /************************************************************/
314 /* Gtk Tree Model Required Interface Functions */
315 /************************************************************/
316 
317 static void
318 gnc_tree_model_owner_tree_model_init (GtkTreeModelIface *iface)
319 {
320  iface->get_flags = gnc_tree_model_owner_get_flags;
321  iface->get_n_columns = gnc_tree_model_owner_get_n_columns;
322  iface->get_column_type = gnc_tree_model_owner_get_column_type;
323  iface->get_iter = gnc_tree_model_owner_get_iter;
324  iface->get_path = gnc_tree_model_owner_get_path;
325  iface->get_value = gnc_tree_model_owner_get_value;
326  iface->iter_next = gnc_tree_model_owner_iter_next;
327  iface->iter_children = gnc_tree_model_owner_iter_children;
328  iface->iter_has_child = gnc_tree_model_owner_iter_has_child;
329  iface->iter_n_children = gnc_tree_model_owner_iter_n_children;
330  iface->iter_nth_child = gnc_tree_model_owner_iter_nth_child;
331  iface->iter_parent = gnc_tree_model_owner_iter_parent;
332 }
333 
334 static GtkTreeModelFlags
335 gnc_tree_model_owner_get_flags (GtkTreeModel *tree_model)
336 {
337  return 0;
338 }
339 
340 static int
341 gnc_tree_model_owner_get_n_columns (GtkTreeModel *tree_model)
342 {
343  g_return_val_if_fail(GNC_IS_TREE_MODEL_OWNER(tree_model), -1);
344 
345  return GNC_TREE_MODEL_OWNER_NUM_COLUMNS;
346 }
347 
348 static GType
349 gnc_tree_model_owner_get_column_type (GtkTreeModel *tree_model,
350  int index)
351 {
352  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), G_TYPE_INVALID);
353  g_return_val_if_fail ((index < GNC_TREE_MODEL_OWNER_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
354 
355  switch (index)
356  {
357  case GNC_TREE_MODEL_OWNER_COL_NAME:
358  case GNC_TREE_MODEL_OWNER_COL_TYPE:
359  case GNC_TREE_MODEL_OWNER_COL_CURRENCY:
360  case GNC_TREE_MODEL_OWNER_COL_ID:
361  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_NAME:
362  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_1:
363  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_2:
364  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_3:
365  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_4:
366  case GNC_TREE_MODEL_OWNER_COL_PHONE:
367  case GNC_TREE_MODEL_OWNER_COL_FAX:
368  case GNC_TREE_MODEL_OWNER_COL_EMAIL:
369  case GNC_TREE_MODEL_OWNER_COL_BALANCE:
370  case GNC_TREE_MODEL_OWNER_COL_BALANCE_REPORT:
371  case GNC_TREE_MODEL_OWNER_COL_NOTES:
372 
373  case GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE:
374  return G_TYPE_STRING;
375 
376  case GNC_TREE_MODEL_OWNER_COL_ACTIVE:
377  return G_TYPE_BOOLEAN;
378 
379  default:
380  g_assert_not_reached ();
381  return G_TYPE_INVALID;
382  }
383 }
384 
385 static gboolean
386 gnc_tree_model_owner_get_iter (GtkTreeModel *tree_model,
387  GtkTreeIter *iter,
388  GtkTreePath *path)
389 {
391  GncTreeModelOwner *model;
392  GncOwner *owner;
393  gint *indices;
394 
395  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
396 
397  {
398  gchar *path_string = gtk_tree_path_to_string(path);
399  ENTER("model %p, iter %p, path %s", tree_model, iter, path_string);
400  g_free(path_string);
401  }
402 
403  model = GNC_TREE_MODEL_OWNER (tree_model);
404  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
405 
406  /* We keep a simple list of owners, not a tree, so only depth 1 is valid */
407  if (gtk_tree_path_get_depth (path) != 1)
408  {
409  LEAVE("bad depth");
410  return FALSE;
411  }
412 
413  indices = gtk_tree_path_get_indices (path);
414 
415  owner = g_list_nth_data (priv->owner_list, indices[0]);
416  if (owner == NULL)
417  {
418  iter->stamp = 0;
419  LEAVE("bad index");
420  return FALSE;
421  }
422 
423  iter->stamp = model->stamp;
424  iter->user_data = owner;
425  iter->user_data2 = GINT_TO_POINTER (indices[0]);
426  iter->user_data3 = NULL;
427 
428  LEAVE("iter %s", iter_to_string (iter));
429  return TRUE;
430 }
431 
432 static GtkTreePath *
433 gnc_tree_model_owner_get_path (GtkTreeModel *tree_model,
434  GtkTreeIter *iter)
435 {
436  GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
438  GncOwner *owner;
439  GtkTreePath *path;
440  gint i;
441 
442  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
443  g_return_val_if_fail (iter != NULL, NULL);
444  g_return_val_if_fail (iter->user_data != NULL, NULL);
445  g_return_val_if_fail (iter->stamp == model->stamp, NULL);
446 
447  ENTER("model %p, iter %s", model, iter_to_string(iter));
448 
449  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
450  if (priv->owner_list == NULL)
451  {
452  LEAVE("failed (1)");
453  return NULL;
454  }
455 
456  owner = (GncOwner *) iter->user_data;
457 
458  path = gtk_tree_path_new ();
459  i = g_list_index (priv->owner_list, owner);
460  if (i == -1)
461  {
462  gtk_tree_path_free (path);
463  LEAVE("failed (3)");
464  return NULL;
465  }
466  gtk_tree_path_prepend_index (path, i);
467 
468  {
469  gchar *path_string = gtk_tree_path_to_string(path);
470  LEAVE("path (4) %s", path_string);
471  g_free(path_string);
472  }
473  return path;
474 }
475 
476 static void
477 gnc_tree_model_owner_set_color(GncTreeModelOwner *model,
478  gboolean negative,
479  GValue *value)
480 {
482 
483  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
484  if (negative)
485  g_value_set_static_string (value, priv->negative_color);
486  else
487  g_value_set_static_string (value, NULL);
488 }
489 
490 static void
491 gnc_tree_model_owner_get_value (GtkTreeModel *tree_model,
492  GtkTreeIter *iter,
493  int column,
494  GValue *value)
495 {
496  GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
497  GncOwner *owner;
498  gboolean negative; /* used to set "deficit style" also known as red numbers */
499  gchar *string = NULL;
500 
501  g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (model));
502  g_return_if_fail (iter != NULL);
503  g_return_if_fail (iter->user_data != NULL);
504  g_return_if_fail (iter->stamp == model->stamp);
505 
506  ENTER("model %p, iter %s, col %d", tree_model,
507  iter_to_string(iter), column);
508 
509  owner = (GncOwner *) iter->user_data;
510 
511  switch (column)
512  {
513  case GNC_TREE_MODEL_OWNER_COL_NAME:
514  g_value_init (value, G_TYPE_STRING);
515  g_value_set_string (value, gncOwnerGetName (owner));
516  break;
517  case GNC_TREE_MODEL_OWNER_COL_TYPE:
518  g_value_init (value, G_TYPE_STRING);
519  g_value_set_string (value,
521  break;
522  case GNC_TREE_MODEL_OWNER_COL_ID:
523  g_value_init (value, G_TYPE_STRING);
524  g_value_set_string (value, gncOwnerGetID (owner));
525  break;
526  case GNC_TREE_MODEL_OWNER_COL_CURRENCY:
527  g_value_init (value, G_TYPE_STRING);
528  g_value_set_string (value,
529  gnc_commodity_get_fullname(gncOwnerGetCurrency (owner)));
530  break;
531  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_NAME:
532  g_value_init (value, G_TYPE_STRING);
533  string = g_strdup (gncAddressGetName (gncOwnerGetAddr (owner)));
534  if (string)
535  g_value_take_string (value, string);
536  else
537  g_value_set_static_string (value, "");
538  break;
539  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_1:
540  g_value_init (value, G_TYPE_STRING);
541  string = g_strdup (gncAddressGetAddr1 (gncOwnerGetAddr (owner)));
542  if (string)
543  g_value_take_string (value, string);
544  else
545  g_value_set_static_string (value, "");
546  break;
547  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_2:
548  g_value_init (value, G_TYPE_STRING);
549  string = g_strdup (gncAddressGetAddr2 (gncOwnerGetAddr (owner)));
550  if (string)
551  g_value_take_string (value, string);
552  else
553  g_value_set_static_string (value, "");
554  break;
555  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_3:
556  g_value_init (value, G_TYPE_STRING);
557  string = g_strdup (gncAddressGetAddr3 (gncOwnerGetAddr (owner)));
558  if (string)
559  g_value_take_string (value, string);
560  else
561  g_value_set_static_string (value, "");
562  break;
563  case GNC_TREE_MODEL_OWNER_COL_ADDRESS_4:
564  g_value_init (value, G_TYPE_STRING);
565  string = g_strdup (gncAddressGetAddr4 (gncOwnerGetAddr (owner)));
566  if (string)
567  g_value_take_string (value, string);
568  else
569  g_value_set_static_string (value, "");
570  break;
571  case GNC_TREE_MODEL_OWNER_COL_PHONE:
572  g_value_init (value, G_TYPE_STRING);
573  string = g_strdup (gncAddressGetPhone (gncOwnerGetAddr (owner)));
574  if (string)
575  g_value_take_string (value, string);
576  else
577  g_value_set_static_string (value, "");
578  break;
579  case GNC_TREE_MODEL_OWNER_COL_FAX:
580  g_value_init (value, G_TYPE_STRING);
581  string = g_strdup (gncAddressGetFax (gncOwnerGetAddr (owner)));
582  if (string)
583  g_value_take_string (value, string);
584  else
585  g_value_set_static_string (value, "");
586  break;
587  case GNC_TREE_MODEL_OWNER_COL_EMAIL:
588  g_value_init (value, G_TYPE_STRING);
589  string = g_strdup (gncAddressGetEmail (gncOwnerGetAddr (owner)));
590  if (string)
591  g_value_take_string (value, string);
592  else
593  g_value_set_static_string (value, "");
594  break;
595 
596  case GNC_TREE_MODEL_OWNER_COL_BALANCE:
597  g_value_init (value, G_TYPE_STRING);
598  string = gnc_ui_owner_get_print_balance(owner, &negative);
599  g_value_take_string (value, string);
600  break;
601 
602  case GNC_TREE_MODEL_OWNER_COL_BALANCE_REPORT:
603  g_value_init (value, G_TYPE_STRING);
604  string = gnc_ui_owner_get_print_report_balance(owner, &negative);
605  g_value_take_string (value, string);
606  break;
607  case GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE:
608  g_value_init (value, G_TYPE_STRING);
609  string = gnc_ui_owner_get_print_balance(owner, &negative);
610  gnc_tree_model_owner_set_color(model, negative, value);
611  g_free(string);
612  break;
613 
614  case GNC_TREE_MODEL_OWNER_COL_NOTES:
615  g_value_init (value, G_TYPE_STRING);
616  switch (gncOwnerGetType (owner))
617  {
618  case GNC_OWNER_NONE:
619  case GNC_OWNER_UNDEFINED:
620  case GNC_OWNER_EMPLOYEE:
621  case GNC_OWNER_JOB:
622  default:
623  g_value_set_static_string (value, "");
624  break;
625  case GNC_OWNER_VENDOR:
626  g_value_set_string (value, gncVendorGetNotes (gncOwnerGetVendor (owner)));
627  break;
628  case GNC_OWNER_CUSTOMER:
629  g_value_set_string (value, gncCustomerGetNotes (gncOwnerGetCustomer (owner)));
630  break;
631  }
632  break;
633 
634  case GNC_TREE_MODEL_OWNER_COL_ACTIVE:
635  g_value_init (value, G_TYPE_BOOLEAN);
636  g_value_set_boolean (value, gncOwnerGetActive (owner));
637  break;
638 
639  default:
640  g_assert_not_reached ();
641  }
642  LEAVE(" ");
643 }
644 
645 static gboolean
646 gnc_tree_model_owner_iter_next (GtkTreeModel *tree_model,
647  GtkTreeIter *iter)
648 {
649  GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
651  GncOwner *owner;
652  gint i;
653 
654  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), FALSE);
655  g_return_val_if_fail (iter != NULL, FALSE);
656  g_return_val_if_fail (iter->user_data != NULL, FALSE);
657  g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
658 
659  ENTER("model %p, iter %s", tree_model, iter_to_string (iter));
660 
661  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
662 
663  /* Get the *next* sibling owner. */
664  i = GPOINTER_TO_INT (iter->user_data2);
665  owner = g_list_nth_data (priv->owner_list, i + 1);
666  if (owner == NULL)
667  {
668  iter->stamp = 0;
669  LEAVE("failed (3)");
670  return FALSE;
671  }
672 
673  iter->user_data = owner;
674  iter->user_data2 = GINT_TO_POINTER (i + 1);
675  iter->user_data3 = NULL;
676 
677  LEAVE("iter %s", iter_to_string(iter));
678  return TRUE;
679 }
680 
681 static gboolean
682 gnc_tree_model_owner_iter_children (GtkTreeModel *tree_model,
683  GtkTreeIter *iter,
684  GtkTreeIter *parent_iter)
685 {
687  GncTreeModelOwner *model;
688 
689  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
690  ENTER("model %p, iter %p (to be filed in), parent %s",
691  tree_model, iter, (parent_iter ? iter_to_string(parent_iter) : "(null)"));
692 
693  model = GNC_TREE_MODEL_OWNER (tree_model);
694  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
695 
696  /* Owner lists don't have children, so this function call only
697  * makes sense if no parent_iter was supplied. In that case,
698  * return the first owner in the list */
699  if (!parent_iter)
700  {
701  iter->user_data = g_list_nth_data (priv->owner_list, 0);
702  iter->user_data2 = GINT_TO_POINTER (0);
703  iter->user_data3 = NULL;
704  iter->stamp = model->stamp;
705  LEAVE("iter (2) %s", iter_to_string(iter));
706  return TRUE;
707  }
708  else
709  {
710  iter->stamp = 0;
711  LEAVE("failed (owners don't have children)");
712  return FALSE;
713  }
714 }
715 
716 static gboolean
717 gnc_tree_model_owner_iter_has_child (GtkTreeModel *tree_model,
718  GtkTreeIter *iter)
719 {
720  /* Owner lists don't have children, so always return false */
721  return FALSE;
722 }
723 
724 static int
725 gnc_tree_model_owner_iter_n_children (GtkTreeModel *tree_model,
726  GtkTreeIter *iter)
727 {
728  GncTreeModelOwner *model;
730 
731  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), -1);
732 
733  model = GNC_TREE_MODEL_OWNER (tree_model);
734  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE (model);
735 
736  /* Owner lists don't have children, so always return 0, except for
737  * the special case this request comes for the special "root" iter
738  * (NULL). For that exception we return the size of the owner list.
739  */
740  if (iter == NULL)
741  return (gint) g_list_length (priv->owner_list);
742 
743  g_return_val_if_fail (
744  GNC_TREE_MODEL_OWNER (tree_model)->stamp == iter->stamp, -1);
745 
746  return 0;
747 }
748 
749 static gboolean
750 gnc_tree_model_owner_iter_nth_child (GtkTreeModel *tree_model,
751  GtkTreeIter *iter,
752  GtkTreeIter *parent_iter,
753  int n)
754 {
755  GncTreeModelOwner *model;
757 
758  if (parent_iter)
759  {
760  gchar *parent_string;
761  parent_string = g_strdup(iter_to_string(parent_iter));
762  ENTER("model %p, iter %s, parent_iter %s, n %d",
763  tree_model, iter_to_string(iter),
764  parent_string, n);
765  g_free(parent_string);
766  }
767  else
768  {
769  ENTER("model %p, iter %s, parent_iter (null), n %d",
770  tree_model, iter_to_string(iter), n);
771  }
772  gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
773 
774  model = GNC_TREE_MODEL_OWNER (tree_model);
775  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
776 
777  /* Owner lists don't have children, so this function call only
778  * makes sense if no parent_iter was supplied. In that case,
779  * return the first owner in the list */
780  if (!parent_iter)
781  {
782  iter->user_data = g_list_nth_data (priv->owner_list, n);
783  iter->user_data2 = GINT_TO_POINTER (n);
784  iter->user_data3 = NULL;
785  iter->stamp = model->stamp;
786  LEAVE("iter (2) %s", iter_to_string(iter));
787  return TRUE;
788  }
789  else
790  {
791  iter->stamp = 0;
792  LEAVE("failed (owners don't have children)");
793  return FALSE;
794  }
795 }
796 
797 static gboolean
798 gnc_tree_model_owner_iter_parent (GtkTreeModel *tree_model,
799  GtkTreeIter *iter,
800  GtkTreeIter *child)
801 {
802  /* Owner lists don't have children, so always return false */
803  iter->stamp = 0;
804  return FALSE;
805 }
806 
807 
808 /************************************************************/
809 /* Owner Tree View Filter Functions */
810 /************************************************************/
811 
812 /*
813  * Convert a model/iter pair to a gnucash owner. This routine should
814  * only be called from an owner tree view filter function.
815  */
816 GncOwner *
818  GtkTreeIter *iter)
819 {
820  g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
821  g_return_val_if_fail (iter != NULL, NULL);
822  g_return_val_if_fail (iter->user_data != NULL, NULL);
823  g_return_val_if_fail (iter->stamp == model->stamp, NULL);
824 
825  return (GncOwner *) iter->user_data;
826 }
827 
828 /*
829  * Convert a model/owner pair into a gtk_tree_model_iter. This
830  * routine should only be called from the file
831  * gnc-tree-view-owner.c.
832  */
833 gboolean
835  GncOwner *owner,
836  GtkTreeIter *iter)
837 {
839  GList *owner_in_list;
840 
841  ENTER("model %p, owner %p, iter %p", model, owner, iter);
842  gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), FALSE);
843  gnc_leave_return_val_if_fail ((owner != NULL), FALSE);
844  gnc_leave_return_val_if_fail ((iter != NULL), FALSE);
845 
846 
847  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
848  owner_in_list = g_list_find_custom (priv->owner_list, (gconstpointer)owner, (GCompareFunc)gncOwnerGCompareFunc);
849  if (owner_in_list)
850  {
851  iter->stamp = model->stamp;
852  iter->user_data = owner_in_list->data;
853  iter->user_data2 = GINT_TO_POINTER (g_list_position (priv->owner_list, owner_in_list));
854  iter->user_data3 = NULL;
855  LEAVE("iter %s", iter_to_string (iter));
856  return TRUE;
857  }
858  else
859  {
860  iter->stamp = 0;
861  iter->user_data = NULL;
862  LEAVE("Owner not found in list");
863  return FALSE;
864  }
865 }
866 
867 /*
868  * Convert a model/owner pair into a gtk_tree_model_path. This
869  * routine should only be called from the file
870  * gnc-tree-view-owner.c.
871  */
872 GtkTreePath *
874  GncOwner *owner)
875 {
876  GtkTreeIter tree_iter;
877  GtkTreePath *tree_path;
878 
879  ENTER("model %p, owner %p", model, owner);
880  gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
881  gnc_leave_return_val_if_fail (owner != NULL, NULL);
882 
883  if (!gnc_tree_model_owner_get_iter_from_owner (model, owner,
884  &tree_iter))
885  {
886  LEAVE("no iter");
887  return NULL;
888  }
889 
890  tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &tree_iter);
891  if (tree_path)
892  {
893  gchar *path_string = gtk_tree_path_to_string(tree_path);
894  LEAVE("path (2) %s", path_string);
895  g_free(path_string);
896  }
897  else
898  {
899  LEAVE("no path");
900  }
901  return tree_path;
902 }
903 
904 /************************************************************/
905 /* Owner Tree Model - Engine Event Handling Functions */
906 /************************************************************/
907 
908 static void
909 increment_stamp(GncTreeModelOwner *model)
910 {
911  do model->stamp++;
912  while (!model->stamp);
913 }
914 
943 static void
944 gnc_tree_model_owner_event_handler (QofInstance *entity,
945  QofEventId event_type,
946  GncTreeModelOwner *model,
947  GncEventData *ed)
948 {
950  GtkTreePath *path = NULL;
951  GtkTreeIter iter;
952  GncOwner owner;
953 
954  g_return_if_fail(model); /* Required */
955 
956  if (!GNC_IS_OWNER(entity))
957  return;
958 
959  ENTER("entity %p of type %d, model %p, event_data %p",
960  entity, event_type, model, ed);
961  priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
962 
963  qofOwnerSetEntity (&owner, entity);
964  if (gncOwnerGetType(&owner) != priv->owner_type)
965  {
966  LEAVE("model type and owner type differ");
967  return;
968  }
969 
970  if (qof_instance_get_book (entity) != priv->book)
971  {
972  LEAVE("not in this book");
973  return;
974  }
975 
976  /* What to do, that to do. */
977  switch (event_type)
978  {
979  case QOF_EVENT_ADD:
980  /* Tell the filters/views where the new owner was added. */
981  DEBUG("add owner %p (%s)", &owner, gncOwnerGetName(&owner));
982  /* First update our copy of the owner list. This isn't done automatically */
983  if (priv->owner_list)
984  g_list_free_full (priv->owner_list, (GDestroyNotify) gncOwnerFree);
985 
986  priv->owner_list = gncBusinessGetOwnerList (priv->book,
987  gncOwnerTypeToQofIdType(priv->owner_type), TRUE);
988  increment_stamp(model);
989  if (!gnc_tree_model_owner_get_iter_from_owner (model, &owner, &iter))
990  {
991  LEAVE("can't generate iter");
992  break;
993  }
994  path = gnc_tree_model_owner_get_path(GTK_TREE_MODEL(model), &iter);
995  if (!path)
996  {
997  DEBUG("can't generate path");
998  break;
999  }
1000  gtk_tree_model_row_inserted (GTK_TREE_MODEL(model), path, &iter);
1001  break;
1002 
1003  case QOF_EVENT_REMOVE:
1004  if (!ed) /* Required for a remove. */
1005  break;
1006  DEBUG("remove owner %d (%s) from owner_list %p", ed->idx,
1007  gncOwnerGetName(&owner), priv->owner_list);
1008  path = gtk_tree_path_new();
1009  if (!path)
1010  {
1011  DEBUG("can't generate path");
1012  break;
1013  }
1014  increment_stamp(model);
1015  gtk_tree_path_append_index (path, ed->idx);
1016  gtk_tree_model_row_deleted (GTK_TREE_MODEL(model), path);
1017  break;
1018 
1019  case QOF_EVENT_MODIFY:
1020  DEBUG("modify owner %p (%s)", &owner, gncOwnerGetName(&owner));
1021  if (!gnc_tree_model_owner_get_iter_from_owner (model, &owner, &iter))
1022  {
1023  LEAVE("can't generate iter");
1024  return;
1025  }
1026  path = gnc_tree_model_owner_get_path(GTK_TREE_MODEL(model), &iter);
1027  if (!path)
1028  {
1029  DEBUG("can't generate path");
1030  break;
1031  }
1032  gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter);
1033  break;
1034 
1035  default:
1036  LEAVE("unknown event type");
1037  return;
1038  }
1039 
1040  if (path)
1041  gtk_tree_path_free(path);
1042  LEAVE(" ");
1043  return;
1044 }
OwnerList * gncBusinessGetOwnerList(QofBook *book, QofIdTypeConst type_name, gboolean all_including_inactive)
Returns a GList of all objects of the given type_name in the given book, but each object is wrapped i...
The instance data structure for an owner tree model.
Business Interface: Object OWNERs.
const GList * gnc_gobject_tracking_get_list(const gchar *name)
Get a list of all known objects of a specified type.
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.
Definition: gnc-prefs.c:128
GtkTreeModel implementation for gnucash owner tree.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
void(* QofEventHandler)(QofInstance *ent, QofEventId event_type, gpointer handler_data, gpointer event_data)
Handler invoked when an event is generated.
Definition: qofevent.h:89
utility functions for the GnuCash UI
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
The instance private data for an owner tree model.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
#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
The class data structure for an owner tree model.
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition: qofevent.cpp:73
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:412
GtkTreeModel * gnc_tree_model_owner_new(GncOwnerType owner_type)
Create a new GtkTreeModel for manipulating gnucash owners.
gint QofEventId
Define the type of events allowed.
Definition: qofevent.h:45
Gobject helper routines.
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
Definition: qofevent.cpp:103
void qofOwnerSetEntity(GncOwner *owner, QofInstance *ent)
set the owner from the entity.
Definition: gncOwner.c:320
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
Retrieve the full name for the specified commodity.
QofIdTypeConst gncOwnerTypeToQofIdType(GncOwnerType t)
Returns the QofIdType of the given GncOwnerType, or NULL if no suitable one exists.
Definition: gncOwner.c:236
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.
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)
Check if entity is an owner kind.
Definition: gncOwner.c:353
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Returns the GncOwnerType of this owner.
Definition: gncOwner.c:201
int stamp
The state of the model.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
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.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
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:384
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:370
Commodity handling public routines.
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.
Definition: gnc-prefs.c:143
GList OwnerList
For SWIG: A GList containing GncOwner.
Definition: gncBusiness.h:82