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