GnuCash  5.6-150-g038405b370+
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 #include "gnc-ui.h"
43 
45 static QofLogModule log_module = GNC_MOD_GUI;
46 
47 static void gnc_plugin_page_constructed (GObject *object);
48 static void gnc_plugin_page_finalize (GObject *object);
49 static void gnc_plugin_page_set_property (GObject *object,
50  guint prop_id,
51  const GValue *value,
52  GParamSpec *pspec);
53 static void gnc_plugin_page_get_property (GObject *object,
54  guint prop_id,
55  GValue *value,
56  GParamSpec *pspec);
57 
58 static void gnc_plugin_page_default_focus (GncPluginPage *plugin_page,
59  gboolean on_current_page);
60 
61 enum
62 {
63  INSERTED,
64  REMOVED,
65  SELECTED,
66  UNSELECTED,
67  LAST_SIGNAL
68 };
69 
70 enum
71 {
72  PROP_0,
73  PROP_PAGE_NAME,
74  PROP_PAGE_COLOR,
75  PROP_BOOK,
76  PROP_STATUSBAR_TEXT,
77  PROP_USE_NEW_WINDOW,
78  PROP_UI_DESCRIPTION,
79 };
80 
81 static guint signals[LAST_SIGNAL] = { 0 };
82 
83 
85 typedef struct _GncPluginPagePrivate
86 {
89 
90  GtkBuilder *builder;
91  GSimpleActionGroup *simple_action_group;
92  const gchar *simple_action_group_name;
93  const gchar *menu_qualifier;
94  const gchar *menu_popup_qualifier;
95 
96  GList *books;
97 
98  gboolean use_new_window;
99 
100  gchar *page_name;
101  gchar *page_long_name;
102  gchar *page_color;
103  gchar *uri;
104  gchar *statusbar_text;
105 
106  gulong page_changed_id;
107  guint focus_source_id;
108 
110 
111 G_DEFINE_TYPE_WITH_CODE(GncPluginPage, gnc_plugin_page, G_TYPE_OBJECT,
112  G_ADD_PRIVATE(GncPluginPage))
113 
114 #define GNC_PLUGIN_PAGE_GET_PRIVATE(o) \
115  ((GncPluginPagePrivate*)gnc_plugin_page_get_instance_private((GncPluginPage*)o))
116 
117 /* Create the display widget that corresponds to this plugin. This
118  * function will be called by the main/embedded window manipulation
119  * code to create a widget that they can display. The returned
120  * widget should encompass all information that goes with this page,
121  * including scroll bars, a summary bar, etc. */
122 GtkWidget *
124 {
125  GncPluginPageClass *klass;
126  GtkWidget *widget;
127 
128  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page), NULL);
129 
130  klass = GNC_PLUGIN_PAGE_GET_CLASS(plugin_page);
131  g_return_val_if_fail (klass != NULL, NULL);
132  g_return_val_if_fail (klass->create_widget != NULL, NULL);
133 
134  widget = klass->create_widget (plugin_page);
135 
136  /*
137  * If there is a destroy function, add a ref so that the
138  * widgets will exists when the destroy function is called.
139  * Otherwise it will be destroyed when it is removed from the
140  * main notebook for the window.
141  */
142  if (klass->destroy_widget)
143  g_object_ref (widget);
144 
145  return widget;
146 }
147 
148 
149 /* Destroy the display widget that corresponds to this plugin. This
150  * function will be called by the main/embedded window manipulation
151  * code when a page is closed. */
152 void
154 {
155  GncPluginPageClass *klass;
156 
157  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
158 
159  klass = GNC_PLUGIN_PAGE_GET_CLASS(plugin_page);
160  g_return_if_fail (klass != NULL);
161  g_return_if_fail (klass->destroy_widget != NULL);
162 
163  klass->destroy_widget (plugin_page);
164 }
165 
166 
167 /* Show/hide the summarybar associated with this page. */
168 void
170  gboolean visible)
171 {
172  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
173 
174  if (!page->summarybar)
175  return;
176 
177  if (visible)
178  gtk_widget_show (page->summarybar);
179  else
180  gtk_widget_hide (page->summarybar);
181 }
182 
183 
184 /* Call the plugin specific function that will save the state of a
185  * content page to a disk. That function must save enough
186  * information about the page that it can be recreated next time the
187  * user starts gnucash. */
188 void
190  GKeyFile *key_file,
191  const gchar *group_name)
192 {
193  GncPluginPageClass *klass;
194 
195  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
196  g_return_if_fail (key_file != NULL);
197  g_return_if_fail (group_name != NULL);
198 
199  ENTER(" ");
200  klass = GNC_PLUGIN_PAGE_GET_CLASS(page);
201  g_return_if_fail (klass != NULL);
202  g_return_if_fail (klass->save_page != NULL);
203 
204  klass->save_page (page, key_file, group_name);
205  LEAVE(" ");
206 }
207 
208 
209 /* This function looks up a specific plugin type by name, and then
210  * calls a plugin specific function to create a new page and restore
211  * its content to a previous state. */
214  const gchar *page_type,
215  GKeyFile *key_file,
216  const gchar *page_group)
217 {
218  GncPluginPageClass *klass;
219  GncPluginPage *page = NULL;
220  GType type;
221 
222  ENTER("type %s, keyfile %p, group %s", page_type, key_file, page_group);
223  type = g_type_from_name (page_type);
224  if (type == 0)
225  {
226  LEAVE("Cannot find type named %s", page_type);
227  return NULL;
228  }
229 
230  klass = g_type_class_ref (type);
231  if (klass == NULL)
232  {
233  const gchar *type_name = g_type_name (type);
234  LEAVE("Cannot create class %s(%s)", page_type, type_name ? type_name : "invalid type");
235  return NULL;
236  }
237 
238  if (!klass->recreate_page)
239  {
240  LEAVE("Class %shas no recreate function.", page_type);
241  g_type_class_unref (klass);
242  return NULL;
243  }
244 
245  page = (klass->recreate_page)(window, key_file, page_group);
246  g_type_class_unref (klass);
247  LEAVE(" ");
248  return page;
249 }
250 
251 
252 void
254 {
255  GncPluginPagePrivate *priv;
256  GError *error = NULL;
257  gchar *resource;
258 
259  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
260 
261  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
262 
263  if (!priv->builder)
264  priv->builder = gtk_builder_new ();
265 
266  resource = g_strconcat (GNUCASH_RESOURCE_PREFIX "/", priv->ui_description, NULL);
267 
268  gtk_builder_set_translation_domain (priv->builder, PROJECT_NAME);
269 
270  gtk_builder_add_from_resource (priv->builder, resource, &error);
271 
272  if (error)
273  {
274  g_critical ("Failed to load ui resource %s, Error %s", resource, error->message);
275  g_error_free (error);
276  }
277  g_free (resource);
278 }
279 
280 
281 GAction *
282 gnc_plugin_page_get_action (GncPluginPage *page, const gchar *name)
283 {
284  GncPluginPagePrivate *priv;
285 
286  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
287  g_return_val_if_fail (name != NULL, NULL);
288 
289  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
290  if (!priv->simple_action_group)
291  return NULL;
292  return g_action_map_lookup_action (G_ACTION_MAP(priv->simple_action_group), name);
293 }
294 
295 
296 /* Retrieve the textual name of a plugin. */
297 const gchar *
299 {
300  GncPluginPageClass *klass;
301 
302  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page), NULL);
303 
304  klass = GNC_PLUGIN_PAGE_GET_CLASS(plugin_page);
305  g_return_val_if_fail (klass != NULL, NULL);
306 
307  return (klass->plugin_name);
308 }
309 
310 
311 /* Signals */
312 void
313 gnc_plugin_page_inserted (GncPluginPage *plugin_page)
314 {
315  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
316 
317  g_signal_emit (G_OBJECT(plugin_page), signals[INSERTED], 0);
318 }
319 
320 void
321 gnc_plugin_page_removed (GncPluginPage *plugin_page)
322 {
323  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
324 
325  g_signal_emit (G_OBJECT(plugin_page), signals[REMOVED], 0);
326 }
327 
328 void
329 gnc_plugin_page_selected (GncPluginPage *plugin_page)
330 {
331  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
332 
333  g_signal_emit (G_OBJECT(plugin_page), signals[SELECTED], 0);
334 }
335 
336 void
337 gnc_plugin_page_unselected (GncPluginPage *plugin_page)
338 {
339  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
340 
341  g_signal_emit (G_OBJECT(plugin_page), signals[UNSELECTED], 0);
342 }
343 
351 static void
352 gnc_plugin_page_class_init (GncPluginPageClass *klass)
353 {
354  GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
355 
356  gobject_class->constructed = gnc_plugin_page_constructed;
357  gobject_class->finalize = gnc_plugin_page_finalize;
358  gobject_class->set_property = gnc_plugin_page_set_property;
359  gobject_class->get_property = gnc_plugin_page_get_property;
360 
361  klass->tab_icon = NULL;
362  klass->plugin_name = NULL;
363  klass->focus_page = gnc_plugin_page_default_focus;
364 
365  g_object_class_install_property
366  (gobject_class,
367  PROP_PAGE_NAME,
368  g_param_spec_string ("page-name",
369  "Page Name",
370  "The name of this page. This value is "
371  "used to generate the notebook tab and "
372  "menu items, and also the window title "
373  "when this page is visible.",
374  NULL,
375  G_PARAM_READWRITE));
376 
377  g_object_class_install_property
378  (gobject_class,
379  PROP_PAGE_COLOR,
380  g_param_spec_string ("page-color",
381  "Page Color",
382  "The color of this page. This value is "
383  "used to generate the notebook tab color "
384  "when this page is visible.",
385  NULL,
386  G_PARAM_READWRITE));
387 
388  g_object_class_install_property
389  (gobject_class,
390  PROP_STATUSBAR_TEXT,
391  g_param_spec_string ("statusbar-text",
392  "Statusbar Text",
393  "The text to be displayed in the statusbar "
394  "at the bottom of the window when this page "
395  "is visible.",
396  NULL,
397  G_PARAM_READWRITE));
398 
399  g_object_class_install_property
400  (gobject_class,
401  PROP_USE_NEW_WINDOW,
402  g_param_spec_boolean ("use-new-window",
403  "Use New Window",
404  "When TRUE a new top level window will be "
405  "created to hold this page.",
406  FALSE,
407  G_PARAM_READWRITE));
408 
409  g_object_class_install_property
410  (gobject_class,
411  PROP_UI_DESCRIPTION,
412  g_param_spec_string ("ui-description",
413  "UI Description File",
414  "The filename containing the XML data that "
415  "describes this pages menus and toolbars.",
416  NULL,
417  G_PARAM_READWRITE));
418 
419 
420 
421  signals[INSERTED] = g_signal_new ("inserted",
422  G_OBJECT_CLASS_TYPE (klass),
423  G_SIGNAL_RUN_FIRST,
424  G_STRUCT_OFFSET (GncPluginPageClass, inserted),
425  NULL, NULL,
426  g_cclosure_marshal_VOID__VOID,
427  G_TYPE_NONE,
428  0);
429  signals[REMOVED] = g_signal_new ("removed",
430  G_OBJECT_CLASS_TYPE (klass),
431  G_SIGNAL_RUN_FIRST,
432  G_STRUCT_OFFSET (GncPluginPageClass, removed),
433  NULL, NULL,
434  g_cclosure_marshal_VOID__VOID,
435  G_TYPE_NONE,
436  0);
437  signals[SELECTED] = g_signal_new ("selected",
438  G_OBJECT_CLASS_TYPE (klass),
439  G_SIGNAL_RUN_FIRST,
440  G_STRUCT_OFFSET (GncPluginPageClass, selected),
441  NULL, NULL,
442  g_cclosure_marshal_VOID__VOID,
443  G_TYPE_NONE,
444  0);
445  signals[UNSELECTED] = g_signal_new ("unselected",
446  G_OBJECT_CLASS_TYPE (klass),
447  G_SIGNAL_RUN_FIRST,
448  G_STRUCT_OFFSET (GncPluginPageClass, unselected),
449  NULL, NULL,
450  g_cclosure_marshal_VOID__VOID,
451  G_TYPE_NONE,
452  0);
453 }
454 
455 
461 static void
462 gnc_plugin_page_init (GncPluginPage *page)
463 {
464  GncPluginPagePrivate *priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
465  priv->page_name = NULL;
466  priv->page_color = NULL;
467  priv->page_changed_id = 0;
468  priv->focus_source_id = 0;
469  priv->menu_qualifier = NULL;
470 
471  page->window = NULL;
472  page->summarybar = NULL;
473 }
474 
481  static void
482 gnc_plugin_page_constructed (GObject *obj)
483 {
485 
486  G_OBJECT_CLASS (gnc_plugin_page_parent_class)->constructed (obj);
487 }
488 
496 static void
497 gnc_plugin_page_finalize (GObject *object)
498 {
499  GncPluginPagePrivate *priv;
500  GncPluginPage *page;
501 
502  page = GNC_PLUGIN_PAGE(object);
503 
504  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
505 
506  if (priv->ui_description)
507  g_free (priv->ui_description);
508 
509  if (priv->page_name)
510  g_free (priv->page_name);
511 
512  if (priv->page_long_name)
513  g_free (priv->page_long_name);
514 
515  if (priv->page_color)
516  g_free (priv->page_color);
517 
518  if (priv->statusbar_text)
519  g_free (priv->statusbar_text);
520 
521  if (priv->books)
522  {
523  g_list_free (priv->books);
524  priv->books = NULL;
525  }
526 
527  if (priv->builder)
528  g_object_unref (priv->builder);
529 
530  page->window = NULL; // Don't need to free it.
531 
533  G_OBJECT_CLASS(gnc_plugin_page_parent_class)->finalize (object);
534 }
535 
536 /************************************************************/
537 /* g_object other functions */
538 /************************************************************/
539 
540 
557 /* Note that g_value_set_object() refs the object, as does
558  * g_object_get(). But g_object_get() only unrefs once when it disgorges
559  * the object, leaving an unbalanced ref, which leaks. So instead of
560  * using g_value_set_object(), use g_value_take_object() which doesn't
561  * ref the object when used in get_property().
562  */
563 static void
564 gnc_plugin_page_get_property (GObject *object,
565  guint prop_id,
566  GValue *value,
567  GParamSpec *pspec)
568 {
569  GncPluginPage *page;
570  GncPluginPagePrivate *priv;
571 
572  g_return_if_fail(GNC_IS_PLUGIN_PAGE(object));
573 
574  page = GNC_PLUGIN_PAGE(object);
575  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
576  switch (prop_id)
577  {
578  case PROP_PAGE_NAME:
579  g_value_set_string (value, priv->page_name);
580  break;
581  case PROP_PAGE_COLOR:
582  g_value_set_string (value, priv->page_color);
583  break;
584  case PROP_STATUSBAR_TEXT:
585  g_value_set_string (value, priv->statusbar_text);
586  break;
587  case PROP_USE_NEW_WINDOW:
588  g_value_set_boolean (value, priv->use_new_window);
589  break;
590  case PROP_UI_DESCRIPTION:
591  g_value_set_string (value, priv->ui_description);
592  break;
593  default:
594  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
595  break;
596  }
597 }
598 
599 
616 static void
617 gnc_plugin_page_set_property (GObject *object,
618  guint prop_id,
619  const GValue *value,
620  GParamSpec *pspec)
621 {
622  GncPluginPage *page;
623 
624  g_return_if_fail(GNC_IS_PLUGIN_PAGE(object));
625 
626  page = GNC_PLUGIN_PAGE(object);
627 
628  switch (prop_id)
629  {
630  case PROP_PAGE_NAME:
631  gnc_plugin_page_set_page_name (page, g_value_get_string (value));
632  break;
633  case PROP_PAGE_COLOR:
634  gnc_plugin_page_set_page_color (page, g_value_get_string (value));
635  break;
636  case PROP_STATUSBAR_TEXT:
637  gnc_plugin_page_set_statusbar_text (page, g_value_get_string (value));
638  break;
639  case PROP_USE_NEW_WINDOW:
640  gnc_plugin_page_set_use_new_window (page, g_value_get_boolean (value));
641  break;
642  case PROP_UI_DESCRIPTION:
643  gnc_plugin_page_set_ui_description (page, g_value_get_string (value));
644  break;
645  default:
646  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
647  break;
648  }
649 }
650 
651 /************************************************************/
652 /* */
653 /************************************************************/
654 
655 /* Add a book reference to the specified page. */
656 void
658 {
659  GncPluginPagePrivate *priv;
660 
661  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
662  g_return_if_fail (book != NULL);
663 
664  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
665  priv->books = g_list_append (priv->books, book);
666 }
667 
668 
669 /* Query a page to see if it has a reference to a given book. */
670 gboolean
672 {
673  GncPluginPagePrivate *priv;
674  GList *item;
675 
676  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), FALSE);
677  g_return_val_if_fail (book != NULL, FALSE);
678 
679  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
680  for (item = priv->books; item; item = g_list_next (item))
681  {
682  if (item->data == book)
683  {
684  return TRUE;
685  }
686  }
687  return FALSE;
688 }
689 
690 
691 /* Query a page to see if it has a reference to any book. */
692 gboolean
694 {
695  GncPluginPagePrivate *priv;
696 
697  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), FALSE);
698 
699  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
700  return (priv->books != NULL);
701 }
702 
703 
704 /* Retrieve a pointer to the GncMainWindow (GtkWindow) containing
705  * this page. */
706 GtkWidget *
708 {
709  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
710 
711  return page->window;
712 }
713 
714 
715 /* Retrieve the name of this page. This is the string used in the
716  * window title, and in the notebook tab and page selection menus. */
717 const gchar *
719 {
720  GncPluginPagePrivate *priv;
721 
722  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
723 
724  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
725  return priv->page_name;
726 }
727 
728 
729 /* Set the name of this page. This is the string used in the window
730  * title, and in the notebook tab and page selection menus. */
731 void
732 gnc_plugin_page_set_page_name (GncPluginPage *page, const gchar *name)
733 {
734  GncPluginPagePrivate *priv;
735  GncPluginPageClass *klass;
736 
737  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
738 
739  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
740  if (priv->page_name)
741  g_free (priv->page_name);
742 
743  priv->page_name = g_strdup (name);
744 
745  /* Perform page specific actions */
746  klass = GNC_PLUGIN_PAGE_GET_CLASS (page);
747  if (klass->page_name_changed)
748  {
749  klass->page_name_changed(page, name);
750  }
751 }
752 
753 
754 /* Retrieve the long name of this page. This is the string used in
755  * the tooltip that is attached to the page name in the notebook
756  * tab. */
757 const gchar *
759 {
760  GncPluginPagePrivate *priv;
761 
762  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
763 
764  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
765  return priv->page_long_name;
766 }
767 
768 
769 /* Set the long name of this page. This is the string used in the
770  * tooltip that is attached to the page name in the notebook tab. */
771 void
772 gnc_plugin_page_set_page_long_name (GncPluginPage *page, const gchar *name)
773 {
774  GncPluginPagePrivate *priv;
775 
776  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
777 
778  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
779  if (priv->page_long_name)
780  g_free (priv->page_long_name);
781 
782  priv->page_long_name = g_strdup (name);
783 }
784 
785 
786 /* Get the color of this page. This is the string used in the notebook tab. */
787 const gchar *
789 {
790  GncPluginPagePrivate *priv;
791 
792  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
793 
794  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
795  return priv->page_color;
796 }
797 
798 
799 /* Set the color of this page. This is the string used in the notebook tab. */
800 void
801 gnc_plugin_page_set_page_color (GncPluginPage *page, const gchar *color)
802 {
803  GncPluginPagePrivate *priv;
804 
805  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
806 
807  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
808  if (priv->page_color)
809  g_free (priv->page_color);
810 
811  if (color)
812  priv->page_color = g_strdup (color);
813 }
814 
815 
816 static void
817 gnc_plugin_page_focus_idle_destroy (GncPluginPage *plugin_page)
818 {
819  GncPluginPagePrivate *priv = GNC_PLUGIN_PAGE_GET_PRIVATE(plugin_page);
820  priv->focus_source_id = 0;
821 }
822 
823 
824 static void
825 gnc_plugin_page_default_focus (GncPluginPage *plugin_page,
826  gboolean on_current_page)
827 {
828  GncPluginPagePrivate *priv;
829 
830  if (!on_current_page)
831  return;
832 
833  g_return_if_fail (GNC_IS_PLUGIN_PAGE(plugin_page));
834 
835  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(plugin_page);
836 
837  if (G_LIKELY(GNC_PLUGIN_PAGE_GET_CLASS(plugin_page)->focus_page_function))
838  {
839  // The page changed signal is emitted multiple times so we need
840  // to use an idle_add to change the focus
841 
842  if (priv->focus_source_id > 0)
843  g_source_remove (priv->focus_source_id);
844 
845  priv->focus_source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
846  (GSourceFunc)(GNC_PLUGIN_PAGE_GET_CLASS(plugin_page)->focus_page_function),
847  GNC_PLUGIN_PAGE(plugin_page),
848  (GDestroyNotify)gnc_plugin_page_focus_idle_destroy);
849  }
850 }
851 
852 
853 /* this is the callback for the plugin "page_changed" signal */
854 static void
855 gnc_plugin_page_main_window_changed (GtkWindow *window,
856  GObject *object,
857  gpointer user_data)
858 {
859  GncPluginPage *current_plugin_page = GNC_PLUGIN_PAGE(object);
860  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(user_data);
861  gboolean on_current_page = FALSE;
862 
863  // Continue if current_plugin_page is valid
864  if (!current_plugin_page || !GNC_IS_PLUGIN_PAGE(current_plugin_page))
865  return;
866 
867  // Continue only if the plugin_page is valid
868  if (!plugin_page || !GNC_IS_PLUGIN_PAGE(plugin_page))
869  return;
870 
871  if (current_plugin_page == plugin_page)
872  on_current_page = TRUE;
873 
874  (GNC_PLUGIN_PAGE_GET_CLASS(plugin_page)->focus_page)(plugin_page, on_current_page);
875 }
876 
877 
878 /* this is the callback for the plugin "inserted" signal which will setup
879  * the callback for the "page_changed" signal and save a pointer to the
880  * page focus function. */
881 void
882 gnc_plugin_page_inserted_cb (GncPluginPage *page, gpointer user_data)
883 {
884  GncPluginPagePrivate *priv;
885 
886  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
887 
888  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
889 
890  priv->page_changed_id = g_signal_connect (G_OBJECT(page->window), "page_changed",
891  G_CALLBACK(gnc_plugin_page_main_window_changed),
892  page);
893 
894  // on initial load try and set the page focus
895  if (!gnc_main_window_is_restoring_pages (GNC_MAIN_WINDOW (gnc_ui_get_main_window (page->window))))
896  (GNC_PLUGIN_PAGE_GET_CLASS(page)->focus_page)(page, TRUE);
897 }
898 
899 
900 /* disconnect the page_changed callback */
901 void
903 {
904  GncPluginPagePrivate *priv;
905 
906  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
907 
908  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
909 
910  if (priv->page_changed_id > 0)
911  {
912  g_signal_handler_disconnect (G_OBJECT(page->window), priv->page_changed_id);
913  priv->page_changed_id = 0;
914  }
915 }
916 
917 
918 /* Retrieve the statusbar text associated with this page. */
919 const gchar *
921 {
922  GncPluginPagePrivate *priv;
923 
924  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
925 
926  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
927  return priv->statusbar_text;
928 }
929 
930 
931 /* Set the statusbar text associated with this page. */
932 void
933 gnc_plugin_page_set_statusbar_text (GncPluginPage *page, const gchar *message)
934 {
935  GncPluginPagePrivate *priv;
936 
937  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
938 
939  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
940  if (priv->statusbar_text)
941  g_free (priv->statusbar_text);
942 
943  priv->statusbar_text = g_strdup (message);
944 }
945 
946 
947 /* Retrieve the "use new window" setting associated with this page. */
948 gboolean
950 {
951  GncPluginPagePrivate *priv;
952 
953  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), FALSE);
954 
955  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
956  return priv->use_new_window;
957 }
958 
959 
960 /* Set the "use new window" setting associated with this page. If
961  * this setting is TRUE, the page will be installed into a new
962  * window. Otherwise the page will be installed into an existing
963  * window. */
964 void
966 {
967  GncPluginPagePrivate *priv;
968 
969  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
970 
971  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
972  priv->use_new_window = use_new;
973 }
974 
975 
976 /* Retrieve the name of the XML UI file associated with this page. */
977 const gchar *
979 {
980  GncPluginPagePrivate *priv;
981 
982  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), FALSE);
983 
984  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
985  return priv->ui_description;
986 }
987 
988 
989 /* Set an alternate UI for the specified page. This alternate ui
990  * may only use actions specified in the source for the page. */
991 void
993  const char *ui_filename)
994 {
995  GncPluginPagePrivate *priv;
996 
997  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
998 
999  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1000  if (priv->ui_description)
1001  g_free (priv->ui_description);
1002 
1003  priv->ui_description = g_strdup (ui_filename);
1004 }
1005 
1006 
1007 /* Retrieve the GtkBuilder object associated with this page. */
1008 GtkBuilder *
1010 {
1011  GncPluginPagePrivate *priv;
1012 
1013  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
1014 
1015  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1016  return priv->builder;
1017 }
1018 
1019 
1020 /* Retrieve the menu qualifier associated with this page. */
1021 const gchar *
1023 {
1024  GncPluginPagePrivate *priv;
1025 
1026  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
1027 
1028  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1029  return priv->menu_qualifier;
1030 }
1031 
1032 void
1034  const char *menu_qualifier)
1035 {
1036  GncPluginPagePrivate *priv;
1037 
1038  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
1039 
1040  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1041 
1042  priv->menu_qualifier = menu_qualifier;
1043 }
1044 
1045 const gchar *
1047 {
1048  GncPluginPagePrivate *priv;
1049 
1050  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
1051 
1052  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1053  return priv->menu_popup_qualifier;
1054 }
1055 
1056 void
1058  const char *menu_qualifier)
1059 {
1060  GncPluginPagePrivate *priv;
1061 
1062  g_return_if_fail (GNC_IS_PLUGIN_PAGE(page));
1063 
1064  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1065 
1066  priv->menu_popup_qualifier = menu_qualifier;
1067 }
1068 
1069 
1070 GSimpleActionGroup *
1072 {
1073  GncPluginPagePrivate *priv;
1074 
1075  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
1076 
1077  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1078  return priv->simple_action_group;
1079 }
1080 
1081 GSimpleActionGroup *
1082 gnc_plugin_page_create_action_group (GncPluginPage *page, const gchar *group_name)
1083 {
1084  GncPluginPagePrivate *priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1085 
1086  priv->simple_action_group = g_simple_action_group_new ();
1087  priv->simple_action_group_name = group_name;
1088 
1089  return priv->simple_action_group;
1090 }
1091 
1092 const gchar *
1094 {
1095  GncPluginPagePrivate *priv;
1096 
1097  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), NULL);
1098 
1099  priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
1100 
1101  return priv->simple_action_group_name;
1102 }
1103 
1104 gboolean
1106 {
1107  if (!page)
1108  return TRUE;
1109 
1110  if (!GNC_IS_PLUGIN_PAGE(page))
1111  return TRUE;
1112 
1113  if (!GNC_PLUGIN_PAGE_GET_CLASS(page)->finish_pending)
1114  return TRUE;
1115 
1116  return (GNC_PLUGIN_PAGE_GET_CLASS(page)->finish_pending)(page);
1117 }
1118 
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.
void gnc_plugin_page_set_menu_qualifier(GncPluginPage *page, const char *menu_qualifier)
Set a qualifier string 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.
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
void gnc_plugin_page_merge_actions(GncPluginPage *page)
Add the actions for a content page to the specified window.
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_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.
GSimpleActionGroup * gnc_plugin_page_get_action_group(GncPluginPage *page)
Retrieve the GSimpleActionGroup object associated with this page.
GtkBuilder * gnc_plugin_page_get_builder(GncPluginPage *page)
Retrieve the GtkBuilder object associated with this page.
char * ui_description
The group of all actions provided by this plugin.
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.
gboolean gnc_main_window_is_restoring_pages(GncMainWindow *window)
Check if the main window is restoring the plugin pages.
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.
GSimpleActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GSimpleActionGroup object associated with this page.
const gchar * gnc_plugin_page_get_menu_qualifier(GncPluginPage *page)
Retrieve the menu qualifier for this page.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
const gchar * gnc_plugin_page_get_menu_popup_qualifier(GncPluginPage *page)
Retrieve the menu popup qualifier for this page.
void(* destroy_widget)(GncPluginPage *plugin_page)
Function called to destroy the display widget for a particular type of plugin.
void gnc_gobject_tracking_remember(GObject *object)
Tell gnucash to remember this object in the database.
The class data structure for a content plugin.
Gobject helper routines.
void gnc_plugin_page_set_use_new_window(GncPluginPage *page, gboolean use_new)
Set the "use new window" setting associated with this page.
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_simple_action_group_name(GncPluginPage *page)
Retrieve the simple action group name associated with this plugin page.
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.
void gnc_plugin_page_set_page_color(GncPluginPage *page, const char *color)
Set the color of this page.
void gnc_plugin_page_set_menu_popup_qualifier(GncPluginPage *page, const char *menu_qualifier)
Set a qualifier string for this page.
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.
GAction * gnc_plugin_page_get_action(GncPluginPage *page, const gchar *name)
Retrieve a GAction 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.