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