GnuCash  4.11-627-g58c1a51897
gnc-tree-view.c
Go to the documentation of this file.
1 /*
2  * gnc-tree-view.c -- new GtkTreeView with extra features used by
3  * all the tree views in gnucash
4  *
5  * Copyright (C) 2003,2005 David Hampton <hampton@employees.org>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, contact:
19  *
20  * Free Software Foundation Voice: +1-617-542-5942
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
22  * Boston, MA 02110-1301, USA gnu@gnu.org
23  */
24 
34 #include <config.h>
35 
36 #include <gtk/gtk.h>
37 #include <glib/gi18n.h>
38 #include <gdk/gdkkeysyms.h>
39 #include <string.h>
40 
41 #include "gnc-tree-view.h"
42 #include "gnc-engine.h"
43 #include "gnc-gnome-utils.h"
44 #include "gnc-gobject-utils.h"
45 #include "gnc-cell-renderer-date.h"
46 #include "gnc-cell-renderer-text-view.h"
47 #include "gnc-state.h"
48 #include "gnc-prefs.h"
49 #include "dialog-utils.h"
50 
51 /* The actual state key for a particular column visibility. This is
52  * attached to the menu items that are in the column selection menu.
53  * Makes it very easy to update saved state when a menu item is toggled. */
54 #define STATE_KEY "state-key"
55 
56 /* State keys within this particular saved state section. */
57 #define STATE_KEY_SORT_COLUMN "sort_column"
58 #define STATE_KEY_SORT_ORDER "sort_order"
59 #define STATE_KEY_COLUMN_ORDER "column_order"
60 
61 /* Partial state keys within this particular saved state section. These
62  are appended to the various column names to create the actual
63  keys. */
64 #define STATE_KEY_SUFF_VISIBLE "visible"
65 #define STATE_KEY_SUFF_WIDTH "width"
66 
67 enum
68 {
69  PROP_0,
70  PROP_STATE_SECTION,
71  PROP_SHOW_COLUMN_MENU,
72 };
73 
76 /* This static indicates the debugging module that this .o belongs to. */
77 static QofLogModule log_module = GNC_MOD_GUI;
78 
79 /**** Declarations ******************************************************/
80 static void gnc_tree_view_class_init (GncTreeViewClass *klass);
81 static void gnc_tree_view_init (GncTreeView *view, void *data);
82 static void gnc_tree_view_finalize (GObject *object);
83 static void gnc_tree_view_destroy (GtkWidget *widget);
84 static void gnc_tree_view_set_property (GObject *object,
85  guint prop_id,
86  const GValue *value,
87  GParamSpec *pspec);
88 static void gnc_tree_view_get_property (GObject *object,
89  guint prop_id,
90  GValue *value,
91  GParamSpec *pspec);
92 static gboolean gnc_tree_view_drop_ok_cb (GtkTreeView *view,
93  GtkTreeViewColumn *column,
94  GtkTreeViewColumn *prev_column,
95  GtkTreeViewColumn *next_column,
96  gpointer data);
97 static void gnc_tree_view_build_column_menu (GncTreeView *view);
98 static void gnc_tree_view_select_column_cb (GtkTreeViewColumn *column,
99  GncTreeView *view);
100 static gchar *gnc_tree_view_get_sort_order (GncTreeView *view);
101 static gchar *gnc_tree_view_get_sort_column (GncTreeView *view);
102 static gchar **gnc_tree_view_get_column_order (GncTreeView *view,
103  gsize *length);
104 
107 typedef struct GncTreeViewPrivate
108 {
109  /* Column selection menu related values */
110  GtkTreeViewColumn *column_menu_column;
111  GtkWidget *column_menu;
112  gboolean show_column_menu;
113  GtkWidget *column_menu_icon_box;
114 
115  /* Sort callback model */
116  GtkTreeModel *sort_model;
117 
118  /* Editing callback functions */
119  GFunc editing_started_cb;
120  GFunc editing_finished_cb;
121  gpointer editing_cb_data;
122 
123  /* State related values */
124  gchar *state_section;
125  gboolean seen_state_visibility;
126  gulong columns_changed_cb_id;
127  gulong sort_column_changed_cb_id;
128  gulong size_allocate_cb_id;
130 
131 GNC_DEFINE_TYPE_WITH_CODE(GncTreeView, gnc_tree_view, GTK_TYPE_TREE_VIEW,
132  G_ADD_PRIVATE(GncTreeView))
133 
134 #define GNC_TREE_VIEW_GET_PRIVATE(o) \
135  ((GncTreeViewPrivate*)gnc_tree_view_get_instance_private((GncTreeView*)o))
136 
137 
138 /************************************************************/
139 /* g_object required functions */
140 /************************************************************/
141 
145 static GObjectClass *parent_class = NULL;
146 
156 static void
157 gnc_tree_view_class_init (GncTreeViewClass *klass)
158 {
159  GObjectClass *gobject_class;
160  GtkWidgetClass *gtkwidget_class;
161 
162  parent_class = g_type_class_peek_parent (klass);
163 
164  gobject_class = G_OBJECT_CLASS(klass);
165  gtkwidget_class = GTK_WIDGET_CLASS(klass);
166 
167  gobject_class->set_property = gnc_tree_view_set_property;
168  gobject_class->get_property = gnc_tree_view_get_property;
169 
170  g_object_class_install_property (gobject_class,
171  PROP_STATE_SECTION,
172  g_param_spec_string ("state-section",
173  "State Section",
174  "The section name in the saved state to use for (re)storing the treeview's visual state (visible columns, sort order,...",
175  NULL,
176  G_PARAM_READWRITE));
177  g_object_class_install_property (gobject_class,
178  PROP_SHOW_COLUMN_MENU,
179  g_param_spec_boolean ("show-column-menu",
180  "Show Column Menu",
181  "Show the column menu so user can change what columns are visible.",
182  FALSE,
183  G_PARAM_READWRITE));
184 
185  /* GObject signals */
186  gobject_class->finalize = gnc_tree_view_finalize;
187 
188  /* GtkWidget signals */
189  gtkwidget_class->destroy = gnc_tree_view_destroy;
190 }
191 
192 static void
193 gnc_tree_view_update_grid_lines (gpointer prefs, gchar* pref, gpointer user_data)
194 {
195  GncTreeView *view = user_data;
196  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW(view), gnc_tree_view_get_grid_lines_pref ());
197 }
198 
199 static gboolean
200 gnc_tree_view_select_column_icon_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
201 {
202  GncTreeView *view = user_data;
203  GncTreeViewPrivate *priv;
204  GtkStyleContext *stylectxt = gtk_widget_get_style_context (widget);
205  GtkBorder padding;
206 
207  // if the event button is not the right one, leave.
208  if (event->button != 1)
209  return FALSE;
210 
211  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
212 
213  gtk_style_context_get_padding (stylectxt, GTK_STATE_FLAG_NORMAL, &padding);
214 
215  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
216  {
217  if (event->x < (gtk_widget_get_allocated_width (priv->column_menu_icon_box) + padding.left))
218  gnc_tree_view_select_column_cb (priv->column_menu_column, view);
219  }
220  else
221  {
222  if (event->x > (gtk_widget_get_allocated_width (widget) -
223  (gtk_widget_get_allocated_width (priv->column_menu_icon_box) + padding.right)))
224  gnc_tree_view_select_column_cb (priv->column_menu_column, view);
225  }
226  return FALSE;
227 }
228 
238 static void
239 gnc_tree_view_init (GncTreeView *view, void *data)
240 {
241  GncTreeViewPrivate *priv;
242  GtkTreeViewColumn *column;
243  GtkWidget *sep, *icon;
244 
245  GncTreeViewClass *klass = (GncTreeViewClass*)data;
246 
247  gnc_gobject_tracking_remember (G_OBJECT(view),
248  G_OBJECT_CLASS(klass));
249 
250  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
251  priv->column_menu = NULL;
252  priv->show_column_menu = FALSE;
253  priv->sort_model = NULL;
254  priv->state_section = NULL;
255  priv->seen_state_visibility = FALSE;
256  priv->columns_changed_cb_id = 0;
257  priv->sort_column_changed_cb_id = 0;
258  priv->size_allocate_cb_id = 0;
259 
260  // Set the name for this widget so it can be easily manipulated with css
261  gtk_widget_set_name (GTK_WIDGET(view), "gnc-id-tree-view");
262 
263  /* Handle column drag and drop */
264  gtk_tree_view_set_column_drag_function (GTK_TREE_VIEW(view),
265  gnc_tree_view_drop_ok_cb, NULL, NULL);
266 
267  // Set grid lines option to preference
268  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW(view), gnc_tree_view_get_grid_lines_pref ());
269  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL, GNC_PREF_GRID_LINES_HORIZONTAL,
270  gnc_tree_view_update_grid_lines, view);
271  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL, GNC_PREF_GRID_LINES_VERTICAL,
272  gnc_tree_view_update_grid_lines, view);
273 
274  /* Create the last column which contains the column selection
275  * widget. gnc_tree_view_add_text_column will do most of the
276  * work. */
277  icon = gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
278 
279  priv->column_menu_icon_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
280  gtk_box_set_homogeneous (GTK_BOX(priv->column_menu_icon_box), FALSE);
281 
282  gtk_widget_set_margin_start (GTK_WIDGET(icon), 5);
283 
284  gtk_box_pack_end (GTK_BOX(priv->column_menu_icon_box), icon, FALSE, FALSE, 0);
285 
286  sep = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
287  gtk_box_pack_end (GTK_BOX(priv->column_menu_icon_box), sep, FALSE, FALSE, 0);
288 
289  gtk_widget_show_all (priv->column_menu_icon_box);
290 
291  column = gnc_tree_view_add_text_column (view, NULL, NULL, NULL, NULL,
292  -1, -1, NULL);
293  g_object_set (G_OBJECT(column),
294  "clickable", TRUE,
295  "widget", priv->column_menu_icon_box,
296  "alignment", 1.0,
297  "expand", TRUE,
298  (gchar *)NULL);
299 
300  priv->column_menu_column = column;
301 
302  // get the actual column button by looking at the parents of the column_menu_icon
303  {
304  GtkWidget *mybox = gtk_widget_get_parent (icon);
305  GtkWidget *walign = gtk_widget_get_parent (mybox);
306  GtkWidget *box = gtk_widget_get_parent (walign);
307  GtkWidget *button = gtk_widget_get_parent (box);
308 
309  if (!GTK_IS_BUTTON(button)) // just in case this order changes.
310  {
311  // this will fire for the whole column header
312  g_signal_connect (G_OBJECT(column), "clicked",
313  G_CALLBACK(gnc_tree_view_select_column_cb),
314  view);
315  }
316  else
317  {
318  /* this part will restrict the mouse click to just where the
319  icon is, tried using an eventbox but it would only work
320  some of the time */
321  gtk_widget_set_events (button, GDK_BUTTON_PRESS_MASK);
322 
323  g_signal_connect (G_OBJECT(button), "button_press_event",
324  G_CALLBACK(gnc_tree_view_select_column_icon_cb),
325  view);
326  }
327  }
328  gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
329 }
330 
341 static void
342 gnc_tree_view_finalize (GObject *object)
343 {
344  ENTER("view %p", object);
345  g_return_if_fail (object != NULL);
346  g_return_if_fail (GNC_IS_TREE_VIEW(object));
347 
349 
350  if (G_OBJECT_CLASS(parent_class)->finalize)
351  G_OBJECT_CLASS(parent_class)->finalize (object);
352  LEAVE(" ");
353 }
354 
366 static void
367 gnc_tree_view_destroy (GtkWidget *widget)
368 {
369  GncTreeView *view;
370  GncTreeViewPrivate *priv;
371 
372  ENTER("view %p", widget);
373  g_return_if_fail (widget != NULL);
374  g_return_if_fail (GNC_IS_TREE_VIEW(widget));
375 
376  view = GNC_TREE_VIEW(widget);
377 
378  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL, GNC_PREF_GRID_LINES_HORIZONTAL,
379  gnc_tree_view_update_grid_lines, view);
380  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL, GNC_PREF_GRID_LINES_VERTICAL,
381  gnc_tree_view_update_grid_lines, view);
382 
383  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
384 
385  if (priv->state_section)
386  {
388  }
389  g_free (priv->state_section);
390  priv->state_section = NULL;
391 
392  if (priv->column_menu)
393  {
394  DEBUG("removing column selection menu");
395  g_object_unref (priv->column_menu);
396  priv->column_menu = NULL;
397  }
398 
399  if (GTK_WIDGET_CLASS(parent_class)->destroy)
400  GTK_WIDGET_CLASS(parent_class)->destroy (widget);
401  LEAVE(" ");
402 }
403 
406 /************************************************************/
407 /* g_object other functions */
408 /************************************************************/
409 
420 static void
421 gnc_tree_view_get_property (GObject *object,
422  guint prop_id,
423  GValue *value,
424  GParamSpec *pspec)
425 {
426  GncTreeView *view = GNC_TREE_VIEW(object);
427  GncTreeViewPrivate *priv;
428 
429  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
430  switch (prop_id)
431  {
432  case PROP_STATE_SECTION:
433  g_value_set_string (value, priv->state_section);
434  break;
435  case PROP_SHOW_COLUMN_MENU:
436  g_value_set_boolean (value, priv->show_column_menu);
437  break;
438  default:
439  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
440  break;
441  }
442 }
443 
444 
453 static void
454 gnc_tree_view_set_property (GObject *object,
455  guint prop_id,
456  const GValue *value,
457  GParamSpec *pspec)
458 {
459  GncTreeView *view = GNC_TREE_VIEW(object);
460 
461  switch (prop_id)
462  {
463  case PROP_STATE_SECTION:
464  gnc_tree_view_set_state_section (view, g_value_get_string (value));
465  break;
466  case PROP_SHOW_COLUMN_MENU:
467  gnc_tree_view_set_show_column_menu (view, g_value_get_boolean (value));
468  break;
469  default:
470  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
471  break;
472  }
473 }
474 
477 /************************************************************/
478 /* Auxiliary Functions */
479 /************************************************************/
498 static GtkTreeViewColumn *
499 view_column_find_by_model_id (GncTreeView *view,
500  const gint wanted)
501 {
502  GtkTreeViewColumn *column, *found = NULL;
503  GList *column_list, *tmp;
504  gint id;
505 
506  // ENTER("view %p, name %s", view, name);
507  column_list = gtk_tree_view_get_columns (GTK_TREE_VIEW(view));
508  for (tmp = column_list; tmp; tmp = g_list_next (tmp))
509  {
510  column = tmp->data;
511  id = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), MODEL_COLUMN));
512  if (id != wanted)
513  continue;
514  found = column;
515  break;
516  }
517  g_list_free (column_list);
518 
519  // LEAVE("column %p", found);
520  return found;
521 }
522 
533 GtkTreeViewColumn *
535  const gchar *wanted)
536 {
537  GtkTreeViewColumn *column, *found = NULL;
538  GList *column_list, *tmp;
539  const gchar *name;
540 
541  // ENTER("view %p, wanted %s", view, wanted);
542  column_list = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
543  for (tmp = column_list; tmp; tmp = g_list_next (tmp))
544  {
545  column = tmp->data;
546  name = g_object_get_data (G_OBJECT(column), PREF_NAME);
547  if (!name || (strcmp(name, wanted) != 0))
548  continue;
549  found = column;
550  break;
551  }
552  g_list_free (column_list);
553 
554  // LEAVE("column %p", found);
555  return found;
556 }
557 
560 /************************************************************/
561 /* Tree Callbacks */
562 /************************************************************/
563 
592 static gboolean
593 gnc_tree_view_drop_ok_cb (GtkTreeView *view,
594  GtkTreeViewColumn *column,
595  GtkTreeViewColumn *prev_column,
596  GtkTreeViewColumn *next_column,
597  gpointer data)
598 {
599  const gchar *pref_name;
600 
601  /* Should we allow a drop at the left side of the tree view before
602  * the widget to open a new display level? I can think of cases
603  * where the user might want to do this with a checkbox column. */
604  if (prev_column == NULL)
605  return TRUE;
606 
607  /* Do not allow a drop at the right side of the tree view after the
608  * column selection widget. */
609  if (next_column == NULL)
610  return FALSE;
611 
612  /* Columns without pref names are considered fixed at the right hand
613  * side of the view. At the time of this writing, the only two are
614  * the column where the "column selection widget" is stored, and the
615  * "padding" column to the left of that where extra view space ends
616  * up. */
617  pref_name = g_object_get_data (G_OBJECT(prev_column), PREF_NAME);
618  if (!pref_name)
619  return FALSE;
620 
621  /* Everything else is allowed. */
622  return TRUE;
623 }
624 
627 /************************************************************/
628 /* State Setup / Callbacks */
629 /************************************************************/
630 
653 static gboolean
654 gnc_tree_view_column_visible (GncTreeView *view,
655  GtkTreeViewColumn *column,
656  const gchar *pref_name)
657 {
658  GncTreeViewPrivate *priv;
659  gboolean visible;
660  const gchar *col_name = pref_name;
661 
662  ENTER("column %p, name %s", column, pref_name ? pref_name : "(null)");
663  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
664  if (column)
665  {
666  if (g_object_get_data (G_OBJECT(column), ALWAYS_VISIBLE))
667  {
668  LEAVE("1, first column");
669  return TRUE;
670  }
671  col_name = g_object_get_data (G_OBJECT(column), PREF_NAME);
672  DEBUG("col_name is %s", col_name ? col_name : "(null)");
673  }
674 
675  if (!col_name)
676  {
677  LEAVE("1, no pref name");
678  return TRUE;
679  }
680 
681  /* Using saved state ? */
682  if (priv->state_section)
683  {
684  GKeyFile *state_file = gnc_state_get_current ();
685  gchar *key = g_strdup_printf ("%s_%s", col_name, STATE_KEY_SUFF_VISIBLE);
686 
687  if (g_key_file_has_key (state_file, priv->state_section, key, NULL))
688  {
689  visible = g_key_file_get_boolean (state_file, priv->state_section, key, NULL);
690  g_free (key);
691  LEAVE("%d, state defined visibility", visible);
692  return visible;
693  }
694  }
695 
696  /* Check the default columns list */
697  visible = column ?
698  (g_object_get_data (G_OBJECT(column), DEFAULT_VISIBLE) != NULL) : FALSE;
699  LEAVE("defaults says %d", visible);
700  return visible;
701 }
702 
713 static void
714 gnc_tree_view_update_visibility (GtkTreeViewColumn *column,
715  GncTreeView *view)
716 {
717  gboolean visible;
718 
719  g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN(column));
720  g_return_if_fail (GNC_IS_TREE_VIEW(view));
721 
722  ENTER(" ");
723  visible = gnc_tree_view_column_visible (view, column, NULL);
724  gtk_tree_view_column_set_visible (column, visible);
725  LEAVE("made %s", visible ? "visible" : "invisible");
726 }
727 
738 static gchar *
739 gnc_tree_view_get_sort_order (GncTreeView *view)
740 {
741  GtkTreeModel *s_model;
742  GtkSortType order;
743  gint current;
744  gchar *order_str = NULL;
745 
746  s_model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
747  if (!s_model)
748  return NULL; /* no model, so sort order doesn't make sense */
749 
750  if (!gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE(s_model),
751  &current, &order))
752  return NULL; /* Model is not sorted, return */
753 
754  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(s_model),
755  current, order);
756  order_str = g_strdup (order == GTK_SORT_ASCENDING ? "ascending" : "descending");
757  DEBUG("current sort_order is %s", order_str);
758  return order_str;
759 }
760 
770 static gchar *
771 gnc_tree_view_get_sort_column (GncTreeView *view)
772 {
773  GtkTreeModel *s_model;
774  GtkTreeViewColumn *column;
775  GtkSortType order;
776  gint current;
777  const gchar *name;
778 
779  s_model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
780  if (!s_model)
781  return NULL; /* no model -> no sort column */
782 
783  if (!gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE(s_model),
784  &current, &order))
785  return NULL; /* model not sorted */
786 
787  column = view_column_find_by_model_id (view, current);
788  if (!column)
789  return NULL; /* column not visible, can't be used for sorting */
790 
791  name = g_object_get_data (G_OBJECT(column), PREF_NAME);
792  DEBUG("current sort column is %s", name ? name : "(NULL)");
793  return g_strdup (name);
794 }
795 
796 
797 
808 static gchar **
809 gnc_tree_view_get_column_order (GncTreeView *view,
810  gsize *length)
811 {
812  const GList *tmp;
813  GList *columns;
814  gulong num_cols = 0;
815  gchar *col_names = NULL;
816  gchar **col_str_list;
817 
818  /* First, convert from names to pointers */
819  ENTER(" ");
820 
821  columns = gtk_tree_view_get_columns (GTK_TREE_VIEW(view));
822  for (tmp = columns; tmp; tmp = g_list_next(tmp))
823  {
824  GtkTreeViewColumn *column = tmp->data;
825  const gchar *name = g_object_get_data (G_OBJECT(column), PREF_NAME);
826  if (!col_names)
827  col_names = g_strdup (name);
828  else
829  {
830  gchar *col_names_prev = col_names;
831  col_names = g_strjoin (";", col_names_prev, name, NULL);
832  g_free (col_names_prev);
833  }
834  num_cols++;
835  }
836  //DEBUG ("got %lu columns: %s", num_cols, col_names);
837  col_str_list = g_strsplit (col_names, ";", 0);
838 
839  /* Clean up */
840  g_list_free (columns);
841  g_free (col_names);
842 
843  LEAVE("column order get");
844  *length = num_cols;
845  return col_str_list;
846 }
847 
858 static void
859 gnc_tree_view_set_sort_order (GncTreeView *view,
860  const gchar *name)
861 {
862  GtkTreeModel *s_model;
863  GtkSortType order = GTK_SORT_ASCENDING;
864  gint current;
865 
866  s_model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
867  if (!s_model)
868  return;
869  if (g_strcmp0 (name, "descending") == 0)
870  order = GTK_SORT_DESCENDING;
871  if (!gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE(s_model),
872  &current, NULL))
873  current = GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID;
874  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(s_model),
875  current, order);
876  DEBUG("sort_order set to %s", order == GTK_SORT_ASCENDING ? "ascending" : "descending");
877 }
878 
887 static void
888 gnc_tree_view_set_sort_column (GncTreeView *view,
889  const gchar *name)
890 {
891  GtkTreeModel *s_model;
892  GtkTreeViewColumn *column;
893  GtkSortType order;
894  gint model_column, current;
895 
896  s_model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
897  if (!s_model)
898  return;
899 
900  column = gnc_tree_view_find_column_by_name (view, name);
901  if (!column)
902  {
903  gtk_tree_sortable_set_sort_column_id (
904  GTK_TREE_SORTABLE(s_model), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
905  GTK_SORT_ASCENDING);
906  return;
907  }
908 
909  model_column =
910  GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), MODEL_COLUMN));
911  if (model_column == GNC_TREE_VIEW_COLUMN_DATA_NONE)
912  return;
913 
914  if (!gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE(s_model),
915  &current, &order))
916  order = GTK_SORT_ASCENDING;
917 
918  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(s_model),
919  model_column, order);
920  DEBUG("sort column set to %s", name);
921 }
922 
935 static void
936 gnc_tree_view_set_column_order (GncTreeView *view,
937  gchar **column_names,
938  gsize length)
939 {
940  GtkTreeViewColumn *column, *prev;
941  const GSList *tmp;
942  GSList *columns;
943  gsize idx;
944 
945  /* First, convert from names to pointers */
946  ENTER(" ");
947  columns = NULL;
948  for (idx = 0; idx < length; idx++)
949  {
950  const gchar *name = column_names [idx];
951  column = gnc_tree_view_find_column_by_name (view, name);
952  if (!column)
953  continue;
954  columns = g_slist_append (columns, column);
955  }
956 
957  /* Then reorder the columns */
958  for (prev = NULL, tmp = columns; tmp; tmp = g_slist_next (tmp))
959  {
960  column = tmp->data;
961  gtk_tree_view_move_column_after (GTK_TREE_VIEW(view), column, prev);
962  prev = column;
963  }
964 
965  /* Clean up */
966  g_slist_free (columns);
967  LEAVE("column order set");
968 }
969 
979 {
980  GncTreeViewPrivate *priv;
981  GKeyFile *state_file = gnc_state_get_current ();
982 
983  ENTER(" ");
984  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
985  if (!priv->state_section)
986  {
987  LEAVE("no state section");
988  return;
989  }
990 
991  g_key_file_remove_group (state_file, priv->state_section, NULL);
992  g_free (priv->state_section);
993  priv->state_section = NULL;
994  LEAVE(" ");
995 }
996 
1004 void
1006  const gchar *section)
1007 {
1008  GncTreeViewPrivate *priv;
1009  GKeyFile *state_file;
1010 
1011  g_return_if_fail (GNC_IS_TREE_VIEW(view));
1012 
1013  ENTER("view %p, section %s", view, section);
1014 
1015  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1016 
1017  /* Drop any previous state section */
1018  if (priv->state_section)
1020 
1021  if (!section)
1022  {
1023  LEAVE("cleared state section");
1024  return;
1025  }
1026 
1027  /* Catch changes in state. Propagate to view. */
1028  priv->state_section = g_strdup (section);
1029 
1030  state_file = gnc_state_get_current ();
1031  if (g_key_file_has_group (state_file, priv->state_section))
1032  {
1033  gsize num_keys, idx;
1034  gchar **keys = g_key_file_get_keys (state_file, priv->state_section, &num_keys, NULL);
1035  for (idx = 0; idx < num_keys; idx++)
1036  {
1037  gchar *key = keys[idx];
1038  if (g_strcmp0 (key, STATE_KEY_SORT_COLUMN) == 0)
1039  {
1040  gchar *name = g_key_file_get_string (state_file, priv->state_section,
1041  key, NULL);
1042  gnc_tree_view_set_sort_column (view, name);
1043  g_free (name);
1044  }
1045  else if (g_strcmp0 (key, STATE_KEY_SORT_ORDER) == 0)
1046  {
1047  gchar *name = g_key_file_get_string (state_file, priv->state_section,
1048  key, NULL);
1049  gnc_tree_view_set_sort_order (view, name);
1050  g_free (name);
1051  }
1052  else if (g_strcmp0 (key, STATE_KEY_COLUMN_ORDER) == 0)
1053  {
1054  gsize length;
1055  gchar **columns = g_key_file_get_string_list (state_file, priv->state_section,
1056  key, &length, NULL);
1057  gnc_tree_view_set_column_order (view, columns, length);
1058  g_strfreev (columns);
1059  }
1060  else
1061  {
1062  /* Make a copy of the local part of the key so it can be split
1063  * into column name and key type */
1064  gboolean known = FALSE;
1065  gchar *column_name = g_strdup (key);
1066  gchar *type_name = g_strrstr (column_name, "_");
1067 
1068  if (type_name != NULL) //guard against not finding '_'
1069  {
1070  *type_name++ = '\0';
1071 
1072  if (g_strcmp0 (type_name, STATE_KEY_SUFF_VISIBLE) == 0)
1073  {
1074  GtkTreeViewColumn *column = gnc_tree_view_find_column_by_name (view, column_name);
1075  if (column)
1076  {
1077  known = TRUE;
1078  if (!g_object_get_data (G_OBJECT (column), ALWAYS_VISIBLE))
1079  {
1080  gtk_tree_view_column_set_visible (column,
1081  g_key_file_get_boolean (state_file, priv->state_section, key, NULL));
1082  }
1083  }
1084  }
1085  else if (g_strcmp0 (type_name, STATE_KEY_SUFF_WIDTH) == 0)
1086  {
1087  gint width = g_key_file_get_integer (state_file, priv->state_section, key, NULL);
1088  GtkTreeViewColumn *column = gnc_tree_view_find_column_by_name (view, column_name);
1089  if (column)
1090  {
1091  known = TRUE;
1092  if (width && (width != gtk_tree_view_column_get_width (column)))
1093  {
1094  gtk_tree_view_column_set_fixed_width (column, width);
1095  }
1096  }
1097  }
1098  if (!known)
1099  DEBUG ("Ignored key %s", key);
1100 
1101  g_free (column_name);
1102  }
1103  }
1104  }
1105  g_strfreev (keys);
1106  }
1107 
1108  /* Rebuild the column visibility menu */
1109  gnc_tree_view_build_column_menu (view);
1110  LEAVE ("set state section");
1111 }
1112 
1119 const gchar *
1121 {
1122  GncTreeViewPrivate *priv;
1123 
1124  g_return_val_if_fail (GNC_IS_TREE_VIEW(view), NULL);
1125 
1126  priv = GNC_TREE_VIEW_GET_PRIVATE (view);
1127  return priv->state_section;
1128 }
1129 
1131 {
1132  GncTreeViewPrivate *priv;
1133 
1134  ENTER("view %p", view);
1135  g_return_if_fail (view != NULL);
1136  g_return_if_fail (GNC_IS_TREE_VIEW(view));
1137 
1138  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1139 
1140  if (priv->state_section)
1141  {
1142  /* Save state. Only store non-default values when possible. */
1143  GList *column_list, *tmp;
1144  GKeyFile *state_file = gnc_state_get_current();
1145  gsize num_cols = 0;
1146  gchar *sort_column = gnc_tree_view_get_sort_column (view);
1147  gchar *sort_order = gnc_tree_view_get_sort_order (view);
1148  gchar **col_order = gnc_tree_view_get_column_order (view, &num_cols);
1149 
1150  /* Default sort column is the name column */
1151  if (sort_column && (g_strcmp0 (sort_column, "name") != 0))
1152  g_key_file_set_string (state_file, priv->state_section, STATE_KEY_SORT_COLUMN, sort_column);
1153  else if (g_key_file_has_key (state_file, priv->state_section, STATE_KEY_SORT_COLUMN, NULL))
1154  g_key_file_remove_key (state_file, priv->state_section, STATE_KEY_SORT_COLUMN, NULL);
1155  g_free (sort_column);
1156 
1157 
1158  /* Default sort order is "ascending" */
1159  if (g_strcmp0 (sort_order, "descending") == 0)
1160  g_key_file_set_string (state_file, priv->state_section, STATE_KEY_SORT_ORDER, sort_order);
1161  else if (g_key_file_has_key (state_file, priv->state_section, STATE_KEY_SORT_ORDER, NULL))
1162  g_key_file_remove_key (state_file, priv->state_section, STATE_KEY_SORT_ORDER, NULL);
1163  g_free (sort_order);
1164 
1165  if (col_order && (num_cols > 0))
1166  g_key_file_set_string_list (state_file, priv->state_section, STATE_KEY_COLUMN_ORDER,
1167  (const gchar**) col_order, num_cols);
1168  else if (g_key_file_has_key (state_file, priv->state_section, STATE_KEY_COLUMN_ORDER, NULL))
1169  g_key_file_remove_key (state_file, priv->state_section, STATE_KEY_COLUMN_ORDER, NULL);
1170 
1171  g_strfreev (col_order);
1172 
1173 
1174  // ENTER("view %p, wanted %s", view, wanted);
1175  column_list = gtk_tree_view_get_columns (GTK_TREE_VIEW(view));
1176  for (tmp = column_list; tmp; tmp = g_list_next (tmp))
1177  {
1178  GtkTreeViewColumn *column = tmp->data;
1179  gchar *key=NULL;
1180  const gchar *name = g_object_get_data (G_OBJECT(column), PREF_NAME);
1181  if (!name)
1182  continue;
1183 
1184  if (!g_object_get_data (G_OBJECT(column), ALWAYS_VISIBLE))
1185  {
1186  key = g_strjoin ("_", name, STATE_KEY_SUFF_VISIBLE, NULL);
1187  g_key_file_set_boolean (state_file, priv->state_section, key,
1188  gtk_tree_view_column_get_visible (column));
1189  g_free (key);
1190  }
1191 
1192  key = g_strjoin ("_", name, STATE_KEY_SUFF_WIDTH, NULL);
1193  if (g_object_get_data (G_OBJECT(column), "default-width") &&
1194  (GPOINTER_TO_INT((g_object_get_data (G_OBJECT(column), "default-width")))
1195  != gtk_tree_view_column_get_width (column)))
1196  {
1197  g_key_file_set_integer (state_file, priv->state_section, key,
1198  gtk_tree_view_column_get_width (column));
1199  }
1200  else if (g_key_file_has_key (state_file, priv->state_section, key, NULL))
1201  g_key_file_remove_key (state_file, priv->state_section, key, NULL);
1202  g_free (key);
1203  }
1204  g_list_free (column_list);
1205  }
1206 
1207  LEAVE(" ");
1208 }
1209 
1210 
1213 /************************************************************/
1214 /* Column Selection Menu */
1215 /************************************************************/
1216 
1235 static void
1236 gnc_tree_view_create_menu_item (GtkTreeViewColumn *column,
1237  GncTreeView *view)
1238 {
1239  GncTreeViewPrivate *priv;
1240  GtkWidget *widget;
1241  const gchar *column_name, *pref_name;
1242  gchar *key;
1243  GBinding *binding;
1244 
1245  // ENTER("view %p, column %p", view, column);
1246  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1247  if (!priv->state_section)
1248  {
1249  // LEAVE("no state section");
1250  return;
1251  }
1252 
1253  pref_name = g_object_get_data (G_OBJECT(column), PREF_NAME);
1254  if (!pref_name)
1255  {
1256  // LEAVE("column has no pref_name");
1257  return;
1258  }
1259 
1260  /* Create the menu if we don't have one already */
1261  if (!priv->column_menu)
1262  {
1263  priv->column_menu = gtk_menu_new();
1264  g_object_ref_sink (priv->column_menu);
1265  }
1266 
1267  /* Create the check menu item */
1268  column_name = g_object_get_data (G_OBJECT(column), REAL_TITLE);
1269  if (!column_name)
1270  column_name = gtk_tree_view_column_get_title (column);
1271  widget = gtk_check_menu_item_new_with_label (column_name);
1272  gtk_menu_shell_append (GTK_MENU_SHELL(priv->column_menu), widget);
1273 
1274  /* Should never be able to hide the first column */
1275  if (g_object_get_data (G_OBJECT(column), ALWAYS_VISIBLE))
1276  {
1277  g_object_set_data (G_OBJECT(widget), ALWAYS_VISIBLE, GINT_TO_POINTER(1));
1278  gtk_widget_set_sensitive (widget, FALSE);
1279  }
1280 
1281  binding = g_object_bind_property (G_OBJECT(widget), "active", G_OBJECT(column), "visible", 0);
1282  g_object_set_data (G_OBJECT(widget), "column-binding", binding);
1283 
1284  /* Store data on the widget for callbacks */
1285  key = g_strdup_printf ("%s_%s", pref_name, STATE_KEY_SUFF_VISIBLE);
1286  g_object_set_data_full (G_OBJECT(widget), STATE_KEY, key, g_free);
1287  // LEAVE(" ");
1288 }
1289 
1301 static void
1302 gnc_tree_view_build_column_menu (GncTreeView *view)
1303 {
1304  GncTreeViewPrivate *priv;
1305  GList *column_list;
1306 
1307  g_return_if_fail (GNC_IS_TREE_VIEW(view));
1308 
1309  ENTER("view %p", view);
1310  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1311 
1312  /* Destroy any old menu */
1313  if (priv->column_menu)
1314  {
1315  g_object_unref (priv->column_menu);
1316  priv->column_menu = NULL;
1317  }
1318 
1319  if (priv->show_column_menu && priv->state_section)
1320  {
1321  /* Show the menu popup button */
1322  if (priv->column_menu_column)
1323  gtk_tree_view_column_set_visible (priv->column_menu_column, TRUE);
1324 
1325  /* Now build a new menu */
1326  column_list = gtk_tree_view_get_columns (GTK_TREE_VIEW(view));
1327  g_list_foreach (column_list, (GFunc)gnc_tree_view_create_menu_item, view);
1328  g_list_free (column_list);
1329  }
1330  else
1331  {
1332  /* Hide the menu popup button */
1333  if (priv->column_menu_column)
1334  gtk_tree_view_column_set_visible (priv->column_menu_column, FALSE);
1335  }
1336  LEAVE("menu: show %d, section %s", priv->show_column_menu,
1337  priv->state_section ? priv->state_section : "(null)");
1338 }
1339 
1349 static void
1350 gnc_tree_view_update_column_menu_item (GtkCheckMenuItem *checkmenuitem,
1351  GncTreeView *view)
1352 {
1353  gboolean visible;
1354 
1355  g_return_if_fail (GTK_IS_CHECK_MENU_ITEM(checkmenuitem));
1356  g_return_if_fail (GNC_IS_TREE_VIEW(view));
1357 
1358  if (g_object_get_data (G_OBJECT(checkmenuitem), ALWAYS_VISIBLE))
1359  {
1360  visible = TRUE;
1361  }
1362  else
1363  {
1364  GBinding *binding = g_object_get_data (G_OBJECT(checkmenuitem), "column-binding");
1365  GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(g_binding_get_target (binding));
1366 
1367  visible = gtk_tree_view_column_get_visible (column);
1368  }
1369  gtk_check_menu_item_set_active (checkmenuitem, visible);
1370 }
1371 
1384 static void
1385 gnc_tree_view_select_column_cb (GtkTreeViewColumn *column,
1386  GncTreeView *view)
1387 {
1388  GncTreeViewPrivate *priv;
1389  GtkWidget *menu;
1390 
1391  g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN(column));
1392  g_return_if_fail (GNC_IS_TREE_VIEW(view));
1393 
1394  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1395  menu = priv->column_menu;
1396  if (!menu)
1397  return;
1398 
1399  /* Synchronize the menu before display */
1400  gtk_container_foreach (GTK_CONTAINER(menu),
1401  (GtkCallback)gnc_tree_view_update_column_menu_item,
1402  view);
1403 
1404  /* Ensure all components are visible */
1405  gtk_widget_show_all (menu);
1406 
1407  /* Pop the menu up at the button */
1408  gtk_menu_popup_at_pointer (GTK_MENU(priv->column_menu), NULL);
1409 }
1410 
1411 
1413  gchar *first_column_name,
1414  ...)
1415 {
1416  GncTreeViewPrivate *priv;
1417  GtkTreeViewColumn *column;
1418  gboolean hide_spacer;
1419  GList *columns, *tmp;
1420  gchar *name, *pref_name;
1421  va_list args;
1422 
1423  g_return_if_fail (GNC_IS_TREE_VIEW(view));
1424  ENTER(" ");
1425  va_start (args, first_column_name);
1426  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1427  name = first_column_name;
1428  hide_spacer = FALSE;
1429 
1430  /* First disable the expand property on all (non-infrastructure) columns. */
1431  columns = gtk_tree_view_get_columns (GTK_TREE_VIEW(view));
1432  for (tmp = columns; tmp; tmp = g_list_next (tmp))
1433  {
1434  column = tmp->data;
1435  pref_name = g_object_get_data (G_OBJECT(column), PREF_NAME);
1436  if (pref_name != NULL)
1437  gtk_tree_view_column_set_expand (column, FALSE);
1438  }
1439  g_list_free(columns);
1440 
1441  /* Now enable it on the requested columns. */
1442  while (name != NULL)
1443  {
1444  column = gnc_tree_view_find_column_by_name (view, name);
1445  if (column != NULL)
1446  {
1447  gtk_tree_view_column_set_expand (column, TRUE);
1448  hide_spacer = TRUE;
1449  }
1450  name = va_arg (args, gchar*);
1451  }
1452  va_end (args);
1453 
1454  LEAVE(" ");
1455 }
1456 
1457 
1458 /* Links the cell backgrounds of the two control columns to the model or
1459  cell data function */
1460 static void
1461 update_control_cell_renderers_background (GncTreeView *view, GtkTreeViewColumn *col,
1462  gint column, GtkTreeCellDataFunc func )
1463 {
1464  GList *renderers;
1465  GtkCellRenderer *cell;
1466  GList *node;
1467 
1468  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT(col));
1469 
1470  /* Update the cell background in the list of renderers */
1471  for (node = renderers; node; node = node->next)
1472  {
1473  cell = node->data;
1474  if (func == NULL)
1475  gtk_tree_view_column_add_attribute (col, cell, "cell-background", column);
1476  else
1477  gtk_tree_view_column_set_cell_data_func (col, cell, func, view, NULL);
1478  }
1479  g_list_free (renderers);
1480 }
1481 
1482 
1483 /* This function links the cell backgrounds of the two control columns to a column
1484  in the model that has color strings or a cell data function */
1485 void
1486 gnc_tree_view_set_control_column_background (GncTreeView *view, gint column, GtkTreeCellDataFunc func )
1487 {
1488  GncTreeViewPrivate *priv;
1489 
1490  g_return_if_fail (GNC_IS_TREE_VIEW(view));
1491 
1492  ENTER("view %p, column %d, func %p", view, column, func);
1493  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1494 
1495  update_control_cell_renderers_background (view, priv->column_menu_column, column, func);
1496 
1497  LEAVE(" ");
1498 }
1499 
1500 
1501 /* This allows the columns to be setup without the model connected */
1502 //FIXME I think this should be specified as a parameter to the add columns functions...
1503 void
1504 gnc_tree_view_set_sort_user_data (GncTreeView *view, GtkTreeModel *s_model)
1505 {
1506  GncTreeViewPrivate *priv;
1507 
1508  g_return_if_fail (GNC_IS_TREE_VIEW(view));
1509 
1510  ENTER("view %p, sort_model %p", view, s_model);
1511  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1512 
1513  priv->sort_model = s_model;
1514  LEAVE(" ");
1515 }
1516 
1517 
1524 void
1526  gboolean visible)
1527 {
1528  GncTreeViewPrivate *priv;
1529 
1530  g_return_if_fail (GNC_IS_TREE_VIEW(view));
1531 
1532  ENTER("view %p, show menu %d", view, visible);
1533  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1534  priv->show_column_menu = visible;
1535  gnc_tree_view_build_column_menu (view);
1536  LEAVE(" ");
1537 }
1538 
1545 gboolean
1547 {
1548  GncTreeViewPrivate *priv;
1549 
1550  g_return_val_if_fail (GNC_IS_TREE_VIEW(view), FALSE);
1551 
1552  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1553  return (priv->show_column_menu);
1554 }
1555 
1558 /************************************************************/
1559 /* Tree View Creation */
1560 /************************************************************/
1561 
1562 static gint
1563 gnc_tree_view_count_visible_columns (GncTreeView *view)
1564 {
1565  GList *columns, *node;
1566  gint count = 0;
1567 
1568  columns = gtk_tree_view_get_columns (GTK_TREE_VIEW(view));
1569  for (node = columns; node; node = node->next)
1570  {
1571  GtkTreeViewColumn *col = GTK_TREE_VIEW_COLUMN(node->data);
1572 
1573  if (g_object_get_data (G_OBJECT(col), DEFAULT_VISIBLE) ||
1574  g_object_get_data (G_OBJECT(col), ALWAYS_VISIBLE))
1575  count++;
1576  }
1577  g_list_free (columns);
1578  return count;
1579 }
1580 
1581 void
1583 {
1584  GncTreeViewPrivate *priv;
1585  GtkTreeViewColumn *column;
1586  GList *columns;
1587  gboolean hide_menu_column;
1588 
1589  g_return_if_fail (GNC_IS_TREE_VIEW(view));
1590 
1591  ENTER(" ");
1592 
1593  /* Update the view and saved state */
1594  columns = gtk_tree_view_get_columns (GTK_TREE_VIEW(view));
1595  g_list_foreach (columns, (GFunc)gnc_tree_view_update_visibility, view);
1596  g_list_free (columns);
1597 
1598  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1599  if (priv->state_section)
1600  priv->seen_state_visibility = TRUE;
1601 
1602  /* If only the first column is visible, hide the spacer and make that
1603  * column expand. */
1604  hide_menu_column = (gnc_tree_view_count_visible_columns (view) == 1);
1605  column = gtk_tree_view_get_column (GTK_TREE_VIEW(view), 0);
1606  gtk_tree_view_column_set_expand (column, hide_menu_column);
1607  gtk_tree_view_column_set_visible (priv->column_menu_column, !hide_menu_column);
1608 
1609  LEAVE(" ");
1610 }
1611 
1612 
1642 static void
1643 gnc_tree_view_column_properties (GncTreeView *view,
1644  GtkTreeViewColumn *column,
1645  const gchar *pref_name,
1646  gint data_column,
1647  gint default_width,
1648  gboolean resizable,
1649  GtkTreeIterCompareFunc column_sort_fn)
1650 {
1651  GncTreeViewPrivate *priv;
1652  GtkTreeModel *s_model;
1653  gboolean visible;
1654  int width = 0;
1655 
1656  /* Set data used by other functions */
1657  if (pref_name)
1658  g_object_set_data (G_OBJECT(column), PREF_NAME, (gpointer)pref_name);
1659  if (data_column == 0)
1660  g_object_set_data (G_OBJECT(column), ALWAYS_VISIBLE, GINT_TO_POINTER(1));
1661  g_object_set_data (G_OBJECT(column), MODEL_COLUMN,
1662  GINT_TO_POINTER(data_column));
1663 
1664  /* Get visibility */
1665  visible = gnc_tree_view_column_visible (view, NULL, pref_name);
1666 
1667  /* Set column attributes (without the sizing) */
1668  g_object_set (G_OBJECT(column),
1669  "visible", visible,
1670  "resizable", resizable && pref_name != NULL,
1671  "reorderable", pref_name != NULL,
1672  NULL);
1673 
1674  /* Get width */
1675  if (default_width == 0)
1676  {
1677  /* Set the sizing column attributes */
1678  g_object_set (G_OBJECT(column),
1679  "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE,
1680  NULL);
1681  }
1682  else
1683  {
1684 
1685  /* If saved state comes back with a width of zero (or there is no saved
1686  * state width) the use the default width for the column. Allow for
1687  * padding L and R of the displayed data. */
1688  if (width == 0)
1689  width = default_width + 10;
1690  if (width == 0)
1691  width = 10;
1692 
1693  /* Set the sizing column attributes (including fixed-width) */
1694  g_object_set (G_OBJECT(column),
1695  "sizing", GTK_TREE_VIEW_COLUMN_FIXED,
1696  "fixed-width", width,
1697  NULL);
1698  /* Save the initially calculated preferred width for later
1699  * comparison to the actual width when saving state. Can't
1700  * use the "fixed-width" property for that because it changes
1701  * when the user resizes the column.
1702  */
1703  g_object_set_data (G_OBJECT(column),
1704  "default-width", GINT_TO_POINTER(width));
1705  }
1706 
1707  s_model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
1708  if (GTK_IS_TREE_SORTABLE(s_model))
1709  {
1710  gtk_tree_view_column_set_sort_column_id (column, data_column);
1711  if (column_sort_fn)
1712  {
1713  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(s_model),
1714  data_column, column_sort_fn,
1715  GINT_TO_POINTER(data_column),
1716  NULL /* destroy fn */);
1717  }
1718  }
1719 
1720  // Used in registers, sort model not connected to view yet
1721  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1722  if (priv->sort_model != NULL)
1723  {
1724  gtk_tree_view_column_set_sort_column_id (column, data_column);
1725  if (column_sort_fn)
1726  {
1727  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(priv->sort_model),
1728  data_column, column_sort_fn,
1729  view,
1730  NULL /* destroy fn */);
1731  }
1732  }
1733 
1734  /* Add to the column selection menu */
1735  if (pref_name)
1736  {
1737  gnc_tree_view_create_menu_item (column, view);
1738  }
1739 }
1740 
1751 GtkTreeViewColumn *
1753  const gchar *column_title,
1754  const gchar *column_short_title,
1755  const gchar *pref_name,
1756  gint model_data_column,
1757  gint model_visibility_column,
1758  GtkTreeIterCompareFunc column_sort_fn,
1759  renderer_toggled toggle_edited_cb)
1760 {
1761  GtkTreeViewColumn *column;
1762  GtkCellRenderer *renderer;
1763 
1764  g_return_val_if_fail (GNC_IS_TREE_VIEW(view), NULL);
1765 
1766  renderer = gtk_cell_renderer_toggle_new ();
1767  if (!toggle_edited_cb)
1768  {
1769  gtk_cell_renderer_toggle_set_activatable (GTK_CELL_RENDERER_TOGGLE(renderer), FALSE);
1770  }
1771  column =
1772  gtk_tree_view_column_new_with_attributes (column_short_title,
1773  renderer,
1774  "active", model_data_column,
1775  NULL);
1776 
1777  /* Add the full title to the object for menu creation */
1778  g_object_set_data_full (G_OBJECT(column), REAL_TITLE,
1779  g_strdup(column_title), g_free);
1780  if (toggle_edited_cb)
1781  g_signal_connect (G_OBJECT(renderer), "toggled",
1782  G_CALLBACK(toggle_edited_cb), view);
1783 
1784  if (model_visibility_column != GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS)
1785  gtk_tree_view_column_add_attribute (column, renderer,
1786  "visible", model_visibility_column);
1787 
1788 
1789  gnc_tree_view_column_properties (view, column, pref_name, model_data_column,
1790  0, FALSE, column_sort_fn);
1791 
1792  gnc_tree_view_append_column (view, column);
1793 
1794  /* Also add the full title to the object as a tooltip */
1795  gtk_widget_set_tooltip_text (gtk_tree_view_column_get_button (column), column_title);
1796 
1797  return column;
1798 }
1799 
1800 static void
1801 renderer_editing_canceled_cb (GtkCellRenderer *renderer, gpointer user_data)
1802 {
1803  GncTreeView *view = user_data;
1804  GncTreeViewPrivate *priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1805  if (priv->editing_finished_cb)
1806  (priv->editing_finished_cb)(view, priv->editing_cb_data);
1807 }
1808 
1809 static void
1810 renderer_editing_started_cb (GtkCellRenderer *renderer,
1811  GtkCellEditable *editable, gchar *path, gpointer user_data)
1812 {
1813  GncTreeView *view = user_data;
1814  GncTreeViewPrivate *priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1815  if (priv->editing_started_cb)
1816  (priv->editing_started_cb)(view, priv->editing_cb_data);
1817 }
1818 
1819 static void
1820 renderer_edited_cb (GtkCellRendererText *renderer, gchar *path,
1821  gchar *new_text, gpointer user_data)
1822 {
1823  GncTreeView *view = user_data;
1824  GncTreeViewPrivate *priv = GNC_TREE_VIEW_GET_PRIVATE(view);
1825  if (priv->editing_finished_cb)
1826  (priv->editing_finished_cb)(view, priv->editing_cb_data);
1827 }
1828 
1829 
1830 static GtkTreeViewColumn *
1831 add_text_column_variant (GncTreeView *view, GtkCellRenderer *renderer,
1832  const gchar *column_title,
1833  const gchar *pref_name,
1834  const gchar *icon_name,
1835  const gchar *sizing_text,
1836  gint model_data_column,
1837  gint model_visibility_column,
1838  GtkTreeIterCompareFunc column_sort_fn)
1839 {
1840  GtkTreeViewColumn *column;
1841  PangoLayout* layout;
1842  int default_width, title_width;
1843 
1844  g_return_val_if_fail (GNC_IS_TREE_VIEW(view), NULL);
1845 
1846  column = gtk_tree_view_column_new ();
1847  gtk_tree_view_column_set_title (column, column_title);
1848 
1849  /* Set up an icon renderer if requested */
1850  if (icon_name)
1851  {
1852  GtkCellRenderer *renderer_pix = gtk_cell_renderer_pixbuf_new ();
1853  g_object_set (renderer_pix, "icon-name", icon_name, NULL);
1854  gtk_tree_view_column_pack_start (column, renderer_pix, FALSE);
1855  }
1856 
1857  /* Set up a text renderer and attributes */
1858  gtk_tree_view_column_pack_start (column, renderer, TRUE);
1859 
1860  /* Set up the callbacks for when editing */
1861  g_signal_connect (G_OBJECT(renderer), "editing-canceled",
1862  (GCallback)renderer_editing_canceled_cb, view);
1863 
1864  g_signal_connect (G_OBJECT(renderer), "editing-started",
1865  (GCallback)renderer_editing_started_cb, view);
1866 
1867  g_signal_connect (G_OBJECT(renderer), "edited",
1868  (GCallback)renderer_edited_cb, view);
1869 
1870  /* Set renderer attributes controlled by the model */
1871  if (model_data_column != GNC_TREE_VIEW_COLUMN_DATA_NONE)
1872  gtk_tree_view_column_add_attribute (column, renderer,
1873  "text", model_data_column);
1874  if (model_visibility_column != GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS)
1875  gtk_tree_view_column_add_attribute (column, renderer,
1876  "visible", model_visibility_column);
1877 
1878  /* Default size is the larger of the column title and the sizing text */
1879  layout = gtk_widget_create_pango_layout (GTK_WIDGET(view), column_title);
1880  pango_layout_get_pixel_size (layout, &title_width, NULL);
1881  g_object_unref (layout);
1882  layout = gtk_widget_create_pango_layout (GTK_WIDGET(view), sizing_text);
1883  pango_layout_get_pixel_size (layout, &default_width, NULL);
1884  g_object_unref (layout);
1885  default_width = MAX(default_width, title_width);
1886  if (default_width)
1887  default_width += 10; /* padding on either side */
1888  gnc_tree_view_column_properties (view, column, pref_name, model_data_column,
1889  default_width, TRUE, column_sort_fn);
1890 
1891  gnc_tree_view_append_column (view, column);
1892  return column;
1893 }
1894 
1895 
1904 GtkTreeViewColumn *
1906  const gchar *column_title,
1907  const gchar *pref_name,
1908  const gchar *icon_name,
1909  const gchar *sizing_text,
1910  gint model_data_column,
1911  gint model_visibility_column,
1912  GtkTreeIterCompareFunc column_sort_fn)
1913 {
1914  GtkCellRenderer *renderer;
1915 
1916  g_return_val_if_fail (GNC_IS_TREE_VIEW(view), NULL);
1917 
1918  renderer = gtk_cell_renderer_text_new ();
1919 
1920  return add_text_column_variant (view, renderer,
1921  column_title, pref_name,
1922  icon_name, sizing_text,
1923  model_data_column,
1924  model_visibility_column,
1925  column_sort_fn);
1926 }
1927 
1936 GtkTreeViewColumn *
1938  const gchar *column_title,
1939  const gchar *pref_name,
1940  const gchar *icon_name,
1941  const gchar *sizing_text,
1942  gint model_data_column,
1943  gint model_visibility_column,
1944  GtkTreeIterCompareFunc column_sort_fn)
1945 {
1946  GtkCellRenderer *renderer;
1947 
1948  g_return_val_if_fail (GNC_IS_TREE_VIEW(view), NULL);
1949 
1950  renderer = gnc_cell_renderer_text_view_new ();
1951 
1952  return add_text_column_variant (view, renderer,
1953  column_title, pref_name,
1954  icon_name, sizing_text,
1955  model_data_column,
1956  model_visibility_column,
1957  column_sort_fn);
1958 }
1959 
1960 
1969 GtkTreeViewColumn *
1971  const gchar *column_title,
1972  const gchar *pref_name,
1973  const gchar *icon_name,
1974  const gchar *sizing_text,
1975  gint model_data_column,
1976  gint model_visibility_column,
1977  GtkTreeIterCompareFunc column_sort_fn)
1978 {
1979  GtkTreeViewColumn *column;
1980  GtkCellRenderer *renderer;
1981  PangoLayout* layout;
1982  int default_width, title_width;
1983 
1984  g_return_val_if_fail (GNC_IS_TREE_VIEW(view), NULL);
1985 
1986  column = gtk_tree_view_column_new ();
1987  gtk_tree_view_column_set_title (column, column_title);
1988 
1989  /* Set up an icon renderer if requested */
1990  if (icon_name)
1991  {
1992  renderer = gtk_cell_renderer_pixbuf_new ();
1993  g_object_set (renderer, "icon-name", icon_name, NULL);
1994  gtk_tree_view_column_pack_start (column, renderer, FALSE);
1995  }
1996 
1997  /* Set up a text renderer and attributes */
1998  renderer = gnc_cell_renderer_date_new (TRUE);
1999  gtk_tree_view_column_pack_start (column, renderer, TRUE);
2000 
2001  /* Set renderer attributes controlled by the model */
2002  if (model_data_column != GNC_TREE_VIEW_COLUMN_DATA_NONE)
2003  gtk_tree_view_column_add_attribute (column, renderer,
2004  "text", model_data_column);
2005  if (model_visibility_column != GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS)
2006  gtk_tree_view_column_add_attribute (column, renderer,
2007  "visible", model_visibility_column);
2008 
2009  /* Default size is the larger of the column title and the sizing text */
2010  layout = gtk_widget_create_pango_layout (GTK_WIDGET(view), column_title);
2011  pango_layout_get_pixel_size (layout, &title_width, NULL);
2012  g_object_unref (layout);
2013  layout = gtk_widget_create_pango_layout (GTK_WIDGET(view), sizing_text);
2014  pango_layout_get_pixel_size (layout, &default_width, NULL);
2015  g_object_unref (layout);
2016  default_width = MAX(default_width, title_width);
2017  if (default_width)
2018  default_width += 10; /* padding on either side */
2019  gnc_tree_view_column_properties (view, column, pref_name, model_data_column,
2020  default_width, TRUE, column_sort_fn);
2021 
2022  gnc_tree_view_append_column (view, column);
2023  return column;
2024 }
2025 
2026 
2027 GtkTreeViewColumn *
2029  const gchar *column_title,
2030  const gchar *pref_name,
2031  const gchar *sizing_text,
2032  gint model_data_column,
2033  gint model_visibility_column,
2034  GtkTreeModel *combo_tree_model,
2035  gint combo_model_text_column,
2036  GtkTreeIterCompareFunc column_sort_fn)
2037 {
2038  GtkTreeViewColumn *column;
2039  GtkCellRenderer *renderer;
2040  PangoLayout* layout;
2041  int default_width, title_width;
2042 
2043  g_return_val_if_fail (GNC_IS_TREE_VIEW(view), NULL);
2044 
2045  column = gtk_tree_view_column_new ();
2046  gtk_tree_view_column_set_title (column, gettext(column_title));
2047 
2048  /* Set up a renderer and attributes */
2049  renderer = gtk_cell_renderer_combo_new ();
2050  gtk_tree_view_column_pack_start (column, renderer, TRUE);
2051 
2052  /* Set renderer attributes controlled by the model */
2053  if (model_data_column != GNC_TREE_VIEW_COLUMN_DATA_NONE)
2054  gtk_tree_view_column_add_attribute (column, renderer,
2055  "text", model_data_column);
2056  if (model_visibility_column != GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS)
2057  gtk_tree_view_column_add_attribute (column, renderer,
2058  "visible", model_visibility_column);
2059 
2060  /* Default size is the larger of the column title and the sizing text */
2061  layout = gtk_widget_create_pango_layout (GTK_WIDGET(view), column_title);
2062  pango_layout_get_pixel_size (layout, &title_width, NULL);
2063  g_object_unref (layout);
2064  layout = gtk_widget_create_pango_layout (GTK_WIDGET(view), sizing_text);
2065  pango_layout_get_pixel_size (layout, &default_width, NULL);
2066  g_object_unref (layout);
2067  default_width = MAX(default_width, title_width);
2068  if (default_width)
2069  default_width += 10; /* padding on either side */
2070 
2071  gnc_tree_view_column_properties (view, column, pref_name, model_data_column,
2072  default_width, TRUE, column_sort_fn);
2073 
2074  /* Stuff specific to combo */
2075  if (combo_tree_model)
2076  {
2077  g_object_set (G_OBJECT(renderer), "model", combo_tree_model,
2078  "text-column", combo_model_text_column, NULL);
2079  }
2080  /* TODO: has-entry? */
2081 
2082  gnc_tree_view_append_column (view, column);
2083  return column;
2084 }
2085 
2086 GtkCellRenderer *
2087 gnc_tree_view_column_get_renderer (GtkTreeViewColumn *column)
2088 {
2089  GList *renderers;
2090  GtkCellRenderer *cr = NULL;
2091 
2092  g_return_val_if_fail (GTK_TREE_VIEW_COLUMN(column), NULL);
2093 
2094  /* Get the list of one renderer */
2095  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT(column));
2096  if (g_list_length (renderers) > 0)
2097  cr = GTK_CELL_RENDERER(renderers->data);
2098  g_list_free (renderers);
2099 
2100  return cr;
2101 }
2102 
2113 GtkTreeViewColumn *
2115  const gchar *column_title,
2116  const gchar *pref_name,
2117  const gchar *sizing_text,
2118  gint model_data_column,
2119  gint model_color_column,
2120  gint model_visibility_column,
2121  GtkTreeIterCompareFunc column_sort_fn)
2122 {
2123  GtkTreeViewColumn *column;
2124  GtkCellRenderer *renderer;
2125  gfloat alignment = 1.0;
2126 
2127  column = gnc_tree_view_add_text_column (view, column_title, pref_name,
2128  NULL, sizing_text, model_data_column,
2129  model_visibility_column,
2130  column_sort_fn);
2131 
2132  renderer = gnc_tree_view_column_get_renderer (column);
2133 
2134  /* Right align the column title and data for both ltr and rtl */
2135  if (gtk_widget_get_direction (GTK_WIDGET(view)) == GTK_TEXT_DIR_RTL)
2136  alignment = 0.0;
2137 
2138  g_object_set (G_OBJECT(column), "alignment", alignment, NULL);
2139  g_object_set (G_OBJECT(renderer), "xalign", alignment, NULL);
2140 
2141  /* Change the text color */
2142  if (model_color_column != GNC_TREE_VIEW_COLUMN_COLOR_NONE)
2143  gtk_tree_view_column_add_attribute (column, renderer,
2144  "foreground", model_color_column);
2145 
2146  return column;
2147 }
2148 
2157 gint
2159  GtkTreeViewColumn *column)
2160 {
2161  int n = gtk_tree_view_get_n_columns (GTK_TREE_VIEW(view));
2162 
2163  /* Ignore the initial column, the selection menu */
2164  if (n >= 1)
2165  n -= 1;
2166  return gtk_tree_view_insert_column (GTK_TREE_VIEW(view), column, n);
2167 }
2168 
2169 static gboolean
2170 get_column_next_to (GtkTreeView *tv, GtkTreeViewColumn **col, gboolean backward)
2171 {
2172  GList *cols, *node;
2173  GtkTreeViewColumn *c = NULL;
2174  gint seen = 0;
2175  gboolean wrapped = FALSE;
2176 
2177  cols = gtk_tree_view_get_columns (tv);
2178  g_return_val_if_fail (cols != NULL, FALSE);
2179 
2180  node = g_list_find (cols, *col);
2181  g_return_val_if_fail (node, FALSE);
2182  do
2183  {
2184  node = backward ? node->prev : node->next;
2185  if (!node)
2186  {
2187  wrapped = TRUE;
2188  node = backward ? g_list_last (cols) : cols;
2189  }
2190  c = GTK_TREE_VIEW_COLUMN (node->data);
2191  if (c && gtk_tree_view_column_get_visible (c))
2192  seen++;
2193  if (c == *col) break;
2194  }
2195  while (!seen);
2196 
2197  g_list_free (cols);
2198  *col = c;
2199  return wrapped;
2200 }
2201 
2202 gboolean
2203 gnc_tree_view_path_is_valid (GncTreeView *view, GtkTreePath *path)
2204 {
2205  GtkTreeView *tv = GTK_TREE_VIEW(view);
2206  GtkTreeModel *s_model;
2207  GtkTreeIter iter;
2208 
2209  s_model = gtk_tree_view_get_model (tv);
2210  return gtk_tree_model_get_iter (s_model, &iter, path);
2211 }
2212 
2213 void
2214 gnc_tree_view_keynav (GncTreeView *view, GtkTreeViewColumn **col,
2215  GtkTreePath *path, GdkEventKey *event)
2216 {
2217  GtkTreeView *tv = GTK_TREE_VIEW(view);
2218  gint depth;
2219  gboolean shifted;
2220 
2221  if (event->type != GDK_KEY_PRESS) return;
2222 
2223  switch (event->keyval)
2224  {
2225  case GDK_KEY_Tab:
2226  case GDK_KEY_ISO_Left_Tab:
2227  case GDK_KEY_KP_Tab:
2228  shifted = event->state & GDK_SHIFT_MASK;
2229  if (get_column_next_to (tv, col, shifted))
2230  {
2231  /* This is the end (or beginning) of the line, buddy. */
2232  depth = gtk_tree_path_get_depth (path);
2233  if (shifted)
2234  {
2235  if (!gtk_tree_path_prev (path) && depth > 1)
2236  {
2237  gtk_tree_path_up (path);
2238  }
2239  }
2240  else if (gtk_tree_view_row_expanded (tv, path))
2241  {
2242  gtk_tree_path_down (path);
2243  }
2244  else
2245  {
2246  gtk_tree_path_next (path);
2247  if (!gnc_tree_view_path_is_valid (view, path) && depth > 2)
2248  {
2249  gtk_tree_path_prev (path);
2250  gtk_tree_path_up (path);
2251  gtk_tree_path_next (path);
2252  }
2253  if (!gnc_tree_view_path_is_valid (view, path) && depth > 1)
2254  {
2255  gtk_tree_path_prev (path);
2256  gtk_tree_path_up (path);
2257  gtk_tree_path_next (path);
2258  }
2259  }
2260  }
2261  break;
2262 
2263  case GDK_KEY_Return:
2264  case GDK_KEY_KP_Enter:
2265  if (gtk_tree_view_row_expanded (tv, path))
2266  {
2267  gtk_tree_path_down (path);
2268  }
2269  else
2270  {
2271  depth = gtk_tree_path_get_depth (path);
2272  gtk_tree_path_next (path);
2273  if (!gnc_tree_view_path_is_valid (view, path) && depth > 1)
2274  {
2275  gtk_tree_path_prev (path);
2276  gtk_tree_path_up (path);
2277  gtk_tree_path_next (path);
2278  }
2279  }
2280  break;
2281  }
2282  return;
2283 }
2284 
2285 void
2286 gnc_tree_view_set_editing_started_cb (GncTreeView *view, GFunc editing_started_cb, gpointer editing_cb_data)
2287 {
2288  GncTreeViewPrivate *priv;
2289 
2290  if (!view && !editing_started_cb)
2291  return;
2292 
2293  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
2294 
2295  priv->editing_started_cb = editing_started_cb;
2296  priv->editing_cb_data = editing_cb_data;
2297 }
2298 
2299 void
2300 gnc_tree_view_set_editing_finished_cb (GncTreeView *view, GFunc editing_finished_cb, gpointer editing_cb_data)
2301 {
2302  GncTreeViewPrivate *priv;
2303 
2304  if (!view && !editing_finished_cb)
2305  return;
2306 
2307  priv = GNC_TREE_VIEW_GET_PRIVATE(view);
2308 
2309  priv->editing_finished_cb = editing_finished_cb;
2310  priv->editing_cb_data = editing_cb_data;
2311 }
2312 
void gnc_tree_view_set_sort_user_data(GncTreeView *view, GtkTreeModel *s_model)
This allows the columns to be setup without the model connected.
Functions to load, save and get gui state.
void gnc_tree_view_expand_columns(GncTreeView *view, gchar *first_column_name,...)
This function set the columns that will be allocated the free space in the view.
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Register a callback that gets triggered when the given preference changes.
Definition: gnc-prefs.c:128
void gnc_gobject_tracking_remember(GObject *object, GObjectClass *klass)
Tell gnucash to remember this object in the database.
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_gobject_tracking_forget(GObject *object)
Tell gnucash to remember this object in the database.
common utilities for manipulating a GtkTreeView within gnucash
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
GtkTreeViewColumn * gnc_tree_view_add_date_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 date column to a GncTreeView base view.
gboolean gnc_tree_view_get_show_column_menu(GncTreeView *view)
This function is called to get the current value of the "show-column-menu" property.
GtkTreeViewColumn * gnc_tree_view_add_combo_column(GncTreeView *view, const gchar *column_title, const gchar *pref_name, const gchar *sizing_text, gint model_data_column, gint model_visibility_column, GtkTreeModel *combo_tree_model, gint combo_model_text_column, GtkTreeIterCompareFunc column_sort_fn)
This function adds a new combobox column to a GncTreeView base view.
void gnc_tree_view_remove_state_information(GncTreeView *view)
Completely wipe the treeview&#39;s state information (column visibility, width, sorting order...
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_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.
GtkTreeViewColumn * gnc_tree_view_find_column_by_name(GncTreeView *view, const gchar *wanted)
Find a tree column given the "pref name" used with saved state.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition: gnc-state.c:248
gint gnc_tree_view_append_column(GncTreeView *view, GtkTreeViewColumn *column)
Add a column to a view based upon a GncTreeView.
GtkTreeViewColumn * gnc_tree_view_add_toggle_column(GncTreeView *view, const gchar *column_title, const gchar *column_short_title, const gchar *pref_name, gint model_data_column, gint model_visibility_column, GtkTreeIterCompareFunc column_sort_fn, renderer_toggled toggle_edited_cb)
This function adds a new toggle column to a GncTreeView base view.
void gnc_tree_view_set_editing_finished_cb(GncTreeView *view, GFunc editing_finished_cb, gpointer editing_cb_data)
Setup a callback for when the user finishes editing so appropriate actions can be taken like enable t...
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_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.
Gobject helper routines.
void gnc_tree_view_configure_columns(GncTreeView *view)
Make all the correct columns visible, respecting their default visibility setting, their "always" visibility setting, and the last saved state if available.
void gnc_tree_view_save_state(GncTreeView *view)
This function is called to write the treeview&#39;s state information (column visibility, width, sorting order,..) to the state file.
void gnc_tree_view_set_control_column_background(GncTreeView *view, gint column, GtkTreeCellDataFunc func)
This function links the cell backgrounds of the two control columns to a column in the model that has...
Gnome specific utility functions.
All type declarations for the whole Gnucash engine.
const gchar * gnc_tree_view_get_state_section(GncTreeView *view)
Get the name of the state section this tree view is associated with.
Generic api to store and retrieve preferences.
void gnc_tree_view_set_state_section(GncTreeView *view, const gchar *section)
Set up or remove an association between a saved state section and the display of a view...
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.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
Private Data Structure.
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
Definition: gnc-prefs.c:143