No issues found
1 /*
2 *
3 * Evolution calendar - Base class for calendar component editor pages
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with the program; if not, see <http://www.gnu.org/licenses/>
17 *
18 *
19 * Authors:
20 * Federico Mena-Quintero <federico@ximian.com>
21 *
22 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
23 *
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <glib/gi18n.h>
31 #include "comp-editor.h"
32 #include "comp-editor-page.h"
33
34 #define COMP_EDITOR_PAGE_GET_PRIVATE(obj) \
35 (G_TYPE_INSTANCE_GET_PRIVATE \
36 ((obj), TYPE_COMP_EDITOR_PAGE, CompEditorPagePrivate))
37
38 struct _CompEditorPagePrivate {
39 CompEditor *editor; /* not referenced */
40 gboolean updating;
41 };
42
43 enum {
44 PROP_0,
45 PROP_EDITOR,
46 PROP_UPDATING
47 };
48
49 enum {
50 DATES_CHANGED,
51 LAST_SIGNAL
52 };
53
54 static guint comp_editor_page_signals[LAST_SIGNAL];
55
56 G_DEFINE_TYPE (CompEditorPage, comp_editor_page, G_TYPE_OBJECT)
57
58 static void
59 comp_editor_page_set_property (GObject *object,
60 guint property_id,
61 const GValue *value,
62 GParamSpec *pspec)
63 {
64 CompEditorPagePrivate *priv;
65
66 priv = COMP_EDITOR_PAGE_GET_PRIVATE (object);
67
68 switch (property_id) {
69 case PROP_EDITOR:
70 priv->editor = g_value_get_object (value);
71 return;
72
73 case PROP_UPDATING:
74 comp_editor_page_set_updating (
75 COMP_EDITOR_PAGE (object),
76 g_value_get_boolean (value));
77 return;
78 }
79
80 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
81 }
82
83 static void
84 comp_editor_page_get_property (GObject *object,
85 guint property_id,
86 GValue *value,
87 GParamSpec *pspec)
88 {
89 switch (property_id) {
90 case PROP_EDITOR:
91 g_value_set_object (
92 value, comp_editor_page_get_editor (
93 COMP_EDITOR_PAGE (object)));
94 return;
95
96 case PROP_UPDATING:
97 g_value_set_boolean (
98 value, comp_editor_page_get_updating (
99 COMP_EDITOR_PAGE (object)));
100 }
101
102 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
103 }
104
105 static void
106 comp_editor_page_dispose (GObject *object)
107 {
108 CompEditorPage *page;
109
110 g_return_if_fail (object != NULL);
111 g_return_if_fail (IS_COMP_EDITOR_PAGE (object));
112
113 page = COMP_EDITOR_PAGE (object);
114
115 if (page->accel_group) {
116 g_object_unref (page->accel_group);
117 page->accel_group = NULL;
118 }
119
120 /* Chain up to parent's dispose() method. */
121 G_OBJECT_CLASS (comp_editor_page_parent_class)->dispose (object);
122 }
123
124 static void
125 comp_editor_page_class_init (CompEditorPageClass *class)
126 {
127 GObjectClass *object_class;
128
129 g_type_class_add_private (class, sizeof (CompEditorPagePrivate));
130
131 object_class = G_OBJECT_CLASS (class);
132 object_class->set_property = comp_editor_page_set_property;
133 object_class->get_property = comp_editor_page_get_property;
134 object_class->dispose = comp_editor_page_dispose;
135
136 g_object_class_install_property (
137 object_class,
138 PROP_EDITOR,
139 g_param_spec_object (
140 "editor",
141 NULL,
142 NULL,
143 TYPE_COMP_EDITOR,
144 G_PARAM_READWRITE |
145 G_PARAM_CONSTRUCT_ONLY));
146
147 g_object_class_install_property (
148 object_class,
149 PROP_UPDATING,
150 g_param_spec_boolean (
151 "updating",
152 NULL,
153 NULL,
154 FALSE,
155 G_PARAM_READWRITE));
156
157 comp_editor_page_signals[DATES_CHANGED] = g_signal_new (
158 "dates_changed",
159 G_TYPE_FROM_CLASS (class),
160 G_SIGNAL_RUN_FIRST,
161 G_STRUCT_OFFSET (CompEditorPageClass, dates_changed),
162 NULL, NULL,
163 g_cclosure_marshal_VOID__POINTER,
164 G_TYPE_NONE, 1,
165 G_TYPE_POINTER);
166 }
167
168 static void
169 comp_editor_page_init (CompEditorPage *page)
170 {
171 page->priv = COMP_EDITOR_PAGE_GET_PRIVATE (page);
172 }
173
174 /**
175 * comp_editor_page_get_editor:
176 * @page: a #CompEditorPage
177 *
178 * Returns the #CompEditor to which @page belongs.
179 *
180 * Returns: the parent #CompEditor
181 **/
182 CompEditor *
183 comp_editor_page_get_editor (CompEditorPage *page)
184 {
185 g_return_val_if_fail (IS_COMP_EDITOR_PAGE (page), NULL);
186
187 return page->priv->editor;
188 }
189
190 /**
191 * comp_editor_page_get_widget:
192 * @page: An editor page.
193 *
194 * Queries the main widget of an editor page.
195 *
196 * Return value: The widget that is the page's upper container. It should
197 * normally be inserted in a notebook widget.
198 **/
199 GtkWidget *
200 comp_editor_page_get_widget (CompEditorPage *page)
201 {
202 CompEditorPageClass *class;
203
204 g_return_val_if_fail (IS_COMP_EDITOR_PAGE (page), NULL);
205
206 class = COMP_EDITOR_PAGE_GET_CLASS (page);
207 g_return_val_if_fail (class->get_widget != NULL, NULL);
208
209 return class->get_widget (page);
210 }
211
212 gboolean
213 comp_editor_page_get_updating (CompEditorPage *page)
214 {
215 g_return_val_if_fail (IS_COMP_EDITOR_PAGE (page), FALSE);
216
217 return page->priv->updating;
218 }
219
220 void
221 comp_editor_page_set_updating (CompEditorPage *page,
222 gboolean updating)
223 {
224 g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
225
226 if (page->priv->updating == updating)
227 return;
228
229 page->priv->updating = updating;
230
231 g_object_notify (G_OBJECT (page), "updating");
232 }
233
234 void
235 comp_editor_page_changed (CompEditorPage *page)
236 {
237 CompEditor *editor;
238
239 g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
240
241 /* Block change notifications if the page is updating. This right
242 * here is why we have an 'updating' flag. It's up to subclasses
243 * to set and clear it at appropriate times. */
244 if (page->priv->updating)
245 return;
246
247 editor = comp_editor_page_get_editor (page);
248 comp_editor_set_changed (editor, TRUE);
249 }
250
251 /**
252 * comp_editor_page_focus_main_widget:
253 * @page: An editor page.
254 *
255 * Makes an editor page focus its main widget. This is used by the component
256 * editor when it first pops up so that it can focus the main widget in the
257 * first page.
258 **/
259 void
260 comp_editor_page_focus_main_widget (CompEditorPage *page)
261 {
262 CompEditorPageClass *class;
263
264 g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
265
266 class = COMP_EDITOR_PAGE_GET_CLASS (page);
267 g_return_if_fail (class->focus_main_widget != NULL);
268
269 class->focus_main_widget (page);
270 }
271
272 /**
273 * comp_editor_page_fill_widgets:
274 * @page: An editor page.
275 * @comp: A calendar component.
276 *
277 * Fills the widgets of an editor page with the data from a calendar component.
278 **/
279 gboolean
280 comp_editor_page_fill_widgets (CompEditorPage *page,
281 ECalComponent *comp)
282 {
283 CompEditorPageClass *class;
284 gboolean success;
285
286 g_return_val_if_fail (IS_COMP_EDITOR_PAGE (page), FALSE);
287 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
288
289 class = COMP_EDITOR_PAGE_GET_CLASS (page);
290 g_return_val_if_fail (class->fill_widgets != NULL, FALSE);
291
292 comp_editor_page_set_updating (page, TRUE);
293 success = class->fill_widgets (page, comp);
294 comp_editor_page_set_updating (page, FALSE);
295
296 return success;
297 }
298
299 /**
300 * comp_editor_page_fill_component:
301 * @page: An editor page.
302 * @comp: A calendar component.
303 *
304 * Takes the data from the widgets of an editor page and sets it on a calendar
305 * component, replacing the contents of the properties that the editor page
306 * knows how to manipulate.
307 *
308 * Returns: TRUE if the component could be filled, FALSE otherwise
309 **/
310 gboolean
311 comp_editor_page_fill_component (CompEditorPage *page,
312 ECalComponent *comp)
313 {
314 CompEditorPageClass *class;
315
316 g_return_val_if_fail (IS_COMP_EDITOR_PAGE (page), FALSE);
317 g_return_val_if_fail (comp != NULL, FALSE);
318
319 class = COMP_EDITOR_PAGE_GET_CLASS (page);
320
321 if (class->fill_component != NULL)
322 return class->fill_component (page, comp);
323
324 return TRUE;
325 }
326
327 /**
328 * comp_editor_page_fill_timezones:
329 * @page: An editor page.
330 * @timezones: Hash table to which timezones will be added.
331 *
332 * Fills the given hash table with all the timezones used by the dates in the
333 * specific editor page.
334 *
335 * Returns: TRUE if the timezones were added, FALSE otherwise.
336 */
337 gboolean
338 comp_editor_page_fill_timezones (CompEditorPage *page,
339 GHashTable *timezones)
340 {
341 CompEditorPageClass *class;
342
343 g_return_val_if_fail (IS_COMP_EDITOR_PAGE (page), FALSE);
344 g_return_val_if_fail (timezones != NULL, FALSE);
345
346 class = COMP_EDITOR_PAGE_GET_CLASS (page);
347
348 if (class->fill_timezones != NULL)
349 return class->fill_timezones (page, timezones);
350
351 return TRUE;
352 }
353
354 /**
355 * comp_editor_page_set_dates:
356 * @page: An editor page
357 * @dates: A collection of various dates in time_t format
358 *
359 * Sets the date values for this group of widgets
360 **/
361 void
362 comp_editor_page_set_dates (CompEditorPage *page,
363 CompEditorPageDates *dates)
364 {
365 CompEditorPageClass *class;
366
367 g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
368
369 class = COMP_EDITOR_PAGE_GET_CLASS (page);
370
371 if (class->set_dates != NULL)
372 class->set_dates (page, dates);
373 }
374
375 /**
376 * comp_editor_page_add_attendee:
377 * @page: a #CompEditorPage
378 * @attendee: an #EMeetingAttendee
379 *
380 * Adds @attendee to an internal meeting store.
381 **/
382 void
383 comp_editor_page_add_attendee (CompEditorPage *page,
384 EMeetingAttendee *attendee)
385 {
386 CompEditorPageClass *class;
387
388 g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
389 g_return_if_fail (E_IS_MEETING_ATTENDEE (attendee));
390
391 class = COMP_EDITOR_PAGE_GET_CLASS (page);
392 g_return_if_fail (class->add_attendee != NULL);
393
394 class->add_attendee (page, attendee);
395 }
396
397 /**
398 * comp_editor_page_notify_dates_changed:
399 * @page: An editor page.
400 *
401 * Makes an editor page emit the "dates_changed" signal. This is meant to be
402 * used only by page implementations.
403 **/
404 void
405 comp_editor_page_notify_dates_changed (CompEditorPage *page,
406 CompEditorPageDates *dates)
407 {
408 g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
409
410 g_signal_emit (
411 page,
412 comp_editor_page_signals[DATES_CHANGED], 0,
413 dates);
414 }
415
416 /**
417 * comp_editor_page_display_validation_error:
418 * @page: An editor page.
419 * @msg: Error message to display.
420 * @field: Widget that caused the validation error.
421 *
422 * Displays an error message about a validation problem in the
423 * given field. Once the error message has been displayed, the
424 * focus is set to the widget that caused the validation error.
425 */
426 void
427 comp_editor_page_display_validation_error (CompEditorPage *page,
428 const gchar *msg,
429 GtkWidget *field)
430 {
431 GtkWidget *dialog;
432
433 g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
434 g_return_if_fail (msg != NULL);
435 g_return_if_fail (GTK_IS_WIDGET (field));
436
437 dialog = gtk_message_dialog_new (
438 NULL, 0,
439 GTK_MESSAGE_ERROR,
440 GTK_BUTTONS_CLOSE,
441 _("Validation error: %s"), msg);
442 gtk_dialog_run (GTK_DIALOG (dialog));
443 gtk_widget_destroy (dialog);
444
445 gtk_widget_grab_focus (field);
446 }