GnuCash  4.11-137-g155922540d+
gnc-plugin-page.c
Go to the documentation of this file.
1 /*
2  * gnc-plugin_page.c --
3  *
4  * Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
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 
35 #include <config.h>
36 
37 #include <gtk/gtk.h>
38 #include "gnc-engine.h"
39 #include "gnc-plugin.h"
40 #include "gnc-plugin-page.h"
41 #include "gnc-gobject-utils.h"
42 
44 static QofLogModule log_module = GNC_MOD_GUI;
46 static gpointer parent_class = NULL;
47 
48 static void gnc_plugin_page_class_init (GncPluginPageClass *klass);
49 static void gnc_plugin_page_init (GncPluginPage *plugin_page,
50  void *data);
51 static void gnc_plugin_page_finalize (GObject *object);
52 static void gnc_plugin_page_set_property (GObject *object,
53  guint prop_id,
54  const GValue *value,
55  GParamSpec *pspec);
56 static void gnc_plugin_page_get_property (GObject *object,
57  guint prop_id,
58  GValue *value,
59  GParamSpec *pspec);
60 
61 static void gnc_plugin_page_default_focus (GncPluginPage *plugin_page,
62  gboolean on_current_page);
63 
64 enum
65 {
66  INSERTED,
67  REMOVED,
68  SELECTED,
69  UNSELECTED,
70  LAST_SIGNAL
71 };
72 
73 enum
74 {
75  PROP_0,
76  PROP_PAGE_NAME,
77  PROP_PAGE_COLOR,
78  PROP_PAGE_URI,
79  PROP_BOOK,
80  PROP_STATUSBAR_TEXT,
81  PROP_USE_NEW_WINDOW,
82  PROP_UI_DESCRIPTION,
83  PROP_UI_MERGE,
84  PROP_ACTION_GROUP,
85 };
86 
87 static guint signals[LAST_SIGNAL] = { 0 };
88 
89 
91 typedef struct _GncPluginPagePrivate
92 {
94  GtkActionGroup *action_group;
95  GtkUIManager *ui_merge;
96  guint merge_id;
97  char *ui_description;
98 
99  GList *books;
100 
101  gboolean use_new_window;
102 
103  gchar *page_name;
104  gchar *page_long_name;
105  gchar *page_color;
106  gchar *uri;
107  gchar *statusbar_text;
108 
109  gulong page_changed_id;
110  guint focus_source_id;
111 
113 
114 GNC_DEFINE_TYPE_WITH_CODE(GncPluginPage, gnc_plugin_page, G_TYPE_OBJECT,
115  G_ADD_PRIVATE(GncPluginPage))
116 
117 #define GNC_PLUGIN_PAGE_GET_PRIVATE(o) \
118  ((GncPluginPagePrivate*)gnc_plugin_page_get_instance_private((GncPluginPage*)o))
119 
120 /* Create the display widget that corresponds to this plugin. This
121  * function will be called by the main/embedded window manipulation
122  * code to create a widget that they can display. The returned
123  * widget should encompass all information that goes with this page,
124  * including scroll bars, a summary bar, etc. */
125 GtkWidget *
127 {
128  GncPluginPageClass *klass;
129  GtkWidget *widget;
130 
131  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page), NULL);
132 
133  klass = GNC_PLUGIN_PAGE_GET_CLASS(plugin_page);
134  g_return_val_if_fail (klass != NULL, NULL);
135  g_return_val_if_fail (klass->create_widget != NULL, NULL);
136 
137  widget = klass->create_widget (plugin_page);
138 
139  /*
140  * If there is a destroy function, add a ref so that the
141  * widgets will exists when the destroy function is called.
142  * Otherwise it will be destroyed when it is removed from the
143  * main notebook for the window.
144  */
145  if (klass->destroy_widget)
146  g_object_ref (widget);
147 
148  return widget;
149 }
150 
151 
152 /* Destroy the display widget that corresponds to this plugin. This
153  * function will be called by the main/embedded window manipulation
154  * code when a page is closed. */
155 void
157 {
158  GncPluginPageClass *klass;
159 
160  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
161 
162  klass = GNC_PLUGIN_PAGE_GET_CLASS(plugin_page);
163  g_return_if_fail (klass != NULL);
164  g_return_if_fail (klass->destroy_widget != NULL);
165 
166  klass->destroy_widget (plugin_page);
167 }
168 
169 
170 /* Show/hide the summarybar associated with this page. */
171 void
173  gboolean visible)
174 {
175  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
176 
177  if (!page->summarybar)
178  return;
179 
180  if (visible)
181  gtk_widget_show (page->summarybar);
182  else
183  gtk_widget_hide (page->summarybar);
184 }
185 
186 
187 /* Call the plugin specific function that will save the state of a
188  * content page to a disk. That function must save enough
189  * information about the page that it can be recreated next time the
190  * user starts gnucash. */
191 void
193  GKeyFile *key_file,
194  const gchar *group_name)
195 {
196  GncPluginPageClass *klass;
197 
198  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
199  g_return_if_fail (key_file != NULL);
200  g_return_if_fail (group_name != NULL);
201 
202  ENTER(" ");
203  klass = GNC_PLUGIN_PAGE_GET_CLASS(page);
204  g_return_if_fail (klass != NULL);
205  g_return_if_fail (klass->save_page != NULL);
206 
207  klass->save_page (page, key_file, group_name);
208  LEAVE(" ");
209 }
210 
211 
212 /* This function looks up a specific plugin type by name, and then
213  * calls a plugin specific function to create a new page and restore
214  * its content to a previous state. */
217  const gchar *page_type,
218  GKeyFile *key_file,
219  const gchar *page_group)
220 {
221  GncPluginPageClass *klass;
222  GncPluginPage *page = NULL;
223  GType type;
224 
225  ENTER("type %s, keyfile %p, group %s", page_type, key_file, page_group);
226  type = g_type_from_name (page_type);
227  if (type == 0)
228  {
229  LEAVE("Cannot find type named %s", page_type);
230  return NULL;
231  }
232 
233  klass = g_type_class_ref (type);
234  if (klass == NULL)
235  {
236  const gchar *type_name = g_type_name (type);
237  LEAVE("Cannot create class %s(%s)", page_type, type_name ? type_name : "invalid type");
238  return NULL;
239  }
240 
241  if (!klass->recreate_page)
242  {
243  LEAVE("Class %shas no recreate function.", page_type);
244  g_type_class_unref (klass);
245  return NULL;
246  }
247 
248  page = (klass->recreate_page)(window, key_file, page_group);
249  g_type_class_unref (klass);
250  LEAVE(" ");
251  return page;
252 }
253 
254 
255 /* Add the actions for a content page to the specified window. */
256 void
258  GtkUIManager *ui_merge)
259 {
260  GncPluginPagePrivate *priv;
261 
262  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
263 
264  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
265  priv->ui_merge = ui_merge;
266  gtk_action_group_set_sensitive (priv->action_group, TRUE);
267  priv->merge_id = gnc_plugin_add_actions (priv->ui_merge,
268  priv->action_group,
269  priv->ui_description);
270 }
271 
272 
273 /* Remove the actions for a content page from the specified window. */
274 void
276  GtkUIManager *ui_merge)
277 {
278  GncPluginPagePrivate *priv;
279 
280  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
281 
282  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
283  g_return_if_fail (priv->merge_id != 0);
284  g_return_if_fail (priv->action_group != NULL);
285 
286  gtk_ui_manager_remove_ui (ui_merge, priv->merge_id);
287  gtk_action_group_set_sensitive (priv->action_group, FALSE);
288  gtk_ui_manager_remove_action_group (ui_merge, priv->action_group);
289 
290  priv->ui_merge = NULL;
291  priv->merge_id = 0;
292 }
293 
294 
295 GtkAction *
296 gnc_plugin_page_get_action (GncPluginPage *page, const gchar *name)
297 {
298  GncPluginPagePrivate *priv;
299 
300  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
301  g_return_val_if_fail (name != NULL, NULL);
302 
303  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
304  if (!priv->action_group)
305  return NULL;
306  return gtk_action_group_get_action (priv->action_group, name);
307 }
308 
309 
310 /* Retrieve the textual name of a plugin. */
311 const gchar *
313 {
314  GncPluginPageClass *klass;
315 
316  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page), NULL);
317 
318  klass = GNC_PLUGIN_PAGE_GET_CLASS(plugin_page);
319  g_return_val_if_fail (klass != NULL, NULL);
320 
321  return (klass->plugin_name);
322 }
323 
324 
325 /* Signals */
326 void
327 gnc_plugin_page_inserted (GncPluginPage *plugin_page)
328 {
329  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
330 
331  g_signal_emit (G_OBJECT(plugin_page), signals[INSERTED], 0);
332 }
333 
334 void
335 gnc_plugin_page_removed (GncPluginPage *plugin_page)
336 {
337  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
338 
339  g_signal_emit (G_OBJECT(plugin_page), signals[REMOVED], 0);
340 }
341 
342 void
343 gnc_plugin_page_selected (GncPluginPage *plugin_page)
344 {
345  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
346 
347  g_signal_emit (G_OBJECT(plugin_page), signals[SELECTED], 0);
348 }
349 
350 void
351 gnc_plugin_page_unselected (GncPluginPage *plugin_page)
352 {
353  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
354 
355  g_signal_emit (G_OBJECT(plugin_page), signals[UNSELECTED], 0);
356 }
357 
365 static void
366 gnc_plugin_page_class_init (GncPluginPageClass *klass)
367 {
368  GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
369 
370  parent_class = g_type_class_peek_parent (klass);
371  gobject_class->finalize = gnc_plugin_page_finalize;
372  gobject_class->set_property = gnc_plugin_page_set_property;
373  gobject_class->get_property = gnc_plugin_page_get_property;
374 
375  klass->tab_icon = NULL;
376  klass->plugin_name = NULL;
377  klass->focus_page = gnc_plugin_page_default_focus;
378 
379  g_object_class_install_property
380  (gobject_class,
381  PROP_PAGE_NAME,
382  g_param_spec_string ("page-name",
383  "Page Name",
384  "The name of this page. This value is "
385  "used to generate the notebook tab and "
386  "menu items, and also the window title "
387  "when this page is visible.",
388  NULL,
389  G_PARAM_READWRITE));
390 
391  g_object_class_install_property
392  (gobject_class,
393  PROP_PAGE_COLOR,
394  g_param_spec_string ("page-color",
395  "Page Color",
396  "The color of this page. This value is "
397  "used to generate the notebook tab color "
398  "when this page is visible.",
399  NULL,
400  G_PARAM_READWRITE));
401 
402  g_object_class_install_property
403  (gobject_class,
404  PROP_PAGE_URI,
405  g_param_spec_string ("page-uri",
406  "Page URI",
407  "The uri for this page.",
408  NULL,
409  G_PARAM_READWRITE));
410 
411  g_object_class_install_property
412  (gobject_class,
413  PROP_STATUSBAR_TEXT,
414  g_param_spec_string ("statusbar-text",
415  "Statusbar Text",
416  "The text to be displayed in the statusbar "
417  "at the bottom of the window when this page "
418  "is visible.",
419  NULL,
420  G_PARAM_READWRITE));
421 
422  g_object_class_install_property
423  (gobject_class,
424  PROP_USE_NEW_WINDOW,
425  g_param_spec_boolean ("use-new-window",
426  "Use New Window",
427  "When TRUE a new top level window will be "
428  "created to hold this page.",
429  FALSE,
430  G_PARAM_READWRITE));
431 
432  g_object_class_install_property
433  (gobject_class,
434  PROP_UI_DESCRIPTION,
435  g_param_spec_string ("ui-description",
436  "UI Description File",
437  "The filename containing the XML data that "
438  "describes this pages menus and toolbars.",
439  NULL,
440  G_PARAM_READWRITE));
441 
442  g_object_class_install_property
443  (gobject_class,
444  PROP_UI_MERGE,
445  g_param_spec_object ("ui-merge",
446  "UI Merge",
447  "A pointer to the GtkUIManager object that "
448  "represents this pages menu hierarchy.",
449  GTK_TYPE_UI_MANAGER,
450  G_PARAM_READABLE));
451 
452  g_object_class_install_property
453  (gobject_class,
454  PROP_ACTION_GROUP,
455  g_param_spec_object ("action-group",
456  "Action Group",
457  "A pointer to the GtkActionGroup object that "
458  "represents this pages available menu/toolbar "
459  "actions.",
460  GTK_TYPE_ACTION_GROUP,
461  G_PARAM_READABLE));
462 
463 
464 
465 
466  signals[INSERTED] = g_signal_new ("inserted",
467  G_OBJECT_CLASS_TYPE (klass),
468  G_SIGNAL_RUN_FIRST,
469  G_STRUCT_OFFSET (GncPluginPageClass, inserted),
470  NULL, NULL,
471  g_cclosure_marshal_VOID__VOID,
472  G_TYPE_NONE,
473  0);
474  signals[REMOVED] = g_signal_new ("removed",
475  G_OBJECT_CLASS_TYPE (klass),
476  G_SIGNAL_RUN_FIRST,
477  G_STRUCT_OFFSET (GncPluginPageClass, removed),
478  NULL, NULL,
479  g_cclosure_marshal_VOID__VOID,
480  G_TYPE_NONE,
481  0);
482  signals[SELECTED] = g_signal_new ("selected",
483  G_OBJECT_CLASS_TYPE (klass),
484  G_SIGNAL_RUN_FIRST,
485  G_STRUCT_OFFSET (GncPluginPageClass, selected),
486  NULL, NULL,
487  g_cclosure_marshal_VOID__VOID,
488  G_TYPE_NONE,
489  0);
490  signals[UNSELECTED] = g_signal_new ("unselected",
491  G_OBJECT_CLASS_TYPE (klass),
492  G_SIGNAL_RUN_FIRST,
493  G_STRUCT_OFFSET (GncPluginPageClass, unselected),
494  NULL, NULL,
495  g_cclosure_marshal_VOID__VOID,
496  G_TYPE_NONE,
497  0);
498 }
499 
500 
509 static void
510 gnc_plugin_page_init (GncPluginPage *page, void *data)
511 {
512  GncPluginPagePrivate *priv;
513 
514  GncPluginPageClass *klass = (GncPluginPageClass*)data;
515 
516  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
517  priv->page_name = NULL;
518  priv->page_color = NULL;
519  priv->uri = NULL;
520  priv->page_changed_id = 0;
521  priv->focus_source_id = 0;
522 
523  page->window = NULL;
524  page->summarybar = NULL;
525 
526  gnc_gobject_tracking_remember (G_OBJECT(page),
527  G_OBJECT_CLASS(klass));
528 }
529 
530 
538 static void
539 gnc_plugin_page_finalize (GObject *object)
540 {
541  GncPluginPagePrivate *priv;
542  GncPluginPage *page;
543 
544  page = GNC_PLUGIN_PAGE(object);
545 
546  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
547 
548  if (priv->ui_description)
549  g_free (priv->ui_description);
550 
551  if (priv->page_name)
552  g_free (priv->page_name);
553 
554  if (priv->page_long_name)
555  g_free (priv->page_long_name);
556 
557  if (priv->page_color)
558  g_free (priv->page_color);
559 
560  if (priv->uri)
561  g_free (priv->uri);
562 
563  if (priv->statusbar_text)
564  g_free (priv->statusbar_text);
565 
566  if (priv->books)
567  {
568  g_list_free (priv->books);
569  priv->books = NULL;
570  }
571 
572  page->window = NULL; // Don't need to free it.
573 
575  G_OBJECT_CLASS(parent_class)->finalize (object);
576 }
577 
578 /************************************************************/
579 /* g_object other functions */
580 /************************************************************/
581 
582 
599 /* Note that g_value_set_object() refs the object, as does
600  * g_object_get(). But g_object_get() only unrefs once when it disgorges
601  * the object, leaving an unbalanced ref, which leaks. So instead of
602  * using g_value_set_object(), use g_value_take_object() which doesn't
603  * ref the object when used in get_property().
604  */
605 static void
606 gnc_plugin_page_get_property (GObject *object,
607  guint prop_id,
608  GValue *value,
609  GParamSpec *pspec)
610 {
611  GncPluginPage *page;
612  GncPluginPagePrivate *priv;
613 
614  g_return_if_fail(GNC_IS_PLUGIN_PAGE(object));
615 
616  page = GNC_PLUGIN_PAGE(object);
617  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
618  switch (prop_id)
619  {
620  case PROP_PAGE_NAME:
621  g_value_set_string (value, priv->page_name);
622  break;
623  case PROP_PAGE_COLOR:
624  g_value_set_string (value, priv->page_color);
625  break;
626  case PROP_PAGE_URI:
627  g_value_set_string (value, priv->uri);
628  break;
629  case PROP_STATUSBAR_TEXT:
630  g_value_set_string (value, priv->statusbar_text);
631  break;
632  case PROP_USE_NEW_WINDOW:
633  g_value_set_boolean (value, priv->use_new_window);
634  break;
635  case PROP_UI_DESCRIPTION:
636  g_value_set_string (value, priv->ui_description);
637  break;
638  case PROP_UI_MERGE:
639  g_value_take_object (value, priv->ui_merge);
640  break;
641  case PROP_ACTION_GROUP:
642  g_value_take_object (value, priv->action_group);
643  break;
644  default:
645  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
646  break;
647  }
648 }
649 
650 
667 static void
668 gnc_plugin_page_set_property (GObject *object,
669  guint prop_id,
670  const GValue *value,
671  GParamSpec *pspec)
672 {
673  GncPluginPage *page;
674 
675  g_return_if_fail(GNC_IS_PLUGIN_PAGE(object));
676 
677  page = GNC_PLUGIN_PAGE(object);
678 
679  switch (prop_id)
680  {
681  case PROP_PAGE_NAME:
682  gnc_plugin_page_set_page_name (page, g_value_get_string (value));
683  break;
684  case PROP_PAGE_COLOR:
685  gnc_plugin_page_set_page_color (page, g_value_get_string (value));
686  break;
687  case PROP_PAGE_URI:
688  gnc_plugin_page_set_uri (page, g_value_get_string (value));
689  break;
690  case PROP_STATUSBAR_TEXT:
691  gnc_plugin_page_set_statusbar_text (page, g_value_get_string (value));
692  break;
693  case PROP_USE_NEW_WINDOW:
694  gnc_plugin_page_set_use_new_window (page, g_value_get_boolean (value));
695  break;
696  case PROP_UI_DESCRIPTION:
697  gnc_plugin_page_set_ui_description (page, g_value_get_string (value));
698  break;
699  default:
700  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
701  break;
702  }
703 }
704 
705 /************************************************************/
706 /* */
707 /************************************************************/
708 
709 /* Add a book reference to the specified page. */
710 void
712 {
713  GncPluginPagePrivate *priv;
714 
715  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
716  g_return_if_fail (book != NULL);
717 
718  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
719  priv->books = g_list_append (priv->books, book);
720 }
721 
722 
723 /* Query a page to see if it has a reference to a given book. */
724 gboolean
726 {
727  GncPluginPagePrivate *priv;
728  GList *item;
729 
730  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), FALSE);
731  g_return_val_if_fail (book != NULL, FALSE);
732 
733  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
734  for (item = priv->books; item; item = g_list_next (item))
735  {
736  if (item->data == book)
737  {
738  return TRUE;
739  }
740  }
741  return FALSE;
742 }
743 
744 
745 /* Query a page to see if it has a reference to any book. */
746 gboolean
748 {
749  GncPluginPagePrivate *priv;
750 
751  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), FALSE);
752 
753  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
754  return (priv->books != NULL);
755 }
756 
757 
758 /* Retrieve a pointer to the GncMainWindow (GtkWindow) containing
759  * this page. */
760 GtkWidget *
762 {
763  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
764 
765  return page->window;
766 }
767 
768 
769 /* Retrieve the name of this page. This is the string used in the
770  * window title, and in the notebook tab and page selection menus. */
771 const gchar *
773 {
774  GncPluginPagePrivate *priv;
775 
776  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
777 
778  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
779  return priv->page_name;
780 }
781 
782 
783 /* Set the name of this page. This is the string used in the window
784  * title, and in the notebook tab and page selection menus. */
785 void
786 gnc_plugin_page_set_page_name (GncPluginPage *page, const gchar *name)
787 {
788  GncPluginPagePrivate *priv;
789  GncPluginPageClass *klass;
790 
791  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
792 
793  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
794  if (priv->page_name)
795  g_free (priv->page_name);
796 
797  priv->page_name = g_strdup (name);
798 
799  /* Perform page specific actions */
800  klass = GNC_PLUGIN_PAGE_GET_CLASS (page);
801  if (klass->page_name_changed)
802  {
803  klass->page_name_changed(page, name);
804  }
805 }
806 
807 
808 /* Retrieve the long name of this page. This is the string used in
809  * the tooltip that is attached to the page name in the notebook
810  * tab. */
811 const gchar *
813 {
814  GncPluginPagePrivate *priv;
815 
816  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
817 
818  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
819  return priv->page_long_name;
820 }
821 
822 
823 /* Set the long name of this page. This is the string used in the
824  * tooltip that is attached to the page name in the notebook tab. */
825 void
826 gnc_plugin_page_set_page_long_name (GncPluginPage *page, const gchar *name)
827 {
828  GncPluginPagePrivate *priv;
829 
830  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
831 
832  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
833  if (priv->page_long_name)
834  g_free (priv->page_long_name);
835 
836  priv->page_long_name = g_strdup (name);
837 }
838 
839 
840 /* Get the color of this page. This is the string used in the notebook tab. */
841 const gchar *
843 {
844  GncPluginPagePrivate *priv;
845 
846  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
847 
848  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
849  return priv->page_color;
850 }
851 
852 
853 /* Set the color of this page. This is the string used in the notebook tab. */
854 void
855 gnc_plugin_page_set_page_color (GncPluginPage *page, const gchar *color)
856 {
857  GncPluginPagePrivate *priv;
858 
859  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
860 
861  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
862  if (priv->page_color)
863  g_free (priv->page_color);
864 
865  if (color)
866  priv->page_color = g_strdup (color);
867 }
868 
869 
870 static void
871 gnc_plugin_page_focus_idle_destroy (GncPluginPage *plugin_page)
872 {
873  GncPluginPagePrivate *priv = GNC_PLUGIN_PAGE_GET_PRIVATE(plugin_page);
874  priv->focus_source_id = 0;
875 }
876 
877 
878 static void
879 gnc_plugin_page_default_focus (GncPluginPage *plugin_page,
880  gboolean on_current_page)
881 {
882  GncPluginPagePrivate *priv;
883 
884  if (!on_current_page)
885  return;
886 
887  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
888 
889  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(plugin_page);
890 
891  if (G_LIKELY(GNC_PLUGIN_PAGE_GET_CLASS(plugin_page)->focus_page_function))
892  {
893  // The page changed signal is emitted multiple times so we need
894  // to use an idle_add to change the focus
895 
896  if (priv->focus_source_id > 0)
897  g_source_remove (priv->focus_source_id);
898 
899  priv->focus_source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
900  (GSourceFunc)(GNC_PLUGIN_PAGE_GET_CLASS(plugin_page)->focus_page_function),
901  GNC_PLUGIN_PAGE(plugin_page),
902  (GDestroyNotify)gnc_plugin_page_focus_idle_destroy);
903  }
904 }
905 
906 
907 /* this is the callback for the plugin "page_changed" signal */
908 static void
909 gnc_plugin_page_main_window_changed (GtkWindow *window,
910  GObject *object,
911  gpointer user_data)
912 {
913  GncPluginPage *current_plugin_page = GNC_PLUGIN_PAGE(object);
914  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(user_data);
915  GncPluginPagePrivate *priv;
916  gboolean on_current_page = FALSE;
917 
918  // Continue if current_plugin_page is valid
919  if (!current_plugin_page || !GNC_IS_PLUGIN_PAGE(current_plugin_page))
920  return;
921 
922  // Continue only if the plugin_page is valid
923  if (!plugin_page || !GNC_IS_PLUGIN_PAGE(plugin_page))
924  return;
925 
926  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(plugin_page);
927 
928  if (current_plugin_page == plugin_page)
929  on_current_page = TRUE;
930 
931  (GNC_PLUGIN_PAGE_GET_CLASS(plugin_page)->focus_page)(plugin_page, on_current_page);
932 }
933 
934 
935 /* this is the callback for the plugin "inserted" signal which will setup
936  * the callback for the "page_changed" signal and save a pointer to the
937  * page focus function. */
938 void
939 gnc_plugin_page_inserted_cb (GncPluginPage *page, gpointer user_data)
940 {
941  GncPluginPagePrivate *priv;
942 
943  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
944 
945  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
946 
947  priv->page_changed_id = g_signal_connect (G_OBJECT(page->window), "page_changed",
948  G_CALLBACK(gnc_plugin_page_main_window_changed),
949  page);
950 
951  // on initial load try and set the page focus
952  (GNC_PLUGIN_PAGE_GET_CLASS(page)->focus_page)(page, TRUE);
953 }
954 
955 
956 /* disconnect the page_changed callback */
957 void
959 {
960  GncPluginPagePrivate *priv;
961 
962  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
963 
964  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
965 
966  if (priv->page_changed_id > 0)
967  {
968  g_signal_handler_disconnect (G_OBJECT(page->window), priv->page_changed_id);
969  priv->page_changed_id = 0;
970  }
971 }
972 
973 
974 /* Retrieve the Uniform Resource Identifier for this page. */
975 const gchar *
977 {
978  GncPluginPagePrivate *priv;
979 
980  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
981 
982  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
983  return priv->uri;
984 }
985 
986 
987 /* Set the Uniform Resource Identifier for this page. */
988 void
989 gnc_plugin_page_set_uri (GncPluginPage *page, const gchar *name)
990 {
991  GncPluginPagePrivate *priv;
992 
993  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
994 
995  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
996  if (priv->uri)
997  g_free (priv->uri);
998 
999  priv->uri = g_strdup (name);
1000 }
1001 
1002 
1003 /* Retrieve the statusbar text associated with this page. */
1004 const gchar *
1006 {
1007  GncPluginPagePrivate *priv;
1008 
1009  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
1010 
1011  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1012  return priv->statusbar_text;
1013 }
1014 
1015 
1016 /* Set the statusbar text associated with this page. */
1017 void
1018 gnc_plugin_page_set_statusbar_text (GncPluginPage *page, const gchar *message)
1019 {
1020  GncPluginPagePrivate *priv;
1021 
1022  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
1023 
1024  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1025  if (priv->statusbar_text)
1026  g_free (priv->statusbar_text);
1027 
1028  priv->statusbar_text = g_strdup (message);
1029 }
1030 
1031 
1032 /* Retrieve the "use new window" setting associated with this page. */
1033 gboolean
1035 {
1036  GncPluginPagePrivate *priv;
1037 
1038  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), FALSE);
1039 
1040  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1041  return priv->use_new_window;
1042 }
1043 
1044 
1045 /* Set the "use new window" setting associated with this page. If
1046  * this setting is TRUE, the page will be installed into a new
1047  * window. Otherwise the page will be installed into an existing
1048  * window. */
1049 void
1051 {
1052  GncPluginPagePrivate *priv;
1053 
1054  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
1055 
1056  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1057  priv->use_new_window = use_new;
1058 }
1059 
1060 
1061 /* Retrieve the name of the XML UI file associated with this page. */
1062 const gchar *
1064 {
1065  GncPluginPagePrivate *priv;
1066 
1067  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), FALSE);
1068 
1069  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1070  return priv->ui_description;
1071 }
1072 
1073 
1074 /* Set an alternate UI for the specified page. This alternate ui
1075  * may only use actions specified in the source for the page. */
1076 void
1078  const char *ui_filename)
1079 {
1080  GncPluginPagePrivate *priv;
1081 
1082  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
1083 
1084  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1085  if (priv->ui_description)
1086  g_free (priv->ui_description);
1087 
1088  priv->ui_description = g_strdup (ui_filename);
1089 }
1090 
1091 
1092 /* Retrieve the GtkUIManager object associated with this page. */
1093 GtkUIManager *
1095 {
1096  GncPluginPagePrivate *priv;
1097 
1098  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
1099 
1100  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1101  return priv->ui_merge;
1102 }
1103 
1104 
1105 /* Retrieve the GtkActionGroup object associated with this page. */
1106 GtkActionGroup *
1108 {
1109  GncPluginPagePrivate *priv;
1110 
1111  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
1112 
1113  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1114  return priv->action_group;
1115 }
1116 
1117 
1118 /* Create the GtkActionGroup object associated with this page. */
1119 GtkActionGroup *
1120 gnc_plugin_page_create_action_group (GncPluginPage *page, const gchar *group_name)
1121 {
1122  GncPluginPagePrivate *priv;
1123  GtkActionGroup *group;
1124 
1125  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1126  group = gtk_action_group_new (group_name);
1127  gtk_action_group_set_translation_domain (group, PROJECT_NAME);
1128  priv->action_group = group;
1129  return group;
1130 }
1131 
1132 gboolean
1134 {
1135  if (!page)
1136  return TRUE;
1137 
1138  if (!GNC_IS_PLUGIN_PAGE(page))
1139  return TRUE;
1140 
1141  if (!GNC_PLUGIN_PAGE_GET_CLASS(page)->finish_pending)
1142  return TRUE;
1143 
1144  return (GNC_PLUGIN_PAGE_GET_CLASS(page)->finish_pending)(page);
1145 }
1146 
GncPluginPage * gnc_plugin_page_recreate_page(GtkWidget *window, const gchar *page_type, GKeyFile *key_file, const gchar *page_group)
This function looks up a specific plugin type by name, and then calls a plugin specific function to c...
GtkWidget * gnc_plugin_page_get_window(GncPluginPage *page)
Retrieve a pointer to the GncMainWindow (GtkWindow) containing this page.
gboolean gnc_plugin_page_has_books(GncPluginPage *page)
Query a page to see if it has a reference to any book.
gboolean gnc_plugin_page_get_use_new_window(GncPluginPage *page)
Retrieve the "use new window" setting associated with this page.
const gchar * tab_icon
The relative name of the icon that should be shown on the tab for this page.
gboolean gnc_plugin_page_finish_pending(GncPluginPage *page)
Tell a page to finish any outstanding activities.
void(* focus_page)(GncPluginPage *plugin_page, gboolean on_current_page)
Perform plugin specific actions to set the focus.
void gnc_plugin_page_destroy_widget(GncPluginPage *plugin_page)
Destroy the display widget that corresponds to this plugin.
The instance data structure for a content plugin.
void gnc_plugin_page_set_statusbar_text(GncPluginPage *page, const char *name)
Set the statusbar text associated with this page.
void gnc_gobject_tracking_remember(GObject *object, GObjectClass *klass)
Tell gnucash to remember this object in the database.
GncPluginPage *(* recreate_page)(GtkWidget *window, GKeyFile *file, const gchar *group)
Create a new page based on the information saved during a previous instantiation of gnucash...
const gchar * gnc_plugin_page_get_page_long_name(GncPluginPage *page)
Retrieve the long name of this page.
void gnc_gobject_tracking_forget(GObject *object)
Tell gnucash to remember this object in the database.
void gnc_plugin_page_set_uri(GncPluginPage *page, const char *name)
Set the Uniform Resource Identifier for this page.
void gnc_plugin_page_set_ui_description(GncPluginPage *page, const char *ui_filename)
Set an alternate UI for the specified page.
const gchar * gnc_plugin_page_get_page_name(GncPluginPage *page)
Retrieve the name of this page.
GtkWidget * window
The window that contains the display widget for this plugin.
const gchar * gnc_plugin_page_get_page_color(GncPluginPage *page)
Retrieve the color of this page.
void gnc_plugin_page_unmerge_actions(GncPluginPage *page, GtkUIManager *ui_merge)
Remove the actions for a content page from the specified window.
void gnc_plugin_page_set_page_long_name(GncPluginPage *page, const char *name)
Set the long name of this page.
const gchar * gnc_plugin_page_get_ui_description(GncPluginPage *page)
Retrieve the name of the XML UI file associated with this page.
GtkActionGroup * gnc_plugin_page_get_action_group(GncPluginPage *page)
Retrieve the GtkActionGroup object associated with this page.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
void(* destroy_widget)(GncPluginPage *plugin_page)
Function called to destroy the display widget for a particular type of plugin.
The class data structure for a content plugin.
Gobject helper routines.
const gchar * gnc_plugin_page_get_uri(GncPluginPage *page)
Retrieve the Uniform Resource Identifier for this page.
void gnc_plugin_page_set_use_new_window(GncPluginPage *page, gboolean use_new)
Set the "use new window" setting associated with this page.
gint gnc_plugin_add_actions(GtkUIManager *ui_merge, GtkActionGroup *action_group, const gchar *filename)
Load a new set of actions into an existing UI.
Definition: gnc-plugin.c:309
void gnc_plugin_page_disconnect_page_changed(GncPluginPage *page)
Disconnect the page_changed_id signal callback.
gboolean gnc_plugin_page_has_book(GncPluginPage *page, QofBook *book)
Query a page to see if it has a reference to a given book.
const gchar * plugin_name
The textual name of this plugin.
Functions for adding plugins to a GnuCash window.
GtkWidget *(* create_widget)(GncPluginPage *plugin_page)
Function called to create the display widget for a particular type of plugin.
const gchar * gnc_plugin_page_get_statusbar_text(GncPluginPage *page)
Retrieve the statusbar text associated with this page.
void(* page_name_changed)(GncPluginPage *plugin_page, const gchar *name)
This function vector allows page specific actions to occur when the page name is changed.
void gnc_plugin_page_save_page(GncPluginPage *page, GKeyFile *key_file, const gchar *group_name)
Call the plugin specific function that will save the state of a content page to a disk...
All type declarations for the whole Gnucash engine.
void(* save_page)(GncPluginPage *page, GKeyFile *file, const gchar *group)
Save enough information about this page so that it can be recreated next time the user starts gnucash...
The instance private data for a content plugin.
GtkAction * gnc_plugin_page_get_action(GncPluginPage *page, const gchar *name)
Retrieve a GtkAction object associated with this page.
void gnc_plugin_page_set_page_color(GncPluginPage *page, const char *color)
Set the color of this page.
void gnc_plugin_page_merge_actions(GncPluginPage *page, GtkUIManager *ui_merge)
Add the actions for a content page to the specified window.
GtkActionGroup * action_group
The group of all actions provided by this plugin.
void gnc_plugin_page_inserted_cb(GncPluginPage *page, gpointer user_data)
Set up the page_changed callback for when the current page is changed.
Functions for adding plugins to a GnuCash window.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
void gnc_plugin_page_set_page_name(GncPluginPage *page, const char *name)
Set the name of this page.
void gnc_plugin_page_add_book(GncPluginPage *page, QofBook *book)
Add a book reference to the specified page.
GtkActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GtkActionGroup object associated with this page.
GtkUIManager * gnc_plugin_page_get_ui_merge(GncPluginPage *page)
Retrieve the GtkUIManager object associated with this page.
void gnc_plugin_page_show_summarybar(GncPluginPage *page, gboolean visible)
Show/hide the summarybar associated with this page.
GtkWidget * summarybar
The summary bar widget (if any) that is associated with this plugin.
GtkWidget * gnc_plugin_page_create_widget(GncPluginPage *plugin_page)
Create the display widget that corresponds to this plugin.
const gchar * gnc_plugin_page_get_plugin_name(GncPluginPage *plugin_page)
Retrieve the textual name of a plugin.