1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /*
3 * Copyright (C) 2012 Red Hat
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Written by:
19 * Jasper St. Pierre <jstpierre@mecheye.net>
20 */
21
22 #include "config.h"
23
24 #include <glib-object.h>
25
26 #include "gis-page.h"
27
28 struct _GisPagePrivate
29 {
30 char *title;
31
32 gboolean applying;
33 GCancellable *apply_cancel;
34 GisPageApplyCallback apply_cb;
35 gpointer apply_data;
36
37 guint complete : 1;
38 guint skippable : 1;
39 guint needs_accept : 1;
40 guint has_forward : 1;
41 guint padding : 5;
42 };
43 typedef struct _GisPagePrivate GisPagePrivate;
44
45 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GisPage, gis_page, GTK_TYPE_BIN);
46
47 enum
48 {
49 PROP_0,
50 PROP_DRIVER,
51 PROP_TITLE,
52 PROP_COMPLETE,
53 PROP_SKIPPABLE,
54 PROP_NEEDS_ACCEPT,
55 PROP_APPLYING,
56 PROP_SMALL_SCREEN,
57 PROP_HAS_FORWARD,
58 PROP_LAST,
59 };
60
61 static GParamSpec *obj_props[PROP_LAST];
62
63 static void
gis_page_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)64 gis_page_get_property (GObject *object,
65 guint prop_id,
66 GValue *value,
67 GParamSpec *pspec)
68 {
69 GisPage *page = GIS_PAGE (object);
70 GisPagePrivate *priv = gis_page_get_instance_private (page);
71 switch (prop_id)
72 {
73 case PROP_DRIVER:
74 g_value_set_object (value, page->driver);
75 break;
76 case PROP_TITLE:
77 g_value_set_string (value, priv->title);
78 break;
79 case PROP_COMPLETE:
80 g_value_set_boolean (value, priv->complete);
81 break;
82 case PROP_SKIPPABLE:
83 g_value_set_boolean (value, priv->skippable);
84 break;
85 case PROP_NEEDS_ACCEPT:
86 g_value_set_boolean (value, priv->needs_accept);
87 break;
88 case PROP_HAS_FORWARD:
89 g_value_set_boolean (value, priv->has_forward);
90 break;
91 case PROP_APPLYING:
92 g_value_set_boolean (value, gis_page_get_applying (page));
93 break;
94 case PROP_SMALL_SCREEN:
95 if (page->driver)
96 g_object_get_property (G_OBJECT (page->driver), "small-screen", value);
97 else
98 g_value_set_boolean (value, FALSE);
99 break;
100 default:
101 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
102 break;
103 }
104 }
105
106 static void
small_screen_changed(GisPage * page)107 small_screen_changed (GisPage *page)
108 {
109 g_object_notify_by_pspec (G_OBJECT (page), obj_props[PROP_SMALL_SCREEN]);
110 }
111
112 static void
gis_page_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)113 gis_page_set_property (GObject *object,
114 guint prop_id,
115 const GValue *value,
116 GParamSpec *pspec)
117 {
118 GisPage *page = GIS_PAGE (object);
119 GisPagePrivate *priv = gis_page_get_instance_private (page);
120 switch (prop_id)
121 {
122 case PROP_DRIVER:
123 page->driver = g_value_dup_object (value);
124 g_signal_connect_swapped (page->driver, "notify::small-screen",
125 G_CALLBACK (small_screen_changed), page);
126 small_screen_changed (page);
127 break;
128 case PROP_TITLE:
129 gis_page_set_title (page, (char *) g_value_get_string (value));
130 break;
131 case PROP_SKIPPABLE:
132 priv->skippable = g_value_get_boolean (value);
133 break;
134 case PROP_NEEDS_ACCEPT:
135 priv->needs_accept = g_value_get_boolean (value);
136 break;
137 case PROP_HAS_FORWARD:
138 priv->has_forward = g_value_get_boolean (value);
139 break;
140 case PROP_COMPLETE:
141 priv->complete = g_value_get_boolean (value);
142 break;
143 default:
144 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
145 break;
146 }
147 }
148
149 static void
gis_page_finalize(GObject * object)150 gis_page_finalize (GObject *object)
151 {
152 GisPage *page = GIS_PAGE (object);
153 GisPagePrivate *priv = gis_page_get_instance_private (page);
154
155 g_free (priv->title);
156 g_assert (!priv->applying);
157 g_assert (priv->apply_cb == NULL);
158 g_assert (priv->apply_cancel == NULL);
159
160 G_OBJECT_CLASS (gis_page_parent_class)->finalize (object);
161 }
162
163 static void
gis_page_dispose(GObject * object)164 gis_page_dispose (GObject *object)
165 {
166 GisPage *page = GIS_PAGE (object);
167 GisPagePrivate *priv = gis_page_get_instance_private (page);
168
169 if (priv->apply_cancel)
170 g_cancellable_cancel (priv->apply_cancel);
171
172 if (page->driver)
173 g_signal_handlers_disconnect_by_func (page->driver, small_screen_changed, page);
174 g_clear_object (&page->driver);
175
176 G_OBJECT_CLASS (gis_page_parent_class)->dispose (object);
177 }
178
179 static void
gis_page_constructed(GObject * object)180 gis_page_constructed (GObject *object)
181 {
182 GisPage *page = GIS_PAGE (object);
183
184 gis_page_locale_changed (page);
185
186 G_OBJECT_CLASS (gis_page_parent_class)->constructed (object);
187
188 }
189
190 static gboolean
gis_page_real_apply(GisPage * page,GCancellable * cancellable)191 gis_page_real_apply (GisPage *page,
192 GCancellable *cancellable)
193 {
194 return FALSE;
195 }
196
197 static void
gis_page_class_init(GisPageClass * klass)198 gis_page_class_init (GisPageClass *klass)
199 {
200 GObjectClass *object_class = G_OBJECT_CLASS (klass);
201
202 object_class->constructed = gis_page_constructed;
203 object_class->dispose = gis_page_dispose;
204 object_class->finalize = gis_page_finalize;
205 object_class->get_property = gis_page_get_property;
206 object_class->set_property = gis_page_set_property;
207
208 klass->apply = gis_page_real_apply;
209
210 obj_props[PROP_DRIVER] =
211 g_param_spec_object ("driver", "", "", GIS_TYPE_DRIVER,
212 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
213 obj_props[PROP_TITLE] =
214 g_param_spec_string ("title", "", "", "",
215 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
216 obj_props[PROP_COMPLETE] =
217 g_param_spec_boolean ("complete", "", "", FALSE,
218 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
219 obj_props[PROP_SKIPPABLE] =
220 g_param_spec_boolean ("skippable", "", "", FALSE,
221 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
222 obj_props[PROP_NEEDS_ACCEPT] =
223 g_param_spec_boolean ("needs-accept", "", "", FALSE,
224 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
225 obj_props[PROP_HAS_FORWARD] =
226 g_param_spec_boolean ("has-forward", "", "", FALSE,
227 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
228 obj_props[PROP_APPLYING] =
229 g_param_spec_boolean ("applying", "", "", FALSE,
230 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
231 obj_props[PROP_SMALL_SCREEN] =
232 g_param_spec_boolean ("small-screen", "", "", FALSE,
233 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
234
235 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
236 }
237
238 static void
gis_page_init(GisPage * page)239 gis_page_init (GisPage *page)
240 {
241 gtk_widget_set_margin_start (GTK_WIDGET (page), 12);
242 gtk_widget_set_margin_top (GTK_WIDGET (page), 12);
243 gtk_widget_set_margin_bottom (GTK_WIDGET (page), 12);
244 gtk_widget_set_margin_end (GTK_WIDGET (page), 12);
245 }
246
247 char *
gis_page_get_title(GisPage * page)248 gis_page_get_title (GisPage *page)
249 {
250 GisPagePrivate *priv = gis_page_get_instance_private (page);
251 if (priv->title != NULL)
252 return priv->title;
253 else
254 return "";
255 }
256
257 void
gis_page_set_title(GisPage * page,char * title)258 gis_page_set_title (GisPage *page, char *title)
259 {
260 GisPagePrivate *priv = gis_page_get_instance_private (page);
261 g_clear_pointer (&priv->title, g_free);
262 priv->title = g_strdup (title);
263 g_object_notify_by_pspec (G_OBJECT (page), obj_props[PROP_TITLE]);
264 }
265
266 gboolean
gis_page_get_complete(GisPage * page)267 gis_page_get_complete (GisPage *page)
268 {
269 GisPagePrivate *priv = gis_page_get_instance_private (page);
270 return priv->complete;
271 }
272
273 void
gis_page_set_complete(GisPage * page,gboolean complete)274 gis_page_set_complete (GisPage *page, gboolean complete)
275 {
276 GisPagePrivate *priv = gis_page_get_instance_private (page);
277 priv->complete = complete;
278 g_object_notify_by_pspec (G_OBJECT (page), obj_props[PROP_COMPLETE]);
279 }
280
281 gboolean
gis_page_get_skippable(GisPage * page)282 gis_page_get_skippable (GisPage *page)
283 {
284 GisPagePrivate *priv = gis_page_get_instance_private (page);
285 return priv->skippable;
286 }
287
288 void
gis_page_set_skippable(GisPage * page,gboolean skippable)289 gis_page_set_skippable (GisPage *page, gboolean skippable)
290 {
291 GisPagePrivate *priv = gis_page_get_instance_private (page);
292 priv->skippable = skippable;
293 g_object_notify_by_pspec (G_OBJECT (page), obj_props[PROP_SKIPPABLE]);
294 }
295
296 gboolean
gis_page_get_needs_accept(GisPage * page)297 gis_page_get_needs_accept (GisPage *page)
298 {
299 GisPagePrivate *priv = gis_page_get_instance_private (page);
300 return priv->needs_accept;
301 }
302
303 void
gis_page_set_needs_accept(GisPage * page,gboolean needs_accept)304 gis_page_set_needs_accept (GisPage *page, gboolean needs_accept)
305 {
306 GisPagePrivate *priv = gis_page_get_instance_private (page);
307 priv->needs_accept = needs_accept;
308 g_object_notify_by_pspec (G_OBJECT (page), obj_props[PROP_NEEDS_ACCEPT]);
309 }
310
311 gboolean
gis_page_get_has_forward(GisPage * page)312 gis_page_get_has_forward (GisPage *page)
313 {
314 GisPagePrivate *priv = gis_page_get_instance_private (page);
315 return priv->has_forward;
316 }
317
318 void
gis_page_set_has_forward(GisPage * page,gboolean has_forward)319 gis_page_set_has_forward (GisPage *page, gboolean has_forward)
320 {
321 GisPagePrivate *priv = gis_page_get_instance_private (page);
322 if (priv->has_forward != has_forward)
323 {
324 priv->has_forward = has_forward;
325 g_object_notify_by_pspec (G_OBJECT (page), obj_props[PROP_HAS_FORWARD]);
326 }
327 }
328
329 void
gis_page_locale_changed(GisPage * page)330 gis_page_locale_changed (GisPage *page)
331 {
332 if (GIS_PAGE_GET_CLASS (page)->locale_changed)
333 return GIS_PAGE_GET_CLASS (page)->locale_changed (page);
334 }
335
336 void
gis_page_apply_begin(GisPage * page,GisPageApplyCallback callback,gpointer user_data)337 gis_page_apply_begin (GisPage *page,
338 GisPageApplyCallback callback,
339 gpointer user_data)
340 {
341 GisPageClass *klass;
342 GisPagePrivate *priv = gis_page_get_instance_private (page);
343
344 g_return_if_fail (GIS_IS_PAGE (page));
345 g_return_if_fail (priv->applying == FALSE);
346
347 klass = GIS_PAGE_GET_CLASS (page);
348
349 priv->apply_cb = callback;
350 priv->apply_data = user_data;
351 priv->apply_cancel = g_cancellable_new ();
352 priv->applying = TRUE;
353
354 if (!klass->apply (page, priv->apply_cancel))
355 {
356 /* Shortcut case where we don't want apply, to avoid flicker */
357 gis_page_apply_complete (page, TRUE);
358 }
359
360 g_object_notify_by_pspec (G_OBJECT (page), obj_props[PROP_APPLYING]);
361 }
362
363 void
gis_page_apply_complete(GisPage * page,gboolean valid)364 gis_page_apply_complete (GisPage *page,
365 gboolean valid)
366 {
367 GisPageApplyCallback callback;
368 gpointer user_data;
369 GisPagePrivate *priv = gis_page_get_instance_private (page);
370
371 g_return_if_fail (GIS_IS_PAGE (page));
372 g_return_if_fail (priv->applying == TRUE);
373
374 callback = priv->apply_cb;
375 priv->apply_cb = NULL;
376 user_data = priv->apply_data;
377 priv->apply_data = NULL;
378
379 g_clear_object (&priv->apply_cancel);
380 priv->applying = FALSE;
381 g_object_notify_by_pspec (G_OBJECT (page), obj_props[PROP_APPLYING]);
382
383 if (callback)
384 (callback) (page, valid, user_data);
385 }
386
387 gboolean
gis_page_get_applying(GisPage * page)388 gis_page_get_applying (GisPage *page)
389 {
390 GisPagePrivate *priv = gis_page_get_instance_private (page);
391 return priv->applying;
392 }
393
394 void
gis_page_apply_cancel(GisPage * page)395 gis_page_apply_cancel (GisPage *page)
396 {
397 GisPagePrivate *priv = gis_page_get_instance_private (page);
398 g_cancellable_cancel (priv->apply_cancel);
399 }
400
401 gboolean
gis_page_save_data(GisPage * page,GError ** error)402 gis_page_save_data (GisPage *page,
403 GError **error)
404 {
405 if (GIS_PAGE_GET_CLASS (page)->save_data == NULL)
406 {
407 /* Not implemented, which presumably means the page has nothing to save. */
408 return TRUE;
409 }
410
411 return GIS_PAGE_GET_CLASS (page)->save_data (page, error);
412 }
413
414 void
gis_page_shown(GisPage * page)415 gis_page_shown (GisPage *page)
416 {
417 if (GIS_PAGE_GET_CLASS (page)->shown)
418 GIS_PAGE_GET_CLASS (page)->shown (page);
419 }
420
421 void
gis_page_skip(GisPage * page)422 gis_page_skip (GisPage *page)
423 {
424 if (GIS_PAGE_GET_CLASS (page)->skip)
425 GIS_PAGE_GET_CLASS (page)->skip (page);
426 }
427