GnuCash  5.6-150-g038405b370+
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_finalize (GObject *object);
49 static void gnc_tree_model_owner_dispose (GObject *object);
50 
52 static void gnc_tree_model_owner_tree_model_init (GtkTreeModelIface *iface);
53 static GtkTreeModelFlags gnc_tree_model_owner_get_flags (GtkTreeModel *tree_model);
54 static int gnc_tree_model_owner_get_n_columns (GtkTreeModel *tree_model);
55 static GType gnc_tree_model_owner_get_column_type (GtkTreeModel *tree_model,
56  int index);
57 static gboolean gnc_tree_model_owner_get_iter (GtkTreeModel *tree_model,
58  GtkTreeIter *iter,
59  GtkTreePath *path);
60 static GtkTreePath *gnc_tree_model_owner_get_path (GtkTreeModel *tree_model,
61  GtkTreeIter *iter);
62 static void gnc_tree_model_owner_get_value (GtkTreeModel *tree_model,
63  GtkTreeIter *iter,
64  int column,
65  GValue *value);
66 static gboolean gnc_tree_model_owner_iter_next (GtkTreeModel *tree_model,
67  GtkTreeIter *iter);
68 static gboolean gnc_tree_model_owner_iter_children (GtkTreeModel *tree_model,
69  GtkTreeIter *iter,
70  GtkTreeIter *parent);
71 static gboolean gnc_tree_model_owner_iter_has_child (GtkTreeModel *tree_model,
72  GtkTreeIter *iter);
73 static int gnc_tree_model_owner_iter_n_children (GtkTreeModel *tree_model,
74  GtkTreeIter *iter);
75 static gboolean gnc_tree_model_owner_iter_nth_child (GtkTreeModel *tree_model,
76  GtkTreeIter *iter,
77  GtkTreeIter *parent,
78  int n);
79 static gboolean gnc_tree_model_owner_iter_parent (GtkTreeModel *tree_model,
80  GtkTreeIter *iter,
81  GtkTreeIter *child);
82 
84 static 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 
103 G_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 
118 static void
119 gnc_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 
133 static void
134 gnc_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 
145 static void
146 gnc_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 
170 static void
171 gnc_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 
192 static void
193 gnc_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 
223 GtkTreeModel *
224 gnc_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 
263 static const gchar *
264 iter_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 
296 static void
297 gnc_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 
313 static GtkTreeModelFlags
314 gnc_tree_model_owner_get_flags (GtkTreeModel *tree_model)
315 {
316  return 0;
317 }
318 
319 static int
320 gnc_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 
327 static GType
328 gnc_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 
364 static gboolean
365 gnc_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 
409 static GtkTreePath *
410 gnc_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 
451 static void
452 gnc_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 
462 static void
463 gnc_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 
617 static gboolean
618 gnc_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 
650 static gboolean
651 gnc_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 
683 static gboolean
684 gnc_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 
691 static int
692 gnc_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 
714 static gboolean
715 gnc_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 
760 static gboolean
761 gnc_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  */
779 GncOwner *
780 gnc_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  */
796 gboolean
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  */
832 GtkTreePath *
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 
843  if (!gnc_tree_model_owner_get_iter_from_owner (model, owner,
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 
868 static void
869 increment_stamp(GncTreeModelOwner *model)
870 {
871  do model->stamp++;
872  while (!model->stamp);
873 }
874 
903 static void
904 gnc_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 }
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...
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
GncTreeModel gnc_tree_model
The parent object data.
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 data structure 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
G_DEFINE_TYPE_WITH_CODE(GncMainWindow, gnc_main_window, GTK_TYPE_APPLICATION_WINDOW, G_IMPLEMENT_INTERFACE(GNC_TYPE_WINDOW, gnc_window_main_window_init)) static guint main_window_signals[LAST_SIGNAL]
A holding place for all the signals generated by the main window code.
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:411
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:319
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:235
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:352
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Returns the GncOwnerType of this owner.
Definition: gncOwner.c:200
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:383
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
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:121