No issues found
1 /*
2 * e-google-chooser-dialog.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <webcal://www.gnu.org/licenses/>
16 *
17 */
18
19 #include "e-google-chooser-dialog.h"
20
21 #include <config.h>
22 #include <glib/gi18n-lib.h>
23
24 #define E_GOOGLE_CHOOSER_DIALOG_GET_PRIVATE(obj) \
25 (G_TYPE_INSTANCE_GET_PRIVATE \
26 ((obj), E_TYPE_GOOGLE_CHOOSER_DIALOG, EGoogleChooserDialogPrivate))
27
28 struct _EGoogleChooserDialogPrivate {
29 EGoogleChooser *chooser;
30 GCancellable *cancellable;
31
32 GtkWidget *info_bar; /* not referenced */
33 GtkWidget *info_bar_label; /* not referenced */
34 };
35
36 enum {
37 PROP_0,
38 PROP_CHOOSER
39 };
40
41 G_DEFINE_DYNAMIC_TYPE (
42 EGoogleChooserDialog,
43 e_google_chooser_dialog,
44 GTK_TYPE_DIALOG)
45
46 static void
47 google_chooser_dialog_populated_cb (EGoogleChooser *chooser,
48 GAsyncResult *result,
49 EGoogleChooserDialog *dialog)
50 {
51 GdkWindow *window;
52 GError *error = NULL;
53
54 e_google_chooser_populate_finish (chooser, result, &error);
55
56 /* Ignore cancellations, and leave the mouse cursor alone
57 * since the GdkWindow may have already been destroyed. */
58 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
59 goto exit;
60
61 /* Reset the mouse cursor to normal. */
62 window = gtk_widget_get_window (GTK_WIDGET (dialog));
63 gdk_window_set_cursor (window, NULL);
64
65 if (error != NULL) {
66 GtkLabel *label;
67
68 label = GTK_LABEL (dialog->priv->info_bar_label);
69 gtk_label_set_text (label, error->message);
70 gtk_widget_show (dialog->priv->info_bar);
71
72 g_error_free (error);
73 goto exit;
74 }
75
76 exit:
77 g_object_unref (dialog);
78 }
79
80 static void
81 google_chooser_dialog_row_activated_cb (GtkTreeView *tree_view,
82 GtkTreePath *path,
83 GtkTreeViewColumn *column,
84 GtkDialog *dialog)
85 {
86 gtk_dialog_response (dialog, GTK_RESPONSE_APPLY);
87 }
88
89 static void
90 google_chooser_dialog_selection_changed_cb (GtkTreeSelection *selection,
91 GtkDialog *dialog)
92 {
93 gboolean sensitive;
94
95 sensitive = (gtk_tree_selection_count_selected_rows (selection) > 0);
96
97 gtk_dialog_set_response_sensitive (
98 dialog, GTK_RESPONSE_APPLY, sensitive);
99 }
100
101 static void
102 google_chooser_dialog_set_chooser (EGoogleChooserDialog *dialog,
103 EGoogleChooser *chooser)
104 {
105 g_return_if_fail (E_IS_GOOGLE_CHOOSER (chooser));
106 g_return_if_fail (dialog->priv->chooser == NULL);
107
108 dialog->priv->chooser = g_object_ref_sink (chooser);
109 }
110
111 static void
112 google_chooser_dialog_set_property (GObject *object,
113 guint property_id,
114 const GValue *value,
115 GParamSpec *pspec)
116 {
117 switch (property_id) {
118 case PROP_CHOOSER:
119 google_chooser_dialog_set_chooser (
120 E_GOOGLE_CHOOSER_DIALOG (object),
121 g_value_get_object (value));
122 return;
123 }
124
125 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
126 }
127
128 static void
129 google_chooser_dialog_get_property (GObject *object,
130 guint property_id,
131 GValue *value,
132 GParamSpec *pspec)
133 {
134 switch (property_id) {
135 case PROP_CHOOSER:
136 g_value_set_object (
137 value,
138 e_google_chooser_dialog_get_chooser (
139 E_GOOGLE_CHOOSER_DIALOG (object)));
140 return;
141 }
142
143 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
144 }
145
146 static void
147 google_chooser_dialog_dispose (GObject *object)
148 {
149 EGoogleChooserDialogPrivate *priv;
150
151 priv = E_GOOGLE_CHOOSER_DIALOG_GET_PRIVATE (object);
152
153 if (priv->chooser != NULL) {
154 g_signal_handlers_disconnect_by_func (
155 priv->chooser, google_chooser_dialog_row_activated_cb,
156 object);
157 g_object_unref (priv->chooser);
158 priv->chooser = NULL;
159 }
160
161 if (priv->cancellable != NULL) {
162 g_cancellable_cancel (priv->cancellable);
163 g_object_unref (priv->cancellable);
164 priv->cancellable = NULL;
165 }
166
167 /* Chain up to parent's dispose() method. */
168 G_OBJECT_CLASS (e_google_chooser_dialog_parent_class)->dispose (object);
169 }
170
171 static void
172 google_chooser_dialog_constructed (GObject *object)
173 {
174 EGoogleChooserDialog *dialog;
175 GtkTreeSelection *selection;
176 GtkWidget *container;
177 GtkWidget *widget;
178 GtkWidget *vbox;
179 const gchar *title;
180
181 dialog = E_GOOGLE_CHOOSER_DIALOG (object);
182
183 /* Chain up to parent's constructed() method. */
184 G_OBJECT_CLASS (e_google_chooser_dialog_parent_class)->
185 constructed (object);
186
187 gtk_dialog_add_button (
188 GTK_DIALOG (dialog),
189 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
190
191 gtk_dialog_add_button (
192 GTK_DIALOG (dialog),
193 GTK_STOCK_APPLY, GTK_RESPONSE_APPLY);
194
195 gtk_dialog_set_default_response (
196 GTK_DIALOG (dialog), GTK_RESPONSE_APPLY);
197 gtk_dialog_set_response_sensitive (
198 GTK_DIALOG (dialog), GTK_RESPONSE_APPLY, FALSE);
199
200 title = _("Choose a Calendar");
201 gtk_window_set_title (GTK_WINDOW (dialog), title);
202 gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 400);
203 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
204
205 container = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
206
207 widget = gtk_vbox_new (FALSE, 6);
208 gtk_container_set_border_width (GTK_CONTAINER (widget), 5);
209 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
210 gtk_widget_show (widget);
211
212 container = vbox = widget;
213
214 widget = gtk_scrolled_window_new (NULL, NULL);
215 gtk_scrolled_window_set_policy (
216 GTK_SCROLLED_WINDOW (widget),
217 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
218 gtk_scrolled_window_set_shadow_type (
219 GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
220 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
221 gtk_widget_show (widget);
222
223 container = widget;
224
225 widget = GTK_WIDGET (dialog->priv->chooser);
226 gtk_container_add (GTK_CONTAINER (container), widget);
227 gtk_widget_show (widget);
228
229 g_signal_connect (
230 widget, "row-activated",
231 G_CALLBACK (google_chooser_dialog_row_activated_cb), dialog);
232
233 /* Build the info bar, but hide it initially. */
234
235 container = vbox;
236
237 widget = gtk_info_bar_new ();
238 gtk_info_bar_set_message_type (
239 GTK_INFO_BAR (widget), GTK_MESSAGE_WARNING);
240 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
241 dialog->priv->info_bar = widget; /* do not reference */
242 gtk_widget_hide (widget);
243
244 container = gtk_info_bar_get_content_area (GTK_INFO_BAR (widget));
245
246 widget = gtk_hbox_new (FALSE, 6);
247 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
248 gtk_widget_show (widget);
249
250 container = widget;
251
252 widget = gtk_image_new_from_stock (
253 GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
254 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
255 gtk_widget_show (widget);
256
257 widget = gtk_label_new ("");
258 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
259 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
260 dialog->priv->info_bar_label = widget; /* do not reference */
261 gtk_widget_show (widget);
262
263 /* Listen for tree view selection changes. */
264
265 selection = gtk_tree_view_get_selection (
266 GTK_TREE_VIEW (dialog->priv->chooser));
267
268 g_signal_connect (
269 selection, "changed",
270 G_CALLBACK (google_chooser_dialog_selection_changed_cb),
271 dialog);
272 }
273
274 static void
275 google_chooser_dialog_realize (GtkWidget *widget)
276 {
277 EGoogleChooserDialogPrivate *priv;
278 GdkCursor *cursor;
279 GdkWindow *window;
280 GdkDisplay *display;
281
282 priv = E_GOOGLE_CHOOSER_DIALOG_GET_PRIVATE (widget);
283
284 /* Chain up to parent's realize() method. */
285 GTK_WIDGET_CLASS (e_google_chooser_dialog_parent_class)->
286 realize (widget);
287
288 g_return_if_fail (priv->cancellable == NULL);
289 priv->cancellable = g_cancellable_new ();
290
291 /* Show a busy mouse cursor while populating. */
292 window = gtk_widget_get_window (widget);
293 display = gtk_widget_get_display (widget);
294 cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
295 gdk_window_set_cursor (window, cursor);
296 gdk_cursor_unref (cursor);
297
298 e_google_chooser_populate (
299 priv->chooser, priv->cancellable, (GAsyncReadyCallback)
300 google_chooser_dialog_populated_cb, g_object_ref (widget));
301 }
302
303 static void
304 google_chooser_dialog_response (GtkDialog *dialog,
305 gint response_id)
306 {
307 EGoogleChooserDialogPrivate *priv;
308
309 priv = E_GOOGLE_CHOOSER_DIALOG_GET_PRIVATE (dialog);
310
311 if (response_id == GTK_RESPONSE_APPLY)
312 e_google_chooser_apply_selected (priv->chooser);
313 }
314
315 static void
316 e_google_chooser_dialog_class_init (EGoogleChooserDialogClass *class)
317 {
318 GObjectClass *object_class;
319 GtkWidgetClass *widget_class;
320 GtkDialogClass *dialog_class;
321
322 g_type_class_add_private (class, sizeof (EGoogleChooserDialogPrivate));
323
324 object_class = G_OBJECT_CLASS (class);
325 object_class->set_property = google_chooser_dialog_set_property;
326 object_class->get_property = google_chooser_dialog_get_property;
327 object_class->dispose = google_chooser_dialog_dispose;
328 object_class->constructed = google_chooser_dialog_constructed;
329
330 widget_class = GTK_WIDGET_CLASS (class);
331 widget_class->realize = google_chooser_dialog_realize;
332
333 dialog_class = GTK_DIALOG_CLASS (class);
334 dialog_class->response = google_chooser_dialog_response;
335
336 g_object_class_install_property (
337 object_class,
338 PROP_CHOOSER,
339 g_param_spec_object (
340 "chooser",
341 NULL,
342 NULL,
343 E_TYPE_GOOGLE_CHOOSER,
344 G_PARAM_READWRITE |
345 G_PARAM_CONSTRUCT_ONLY));
346 }
347
348 static void
349 e_google_chooser_dialog_class_finalize (EGoogleChooserDialogClass *class)
350 {
351 }
352
353 static void
354 e_google_chooser_dialog_init (EGoogleChooserDialog *dialog)
355 {
356 dialog->priv = E_GOOGLE_CHOOSER_DIALOG_GET_PRIVATE (dialog);
357 }
358
359 void
360 e_google_chooser_dialog_type_register (GTypeModule *type_module)
361 {
362 /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
363 * function, so we have to wrap it with a public function in
364 * order to register types from a separate compilation unit. */
365 e_google_chooser_dialog_register_type (type_module);
366 }
367
368 GtkWidget *
369 e_google_chooser_dialog_new (EGoogleChooser *chooser,
370 GtkWindow *parent)
371 {
372 g_return_val_if_fail (E_IS_GOOGLE_CHOOSER (chooser), NULL);
373 g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);
374
375 return g_object_new (
376 E_TYPE_GOOGLE_CHOOSER_DIALOG,
377 "chooser", chooser, "transient-for", parent, NULL);
378 }
379
380 EGoogleChooser *
381 e_google_chooser_dialog_get_chooser (EGoogleChooserDialog *dialog)
382 {
383 g_return_val_if_fail (E_IS_GOOGLE_CHOOSER_DIALOG (dialog), NULL);
384
385 return dialog->priv->chooser;
386 }