1 /*
2  * go-editor.c :
3  *
4  * Copyright (C) 2003-2009 Jody Goldberg (jody@gnome.org)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) version 3.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
19  * USA
20  */
21 
22 /*****************************************************************************/
23 
24 #include <goffice/goffice-config.h>
25 #include <goffice/utils/go-editor.h>
26 #include <string.h>
27 
28 
29 typedef struct {
30 	char const	*label;		/* label for notebook page */
31 	gpointer 	 widget;	/* GtkWidget* */
32 	gpointer scrolled;		/* GtkScrolledWindow embedding the widget.*/
33 } GOEditorPage;
34 
35 struct _GOEditor {
36 	unsigned	*store_page;		/* pointer to a place for storing last edited page */
37 	GSList		*pages;			/* GOEditorPage */
38 	GData		*registered_widgets;
39 	unsigned     ref_count;
40 	gboolean	 use_scrolled;
41 };
42 
43 /**
44  * GOEditor:
45  *
46  * Embeds a notebook containing all the pages added to the editor.
47  **/
48 
49 /**
50  * go_editor_new:
51  *
52  * Returns: (transfer full): a new GOEditor object, which is used to store a collection of
53  * 	property edition widgets (pages). The returned object must be freed
54  * 	using @go_editor_free.
55  **/
56 GOEditor *
go_editor_new(void)57 go_editor_new (void)
58 {
59 	GOEditor *editor = g_new (GOEditor, 1);
60 
61 	editor->store_page = NULL;
62 	editor->pages = NULL;
63 	g_datalist_init (&editor->registered_widgets);
64 	editor->ref_count = 1;
65 	editor->use_scrolled = FALSE;
66 
67 	return editor;
68 }
69 
70 static void
page_free(GOEditorPage * page)71 page_free (GOEditorPage *page)
72 {
73 	if (page->scrolled)
74 		g_object_unref (page->scrolled);
75 	g_free (page);
76 }
77 
78 /**
79  * go_editor_free:
80  * @editor: a #GOEditor
81  *
82  * Frees a GOEditor object.
83  **/
84 
85 void
go_editor_free(GOEditor * editor)86 go_editor_free (GOEditor *editor)
87 {
88 	if (editor == NULL || editor->ref_count-- >1)
89 		return;
90 	g_slist_foreach (editor->pages, (GFunc) page_free, NULL);
91 	g_slist_free (editor->pages);
92 	g_datalist_clear (&editor->registered_widgets);
93 
94 	g_free (editor);
95 }
96 
97 static GOEditor *
go_editor_ref(GOEditor * editor)98 go_editor_ref (GOEditor *editor)
99 {
100 	editor->ref_count++;
101 	return editor;
102 }
103 
104 GType
go_editor_get_type(void)105 go_editor_get_type (void)
106 {
107 	static GType t = 0;
108 
109 	if (t == 0)
110 		t = g_boxed_type_register_static ("GOEditor",
111 			 (GBoxedCopyFunc)go_editor_ref,
112 			 (GBoxedFreeFunc)go_editor_free);
113 	return t;
114 }
115 
116 /**
117  * go_editor_add_page:
118  * @editor: a #GOEditor
119  * @widget: property edition widget
120  * @label: a label identifying the widget
121  *
122  * Adds a page to @editor.
123  */
124 
125 void
go_editor_add_page(GOEditor * editor,gpointer widget,char const * label)126 go_editor_add_page (GOEditor *editor, gpointer widget, char const *label)
127 {
128 	GOEditorPage *page;
129 
130 	g_return_if_fail (editor != NULL);
131 	page = g_new0 (GOEditorPage, 1);
132 
133 	page->widget = widget;
134 #ifdef GOFFICE_WITH_GTK
135 	if (editor->use_scrolled) {
136 		page->scrolled = g_object_ref (gtk_scrolled_window_new (NULL, NULL));
137 		gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (page->scrolled),
138 			                                   widget);
139 	} else
140 #endif
141 		page->scrolled = g_object_ref (widget);
142 	page->label = label;
143 
144 	editor->pages = g_slist_prepend (editor->pages, page);
145 }
146 
147 /**
148  * go_editor_set_store_page:
149  * @editor: a #GOEditor
150  * @store_page: placeholder for the last selected page
151  *
152  * Sets a placeholder for storing the last active editor page.
153  **/
154 
155 void
go_editor_set_store_page(GOEditor * editor,unsigned * store_page)156 go_editor_set_store_page (GOEditor *editor, unsigned *store_page)
157 {
158 	g_return_if_fail (editor != NULL);
159 
160 	editor->store_page = store_page;
161 }
162 
163 /**
164  * go_editor_set_use_scrolled_window:
165  * @editor: a #GOEditor
166  * @use_scrolled: boolean
167  *
168  * Sets whether each page of the editor should be displayed inside a scrolled
169  * window.
170  **/
171 
172 void
go_editor_set_use_scrolled_window(GOEditor * editor,gboolean use_scrolled)173 go_editor_set_use_scrolled_window (GOEditor *editor, gboolean use_scrolled)
174 {
175 	g_return_if_fail (editor != NULL);
176 
177 	editor->use_scrolled = use_scrolled;
178 }
179 
180 #ifdef GOFFICE_WITH_GTK
181 
182 /**
183  * go_editor_register_widget:
184  * @editor: a #GOEditor
185  * @widget: a #GtkWidget
186  *
187  * Registers a widget that then can be retrieved later using
188  * @go_editor_get_registered_widget. The main use of this function is to
189  * provide the ability to extend a page.
190  **/
191 void
go_editor_register_widget(GOEditor * editor,GtkWidget * widget)192 go_editor_register_widget (GOEditor *editor, GtkWidget *widget)
193 {
194 	g_return_if_fail (editor != NULL);
195 	g_return_if_fail (GTK_IS_WIDGET (widget));
196 
197 	g_datalist_set_data (&editor->registered_widgets, gtk_buildable_get_name (GTK_BUILDABLE (widget)), widget);
198 }
199 
200 /**
201  * go_editor_get_registered_widget:
202  * @editor: a #GOEditor
203  * @name: the name of the registered widget
204  *
205  * Returns: (transfer none): a widget previously registered using @go_editor_register_widget.
206  **/
207 GtkWidget *
go_editor_get_registered_widget(GOEditor * editor,char const * name)208 go_editor_get_registered_widget (GOEditor *editor, char const *name)
209 {
210 	g_return_val_if_fail (editor != NULL, NULL);
211 
212 	return g_datalist_get_data (&editor->registered_widgets, name);
213 }
214 
215 static void
cb_switch_page(G_GNUC_UNUSED GtkNotebook * n,G_GNUC_UNUSED GtkWidget * p,guint page_num,guint * store_page)216 cb_switch_page (G_GNUC_UNUSED GtkNotebook *n, G_GNUC_UNUSED GtkWidget *p,
217 		guint page_num, guint *store_page)
218 {
219 		*store_page = page_num;
220 }
221 
222 /**
223  * go_editor_get_notebook:
224  * @editor: a #GOEditor
225  *
226  * Returns: (transfer full): a GtkNotebook from the widget collection stored in @editor.
227  **/
228 GtkWidget *
go_editor_get_notebook(GOEditor * editor)229 go_editor_get_notebook (GOEditor *editor)
230 {
231 	GtkWidget *notebook;
232 	GOEditorPage *page;
233 	GSList *ptr;
234 	unsigned page_count = 0;
235 
236 	notebook = gtk_notebook_new ();
237 	if (editor->pages != NULL) {
238 		for (ptr = editor->pages; ptr != NULL; ptr = ptr->next) {
239 			page = (GOEditorPage *) ptr->data;
240 			gtk_notebook_prepend_page (GTK_NOTEBOOK (notebook),
241 						   GTK_WIDGET (page->scrolled),
242 						   gtk_label_new (page->label));
243 			gtk_widget_show (page->scrolled);
244 			page_count ++;
245 		}
246 	} else {
247 		/* Display a blank page */
248 		GtkWidget *label =  gtk_label_new (NULL);
249 		gtk_notebook_prepend_page (GTK_NOTEBOOK (notebook),
250 					   label, NULL);
251 		gtk_widget_show (label);
252 		page_count = 1;
253 	}
254 
255 	if (editor->store_page != NULL) {
256 		gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), *editor->store_page);
257 		g_signal_connect (G_OBJECT (notebook),
258 				  "switch_page",
259 				  G_CALLBACK (cb_switch_page), editor->store_page);
260 	} else
261 		gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
262 
263 	return notebook;
264 }
265 
266 /**
267  * go_editor_get_page:
268  * @editor: #GOEditor
269  * @name: page name
270  *
271  * Returns: (transfer none): the page with @name as name if any
272  **/
273 GtkWidget *
go_editor_get_page(GOEditor * editor,char const * name)274 go_editor_get_page (GOEditor *editor, char const *name)
275 {
276 	GSList *ptr;
277 	GOEditorPage *page;
278 	for (ptr = editor->pages; ptr; ptr = ptr->next) {
279 		page = (GOEditorPage *) ptr->data;
280 		if (strcmp (page->label, name))
281 			return page->widget;
282 	}
283 	return NULL;
284 }
285 
286 #endif
287