GnuCash  5.6-150-g038405b370+
gnc-tree-view-account.c
1 /**********************************************************************\
2  * gnc-tree-view-account.c -- GtkTreeView implementation to display *
3  * accounts in a GtkTreeView. *
4  * Copyright (C) 2003,2005,2006 David Hampton <hampton@employees.org> *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License *
17  * along with this program; if not, contact: *
18  * *
19  * Free Software Foundation Voice: +1-617-542-5942 *
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21  * Boston, MA 02110-1301, USA gnu@gnu.org *
22  * *
23 \**********************************************************************/
24 
25 #include <config.h>
26 
27 #include <stdbool.h>
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30 #include <string.h>
31 
32 #include "gnc-tree-view.h"
33 #include "gnc-tree-model-account.h"
35 #include "gnc-tree-view-account.h"
36 
37 #include "Account.h"
38 #include "gnc-accounting-period.h"
39 #include "gnc-commodity.h"
40 #include "gnc-component-manager.h"
41 #include "gnc-engine.h"
42 #include "gnc-glib-utils.h"
43 #include "gnc-gobject-utils.h"
44 #include "gnc-prefs.h"
45 #include "gnc-hooks.h"
46 #include "gnc-session.h"
47 #include "gnc-icons.h"
48 #include "gnc-ui-balances.h"
49 #include "dialog-utils.h"
50 #include "window-main-summarybar.h"
51 
52 #define SAMPLE_ACCOUNT_VALUE "$1,000,000.00"
53 #define GNC_PREF_ACCOUNT_COLOR "show-account-color"
54 
57 /* This static indicates the debugging module that this .o belongs to. */
58 static QofLogModule log_module = GNC_MOD_GUI;
59 
61 static void gnc_tree_view_account_finalize (GObject *object);
62 static gboolean gnc_tree_view_search_compare (GtkTreeModel *model, gint column,
63  const gchar *key, GtkTreeIter *iter, gpointer search_data);
64 
65 static void gtva_update_column_names (GncTreeViewAccount *view);
66 static void gtva_currency_changed_cb (void);
67 
68 static gboolean gnc_tree_view_account_filter_helper (GtkTreeModel *model,
69  GtkTreeIter *iter,
70  gpointer data);
71 
72 static void gtva_setup_column_renderer_edited_cb(GncTreeViewAccount *account_view,
73  GtkTreeViewColumn *column,
74  GtkCellRenderer *renderer,
75  GncTreeViewAccountColumnTextEdited col_edited_cb);
76 
77 static void tax_info_data_func (GtkTreeViewColumn *col,
78  GtkCellRenderer *renderer,
79  GtkTreeModel *model,
80  GtkTreeIter *iter,
81  gpointer view);
82 
83 static void acc_color_data_func (GtkTreeViewColumn *col,
84  GtkCellRenderer *renderer,
85  GtkTreeModel *model,
86  GtkTreeIter *iter,
87  gpointer view);
88 
89 static void gnc_tree_view_account_color_update (gpointer gsettings,
90  gchar *key, gpointer user_data);
91 
92 static gboolean
93 gnc_tree_view_tooltip_cb (GtkWidget *widget, gint x, gint y, gboolean keyboard_tip,
94  GtkTooltip *tooltip, gpointer user_data);
95 
97 {
98  GncTreeView gnc_tree_view;
99  int stamp;
100 
101  AccountViewInfo avi;
102 
104  gpointer filter_data;
105  GSourceFunc filter_destroy;
106 
107  GtkTreeViewColumn *name_column;
108  GtkTreeViewColumn *code_column;
109  GtkTreeViewColumn *desc_column;
110  GtkTreeViewColumn *present_report_column;
111  GtkTreeViewColumn *balance_report_column;
112  GtkTreeViewColumn *cleared_report_column;
113  GtkTreeViewColumn *reconciled_report_column;
114  GtkTreeViewColumn *future_min_report_column;
115  GtkTreeViewColumn *total_report_column;
116  GtkTreeViewColumn *notes_column;
117 
118  gboolean show_account_color;
119 
120 } GncTreeViewAccountPrivate;
121 
122 
123 /************************************************************/
124 /* g_object required functions */
125 /************************************************************/
126 
127 G_DEFINE_TYPE(GncTreeViewAccount, gnc_tree_view_account, GNC_TYPE_TREE_VIEW)
128 
129 static void
130 gnc_tree_view_account_class_init (GncTreeViewAccountClass *klass)
131 {
132  GObjectClass *o_class;
133 
134  /* GObject signals */
135  o_class = G_OBJECT_CLASS (klass);
136  o_class->finalize = gnc_tree_view_account_finalize;
137 
138  gnc_hook_add_dangler(HOOK_CURRENCY_CHANGED,
139  (GFunc)gtva_currency_changed_cb, NULL, NULL);
140 }
141 
142 /********************************************************************\
143  * gnc_init_account_view_info *
144  * initialize an account view info structure with default values *
145  * *
146  * Args: avi - structure to initialize *
147  * Returns: nothing *
148 \********************************************************************/
149 static void
150 gnc_init_account_view_info(AccountViewInfo *avi)
151 {
152  int i;
153 
154  for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
155  avi->include_type[i] = TRUE;
156  avi->show_hidden = FALSE;
157 }
158 
159 static void
160 gnc_tree_view_account_init (GncTreeViewAccount *view)
161 {
162  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
163  GNC_PREF_ACCOUNT_COLOR,
164  gnc_tree_view_account_color_update,
165  view);
166 
167  gnc_init_account_view_info(&view->avi);
168 }
169 
170 static void
171 gnc_tree_view_account_finalize (GObject *object)
172 {
173  ENTER("view %p", object);
174  g_return_if_fail (object != NULL);
175  g_return_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (object));
176 
177  GncTreeViewAccount *view = GNC_TREE_VIEW_ACCOUNT (object);
178 
179  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
180  GNC_PREF_ACCOUNT_COLOR,
181  gnc_tree_view_account_color_update,
182  view);
183  if (view->filter_destroy)
184  {
185  view->filter_destroy(view->filter_data);
186  view->filter_destroy = NULL;
187  }
188  view->filter_fn = NULL;
189 
190  G_OBJECT_CLASS (gnc_tree_view_account_parent_class)->finalize (object);
191  LEAVE(" ");
192 }
193 
194 
195 /************************************************************
196  * Callbacks *
197  ************************************************************/
198 static void
199 gnc_tree_view_account_hidden_toggled (GtkCellRendererToggle *cell,
200  const gchar *s_path_str,
201  gpointer user_data)
202 {
203  GncTreeViewAccount *tree_view;
204  GtkTreePath *s_path;
205  Account *account;
206  gboolean hidden;
207 
208  /* Change the requested account */
209  tree_view = user_data;
210  s_path = gtk_tree_path_new_from_string (s_path_str);
211  account = gnc_tree_view_account_get_account_from_path (tree_view, s_path);
212  if (account)
213  {
214  hidden = !gtk_cell_renderer_toggle_get_active (cell); // hasn't changed yet.
215  xaccAccountSetHidden (account, hidden);
216  }
217 
218  /* Clean up */
219  gtk_tree_path_free (s_path);
220 }
221 
222 
223 static void
224 gnc_tree_view_account_placeholder_toggled (GtkCellRendererToggle *cell,
225  const gchar *s_path_str,
226  gpointer user_data)
227 {
228  GncTreeViewAccount *tree_view;
229  GtkTreePath *s_path;
230  Account *account;
231  gboolean placeholder;
232 
233  /* Change the requested account */
234  tree_view = user_data;
235  s_path = gtk_tree_path_new_from_string (s_path_str);
236  account = gnc_tree_view_account_get_account_from_path (tree_view, s_path);
237  if (account)
238  {
239  placeholder = !gtk_cell_renderer_toggle_get_active (cell); // hasn't changed yet.
240  xaccAccountSetPlaceholder (account, placeholder);
241  }
242 
243  /* Clean up */
244  gtk_tree_path_free (s_path);
245 }
246 
247 
248 /************************************************************/
249 /* sort functions */
250 /************************************************************/
251 
252 static GtkTreeModel *
253 sort_cb_setup_w_iters (GtkTreeModel *f_model,
254  GtkTreeIter *f_iter_a,
255  GtkTreeIter *f_iter_b,
256  GtkTreeIter *iter_a,
257  GtkTreeIter *iter_b,
258  const Account **account_a,
259  const Account **account_b)
260 {
261  GtkTreeModel *model;
262 
263  model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
264  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model),
265  iter_a,
266  f_iter_a);
267  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model),
268  iter_b,
269  f_iter_b);
270  *account_a = gnc_tree_model_account_get_account (GNC_TREE_MODEL_ACCOUNT(model), iter_a);
271  *account_b = gnc_tree_model_account_get_account (GNC_TREE_MODEL_ACCOUNT(model), iter_b);
272  return model;
273 }
274 
275 static void
276 sort_cb_setup (GtkTreeModel *f_model,
277  GtkTreeIter *f_iter_a,
278  GtkTreeIter *f_iter_b,
279  const Account **account_a,
280  const Account **account_b)
281 {
282  GtkTreeIter iter_a, iter_b;
283 
284  sort_cb_setup_w_iters (f_model, f_iter_a, f_iter_b,
285  &iter_a, &iter_b, account_a, account_b);
286 }
287 
288 static gint
289 sort_by_last_reconcile_date (GtkTreeModel *f_model,
290  GtkTreeIter *f_iter1,
291  GtkTreeIter *f_iter2,
292  gpointer user_data)
293 {
294  const Account *account1, *account2;
295  time64 account1_date, account2_date;
296 
297  sort_cb_setup (f_model, f_iter1, f_iter2, &account1, &account2);
298 
299  if (!xaccAccountGetReconcileLastDate (account1, &account1_date))
300  account1_date = 0;
301 
302  if (!xaccAccountGetReconcileLastDate (account2, &account2_date))
303  account2_date = 0;
304 
305  if (account1_date < account2_date)
306  return -1;
307  else if (account1_date > account2_date)
308  return 1;
309  else
310  return xaccAccountOrder (account1, account2);
311 }
312 
313 static gint
314 sort_by_string (GtkTreeModel *f_model,
315  GtkTreeIter *f_iter1,
316  GtkTreeIter *f_iter2,
317  gpointer user_data)
318 {
319  GtkTreeModel *model;
320  GtkTreeIter iter1, iter2;
321  const Account *account1, *account2;
322  gchar *str1, *str2;
323  gint column = GPOINTER_TO_INT(user_data);
324  gint result;
325 
326  model = sort_cb_setup_w_iters(f_model, f_iter1, f_iter2, &iter1, &iter2, &account1, &account2);
327 
328  /* Get the strings. */
329  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter1, column, &str1, -1);
330  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter2, column, &str2, -1);
331 
332  result = safe_utf8_collate(str1, str2);
333  g_free(str1);
334  g_free(str2);
335  if (result != 0)
336  return result;
337  return xaccAccountOrder(account1, account2);
338 }
339 
340 static gint
341 sort_by_code (GtkTreeModel *f_model,
342  GtkTreeIter *f_iter_a,
343  GtkTreeIter *f_iter_b,
344  gpointer user_data)
345 {
346  const Account *account_a, *account_b;
347 
348  sort_cb_setup (f_model, f_iter_a, f_iter_b, &account_a, &account_b);
349 
350  /* Default ordering uses this column first. */
351  return xaccAccountOrder(account_a, account_b);
352 }
353 
354 static gint
355 sort_by_xxx_value (xaccGetBalanceInCurrencyFn fn,
356  gboolean recurse,
357  GtkTreeModel *f_model,
358  GtkTreeIter *f_iter_a,
359  GtkTreeIter *f_iter_b,
360  gpointer user_data)
361 {
362  const Account *account_a, *account_b;
363  const gnc_commodity *cur = gnc_default_currency();
364  gnc_numeric balance_a, balance_b;
365  gint result;
366 
367  /* Find the accounts */
368  sort_cb_setup (f_model, f_iter_a, f_iter_b, &account_a, &account_b);
369 
370  /* Get balances */
371  balance_a = gnc_ui_account_get_balance_full(fn, account_a, recurse, NULL, cur);
372  balance_b = gnc_ui_account_get_balance_full(fn, account_b, recurse, NULL, cur);
373 
374  result = gnc_numeric_compare(balance_a, balance_b);
375  if (result != 0)
376  return result;
377  return xaccAccountOrder(account_a, account_b);
378 }
379 
380 static gint
381 sort_by_present_value (GtkTreeModel *f_model,
382  GtkTreeIter *f_iter_a,
383  GtkTreeIter *f_iter_b,
384  gpointer user_data)
385 {
386  return sort_by_xxx_value (xaccAccountGetPresentBalanceInCurrency, TRUE,
387  f_model, f_iter_a, f_iter_b, user_data);
388 }
389 
390 static gint
391 sort_by_balance_value (GtkTreeModel *f_model,
392  GtkTreeIter *f_iter_a,
393  GtkTreeIter *f_iter_b,
394  gpointer user_data)
395 {
396  return sort_by_xxx_value (xaccAccountGetBalanceInCurrency, TRUE,
397  f_model, f_iter_a, f_iter_b, user_data);
398 }
399 
400 static gint
401 sort_by_cleared_value (GtkTreeModel *f_model,
402  GtkTreeIter *f_iter_a,
403  GtkTreeIter *f_iter_b,
404  gpointer user_data)
405 {
406  return sort_by_xxx_value (xaccAccountGetClearedBalanceInCurrency, TRUE,
407  f_model, f_iter_a, f_iter_b, user_data);
408 }
409 
410 static gint
411 sort_by_reconciled_value (GtkTreeModel *f_model,
412  GtkTreeIter *f_iter_a,
413  GtkTreeIter *f_iter_b,
414  gpointer user_data)
415 {
416  return sort_by_xxx_value (xaccAccountGetReconciledBalanceInCurrency, TRUE,
417  f_model, f_iter_a, f_iter_b, user_data);
418 }
419 
420 static gint
421 sort_by_future_min_value (GtkTreeModel *f_model,
422  GtkTreeIter *f_iter_a,
423  GtkTreeIter *f_iter_b,
424  gpointer user_data)
425 {
426  return sort_by_xxx_value (xaccAccountGetProjectedMinimumBalanceInCurrency, TRUE,
427  f_model, f_iter_a, f_iter_b, user_data);
428 }
429 
430 static gint
431 sort_by_total_value (GtkTreeModel *f_model,
432  GtkTreeIter *f_iter_a,
433  GtkTreeIter *f_iter_b,
434  gpointer user_data)
435 {
436  return sort_by_xxx_value (xaccAccountGetBalanceInCurrency, TRUE,
437  f_model, f_iter_a, f_iter_b, user_data);
438 }
439 
440 static gint
441 sort_by_hidden (GtkTreeModel *f_model,
442  GtkTreeIter *f_iter_a,
443  GtkTreeIter *f_iter_b,
444  gpointer user_data)
445 {
446  const Account *account_a, *account_b;
447  gboolean flag_a, flag_b;
448 
449  /* Find the accounts */
450  sort_cb_setup (f_model, f_iter_a, f_iter_b, &account_a, &account_b);
451 
452  /* Get the placeholder flags. */
453  flag_a = xaccAccountGetHidden (account_a);
454  flag_b = xaccAccountGetHidden (account_b);
455 
456  if (flag_a > flag_b)
457  return -1;
458  else if (flag_a < flag_b)
459  return 1;
460  return xaccAccountOrder (account_a, account_b);
461 }
462 
463 static gint
464 sort_by_placeholder (GtkTreeModel *f_model,
465  GtkTreeIter *f_iter_a,
466  GtkTreeIter *f_iter_b,
467  gpointer user_data)
468 {
469  const Account *account_a, *account_b;
470  gboolean flag_a, flag_b;
471 
472  /* Find the accounts */
473  sort_cb_setup (f_model, f_iter_a, f_iter_b, &account_a, &account_b);
474 
475  /* Get the placeholder flags. */
476  flag_a = xaccAccountGetPlaceholder(account_a);
477  flag_b = xaccAccountGetPlaceholder(account_b);
478 
479  if (flag_a > flag_b)
480  return -1;
481  else if (flag_a < flag_b)
482  return 1;
483  return xaccAccountOrder(account_a, account_b);
484 }
485 
486 static gint
487 sort_by_opening_balance (GtkTreeModel *f_model,
488  GtkTreeIter *f_iter_a,
489  GtkTreeIter *f_iter_b,
490  gpointer user_data)
491 {
492  const Account *account_a, *account_b;
493  gboolean flag_a, flag_b;
494 
495  /* Find the accounts */
496  sort_cb_setup (f_model, f_iter_a, f_iter_b, &account_a, &account_b);
497 
498  /* Get the opening balance flags. */
499  flag_a = xaccAccountGetIsOpeningBalance (account_a);
500  flag_b = xaccAccountGetIsOpeningBalance (account_b);
501 
502  if (flag_a > flag_b)
503  return -1;
504  else if (flag_a < flag_b)
505  return 1;
506  return xaccAccountOrder(account_a, account_b);
507 }
508 
509 static gint
510 sort_by_xxx_period_value (GtkTreeModel *f_model,
511  GtkTreeIter *f_iter_a,
512  GtkTreeIter *f_iter_b,
513  gboolean recurse)
514 {
515  Account *acct1, *acct2;
516  time64 t1, t2;
517  gnc_numeric b1, b2;
518  gint result;
519 
520  sort_cb_setup (f_model, f_iter_a, f_iter_b,
521  (const Account **)&acct1, (const Account **)&acct2);
522 
523  t1 = gnc_accounting_period_fiscal_start();
524  t2 = gnc_accounting_period_fiscal_end();
525 
526  b1 = xaccAccountGetBalanceChangeForPeriod(acct1, t1, t2, recurse);
527  b2 = xaccAccountGetBalanceChangeForPeriod(acct2, t1, t2, recurse);
528 
529  result = gnc_numeric_compare(b1, b2);
530  if (result != 0)
531  return result;
532  return xaccAccountOrder(acct1, acct2);
533 }
534 
535 static gint
536 sort_by_balance_period_value (GtkTreeModel *f_model,
537  GtkTreeIter *f_iter_a,
538  GtkTreeIter *f_iter_b,
539  gpointer user_data)
540 {
541  return sort_by_xxx_period_value (f_model, f_iter_a, f_iter_b, FALSE);
542 }
543 
544 static gint
545 sort_by_total_period_value (GtkTreeModel *f_model,
546  GtkTreeIter *f_iter_a,
547  GtkTreeIter *f_iter_b,
548  gpointer user_data)
549 {
550  return sort_by_xxx_period_value (f_model, f_iter_a, f_iter_b, TRUE);
551 }
552 
553 /************************************************************/
554 /* Tax_Info data function */
555 /************************************************************/
556 
557 /*
558  * The tax-info column in the account tree view is based on the
559  * combination of two columns in the account tree model. The data
560  * function displays only the the data in the
561  * GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO model column if the row is
562  * expanded; otherwise it combines it with the data
563  * in the GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO_SUB_ACCT model column.
564  */
565 static void
566 tax_info_data_func (GtkTreeViewColumn *col,
567  GtkCellRenderer *renderer,
568  GtkTreeModel *model,
569  GtkTreeIter *iter,
570  gpointer view)
571 {
572  gchar *tax_info = NULL;
573  GtkTreePath *path;
574 
575  gtk_tree_model_get(model,
576  iter,
577  GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO,
578  &tax_info,
579  -1);
580 
581  path = gtk_tree_model_get_path(model, iter);
582  if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(view), path))
583  g_object_set(renderer, "text",
584  (tax_info == NULL ? "" : tax_info), NULL);
585  else
586  {
587  gchar *tax_info_sub_acct = NULL;
588 
589  gtk_tree_model_get(model,
590  iter,
591  GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO_SUB_ACCT,
592  &tax_info_sub_acct,
593  -1);
594  if ((g_strcmp0 (tax_info_sub_acct, "") == 0) ||
595  (tax_info_sub_acct == NULL))
596  g_object_set(renderer, "text",
597  (tax_info == NULL ? "" : tax_info), NULL);
598  else
599  {
600  if ((g_strcmp0 (tax_info, "") == 0) ||
601  (tax_info == NULL))
602  g_object_set(renderer, "text",
603  (tax_info_sub_acct == NULL ? "" : tax_info_sub_acct),
604  NULL);
605  else
606  {
607  gchar *combined_tax_info;
608  combined_tax_info = g_strdup_printf ("%s; %s",
609  (tax_info == NULL ? "" : tax_info),
610  (tax_info_sub_acct == NULL ? "" :
611  tax_info_sub_acct));
612  g_object_set(renderer, "text", combined_tax_info, NULL);
613  g_free(combined_tax_info);
614  }
615  }
616  g_free(tax_info_sub_acct);
617  }
618  g_free(tax_info);
619  gtk_tree_path_free(path);
620 }
621 
622 /************************************************************/
623 /* acc_color data function */
624 /************************************************************/
625 /*
626  * The account-color column in the account tree view is obtained
627  * from the GNC_TREE_MODEL_ACCOUNT_COL_COLOR_ACCOUNT which is
628  * checked for a valid color string to set the background color
629  * of the cell.
630  */
631 static void
632 update_cell_renderers (GList *renderers, gchar *account_color)
633 {
634  GtkCellRenderer *cell;
635  GList *node;
636 
637  /* Update the cell background in the list of renderers */
638  for (node = renderers; node; node = node->next)
639  {
640  cell = node->data;
641  g_object_set (cell, "cell-background", account_color, NULL);
642  }
643 }
644 
645 /* Colorizes a cell in the account tree view if
646  * - a color is assigned to the given account
647  * - the user enabled account colorization in the preferences
648  * Only the account color column is special: it will always
649  * be colored if a valid color was set, regardless of the
650  * preference setting.
651  */
652 static void
653 acc_color_data_func (GtkTreeViewColumn *col,
654  GtkCellRenderer *renderer,
655  GtkTreeModel *model,
656  GtkTreeIter *iter,
657  gpointer data)
658 {
659  gchar *acc_color = NULL, *acc_cond_color = NULL;
660  gchar *item;
661  GdkRGBA color;
662  gchar *column_name;
663  GList *renderers;
664 
665  gtk_tree_model_get(model,
666  iter,
667  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_ACCOUNT,
668  &item,
669  -1);
670 
671  /* Check if color was set for the account */
672  if ((item) && (*item != '\0'))
673  acc_color = g_strstrip(g_strdup(item));
674  g_free (item);
675 
676  /* Test if the color string represents a valid color */
677  if (acc_color && (!gdk_rgba_parse(&color, acc_color)))
678  {
679  g_free (acc_color);
680  acc_color = NULL;
681  }
682 
683  /* Determine whether columns other than the
684  * Account Color column should be colored. */
685  GncTreeViewAccount *view = data;
686  if (view->show_account_color)
687  acc_cond_color = acc_color;
688 
689  column_name = g_object_get_data(G_OBJECT(col), PREF_NAME);
690  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (col));
691 
692  /* Account Color column is always colored, other columns only conditionally. */
693  if (g_strcmp0(column_name, "account-color") == 0)
694  update_cell_renderers (renderers, acc_color);
695  else
696  update_cell_renderers (renderers, acc_cond_color);
697 
698  g_list_free (renderers);
699  g_free (acc_color);
700 }
701 
707 static void
708 gnc_tree_view_account_color_update (gpointer gsettings, gchar *key, gpointer user_data)
709 {
710  GncTreeViewAccount *view;
711 
712  g_return_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(user_data));
713  view = user_data;
714  if (g_strcmp0 (key, GNC_PREF_ACCOUNT_COLOR) == 0)
715  view->show_account_color = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, key);
716 
717  // do a refilter so the tree view background color gets updated
719 }
720 
724 void
725 gnc_tree_view_account_column_add_color (GncTreeViewAccount *view, GtkTreeViewColumn *col)
726 {
727  GtkCellRenderer *renderer = gnc_tree_view_column_get_renderer(col);
728 
729  gtk_tree_view_column_set_cell_data_func (col, renderer, acc_color_data_func,
730  GTK_TREE_VIEW(view), NULL);
731 }
732 
733 /************************************************************/
734 /* New View Creation */
735 /************************************************************/
736 
737 /*
738  * Create a new account tree view with (optional) top level root node.
739  * This view will be based on a model that is common to all view of
740  * the same set of books, but will have its own private filter on that
741  * model.
742  */
743 GtkTreeView *
744 gnc_tree_view_account_new_with_root (Account *root, gboolean show_root)
745 {
746  GtkTreeModel *model, *f_model, *s_model;
747  GtkTreePath *virtual_root_path = NULL;
748  const gchar *sample_type, *sample_commodity;
749  GtkTreeViewColumn *tax_info_column, *acc_color_column, *acc_balance_limit_column;
750  GtkCellRenderer *renderer;
751  GList *col_list = NULL, *node = NULL;
752 
753  ENTER(" ");
754  /* Create our view */
755  GncTreeViewAccount *view = g_object_new (GNC_TYPE_TREE_VIEW_ACCOUNT,
756  "has-tooltip", true,
757  "name", "gnc-id-account-tree", NULL);
758 
759  /* Get the show_account_color value from gsettings */
760  view->show_account_color = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNT_COLOR);
761 
762  /* Create/get a pointer to the existing model for this set of books. */
763  model = gnc_tree_model_account_new (root);
764 
765  /* Set up the view private filter layer on the common model. */
766  if (!show_root)
767  virtual_root_path = gtk_tree_path_new_first ();
768  f_model = gtk_tree_model_filter_new (model, virtual_root_path);
769  /* A GncTreeModelAccount is based on a GncTreeModel, which is a
770  * GObject that provides a GtkTreeModel interface. */
771  g_object_unref(G_OBJECT(model));
772  if (virtual_root_path)
773  gtk_tree_path_free(virtual_root_path);
774 
775  /* Set up the view private sort layer on the common model. */
776  s_model = gtk_tree_model_sort_new_with_model(f_model);
777  g_object_unref(G_OBJECT(f_model));
778  gtk_tree_view_set_model (GTK_TREE_VIEW (view), s_model);
779  g_object_unref(G_OBJECT(s_model));
780 
781  /* Set default visibilities */
782  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(view), FALSE);
783 
785  sample_commodity = gnc_commodity_get_fullname(gnc_default_currency());
786 
787  view->name_column
788  = gnc_tree_view_add_text_column(GNC_TREE_VIEW(view), _("Account Name"), "name",
789  GNC_ICON_ACCOUNT, "Expenses:Entertainment",
790  GNC_TREE_MODEL_ACCOUNT_COL_NAME,
791  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
792  sort_by_string);
793 
794  gnc_tree_view_add_text_column(GNC_TREE_VIEW(view), _("Type"), "type", NULL, sample_type,
795  GNC_TREE_MODEL_ACCOUNT_COL_TYPE,
796  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
797  sort_by_string);
798 
799  gnc_tree_view_add_text_column(GNC_TREE_VIEW(view), _("Commodity"), "commodity", NULL,
800  sample_commodity,
801  GNC_TREE_MODEL_ACCOUNT_COL_COMMODITY,
802  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
803  sort_by_string);
804  view->code_column
805  = gnc_tree_view_add_text_column(GNC_TREE_VIEW(view), _("Account Code"), "account-code", NULL,
806  "1-123-1234",
807  GNC_TREE_MODEL_ACCOUNT_COL_CODE,
808  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
809  sort_by_code);
810  view->desc_column
811  = gnc_tree_view_add_text_column(GNC_TREE_VIEW(view), _("Description"), "description", NULL,
812  "Sample account description.",
813  GNC_TREE_MODEL_ACCOUNT_COL_DESCRIPTION,
814  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
815  sort_by_string);
816 
817  gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Last Num"), "lastnum", "12345",
818  GNC_TREE_MODEL_ACCOUNT_COL_LASTNUM,
819  GNC_TREE_VIEW_COLUMN_COLOR_NONE,
820  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
821  sort_by_string);
822 
823  gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Present"), "present",
824  SAMPLE_ACCOUNT_VALUE,
825  GNC_TREE_MODEL_ACCOUNT_COL_PRESENT,
826  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_PRESENT,
827  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
828  sort_by_present_value);
829  view->present_report_column
830  = gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Present (Report)"), "present_report",
831  SAMPLE_ACCOUNT_VALUE,
832  GNC_TREE_MODEL_ACCOUNT_COL_PRESENT_REPORT,
833  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_PRESENT,
834  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
835  sort_by_present_value);
836 
837  gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Balance"), "balance",
838  SAMPLE_ACCOUNT_VALUE,
839  GNC_TREE_MODEL_ACCOUNT_COL_BALANCE,
840  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE,
841  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
842  sort_by_balance_value);
843  view->balance_report_column
844  = gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Balance (Report)"), "balance_report",
845  SAMPLE_ACCOUNT_VALUE,
846  GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_REPORT,
847  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE,
848  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
849  sort_by_balance_value);
850 
851  gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Balance (Period)"), "balance-period",
852  SAMPLE_ACCOUNT_VALUE,
853  GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_PERIOD,
854  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE_PERIOD,
855  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
856  sort_by_balance_period_value);
857 
858  gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Cleared"), "cleared",
859  SAMPLE_ACCOUNT_VALUE,
860  GNC_TREE_MODEL_ACCOUNT_COL_CLEARED,
861  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_CLEARED,
862  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
863  sort_by_cleared_value);
864  view->cleared_report_column
865  = gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Cleared (Report)"), "cleared_report",
866  SAMPLE_ACCOUNT_VALUE,
867  GNC_TREE_MODEL_ACCOUNT_COL_CLEARED_REPORT,
868  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_CLEARED,
869  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
870  sort_by_cleared_value);
871 
872  gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Reconciled"), "reconciled",
873  SAMPLE_ACCOUNT_VALUE,
874  GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED,
875  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_RECONCILED,
876  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
877  sort_by_reconciled_value);
878  view->reconciled_report_column
879  = gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Reconciled (Report)"), "reconciled_report",
880  SAMPLE_ACCOUNT_VALUE,
881  GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_REPORT,
882  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_RECONCILED,
883  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
884  sort_by_reconciled_value);
885 
886  gnc_tree_view_add_text_column(GNC_TREE_VIEW(view), _("Last Reconcile Date"), "last-recon-date", NULL,
887  "Last Reconcile Date",
888  GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_DATE,
889  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
890  sort_by_last_reconcile_date);
891 
892  gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Future Minimum"), "future_min",
893  SAMPLE_ACCOUNT_VALUE,
894  GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN,
895  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_FUTURE_MIN,
896  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
897  sort_by_future_min_value);
898  view->future_min_report_column
899  = gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Future Minimum (Report)"), "future_min_report",
900  SAMPLE_ACCOUNT_VALUE,
901  GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN_REPORT,
902  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_FUTURE_MIN,
903  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
904  sort_by_future_min_value);
905 
906  gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Total"), "total",
907  SAMPLE_ACCOUNT_VALUE,
908  GNC_TREE_MODEL_ACCOUNT_COL_TOTAL,
909  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL,
910  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
911  sort_by_total_value);
912  view->total_report_column
913  = gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Total (Report)"), "total_report",
914  SAMPLE_ACCOUNT_VALUE,
915  GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_REPORT,
916  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL,
917  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
918  sort_by_total_value);
919 
920  gnc_tree_view_add_numeric_column(GNC_TREE_VIEW(view), _("Total (Period)"), "total-period",
921  SAMPLE_ACCOUNT_VALUE,
922  GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_PERIOD,
923  GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL_PERIOD,
924  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
925  sort_by_total_period_value);
926 
927  /* Translators: The C is the column title and stands for Color, this should be one character */
928  acc_color_column
929  = gnc_tree_view_add_text_column(GNC_TREE_VIEW(view), C_("Column header for 'Color'", "C"), "account-color", NULL,
930  "xx",
931  GNC_TREE_VIEW_COLUMN_DATA_NONE,
932  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
933  NULL);
934 
935  /* Add the full title to the object for menu creation */
936  g_object_set_data_full(G_OBJECT(acc_color_column), REAL_TITLE,
937  g_strdup(_("Account Color")), g_free);
938 
939  /* Also add the full title to the column header as a tooltip */
940  gtk_widget_set_tooltip_text (gtk_tree_view_column_get_button (acc_color_column), _("Account Color"));
941 
942  acc_balance_limit_column
943  = gnc_tree_view_add_pix_column (GNC_TREE_VIEW(view),
944  C_("Column header for 'Balance Limit'", "L"),
945  "account-balance-limit",
946  "xx",
947  GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_LIMIT,
948  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
949  NULL);
950 
951  /* Add the full title to the object for menu creation */
952  g_object_set_data_full(G_OBJECT(acc_balance_limit_column), REAL_TITLE,
953  g_strdup(_("Balance Limit")), g_free);
954 
955  /* Also add the full title to the column header as a tooltip */
956  gtk_widget_set_tooltip_text (gtk_tree_view_column_get_button (acc_balance_limit_column), _("Balance Limit"));
957 
958  view->notes_column
959  = gnc_tree_view_add_text_view_column(GNC_TREE_VIEW(view), _("Notes"), "notes", NULL,
960  "Sample account notes.",
961  GNC_TREE_MODEL_ACCOUNT_COL_NOTES,
962  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
963  sort_by_string);
964 
965  tax_info_column
966  = gnc_tree_view_add_text_column(GNC_TREE_VIEW(view), _("Tax Info"), "tax-info", NULL,
967  "Sample tax info.",
968  GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO,
969  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
970  sort_by_string);
971 
972  renderer = gnc_tree_view_column_get_renderer(tax_info_column);
973  gtk_tree_view_column_set_cell_data_func(tax_info_column,
974  renderer,
975  tax_info_data_func,
976  GTK_TREE_VIEW(view),
977  NULL);
978 
979  gnc_tree_view_add_toggle_column (GNC_TREE_VIEW(view), _("Hidden"),
980  C_("Column header for 'Hidden'", "H"),
981  "hidden",
982  GNC_TREE_MODEL_ACCOUNT_COL_HIDDEN,
983  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
984  sort_by_hidden,
985  gnc_tree_view_account_hidden_toggled);
986 
987  gnc_tree_view_add_toggle_column(GNC_TREE_VIEW(view), _("Placeholder"),
988  C_("Column header for 'Placeholder'", "P"),
989  "placeholder",
990  GNC_TREE_MODEL_ACCOUNT_COL_PLACEHOLDER,
991  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
992  sort_by_placeholder,
993  gnc_tree_view_account_placeholder_toggled);
994 
995  gnc_tree_view_add_toggle_column(GNC_TREE_VIEW(view), _("Opening Balance"),
996  C_("Column header for 'Opening Balance'", "O"),
997  "opening-balance",
998  GNC_TREE_MODEL_ACCOUNT_COL_OPENING_BALANCE,
999  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
1000  sort_by_opening_balance,
1001  NULL);
1002 
1003  /* Add function to each column that optionally sets a background color for accounts */
1004  col_list = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
1005  for (node = col_list; node; node = node->next)
1006  {
1007  renderer = gnc_tree_view_column_get_renderer(node->data);
1008  gtk_tree_view_column_set_cell_data_func(node->data,
1009  renderer,
1010  acc_color_data_func,
1011  GTK_TREE_VIEW(view),
1012  NULL);
1013  }
1014  g_list_free (col_list);
1015 
1016  /* Update column titles to use the currency name. */
1017  gtva_update_column_names(view);
1018 
1019  /* By default only the first column is visible. */
1020  gnc_tree_view_configure_columns(GNC_TREE_VIEW(view));
1021  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (f_model),
1022  gnc_tree_view_account_filter_helper,
1023  view,
1024  NULL);
1025 
1026  /* Default the sorting to account name */
1027  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_model),
1028  GNC_TREE_MODEL_ACCOUNT_COL_NAME,
1029  GTK_SORT_ASCENDING);
1030 
1031  /* Set account find-as-you-type search function */
1032  gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW(view), gnc_tree_view_search_compare, NULL, NULL);
1033 
1034  g_signal_connect (G_OBJECT(view), "query-tooltip",
1035  G_CALLBACK(gnc_tree_view_tooltip_cb), NULL);
1036 
1037  gtk_widget_show(GTK_WIDGET(view));
1038  LEAVE("%p", view);
1039  return GTK_TREE_VIEW(view);
1040 }
1041 
1042 /*
1043  * Create a new account tree view with (optional) top level root node.
1044  * This view will be based on a model that is common to all view of
1045  * the same set of books, but will have its own private filter on that
1046  * model.
1047  */
1048 GtkTreeView *
1049 gnc_tree_view_account_new (gboolean show_root)
1050 {
1051  Account *root;
1052 
1053  root = gnc_book_get_root_account (gnc_get_current_book ());
1054  return gnc_tree_view_account_new_with_root (root, show_root);
1055 }
1056 
1057 /************************************************************/
1058 /* Auxiliary Functions */
1059 /************************************************************/
1060 
1061 #define debug_path(fn, path) { \
1062  gchar *path_string = gtk_tree_path_to_string(path); \
1063  fn("tree path %s", path_string); \
1064  g_free(path_string); \
1065  }
1066 
1067 static GtkTreePath *
1068 gnc_tree_view_account_get_path_from_account (GncTreeViewAccount *view,
1069  Account *account)
1070 {
1071  GtkTreeModel *model, *f_model, *s_model;
1072  GtkTreePath *path, *f_path, *s_path;
1073 
1074  ENTER("view %p, account %p (%s)", view, account, xaccAccountGetName(account));
1075 
1076  if (account == NULL)
1077  {
1078  LEAVE("no account");
1079  return NULL;
1080  }
1081 
1082  /* Reach down to the real model and get a path for this account */
1083  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
1084  f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
1085  model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
1086  path = gnc_tree_model_account_get_path_from_account (GNC_TREE_MODEL_ACCOUNT(model), account);
1087  if (path == NULL)
1088  {
1089  LEAVE("no path");
1090  return NULL;
1091  }
1092 
1093  /* convert back to a filtered path */
1094  f_path = gtk_tree_model_filter_convert_child_path_to_path (GTK_TREE_MODEL_FILTER (f_model), path);
1095  gtk_tree_path_free(path);
1096  if (!f_path)
1097  {
1098  LEAVE("no filter path");
1099  return NULL;
1100  }
1101 
1102  /* convert back to a sorted path */
1103  s_path = gtk_tree_model_sort_convert_child_path_to_path (GTK_TREE_MODEL_SORT (s_model), f_path);
1104  gtk_tree_path_free(f_path);
1105  debug_path(LEAVE, s_path);
1106  return s_path;
1107 }
1108 
1109 static gboolean
1110 gnc_tree_view_account_get_iter_from_account (GncTreeViewAccount *view,
1111  Account *account,
1112  GtkTreeIter *s_iter)
1113 {
1114  GtkTreeModel *model, *f_model, *s_model;
1115  GtkTreeIter iter, f_iter;
1116 
1117  g_return_val_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(view), FALSE);
1118  g_return_val_if_fail(account != NULL, FALSE);
1119  g_return_val_if_fail(s_iter != NULL, FALSE);
1120 
1121  ENTER("view %p, account %p (%s)", view, account, xaccAccountGetName(account));
1122 
1123  /* Reach down to the real model and get an iter for this account */
1124  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
1125  f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
1126  model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
1128  GNC_TREE_MODEL_ACCOUNT(model), account, &iter))
1129  {
1130  LEAVE("model_get_iter_from_account failed");
1131  return FALSE;
1132  }
1133 
1134  /* convert back to a sort iter */
1135  gtk_tree_model_filter_convert_child_iter_to_iter (
1136  GTK_TREE_MODEL_FILTER(f_model), &f_iter, &iter);
1137  gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT(s_model),
1138  s_iter, &f_iter);
1139  LEAVE(" ");
1140  return TRUE;
1141 }
1142 
1143 gint
1144 gnc_tree_view_account_count_children (GncTreeViewAccount *view,
1145  Account *account)
1146 {
1147  GtkTreeModel *s_model;
1148  GtkTreeIter s_iter;
1149  gint num_children;
1150 
1151  ENTER("view %p, account %p (%s)", view, account, xaccAccountGetName(account));
1152 
1153  if (account == NULL)
1154  {
1155  LEAVE("no account");
1156  return 0;
1157  }
1158 
1159  if (!gnc_tree_view_account_get_iter_from_account (view, account, &s_iter))
1160  {
1161  LEAVE("view_get_iter_from_account failed");
1162  return 0;
1163  }
1164 
1165  /* Any children? */
1166  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
1167  num_children = gtk_tree_model_iter_n_children(s_model, &s_iter);
1168  LEAVE("%d children", num_children);
1169  return num_children;
1170 }
1171 
1172 void
1174 {
1175  GtkTreeModel *model, *f_model, *s_model;
1176 
1177  s_model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
1178  f_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT(s_model));
1179  model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER(f_model));
1180 
1181  gnc_tree_model_account_clear_cache (GNC_TREE_MODEL_ACCOUNT(model));
1182 }
1183 
1184 /************************************************************/
1185 /* Account Tree View Filter Functions */
1186 /************************************************************/
1187 
1188 /*
1189  * Get a copy of the account view info structure in use by the
1190  * specified tree.
1191  */
1192 void
1193 gnc_tree_view_account_get_view_info (GncTreeViewAccount *view,
1194  AccountViewInfo *avi)
1195 {
1196  g_return_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(view));
1197  g_return_if_fail(avi != NULL);
1198 
1199  *avi = view->avi;
1200 }
1201 
1202 /*
1203  * Set the account view info data in use by the specified tree to
1204  * match the callers request.
1205  */
1206 void
1207 gnc_tree_view_account_set_view_info (GncTreeViewAccount *view,
1208  AccountViewInfo *avi)
1209 {
1210  ENTER("%p", view);
1211  g_return_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(view));
1212  g_return_if_fail(avi != NULL);
1213 
1214  view->avi = *avi;
1215 
1217  view, gnc_tree_view_account_filter_by_view_info,
1218  &view->avi, NULL);
1219 
1220  LEAVE(" ");
1221 }
1222 
1223 static gboolean
1224 gnc_tree_view_account_filter_helper (GtkTreeModel *model,
1225  GtkTreeIter *iter,
1226  gpointer data)
1227 {
1228  Account *account;
1229  GncTreeViewAccount *view = data;
1230 
1231  g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), FALSE);
1232  g_return_val_if_fail (iter != NULL, FALSE);
1233 
1235  GNC_TREE_MODEL_ACCOUNT(model), iter);
1236 
1237  if (view->filter_fn)
1238  return view->filter_fn(account, view->filter_data);
1239  else return TRUE;
1240 }
1241 
1242 /*
1243  * Set an GtkTreeModel visible filter on this account. This filter will be
1244  * called for each account that the tree is about to show, and the
1245  * account will be passed to the callback function.
1246  *
1247  * Use NULL as func to remove filter.
1248  */
1249 void
1250 gnc_tree_view_account_set_filter (GncTreeViewAccount *view,
1252  gpointer data,
1253  GSourceFunc destroy)
1254 {
1255  ENTER("view %p, filter func %p, data %p, destroy %p",
1256  view, func, data, destroy);
1257 
1258  g_return_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(view));
1259 
1260  if (view->filter_destroy)
1261  {
1262  view->filter_destroy(view->filter_data);
1263  }
1264  view->filter_destroy = destroy;
1265  view->filter_data = data;
1266  view->filter_fn = func;
1267 
1269  LEAVE(" ");
1270 }
1271 
1272 /*
1273  * Forces the entire account tree to be re-evaluated for visibility.
1274  */
1275 void
1276 gnc_tree_view_account_refilter (GncTreeViewAccount *view)
1277 {
1278  GtkTreeModel *f_model, *s_model;
1279 
1280  g_return_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(view));
1281 
1282  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
1283  f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
1284  gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (f_model));
1285 }
1286 
1287 gboolean
1288 gnc_tree_view_account_filter_by_view_info(Account* acct, gpointer data)
1289 {
1290  GNCAccountType acct_type;
1291  AccountViewInfo* avi = (AccountViewInfo*)data;
1292 
1293  g_return_val_if_fail(GNC_IS_ACCOUNT(acct), FALSE);
1294  acct_type = xaccAccountGetType(acct);
1295 
1296  if (!avi->include_type[acct_type]) return FALSE;
1297  if (!avi->show_hidden && xaccAccountIsHidden(acct)) return FALSE;
1298  return TRUE;
1299 }
1300 
1301 /************************************************************/
1302 /* Account Tree View Get/Set Functions */
1303 /************************************************************/
1304 
1305 /*
1306  * Retrieve the selected account from an account tree view. The
1307  * account tree must be in single selection mode.
1308  */
1309 Account *
1311  GtkTreePath *s_path)
1312 {
1313  GtkTreeModel *model, *f_model, *s_model;
1314  GtkTreePath *path, *f_path;
1315  GtkTreeIter iter;
1316  Account *account;
1317 
1318  ENTER("view %p", view);
1319  g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view), NULL);
1320  g_return_val_if_fail (s_path != NULL, NULL);
1321 
1322  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
1323  f_path = gtk_tree_model_sort_convert_path_to_child_path (
1324  GTK_TREE_MODEL_SORT (s_model), s_path);
1325  if (!f_path)
1326  {
1327  LEAVE("no filter path");
1328  return NULL;
1329  }
1330 
1331  f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
1332  path = gtk_tree_model_filter_convert_path_to_child_path (
1333  GTK_TREE_MODEL_FILTER (f_model), f_path);
1334  gtk_tree_path_free(f_path);
1335  if (!path)
1336  {
1337  LEAVE("no path");
1338  return NULL;
1339  }
1340 
1341  model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
1342  if (!gtk_tree_model_get_iter (model, &iter, path))
1343  {
1344  LEAVE("no iter");
1345  return NULL;
1346  }
1347 
1348  account = iter.user_data;
1349  gtk_tree_path_free(path);
1350  LEAVE("account %p (%s)", account, xaccAccountGetName (account));
1351  return account;
1352 }
1353 
1354 
1355 Account *
1357  GtkTreeIter *s_iter)
1358 {
1359  GtkTreeModel *model, *f_model;
1360  GtkTreeIter iter, f_iter;
1361  Account *account;
1362 
1363  g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT(s_model), NULL);
1364  g_return_val_if_fail (s_iter != NULL, NULL);
1365 
1366  ENTER("model %p, iter %p", s_model, s_iter);
1367 
1368  gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT(s_model),
1369  &f_iter,
1370  s_iter);
1371  f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
1372  gtk_tree_model_filter_convert_iter_to_child_iter (
1373  GTK_TREE_MODEL_FILTER(f_model), &iter, &f_iter);
1374  model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
1376  GNC_TREE_MODEL_ACCOUNT(model), &iter);
1377  LEAVE("account %p (%s)", account, xaccAccountGetName (account));
1378  return account;
1379 }
1380 
1381 
1382 /*
1383  * Retrieve the selected account from an account tree view. The
1384  * account tree must be in single selection mode.
1385  */
1386 Account *
1388 {
1389  GtkTreeSelection *selection;
1390  GtkTreeModel *f_model, *s_model;
1391  GtkTreeIter iter, f_iter, s_iter;
1392  Account *account;
1393  GtkSelectionMode mode;
1394 
1395  ENTER("view %p", view);
1396  g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view), NULL);
1397 
1398  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
1399  mode = gtk_tree_selection_get_mode(selection);
1400  if ((mode != GTK_SELECTION_SINGLE) && (mode != GTK_SELECTION_BROWSE))
1401  {
1402  return NULL;
1403  }
1404  if (!gtk_tree_selection_get_selected (selection, &s_model, &s_iter))
1405  {
1406  LEAVE("no account, get_selected failed");
1407  return FALSE;
1408  }
1409 
1410  gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model),
1411  &f_iter, &s_iter);
1412 
1413  f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
1414  gtk_tree_model_filter_convert_iter_to_child_iter (
1415  GTK_TREE_MODEL_FILTER (f_model), &iter, &f_iter);
1416 
1417  account = iter.user_data;
1418  LEAVE("account %p (%s)", account, xaccAccountGetName (account));
1419  return account;
1420 }
1421 
1422 /*
1423  * Selects a single account in the account tree view. The account
1424  * tree must be in single selection mode.
1425  */
1426 void
1428  Account *account)
1429 {
1430  GtkTreeModel *model, *f_model, *s_model;
1431  GtkTreePath *path, *f_path, *s_path, *parent_path;
1432  GtkTreeSelection *selection;
1433 
1434  ENTER("view %p, account %p (%s)", view,
1435  account, xaccAccountGetName (account));
1436  g_return_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view));
1437 
1438  /* Clear any existing selection. */
1439  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
1440  gtk_tree_selection_unselect_all (selection);
1441 
1442  if (account == NULL)
1443  return;
1444 
1445  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
1446  f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
1447  model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
1448 
1450  GNC_TREE_MODEL_ACCOUNT(model), account);
1451  if (path == NULL)
1452  {
1453  LEAVE("no path");
1454  return;
1455  }
1456  debug_path(DEBUG, path);
1457 
1458  f_path = gtk_tree_model_filter_convert_child_path_to_path (
1459  GTK_TREE_MODEL_FILTER (f_model), path);
1460  gtk_tree_path_free(path);
1461  if (f_path == NULL)
1462  {
1463  LEAVE("no filter path");
1464  return;
1465  }
1466  debug_path(DEBUG, f_path);
1467 
1468  s_path = gtk_tree_model_sort_convert_child_path_to_path (GTK_TREE_MODEL_SORT (s_model),
1469  f_path);
1470  gtk_tree_path_free(f_path);
1471  if (s_path == NULL)
1472  {
1473  LEAVE("no sort path");
1474  return;
1475  }
1476 
1477  /* gtk_tree_view requires that a row be visible before it can be selected */
1478  parent_path = gtk_tree_path_copy (s_path);
1479  if (gtk_tree_path_up (parent_path))
1480  {
1481  /* This function is misnamed. It expands the actual item
1482  * specified, not the path to the item specified. I.E. It expands
1483  * one level too many, thus the get of the parent. */
1484  gtk_tree_view_expand_to_path(GTK_TREE_VIEW(view), parent_path);
1485  }
1486  gtk_tree_path_free(parent_path);
1487 
1488  gtk_tree_selection_select_path (selection, s_path);
1489 
1490  /* give gtk+ a chance to resize the tree view first by handling pending
1491  * configure events */
1492  while (gtk_events_pending ())
1493  gtk_main_iteration ();
1494  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(view), s_path, NULL, FALSE, 0.0, 0.0);
1495  debug_path(LEAVE, s_path);
1496  gtk_tree_path_free(s_path);
1497 }
1498 
1499 /* Information re selection process */
1500 typedef struct
1501 {
1502  GList* return_list;
1503  GncTreeViewAccount* view;
1505 
1506 /*
1507  * This helper function is called once for each row in the tree view
1508  * that is currently selected. Its task is to append the corresponding
1509  * account to the end of a glist.
1510  */
1511 static void
1512 get_selected_accounts_helper (GtkTreeModel *s_model,
1513  GtkTreePath *s_path,
1514  GtkTreeIter *s_iter,
1515  gpointer data)
1516 {
1517  GncTreeViewSelectionInfo *gtvsi = data;
1518  GtkTreeModel *f_model;
1519  GtkTreeIter iter, f_iter;
1520  Account *account;
1521 
1522  gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model),
1523  &f_iter, s_iter);
1524 
1525  f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
1526  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (f_model),
1527  &iter, &f_iter);
1528  account = iter.user_data;
1529 
1530  /* Only selected if it passes the filter */
1531  if (gtvsi->view->filter_fn == NULL || gtvsi->view->filter_fn(account, gtvsi->view->filter_data))
1532  {
1533  gtvsi->return_list = g_list_prepend (gtvsi->return_list, account);
1534  }
1535 }
1536 
1537 /*
1538  * Given an account tree view, return a list of the selected accounts. The
1539  * account tree must be in multiple selection mode.
1540  *
1541  * Note: It is the responsibility of the caller to free the returned
1542  * list.
1543  */
1544 GList *
1546 {
1547  GtkTreeSelection *selection;
1549 
1550  g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view), NULL);
1551 
1552  info.return_list = NULL;
1553  info.view = view;
1554  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
1555  gtk_tree_selection_selected_foreach(selection, get_selected_accounts_helper, &info);
1556  info.return_list = g_list_reverse (info.return_list);
1557  return info.return_list;
1558 }
1559 
1560 /*
1561  * Given an account tree view and a list of accounts, select those
1562  * accounts in the tree view.
1563  */
1564 void
1566  GList *account_list,
1567  gboolean show_last)
1568 {
1569  GtkTreeModel *model, *f_model, *s_model;
1570  GtkTreePath *path, *f_path, *s_path, *parent_path;
1571  GtkTreeSelection *selection;
1572  GList *element;
1573  Account *account;
1574 
1575  g_return_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view));
1576 
1577  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
1578  f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
1579  model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
1580 
1581  /* Clear any existing selection. */
1582  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
1583  gtk_tree_selection_unselect_all (selection);
1584  gtk_tree_view_collapse_all (GTK_TREE_VIEW(view));
1585 
1586  /* Now go select what the user requested. */
1587  for (element = account_list; element; )
1588  {
1589  account = element->data;
1590  element = g_list_next(element);
1591 
1592  if (account == NULL)
1593  {
1594  /*
1595  * Oops. Someone must have deleted this account and not cleaned
1596  * up all references to it.
1597  */
1598  continue;
1599  }
1600 
1601  path = gnc_tree_model_account_get_path_from_account (GNC_TREE_MODEL_ACCOUNT(model), account);
1602  if (path == NULL)
1603  {
1604  /*
1605  * Oops. Someone must have deleted this account and not cleaned
1606  * up all references to it.
1607  */
1608  continue;
1609  }
1610 
1611  f_path = gtk_tree_model_filter_convert_child_path_to_path (GTK_TREE_MODEL_FILTER (f_model),
1612  path);
1613  gtk_tree_path_free(path);
1614  if (f_path == NULL)
1615  continue;
1616 
1617  s_path = gtk_tree_model_sort_convert_child_path_to_path (GTK_TREE_MODEL_SORT (s_model),
1618  f_path);
1619  gtk_tree_path_free(f_path);
1620  if (s_path == NULL)
1621  continue;
1622 
1623  /* gtk_tree_view requires that a row be visible before it can be selected */
1624  parent_path = gtk_tree_path_copy (s_path);
1625  if (gtk_tree_path_up (parent_path))
1626  {
1627  /* This function is misnamed. It expands the actual item
1628  * specified, not the path to the item specified. I.E. It
1629  * expands one level too many, thus the get of the parent. */
1630  gtk_tree_view_expand_to_path(GTK_TREE_VIEW(view), parent_path);
1631  }
1632  gtk_tree_path_free(parent_path);
1633 
1634  gtk_tree_selection_select_path (selection, s_path);
1635  if (show_last && (element == NULL))
1636  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(view), s_path, NULL, FALSE, 0.0, 0.0);
1637  gtk_tree_path_free(s_path);
1638  }
1639 }
1640 
1641 /*
1642  * Selects all sub-accounts of an account.
1643  */
1644 void
1646  Account *account)
1647 {
1648  GtkTreeModel *s_model;
1649  GtkTreeSelection *selection;
1650  GtkTreePath *sp_account, *sp_start, *sp_end;
1651  GtkTreeIter si_account, si_start, si_end;
1652  gboolean have_start, have_end = FALSE;
1653  gint num_children;
1654 
1655  ENTER("view %p, account %p (%s)", view, account, xaccAccountGetName(account));
1656 
1657  g_return_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view));
1658 
1659  if (account == NULL)
1660  {
1661  LEAVE("no account");
1662  return;
1663  }
1664 
1665  if (!gnc_tree_view_account_get_iter_from_account (view, account, &si_account))
1666  {
1667  LEAVE("view_get_iter_from_account failed");
1668  return;
1669  }
1670 
1671  /* Any children? */
1672  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
1673  num_children = gtk_tree_model_iter_n_children(s_model, &si_account);
1674  if (num_children == 0)
1675  {
1676  LEAVE("no children");
1677  return;
1678  }
1679 
1680  /* Expand the tree. Required for selection to work */
1681  sp_account = gtk_tree_model_get_path (s_model, &si_account);
1682  gtk_tree_view_expand_row (GTK_TREE_VIEW(view), sp_account, TRUE);
1683 
1684  /* compute start/end paths */
1685  have_start = gtk_tree_model_iter_nth_child(s_model, &si_start, &si_account, 0);
1686  si_end = si_account;
1687  while (num_children)
1688  {
1689  GtkTreeIter tmp_iter = si_end;
1690  have_end = gtk_tree_model_iter_nth_child(s_model, &si_end, &tmp_iter,
1691  num_children - 1);
1692  if (have_end)
1693  num_children = gtk_tree_model_iter_n_children(s_model, &si_end);
1694  else
1695  num_children = 0;
1696  }
1697 
1698  if (have_start && have_end)
1699  {
1700  sp_start = gtk_tree_model_get_path (s_model, &si_start);
1701  sp_end = gtk_tree_model_get_path (s_model, &si_end);
1702 
1703  /* select everything between */
1704  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
1705  gtk_tree_selection_select_range (selection, sp_start, sp_end);
1706 
1707  /* clean up */
1708  gtk_tree_path_free(sp_start);
1709  gtk_tree_path_free(sp_end);
1710  }
1711  gtk_tree_path_free(sp_account);
1712  LEAVE(" ");
1713  return;
1714 }
1715 
1716 void
1718  Account *account)
1719 {
1720  GtkTreePath *path;
1721 
1722  g_return_if_fail(view != NULL);
1723  g_return_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(view));
1724  ENTER("view %p, account %p", view, account);
1725 
1726  path = gnc_tree_view_account_get_path_from_account(view, account);
1727  if (path)
1728  {
1729  gtk_tree_view_expand_to_path(GTK_TREE_VIEW(view), path);
1730  gtk_tree_path_free(path);
1731  }
1732  LEAVE(" ");
1733 }
1734 
1735 
1736 /*
1737  * Retrieve the account currently under the cursor.
1738  */
1739 Account *
1741 {
1742  GtkTreePath *s_path;
1743  Account *account;
1744 
1745  ENTER("view %p", view);
1746  g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view), NULL);
1747 
1748  gtk_tree_view_get_cursor (GTK_TREE_VIEW(view), &s_path, NULL);
1749  if (!s_path)
1750  {
1751  LEAVE("no account");
1752  return NULL;
1753  }
1754 
1755  account = gnc_tree_view_account_get_account_from_path (view, s_path);
1756  gtk_tree_path_free(s_path);
1757  LEAVE("account %p (%s)", account, xaccAccountGetName (account));
1758  return account;
1759 }
1760 
1761 
1762 /************************************************************/
1763 /* Account Tree View Add Column Functions */
1764 /************************************************************/
1765 
1766 static void
1767 gtva_update_column_name (GtkTreeViewColumn *column,
1768  const gchar *fmt,
1769  const gchar *mnemonic)
1770 {
1771  gchar *name;
1772 
1773  g_return_if_fail(column);
1774 
1775  name = g_strdup_printf(fmt, mnemonic);
1776  gtk_tree_view_column_set_title(column, name);
1777  g_free(name);
1778 }
1779 
1780 
1781 static void
1782 gtva_update_column_names (GncTreeViewAccount *view)
1783 {
1784  const gchar *mnemonic = gnc_commodity_get_mnemonic(gnc_default_report_currency());
1785 
1786  gtva_update_column_name(view->present_report_column,
1787  /* Translators: %s is a currency mnemonic.*/
1788  _("Present (%s)"), mnemonic);
1789  gtva_update_column_name(view->balance_report_column,
1790  /* Translators: %s is a currency mnemonic.*/
1791  _("Balance (%s)"), mnemonic);
1792  gtva_update_column_name(view->cleared_report_column,
1793  /* Translators: %s is a currency mnemonic.*/
1794  _("Cleared (%s)"), mnemonic);
1795  gtva_update_column_name(view->reconciled_report_column,
1796  /* Translators: %s is a currency mnemonic.*/
1797  _("Reconciled (%s)"), mnemonic);
1798  gtva_update_column_name(view->future_min_report_column,
1799  /* Translators: %s is a currency mnemonic.*/
1800  _("Future Minimum (%s)"), mnemonic);
1801  gtva_update_column_name(view->total_report_column,
1802  /* Translators: %s is a currency mnemonic.*/
1803  _("Total (%s)"), mnemonic);
1804  gnc_tree_view_set_show_column_menu(GNC_TREE_VIEW(view), FALSE);
1805  gnc_tree_view_set_show_column_menu(GNC_TREE_VIEW(view), TRUE);
1806 }
1807 
1808 
1809 static void
1810 gtva_currency_changed_cb (void)
1811 {
1812  const GList *views, *ptr;
1813 
1814  views = gnc_gobject_tracking_get_list (GNC_TREE_VIEW_ACCOUNT_NAME);
1815  for (ptr = views; ptr; ptr = g_list_next(ptr))
1816  {
1817  gtva_update_column_names (ptr->data);
1818  }
1819 }
1820 /* Retrieve a specified account string property and put the result
1821  * into the tree column's text property.
1822  */
1823 static void
1824 account_cell_property_data_func (GtkTreeViewColumn *tree_column,
1825  GtkCellRenderer *cell,
1826  GtkTreeModel *s_model,
1827  GtkTreeIter *s_iter,
1828  gpointer key)
1829 {
1830  GncTreeViewAccount *view;
1831  Account *account;
1832  gchar *string = NULL;
1833 
1834  g_return_if_fail (GTK_IS_TREE_MODEL_SORT (s_model));
1835  account = gnc_tree_view_account_get_account_from_iter(s_model, s_iter);
1836  qof_instance_get (QOF_INSTANCE (account), key, &string, NULL);
1837  if (string == NULL)
1838  string = g_strdup ("");
1839 
1840  g_object_set (G_OBJECT (cell), "text", string, "xalign", 0.0, NULL);
1841  g_free (string);
1842 
1843  view = g_object_get_data(G_OBJECT(tree_column), "tree-view");
1844 
1845  if (GNC_IS_TREE_VIEW_ACCOUNT (view))
1846  acc_color_data_func (tree_column, cell, s_model, s_iter, view);
1847 }
1848 
1849 
1850 GtkTreeViewColumn *
1852  const gchar *column_title,
1853  const gchar *propname)
1854 {
1855  GtkCellRenderer *renderer;
1856  GtkTreeViewColumn *column;
1857 
1858  g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view), NULL);
1859  g_return_val_if_fail (propname != NULL, NULL);
1860 
1861  column = gnc_tree_view_add_text_column(GNC_TREE_VIEW(view), column_title,
1862  propname, NULL, "Sample text",
1863  -1, -1, NULL);
1864 
1865  /* This new kvp column has only had one renderer added to it so
1866  * far. Find that renderer. */
1867  renderer = gnc_tree_view_column_get_renderer(column);
1868  g_object_set (G_OBJECT (renderer), "xalign", 1.0, NULL);
1869 
1870  // add a pointer to the view to make it easier to access in data_func
1871  g_object_set_data(G_OBJECT(column), "tree-view", (gpointer)view);
1872 
1873  gtk_tree_view_column_set_cell_data_func (column, renderer,
1874  account_cell_property_data_func,
1875  g_strdup(propname), g_free);
1876  return column;
1877 }
1878 
1879 static void col_edited_helper(GtkCellRendererText *cell, gchar *path_string,
1880  gchar *new_text, gpointer _s_model)
1881 {
1882  Account *account;
1883  GtkTreeModel *s_model;
1884  GtkTreeIter s_iter;
1885  GncTreeViewAccountColumnTextEdited col_edited_cb;
1886  GtkTreeViewColumn *col;
1887 
1888  col_edited_cb = g_object_get_data(G_OBJECT(cell),
1889  "column_edited_callback");
1890  col = GTK_TREE_VIEW_COLUMN(g_object_get_data(G_OBJECT(cell),
1891  "column_view"));
1892  s_model = GTK_TREE_MODEL(_s_model);
1893 
1894  if (!gtk_tree_model_get_iter_from_string(s_model, &s_iter, path_string))
1895  return;
1896 
1897  account = gnc_tree_view_account_get_account_from_iter(s_model, &s_iter);
1898  col_edited_cb(account, col, new_text);
1899 }
1900 
1901 static void col_source_helper(GtkTreeViewColumn *col, GtkCellRenderer *cell,
1902  GtkTreeModel *s_model, GtkTreeIter *s_iter,
1903  gpointer _col_source_cb)
1904 {
1905  Account *account;
1906  gchar *text;
1907  GncTreeViewAccountColumnSource col_source_cb;
1908 
1909  g_return_if_fail (GTK_IS_TREE_MODEL_SORT (s_model));
1910  col_source_cb = (GncTreeViewAccountColumnSource) _col_source_cb;
1911  account = gnc_tree_view_account_get_account_from_iter(s_model, s_iter);
1912  text = col_source_cb(account, col, cell);
1913  g_object_set (G_OBJECT (cell), "text", text, "xalign", 1.0, NULL);
1914  g_free(text);
1915 }
1916 
1921 void
1922 gtva_setup_column_renderer_edited_cb(GncTreeViewAccount *account_view,
1923  GtkTreeViewColumn *column,
1924  GtkCellRenderer *renderer,
1925  GncTreeViewAccountColumnTextEdited col_edited_cb)
1926 {
1927  GtkTreeModel *s_model;
1928 
1929  if (col_edited_cb == NULL)
1930  {
1931  g_object_set(G_OBJECT(renderer), "editable", FALSE, NULL);
1932  g_object_set_data(G_OBJECT(renderer), "column_edited_callback", col_edited_cb);
1933  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(account_view));
1934  g_signal_handlers_disconnect_by_func(G_OBJECT(renderer), col_edited_cb, s_model);
1935  g_object_set_data(G_OBJECT(renderer), "column_view", column);
1936  }
1937  else
1938  {
1939  g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL);
1940  g_object_set_data(G_OBJECT(renderer), "column_edited_callback",
1941  col_edited_cb);
1942  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(account_view));
1943  g_signal_connect(G_OBJECT(renderer), "edited",
1944  (GCallback) col_edited_helper, s_model);
1945  g_object_set_data(G_OBJECT(renderer), "column_view", column);
1946  }
1947 }
1948 
1949 GtkTreeViewColumn *
1950 gnc_tree_view_account_add_custom_column(GncTreeViewAccount *account_view,
1951  const gchar *column_title,
1952  GncTreeViewAccountColumnSource
1953  col_source_cb,
1954  GncTreeViewAccountColumnTextEdited
1955  col_edited_cb)
1956 {
1957  GtkCellRenderer *renderer;
1958 
1959  g_return_val_if_fail(GNC_IS_TREE_VIEW_ACCOUNT(account_view), NULL);
1960 
1961  renderer = gtk_cell_renderer_text_new();
1962 
1963  return gnc_tree_view_account_add_custom_column_renderer(
1964  account_view, column_title, col_source_cb, col_edited_cb, renderer);
1965 }
1966 
1967 GtkTreeViewColumn *
1968 gnc_tree_view_account_add_custom_column_renderer(GncTreeViewAccount *account_view,
1969  const gchar *column_title,
1970  GncTreeViewAccountColumnSource
1971  col_source_cb,
1972  GncTreeViewAccountColumnTextEdited
1973  col_edited_cb,
1974  GtkCellRenderer *renderer)
1975 {
1976  GtkTreeViewColumn *column;
1977 
1978  g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (account_view), NULL);
1979 
1980  g_object_set (G_OBJECT (renderer), "xalign", 1.0, NULL);
1981 
1982  column = gtk_tree_view_column_new_with_attributes (column_title,
1983  renderer, NULL);
1984  if (col_edited_cb)
1985  {
1986  gtva_setup_column_renderer_edited_cb(account_view, column,
1987  renderer, col_edited_cb);
1988  }
1989  gtk_tree_view_column_set_cell_data_func (column, renderer,
1990  col_source_helper,
1991  col_source_cb, NULL);
1992  gnc_tree_view_append_column (GNC_TREE_VIEW(account_view), column);
1993  return column;
1994 }
1995 
1996 
1997 /* BEGIN FILTER FUNCTIONS */
1998 #define FILTER_TREE_VIEW "types_tree_view"
1999 
2011 gboolean
2013  gpointer user_data)
2014 {
2015  AccountFilterDialog *fd = user_data;
2016  GNCAccountType acct_type;
2017  gnc_numeric total;
2018  gboolean result;
2019 
2020  ENTER("account %p:%s", account, xaccAccountGetName(account));
2021 
2022  if (g_hash_table_size (fd->filter_override) > 0)
2023  {
2024  Account *test_acc = NULL;
2025  test_acc = g_hash_table_lookup (fd->filter_override, account);
2026  if (test_acc != NULL)
2027  {
2028  LEAVE(" filter: override");
2029  return TRUE;
2030  }
2031  }
2032 
2033  if (!fd->show_hidden && xaccAccountIsHidden (account))
2034  {
2035  LEAVE(" hide: hidden");
2036  return FALSE;
2037  }
2038 
2039  if (!fd->show_zero_total)
2040  {
2041  total = xaccAccountGetBalanceInCurrency (account, NULL, TRUE);
2042  if (gnc_numeric_zero_p(total))
2043  {
2044  LEAVE(" hide: zero balance");
2045  return FALSE;
2046  }
2047  }
2048 
2049  if (!fd->show_unused)
2050  {
2051  if (gnc_account_and_descendants_empty(account))
2052  {
2053  LEAVE(" hide: unused");
2054  return FALSE;
2055  }
2056  }
2057 
2058  acct_type = xaccAccountGetType(account);
2059  result = (fd->visible_types & (1 << acct_type)) ? TRUE : FALSE;
2060  LEAVE(" %s", result ? "show" : "hide");
2061  return result;
2062 }
2063 
2071 void
2072 gppat_filter_show_hidden_toggled_cb (GtkToggleButton *button,
2073  AccountFilterDialog *fd)
2074 {
2075  g_return_if_fail(GTK_IS_TOGGLE_BUTTON(button));
2076 
2077  ENTER("button %p", button);
2078  fd->show_hidden = gtk_toggle_button_get_active(button);
2079  gnc_tree_view_account_refilter(fd->tree_view);
2080  LEAVE("show_hidden %d", fd->show_hidden);
2081 }
2082 
2090 void
2091 gppat_filter_show_zero_toggled_cb (GtkToggleButton *button,
2092  AccountFilterDialog *fd)
2093 {
2094  g_return_if_fail(GTK_IS_TOGGLE_BUTTON(button));
2095 
2096  ENTER("button %p", button);
2097  fd->show_zero_total = gtk_toggle_button_get_active(button);
2098  gnc_tree_view_account_refilter(fd->tree_view);
2099  LEAVE("show_zero %d", fd->show_zero_total);
2100 }
2101 
2109 void
2110 gppat_filter_show_unused_toggled_cb (GtkToggleButton *button,
2111  AccountFilterDialog *fd)
2112 {
2113  g_return_if_fail(GTK_IS_TOGGLE_BUTTON(button));
2114 
2115  ENTER("button %p", button);
2116  fd->show_unused = gtk_toggle_button_get_active(button);
2117  gnc_tree_view_account_refilter(fd->tree_view);
2118  LEAVE("show_unused %d", fd->show_unused);
2119 }
2120 
2129 void
2130 gppat_filter_clear_all_cb (GtkWidget *button,
2131  AccountFilterDialog *fd)
2132 {
2133  g_return_if_fail(GTK_IS_BUTTON(button));
2134 
2135  ENTER("button %p", button);
2136  fd->visible_types = 0;
2137  gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(fd->model));
2138  gnc_tree_view_account_refilter(fd->tree_view);
2139  LEAVE("types 0x%x", fd->visible_types);
2140 }
2141 
2148 void
2149 gppat_filter_select_all_cb (GtkWidget *button,
2150  AccountFilterDialog *fd)
2151 {
2152  g_return_if_fail(GTK_IS_BUTTON(button));
2153 
2154  ENTER("button %p", button);
2155  fd->visible_types = -1;
2156  gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(fd->model));
2157  gnc_tree_view_account_refilter(fd->tree_view);
2158  LEAVE("types 0x%x", fd->visible_types);
2159 }
2160 
2168 void
2170  AccountFilterDialog *fd)
2171 {
2172  ENTER("button %p", button);
2173  gppat_filter_select_all_cb(button, fd);
2174  LEAVE(" ");
2175 }
2176 
2188 static void
2189 gppat_filter_visible_set_func (GtkTreeViewColumn *column,
2190  GtkCellRenderer *renderer,
2191  GtkTreeModel *model,
2192  GtkTreeIter *iter,
2193  gpointer data)
2194 {
2195  AccountFilterDialog *fd = data;
2196  GNCAccountType type;
2197  gboolean active;
2198 
2199  gtk_tree_model_get(model, iter, GNC_TREE_MODEL_ACCOUNT_TYPES_COL_TYPE, &type, -1);
2200 
2201  active = (fd->visible_types & (1 << type)) ? TRUE : FALSE;
2202  g_object_set (G_OBJECT (renderer), "active", active, NULL);
2203 }
2204 
2210 static void
2211 gppat_filter_visible_toggled_cb (GtkCellRendererToggle *renderer,
2212  gchar *path_str,
2213  AccountFilterDialog *fd)
2214 {
2215  GtkTreeModel *model = fd->model;
2216  GtkTreeIter iter;
2217  GtkTreePath *path;
2218  GNCAccountType type;
2219 
2220  ENTER("toggled %p", path_str);
2221  path = gtk_tree_path_new_from_string(path_str);
2222 
2223  if (gtk_tree_model_get_iter(model, &iter, path))
2224  {
2225  gtk_tree_model_get(model, &iter, GNC_TREE_MODEL_ACCOUNT_TYPES_COL_TYPE, &type, -1);
2226  fd->visible_types ^= (1 << type);
2227  gnc_tree_view_account_refilter(fd->tree_view);
2228  }
2229  gtk_tree_path_free(path);
2230  LEAVE("types 0x%x", fd->visible_types);
2231 }
2232 
2243 void
2244 gppat_filter_response_cb (GtkWidget *dialog,
2245  gint response,
2246  AccountFilterDialog *fd)
2247 {
2248  gpointer gptemp;
2249 
2250  g_return_if_fail(GTK_IS_DIALOG(dialog));
2251 
2252  ENTER("dialog %p, response %d", dialog, response);
2253 
2254  if (response != GTK_RESPONSE_OK)
2255  {
2256  fd->visible_types = fd->original_visible_types;
2257  fd->show_hidden = fd->original_show_hidden;
2258  fd->show_zero_total = fd->original_show_zero_total;
2259  fd->show_unused = fd->original_show_unused;
2260  gnc_tree_view_account_refilter(fd->tree_view);
2261  }
2262 
2263  /* Clean up and delete dialog */
2264  gptemp = (gpointer)fd->dialog;
2265  g_atomic_pointer_compare_and_exchange(&gptemp,
2266  (gpointer)dialog, NULL);
2267  fd->dialog = gptemp;
2268  gtk_widget_destroy(dialog);
2269  LEAVE("types 0x%x", fd->visible_types);
2270 }
2271 
2272 void
2273 account_filter_dialog_create(AccountFilterDialog *fd, GncPluginPage *page)
2274 {
2275  GtkWidget *dialog, *button;
2276  GtkTreeView *view;
2277  GtkCellRenderer *renderer;
2278  GtkBuilder *builder;
2279  gchar *title;
2280 
2281  ENTER("(fd %p, page %p)", fd, page);
2282 
2283  if (fd->dialog)
2284  {
2285  gtk_window_present(GTK_WINDOW(fd->dialog));
2286  LEAVE("existing dialog");
2287  return;
2288  }
2289 
2290  /* Create the dialog */
2291  builder = gtk_builder_new();
2292  gnc_builder_add_from_file (builder, "dialog-account.glade", "account_filter_by_dialog");
2293  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_filter_by_dialog"));
2294  fd->dialog = dialog;
2295  gtk_window_set_transient_for(GTK_WINDOW(dialog),
2296  GTK_WINDOW(GNC_PLUGIN_PAGE(page)->window));
2297  /* Translators: The %s is the name of the plugin page */
2298  title = g_strdup_printf(_("Filter %s by..."),
2299  _(gnc_plugin_page_get_page_name(GNC_PLUGIN_PAGE(page))));
2300  gtk_window_set_title(GTK_WINDOW(dialog), title);
2301  g_free(title);
2302 
2303  /* Remember current state */
2304  fd->original_visible_types = fd->visible_types;
2305  fd->original_show_hidden = fd->show_hidden;
2306  fd->original_show_zero_total = fd->show_zero_total;
2307  fd->original_show_unused = fd->show_unused;
2308 
2309  /* Update the dialog widgets for the current state */
2310  button = GTK_WIDGET(gtk_builder_get_object (builder, "show_hidden"));
2311  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
2312  fd->show_hidden);
2313  button = GTK_WIDGET(gtk_builder_get_object (builder, "show_zero"));
2314  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
2315  fd->show_zero_total);
2316  button = GTK_WIDGET(gtk_builder_get_object (builder, "show_unused"));
2317  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
2318  fd->show_unused);
2319 
2320  /* Set up the tree view and model */
2321  view = GTK_TREE_VIEW(gtk_builder_get_object (builder, FILTER_TREE_VIEW));
2322 
2323  fd->model = gnc_tree_model_account_types_filter_using_mask
2324  (~(1 << ACCT_TYPE_ROOT));
2325  gtk_tree_view_set_model(view, fd->model);
2326  g_object_unref (fd->model);
2327 
2328  renderer = gtk_cell_renderer_toggle_new();
2329 
2330  g_signal_connect(renderer, "toggled",
2331  G_CALLBACK(gppat_filter_visible_toggled_cb), fd);
2332 
2333  gtk_tree_view_insert_column_with_data_func (view, -1, NULL, renderer,
2334  gppat_filter_visible_set_func, fd, NULL);
2335 
2336  gtk_tree_view_insert_column_with_attributes (view,
2337  -1, _("Account Types"), gtk_cell_renderer_text_new(),
2338  "text", GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME, NULL);
2339 
2340  /* Wire up the rest of the callbacks */
2341  gtk_builder_connect_signals(builder, fd);
2342  g_object_unref(G_OBJECT(builder));
2343 
2344  /* Show it */
2345  gtk_widget_show_all(dialog);
2346  LEAVE(" ");
2347 }
2348 
2349 // page state section
2350 #define ACCT_COUNT "NumberOfOpenAccounts"
2351 #define ACCT_OPEN "OpenAccount%d"
2352 #define ACCT_SELECTED "SelectedAccount"
2353 #define SHOW_HIDDEN "ShowHidden"
2354 #define SHOW_ZERO "ShowZeroTotal"
2355 #define SHOW_UNUSED "ShowUnused"
2356 #define ACCT_TYPES "AccountTypes"
2357 
2358 // account/budget state section
2359 // versions less than 3.2 would crash if key did not have an "_"
2360 #define SHOW_HIDDEN_ACCOUNTS "Show_Hidden"
2361 #define SHOW_ZERO_TOTALS "Show_ZeroTotal"
2362 #define SHOW_UNUSED_ACCOUNTS "Show_Unused"
2363 #define ACCOUNT_TYPES "Account_Types"
2364 
2365 
2366 typedef struct foo
2367 {
2368  GKeyFile *key_file;
2369  const gchar *group_name;
2370  int count;
2371 } bar_t;
2372 
2384 static void
2385 tree_save_expanded_row (GncTreeViewAccount *view,
2386  GtkTreePath *path,
2387  gpointer user_data)
2388 {
2389  Account *account;
2390  bar_t *bar = user_data;
2391  gchar *key;
2392  gchar *account_name;
2393 
2394  account = gnc_tree_view_account_get_account_from_path (view, path);
2395  if (account == NULL)
2396  return;
2397 
2398  account_name = gnc_account_get_full_name(account);
2399  if (account_name == NULL)
2400  return;
2401 
2402  key = g_strdup_printf(ACCT_OPEN, ++bar->count);
2403  g_key_file_set_string(bar->key_file, bar->group_name, key, account_name);
2404  g_free(key);
2405  g_free(account_name);
2406 }
2407 
2408 
2419 static void
2420 tree_save_selected_row (GncTreeViewAccount *view,
2421  gpointer user_data)
2422 {
2423  Account *account;
2424  bar_t *bar = user_data;
2425  gchar *account_name;
2426 
2428  if (account == NULL)
2429  return;
2430 
2431  account_name = gnc_account_get_full_name (account);
2432  if (account_name == NULL)
2433  return;
2434 
2435  g_key_file_set_string(bar->key_file, bar->group_name, ACCT_SELECTED,
2436  account_name);
2437  g_free(account_name);
2438 }
2439 
2440 void
2441 gnc_tree_view_account_save(GncTreeViewAccount *view,
2442  AccountFilterDialog *fd,
2443  GKeyFile *key_file, const gchar *group_name)
2444 {
2445  bar_t bar;
2446 
2447  g_return_if_fail (key_file != NULL);
2448  g_return_if_fail (group_name != NULL);
2449 
2450  ENTER("view %p, key_file %p, group_name %s", view, key_file,
2451  group_name);
2452 
2453  g_key_file_set_integer(key_file, group_name, ACCT_TYPES,
2454  fd->visible_types);
2455  g_key_file_set_boolean(key_file, group_name, SHOW_HIDDEN,
2456  fd->show_hidden);
2457  g_key_file_set_boolean(key_file, group_name, SHOW_ZERO,
2458  fd->show_zero_total);
2459  g_key_file_set_boolean(key_file, group_name, SHOW_UNUSED,
2460  fd->show_unused);
2461 
2462  bar.key_file = key_file;
2463  bar.group_name = group_name;
2464  bar.count = 0;
2465  tree_save_selected_row(view, &bar);
2466  gtk_tree_view_map_expanded_rows(
2467  GTK_TREE_VIEW(view), (GtkTreeViewMappingFunc) tree_save_expanded_row,
2468  &bar);
2469  g_key_file_set_integer(key_file, group_name, ACCT_COUNT, bar.count);
2470  LEAVE(" ");
2471 
2472 }
2473 
2474 void
2475 gnc_tree_view_account_save_filter (GncTreeViewAccount *view,
2476  AccountFilterDialog *fd,
2477  GKeyFile *key_file,
2478  const gchar *group_name)
2479 {
2480  g_return_if_fail (key_file != NULL);
2481  g_return_if_fail (group_name != NULL);
2482 
2483  ENTER("view %p, key_file %p, group_name %s", view, key_file,
2484  group_name);
2485 
2486  g_key_file_set_integer (key_file, group_name, ACCOUNT_TYPES,
2487  fd->visible_types);
2488  g_key_file_set_boolean (key_file, group_name, SHOW_HIDDEN_ACCOUNTS,
2489  fd->show_hidden);
2490  g_key_file_set_boolean (key_file, group_name, SHOW_ZERO_TOTALS,
2491  fd->show_zero_total);
2492  g_key_file_set_boolean (key_file, group_name, SHOW_UNUSED_ACCOUNTS,
2493  fd->show_unused);
2494  LEAVE("");
2495 }
2496 
2504 static void
2505 tree_restore_expanded_row (GncTreeViewAccount *view,
2506  const gchar *account_name)
2507 {
2508  Account *account;
2509  QofBook *book;
2510 
2511  book = qof_session_get_book(gnc_get_current_session());
2512  g_return_if_fail(book);
2513  account = gnc_account_lookup_by_full_name(gnc_book_get_root_account(book),
2514  account_name);
2515  if (account)
2517 }
2518 
2519 
2527 static void
2528 tree_restore_selected_row (GncTreeViewAccount *view,
2529  const gchar *account_name)
2530 {
2531  Account *account;
2532  QofBook *book;
2533 
2534  book = qof_session_get_book(gnc_get_current_session());
2535  g_return_if_fail(book);
2536  account = gnc_account_lookup_by_full_name(gnc_book_get_root_account(book),
2537  account_name);
2538  if (account)
2540 }
2541 
2542 void
2543 gnc_tree_view_account_restore(GncTreeViewAccount *view,
2544  AccountFilterDialog *fd,
2545  GKeyFile *key_file, const gchar *group_name)
2546 {
2547  GError *error = NULL;
2548  gchar *key, *value;
2549  gint i, count;
2550  gboolean show;
2551 
2552  /* Filter information. Ignore missing keys. */
2553  show = g_key_file_get_boolean(key_file, group_name, SHOW_HIDDEN, &error);
2554  if (error)
2555  {
2556  g_warning("error reading group %s key %s: %s",
2557  group_name, SHOW_HIDDEN, error->message);
2558  g_error_free(error);
2559  error = NULL;
2560  show = TRUE;
2561  }
2562  fd->show_hidden = show;
2563 
2564  show = g_key_file_get_boolean(key_file, group_name, SHOW_ZERO, &error);
2565  if (error)
2566  {
2567  g_warning("error reading group %s key %s: %s",
2568  group_name, SHOW_ZERO, error->message);
2569  g_error_free(error);
2570  error = NULL;
2571  show = TRUE;
2572  }
2573  fd->show_zero_total = show;
2574 
2575  show = g_key_file_get_boolean(key_file, group_name, SHOW_UNUSED, &error);
2576  if (error)
2577  {
2578  g_warning("error reading group %s key %s: %s",
2579  group_name, SHOW_UNUSED, error->message);
2580  g_error_free(error);
2581  error = NULL;
2582  show = TRUE;
2583  }
2584  fd->show_unused = show;
2585 
2586  i = g_key_file_get_integer(key_file, group_name, ACCT_TYPES, &error);
2587  if (error)
2588  {
2589  g_warning("error reading group %s key %s: %s",
2590  group_name, ACCT_TYPES, error->message);
2591  g_error_free(error);
2592  error = NULL;
2593  i = -1;
2594  }
2595  fd->visible_types = i;
2596 
2597  /* Expanded accounts. Skip if count key missing. */
2598  count = g_key_file_get_integer(key_file, group_name, ACCT_COUNT, &error);
2599  if (error == NULL)
2600  {
2601  for (i = 1; i <= count; i++)
2602  {
2603  key = g_strdup_printf(ACCT_OPEN, i);
2604  value = g_key_file_get_string(key_file, group_name, key, &error);
2605  if (error)
2606  {
2607  g_warning("error reading group %s key %s: %s",
2608  group_name, key, error->message);
2609  g_error_free(error);
2610  error = NULL;
2611  }
2612  else
2613  {
2614  tree_restore_expanded_row(view, value);
2615  g_free(value);
2616  }
2617  g_free(key);
2618  }
2619  }
2620  else
2621  {
2622  g_warning("error reading group %s key %s: %s",
2623  group_name, ACCT_COUNT, error->message);
2624  g_error_free(error);
2625  }
2626 
2627  /* Selected account (if any) */
2628  value = g_key_file_get_string(key_file, group_name, ACCT_SELECTED, NULL);
2629  if (value)
2630  {
2631  tree_restore_selected_row(view, value);
2632  g_free(value);
2633  }
2634 
2635  /* Update tree view for any changes */
2637 }
2638 
2639 void
2640 gnc_tree_view_account_restore_filter (GncTreeViewAccount *view,
2641  AccountFilterDialog *fd,
2642  GKeyFile *key_file,
2643  const gchar *group_name)
2644 {
2645  GError *error = NULL;
2646  gint i;
2647  gboolean show;
2648 
2649  g_return_if_fail (key_file != NULL);
2650  g_return_if_fail (group_name != NULL);
2651 
2652  /* if entry not found, filter will use the default setting */
2653 
2654  /* Filter information. Ignore missing keys. */
2655  show = g_key_file_get_boolean (key_file, group_name, SHOW_HIDDEN_ACCOUNTS, &error);
2656  if (error)
2657  {
2658  g_error_free (error);
2659  error = NULL;
2660  }
2661  else
2662  fd->show_hidden = show;
2663 
2664  show = g_key_file_get_boolean(key_file, group_name, SHOW_ZERO_TOTALS, &error);
2665  if (error)
2666  {
2667  g_error_free (error);
2668  error = NULL;
2669  }
2670  else
2671  fd->show_zero_total = show;
2672 
2673  show = g_key_file_get_boolean(key_file, group_name, SHOW_UNUSED_ACCOUNTS, &error);
2674  if (error)
2675  {
2676  g_error_free (error);
2677  error = NULL;
2678  }
2679  else
2680  fd->show_unused = show;
2681 
2682  i = g_key_file_get_integer(key_file, group_name, ACCOUNT_TYPES, &error);
2683  if (error)
2684  {
2685  g_error_free (error);
2686  error = NULL;
2687  }
2688  else
2689  fd->visible_types = i;
2690 }
2691 
2692 // @@fixme -- factor this app-not-gui-specific-logic out.
2693 void
2694 gnc_tree_view_account_name_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_name)
2695 {
2696  // check for accounts with the same name among our parent's children.
2697  // should probably factor this consistency check out to the account
2698  // itself....
2699  {
2700  Account *parent = gnc_account_get_parent(account);
2701  Account *existing = gnc_account_lookup_by_name(parent, new_name);
2702  if (existing != NULL && existing != account)
2703  {
2704  PERR("account with the same name [%s] already exists.", new_name);
2705  return;
2706  }
2707  }
2708  xaccAccountSetName(account, new_name);
2709 }
2710 
2711 void
2712 gnc_tree_view_account_code_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_code)
2713 {
2714  if (g_strcmp0(xaccAccountGetCode(account), new_code) == 0)
2715  return;
2716  xaccAccountSetCode(account, new_code);
2717 }
2718 
2719 void
2720 gnc_tree_view_account_description_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_desc)
2721 {
2722  if (g_strcmp0(xaccAccountGetDescription(account), new_desc) == 0)
2723  return;
2724  xaccAccountSetDescription(account, new_desc);
2725 }
2726 
2727 void
2728 gnc_tree_view_account_notes_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_notes)
2729 {
2730  if (g_strcmp0(xaccAccountGetNotes(account), new_notes) == 0)
2731  return;
2732  xaccAccountSetNotes(account, new_notes);
2733 }
2734 
2735 static void
2736 gtva_set_column_editor(GncTreeViewAccount *view,
2737  GtkTreeViewColumn *column,
2738  GncTreeViewAccountColumnTextEdited edited_cb)
2739 {
2740  GList *renderers_orig, *renderers;
2741  GtkCellRenderer *renderer = NULL;
2742 
2743  // look for the first text-renderer; on the 0th column of the account tree,
2744  // there are two renderers: pixbuf and text. So find the text one.
2745  for (renderers_orig = renderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
2746  renderers && !GTK_IS_CELL_RENDERER_TEXT(renderers->data);
2747  renderers = renderers->next);
2748  if (renderers)
2749  renderer = GTK_CELL_RENDERER(renderers->data);
2750  g_list_free(renderers_orig);
2751  g_return_if_fail(renderer != NULL);
2752  gtva_setup_column_renderer_edited_cb(GNC_TREE_VIEW_ACCOUNT(view), column, renderer, edited_cb);
2753 }
2754 
2755 void
2756 gnc_tree_view_account_set_name_edited(GncTreeViewAccount *view,
2757  GncTreeViewAccountColumnTextEdited edited_cb)
2758 {
2759  gtva_set_column_editor(view, view->name_column, edited_cb);
2760 }
2761 
2762 void
2763 gnc_tree_view_account_set_code_edited(GncTreeViewAccount *view,
2764  GncTreeViewAccountColumnTextEdited edited_cb)
2765 {
2766  gtva_set_column_editor(view, view->code_column, edited_cb);
2767 }
2768 
2769 void
2770 gnc_tree_view_account_set_description_edited(GncTreeViewAccount *view,
2771  GncTreeViewAccountColumnTextEdited edited_cb)
2772 {
2773  gtva_set_column_editor(view, view->desc_column, edited_cb);
2774 }
2775 
2776 void
2777 gnc_tree_view_account_set_notes_edited(GncTreeViewAccount *view,
2778  GncTreeViewAccountColumnTextEdited edited_cb)
2779 {
2780  gtva_set_column_editor(view, view->notes_column, edited_cb);
2781 }
2782 
2783 static
2784 gboolean gnc_tree_view_search_compare (GtkTreeModel *model, gint column,
2785  const gchar *key, GtkTreeIter *iter, gpointer search_data)
2786 {
2787  gchar *normalized_key;
2788  gchar *case_normalized_key = NULL;
2789  gboolean match = FALSE;
2790 
2791  normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_NFC);
2792  if (normalized_key)
2793  case_normalized_key = g_utf8_casefold (normalized_key, -1);
2794  if (case_normalized_key)
2795  {
2796  int i;
2797 
2798  for (i=0;i<3;i++)
2799  {
2800  gchar *normalized_string;
2801  gchar *case_normalized_string = NULL;
2802  gchar *str = NULL;
2803 
2804  switch (i)
2805  {
2806  case 0:
2807  gtk_tree_model_get(model,iter,GNC_TREE_MODEL_ACCOUNT_COL_NAME,&str,-1);
2808  break;
2809  case 1:
2810  gtk_tree_model_get(model,iter,GNC_TREE_MODEL_ACCOUNT_COL_CODE,&str,-1);
2811  break;
2812  case 2:
2813  gtk_tree_model_get(model,iter,GNC_TREE_MODEL_ACCOUNT_COL_DESCRIPTION,&str,-1);
2814  break;
2815  }
2816 
2817  if (!str)
2818  continue;
2819 
2820  normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_NFC);
2821  if (normalized_string)
2822  case_normalized_string = g_utf8_casefold (normalized_string, -1);
2823  if (case_normalized_string&&NULL!=strstr(case_normalized_string,case_normalized_key))
2824  match=TRUE;
2825 
2826  g_free (str);
2827  g_free (normalized_string);
2828  g_free (case_normalized_string);
2829 
2830  if (match)
2831  break;
2832  }
2833  }
2834 
2835  g_free (normalized_key);
2836  g_free (case_normalized_key);
2837 
2838  // inverted return (FALSE means a match)
2839  return !match;
2840 }
2841 
2842 void gnc_tree_view_account_set_editing_started_cb(GncTreeViewAccount *view,
2843  GFunc editing_started_cb, gpointer editing_cb_data)
2844 {
2845  gnc_tree_view_set_editing_started_cb (GNC_TREE_VIEW(view),
2846  editing_started_cb, editing_cb_data);
2847 }
2848 
2850  GFunc editing_finished_cb, gpointer editing_cb_data)
2851 {
2852  gnc_tree_view_set_editing_finished_cb (GNC_TREE_VIEW(view),
2853  editing_finished_cb, editing_cb_data);
2854 }
2855 
2856 
2857 static gboolean
2858 gnc_tree_view_tooltip_cb (GtkWidget *widget, gint x, gint y, gboolean keyboard_tip,
2859  GtkTooltip *tooltip, gpointer user_data)
2860 {
2861  GtkTreeView *tree_view = GTK_TREE_VIEW(widget);
2862  GtkTreePath *path = NULL;
2863  GtkTreeViewColumn *column = NULL;
2864  gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y, &x, &y);
2865  if (keyboard_tip || !gtk_tree_view_get_path_at_pos (tree_view, x, y, &path,
2866  &column, NULL, NULL))
2867  {
2868  gtk_tree_path_free (path);
2869  return false;
2870  }
2871 
2872  // Get the iter pointing to our current column
2873  gboolean show_tooltip = false;
2874  GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
2875  GtkTreeIter iter;
2876  if (gtk_tree_model_get_iter (model, &iter, path) && column)
2877  {
2878  gchar *ttip = NULL;
2879 
2880  // Select text based on column
2881  switch (gtk_tree_view_column_get_sort_column_id (column))
2882  {
2883  case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_LIMIT:
2884  gtk_tree_model_get (model, &iter,
2885  GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_LIMIT_EXPLANATION, &ttip,
2886  -1);
2887  break;
2888  default:
2889  break;
2890  }
2891 
2892  // Did we select any text? If yes, display the tooltip
2893  if (ttip && *ttip)
2894  {
2895  show_tooltip = true;
2896  gtk_tooltip_set_text (tooltip, ttip);
2897  gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, column, NULL);
2898  }
2899  g_free (ttip);
2900  }
2901 
2902  // Clean up the object
2903  gtk_tree_path_free (path);
2904  return show_tooltip;
2905 }
Account * gnc_account_get_parent(const Account *acc)
This routine returns a pointer to the parent of the specified account.
Definition: Account.cpp:2875
void gnc_tree_view_account_get_view_info(GncTreeViewAccount *view, AccountViewInfo *avi)
Given pointers to an account tree and old style filter block, this function will copy the current con...
GtkTreeViewColumn * gnc_tree_view_account_add_property_column(GncTreeViewAccount *view, const gchar *column_title, const gchar *propname)
Add a new column to the set of columns in an account tree view.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
The instance data structure for a content plugin.
const GList * gnc_gobject_tracking_get_list(const gchar *name)
Get a list of all known objects of a specified type.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
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
GList * gnc_tree_view_account_get_selected_accounts(GncTreeViewAccount *view)
This function returns a list of the accounts associated with the selected items in the account tree v...
Account * gnc_tree_view_account_get_cursor_account(GncTreeViewAccount *view)
This function returns the account in the account tree view at the current location of the cursor...
void xaccAccountSetNotes(Account *acc, const char *str)
Set the account&#39;s notes.
Definition: Account.cpp:2584
void gnc_tree_view_account_set_editing_finished_cb(GncTreeViewAccount *view, GFunc editing_finished_cb, gpointer editing_cb_data)
Setup the callback for when the user finishes editing the account tree so actions can be enabled like...
int safe_utf8_collate(const char *da, const char *db)
Collate two UTF-8 strings.
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3226
void gnc_tree_view_set_editing_started_cb(GncTreeView *view, GFunc editing_started_cb, gpointer editing_cb_data)
Setup a callback for when the user starts editing so appropriate actions can be taken like disable th...
void gppat_filter_response_cb(GtkWidget *dialog, gint response, AccountFilterDialog *fd)
The Filter dialog was closed.
const char * xaccAccountGetCode(const Account *acc)
Get the account&#39;s accounting code.
Definition: Account.cpp:3303
STRUCTS.
common utilities for manipulating a GtkTreeView within gnucash
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
const gchar * gnc_plugin_page_get_page_name(GncPluginPage *page)
Retrieve the name of this page.
Account * gnc_tree_model_account_get_account(GncTreeModelAccount *model, GtkTreeIter *iter)
Convert a model/iter pair to a gnucash account.
void xaccAccountSetCode(Account *acc, const char *str)
Set the account&#39;s accounting code.
Definition: Account.cpp:2459
void gppat_filter_select_all_cb(GtkWidget *button, AccountFilterDialog *fd)
The "select all account types" button in the Filter dialog was clicked.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
stop here; the following types just aren&#39;t ready for prime time
Definition: Account.h:161
void gnc_tree_view_account_expand_to_account(GncTreeViewAccount *view, Account *account)
This function forces the account tree expand whatever levels are necessary to make the specified acco...
void gnc_tree_view_account_column_add_color(GncTreeViewAccount *view, GtkTreeViewColumn *col)
Add the account color background data function to the GncTreeViewAccount column to show or not the co...
void gnc_tree_view_account_set_view_info(GncTreeViewAccount *view, AccountViewInfo *avi)
Given pointers to an account tree and old style filter block, this function will applies the settings...
void gnc_tree_view_set_show_column_menu(GncTreeView *view, gboolean visible)
This function is called to set the "show-column-menu" property on this view.
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
void gppat_filter_clear_all_cb(GtkWidget *button, AccountFilterDialog *fd)
The "clear all account types" button in the Filter dialog was clicked.
void gnc_tree_view_account_set_editing_started_cb(GncTreeViewAccount *view, GFunc editing_started_cb, gpointer editing_cb_data)
Setup the callback for when the user starts editing the account tree so actions can be disabled like ...
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
GtkTreeViewColumn * gnc_tree_view_add_numeric_column(GncTreeView *view, const gchar *column_title, const gchar *pref_name, const gchar *sizing_text, gint model_data_column, gint model_color_column, gint model_visibility_column, GtkTreeIterCompareFunc column_sort_fn)
This function adds a new numeric column to a GncTreeView base view.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gboolean gnc_tree_model_account_get_iter_from_account(GncTreeModelAccount *model, Account *account, GtkTreeIter *iter)
Convert a model/account pair into a gtk_tree_model_iter.
gnc_commodity * gnc_default_report_currency(void)
Return the default currency for use in reports, as set by the user.
void gnc_tree_view_account_set_selected_accounts(GncTreeViewAccount *view, GList *account_list, gboolean show_last)
This function selects a set of accounts in the account tree view.
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
void gppat_filter_show_hidden_toggled_cb(GtkToggleButton *button, AccountFilterDialog *fd)
The "show hidden" button in the Filter dialog changed state.
gboolean xaccAccountIsHidden(const Account *acc)
Should this account be "hidden".
Definition: Account.cpp:4289
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
The gnc_account_lookup_by_name() subroutine fetches the account by name from the descendants of the s...
Definition: Account.cpp:3052
int xaccAccountOrder(const Account *aa, const Account *ab)
The xaccAccountOrder() subroutine defines a sorting order on accounts.
Definition: Account.cpp:2356
gint gnc_tree_view_append_column(GncTreeView *view, GtkTreeViewColumn *column)
Add a column to a view based upon a GncTreeView.
GtkTreeModel implementation for gnucash account tree.
GtkTreeViewColumn * gnc_tree_view_add_pix_column(GncTreeView *view, const gchar *column_title, const gchar *pref_name, const gchar *sizing_text, gint model_data_column, gint model_visibility_column, GtkTreeIterCompareFunc column_sort_fn)
This function adds a new pixbuf view column to a GncTreeView base view.
GtkTreeViewColumn * gnc_tree_view_add_toggle_column(GncTreeView *view, const gchar *column_title, const gchar *column_short_title, const gchar *pref_name, gint model_data_column, gint model_visibility_column, GtkTreeIterCompareFunc column_sort_fn, renderer_toggled toggle_edited_cb)
This function adds a new toggle column to a GncTreeView base view.
void gnc_tree_view_set_editing_finished_cb(GncTreeView *view, GFunc editing_finished_cb, gpointer editing_cb_data)
Setup a callback for when the user finishes editing so appropriate actions can be taken like enable t...
void gnc_tree_view_account_set_filter(GncTreeViewAccount *view, gnc_tree_view_account_filter_func func, gpointer data, GSourceFunc destroy)
This function attaches a filter function to the given account tree.
GtkCellRenderer * gnc_tree_view_column_get_renderer(GtkTreeViewColumn *column)
Return the "main" cell renderer from a GtkTreeViewColumn added to a GncTreeView my one of the conveni...
QofBook * qof_session_get_book(const QofSession *session)
Returns the QofBook of this session.
Definition: qofsession.cpp:574
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3255
GtkTreeViewColumn * gnc_tree_view_add_text_view_column(GncTreeView *view, const gchar *column_title, const gchar *pref_name, const gchar *icon_name, const gchar *sizing_text, gint model_data_column, gint model_visibility_column, GtkTreeIterCompareFunc column_sort_fn)
This function adds a new text view column to a GncTreeView base view.
void gnc_tree_model_account_clear_cache(GncTreeModelAccount *model)
Clear the tree model account cached values.
Account handling public routines.
void gnc_tree_view_account_select_subaccounts(GncTreeViewAccount *view, Account *account)
This function selects all sub-accounts of an account in the account tree view.
void xaccAccountSetPlaceholder(Account *acc, gboolean val)
Set the "placeholder" flag for an account.
Definition: Account.cpp:4199
void gnc_tree_view_account_refilter(GncTreeViewAccount *view)
This function forces the account tree filter to be evaluated.
Gobject helper routines.
GtkTreeView implementation for gnucash account tree.
GtkTreeModel * gnc_tree_model_account_new(Account *root)
Create a new GtkTreeModel for manipulating gnucash accounts.
GtkTreeViewColumn * gnc_tree_view_account_add_custom_column(GncTreeViewAccount *account_view, const gchar *column_title, GncTreeViewAccountColumnSource col_source_cb, GncTreeViewAccountColumnTextEdited col_edited_cb)
Add a new custom column to the set of columns in an account tree view.
GtkTreeView * gnc_tree_view_account_new_with_root(Account *root, gboolean show_root)
Create a new account tree view.
const char * xaccAccountGetDescription(const Account *acc)
Get the account&#39;s description.
Definition: Account.cpp:3310
GtkTreeView * gnc_tree_view_account_new(gboolean show_root)
Create a new account tree view.
void gnc_tree_view_configure_columns(GncTreeView *view)
Make all the correct columns visible, respecting their default visibility setting, their "always" visibility setting, and the last saved state if available.
General utilities for dealing with accounting periods.
gboolean gnc_plugin_page_account_tree_filter_accounts(Account *account, gpointer user_data)
This function tells the account tree view whether or not to filter out a particular account...
void gnc_tree_view_account_clear_model_cache(GncTreeViewAccount *view)
This function clears the tree model account cache so the values will be updated/refreshed.
Account * gnc_tree_view_account_get_account_from_iter(GtkTreeModel *s_model, GtkTreeIter *s_iter)
This function returns the account associated with the specified iter.
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
Retrieve the full name for the specified commodity.
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
The gnc_account_lookup_full_name() subroutine works like gnc_account_lookup_by_name, but uses fully-qualified names using the given separator.
Definition: Account.cpp:3122
Account * gnc_tree_view_account_get_account_from_path(GncTreeViewAccount *view, GtkTreePath *s_path)
This function returns the account associated with the specified path.
All type declarations for the whole Gnucash engine.
gboolean xaccAccountGetReconcileLastDate(const Account *acc, time64 *last_date)
DOCUMENT ME!
Definition: Account.cpp:4653
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed...
Definition: Account.h:101
gboolean xaccAccountGetHidden(const Account *acc)
Get the "hidden" flag for an account.
Definition: Account.cpp:4277
GtkTreeModel implementation to display account types in a GtkTreeView.
GLib helper routines.
Generic api to store and retrieve preferences.
gboolean xaccAccountGetIsOpeningBalance(const Account *acc)
Get the "opening-balance" flag for an account.
Definition: Account.cpp:4217
void gnc_tree_view_account_set_selected_account(GncTreeViewAccount *view, Account *account)
This function selects an account in the account tree view.
void gppat_filter_show_unused_toggled_cb(GtkToggleButton *button, AccountFilterDialog *fd)
The "show unused" button in the Filter dialog changed state.
void xaccAccountSetHidden(Account *acc, gboolean val)
Set the "hidden" flag for an account.
Definition: Account.cpp:4283
gint gnc_tree_view_account_count_children(GncTreeViewAccount *view, Account *account)
This function determines if an account in the account tree view has any visible children.
GtkTreePath * gnc_tree_model_account_get_path_from_account(GncTreeModelAccount *model, Account *account)
Convert a model/account pair into a gtk_tree_model_path.
GtkTreeViewColumn * gnc_tree_view_add_text_column(GncTreeView *view, const gchar *column_title, const gchar *pref_name, const gchar *icon_name, const gchar *sizing_text, gint model_data_column, gint model_visibility_column, GtkTreeIterCompareFunc column_sort_fn)
This function adds a new text column to a GncTreeView base view.
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4193
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
Account * gnc_tree_view_account_get_selected_account(GncTreeViewAccount *view)
This function returns the account associated with the selected item in the account tree view...
gboolean(* gnc_tree_view_account_filter_func)(Account *account, gpointer data)
This is the description of a filter function used by the account tree.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void xaccAccountSetDescription(Account *acc, const char *str)
Set the account&#39;s description.
Definition: Account.cpp:2478
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3248
const char * xaccAccountGetTypeStr(GNCAccountType type)
The xaccAccountGetTypeStr() routine returns a string suitable for use in the GUI/Interface.
Definition: Account.cpp:4444
void xaccAccountSetName(Account *acc, const char *str)
Set the account&#39;s name.
Definition: Account.cpp:2439
The hidden root account of an account tree.
Definition: Account.h:153
Commodity handling public routines.
The Credit card account is used to denote credit (e.g.
Definition: Account.h:113
void gppat_filter_select_default_cb(GtkWidget *button, AccountFilterDialog *fd)
The "select default account types" button in the Filter dialog was clicked.
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
const char * xaccAccountGetNotes(const Account *acc)
Get the account&#39;s notes.
Definition: Account.cpp:3357
void gppat_filter_show_zero_toggled_cb(GtkToggleButton *button, AccountFilterDialog *fd)
The "show zero totals" button in the Filter dialog changed state.