evolution-3.6.4/calendar/gui/e-timezone-entry.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Damon Chaplin <damon@ximian.com>
 18  *
 19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 20  *
 21  */
 22 
 23 /*
 24  * ETimezoneEntry - a field for setting a timezone. It shows the timezone in
 25  * a GtkEntry with a '...' button beside it which shows a dialog for changing
 26  * the timezone. The dialog contains a map of the world with a point for each
 27  * timezone, and an option menu as an alternative way of selecting the
 28  * timezone.
 29  */
 30 
 31 #ifdef HAVE_CONFIG_H
 32 #include <config.h>
 33 #endif
 34 
 35 #include <widgets/e-timezone-dialog/e-timezone-dialog.h>
 36 #include <glib/gi18n.h>
 37 #include "e-timezone-entry.h"
 38 
 39 #define E_TIMEZONE_ENTRY_GET_PRIVATE(obj) \
 40 	(G_TYPE_INSTANCE_GET_PRIVATE \
 41 	((obj), E_TYPE_TIMEZONE_ENTRY, ETimezoneEntryPrivate))
 42 
 43 struct _ETimezoneEntryPrivate {
 44 	/* The current timezone, set in e_timezone_entry_set_timezone()
 45 	 * or from the timezone dialog. Note that we don't copy it or
 46 	 * use a ref count - we assume it is never destroyed for the
 47 	 * lifetime of this widget. */
 48 	icaltimezone *timezone;
 49 
 50 	/* This can be set to the default timezone. If the current timezone
 51 	 * setting in the ETimezoneEntry matches this, then the entry field
 52 	 * is hidden. This makes the user interface simpler. */
 53 	icaltimezone *default_zone;
 54 
 55 	GtkWidget *entry;
 56 	GtkWidget *button;
 57 };
 58 
 59 enum {
 60 	PROP_0,
 61 	PROP_TIMEZONE
 62 };
 63 
 64 enum {
 65 	CHANGED,
 66 	LAST_SIGNAL
 67 };
 68 
 69 static guint signals[LAST_SIGNAL];
 70 
 71 G_DEFINE_TYPE (ETimezoneEntry, e_timezone_entry, GTK_TYPE_HBOX)
 72 
 73 static void
 74 timezone_entry_emit_changed (ETimezoneEntry *timezone_entry)
 75 {
 76 	g_signal_emit (timezone_entry, signals[CHANGED], 0);
 77 }
 78 
 79 static void
 80 timezone_entry_update_entry (ETimezoneEntry *timezone_entry)
 81 {
 82 	const gchar *display_name;
 83 	gchar *name_buffer;
 84 	icaltimezone *timezone;
 85 
 86 	timezone = e_timezone_entry_get_timezone (timezone_entry);
 87 
 88 	if (timezone != NULL) {
 89 		display_name = icaltimezone_get_display_name (timezone);
 90 
 91 		/* We check if it is one of our builtin timezone
 92 		 * names, in which case we call gettext to translate
 93 		 * it. If it isn't a builtin timezone name, we don't. */
 94 		if (icaltimezone_get_builtin_timezone (display_name))
 95 			display_name = _(display_name);
 96 	} else
 97 		display_name = "";
 98 
 99 	name_buffer = g_strdup (display_name);
100 
101 	gtk_entry_set_text (GTK_ENTRY (timezone_entry->priv->entry), name_buffer);
102 
103 	/* XXX Do we need to hide the timezone entry at all?  I know
104 	 *     this overrules the previous case of hiding the timezone
105 	 *     entry field when we select the default timezone. */
106 	gtk_widget_show (timezone_entry->priv->entry);
107 
108 	g_free (name_buffer);
109 }
110 static void
111 timezone_entry_add_relation (ETimezoneEntry *timezone_entry)
112 {
113 	AtkObject *a11y_timezone_entry;
114 	AtkObject *a11y_widget;
115 	AtkRelationSet *set;
116 	AtkRelation *relation;
117 	GtkWidget *widget;
118 	GPtrArray *target;
119 	gpointer target_object;
120 
121 	/* add a labelled_by relation for widget for accessibility */
122 
123 	widget = GTK_WIDGET (timezone_entry);
124 	a11y_timezone_entry = gtk_widget_get_accessible (widget);
125 
126 	widget = timezone_entry->priv->entry;
127 	a11y_widget = gtk_widget_get_accessible (widget);
128 
129 	set = atk_object_ref_relation_set (a11y_widget);
130 	if (set != NULL) {
131 		relation = atk_relation_set_get_relation_by_type (
132 			set, ATK_RELATION_LABELLED_BY);
133 		/* check whether has a labelled_by relation already */
134 		if (relation != NULL)
135 			return;
136 	}
137 
138 	set = atk_object_ref_relation_set (a11y_timezone_entry);
139 	if (!set)
140 		return;
141 
142 	relation = atk_relation_set_get_relation_by_type (
143 		set, ATK_RELATION_LABELLED_BY);
144 	if (relation != NULL) {
145 		target = atk_relation_get_target (relation);
146 		target_object = g_ptr_array_index (target, 0);
147 		if (ATK_IS_OBJECT (target_object)) {
148 			atk_object_add_relationship (
149 				a11y_widget,
150 				ATK_RELATION_LABELLED_BY,
151 				ATK_OBJECT (target_object));
152 		}
153 	}
154 }
155 
156 /* The arrow button beside the date field has been clicked, so we show the
157  * popup with the ECalendar in. */
158 static void
159 timezone_entry_button_clicked_cb (ETimezoneEntry *timezone_entry)
160 {
161 	ETimezoneDialog *timezone_dialog;
162 	GtkWidget *dialog;
163 	icaltimezone *timezone;
164 
165 	timezone_dialog = e_timezone_dialog_new ();
166 
167 	timezone = e_timezone_entry_get_timezone (timezone_entry);
168 	e_timezone_dialog_set_timezone (timezone_dialog, timezone);
169 
170 	dialog = e_timezone_dialog_get_toplevel (timezone_dialog);
171 
172 	if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT)
173 		goto exit;
174 
175 	timezone = e_timezone_dialog_get_timezone (timezone_dialog);
176 	e_timezone_entry_set_timezone (timezone_entry, timezone);
177 	timezone_entry_update_entry (timezone_entry);
178 
179 exit:
180 	g_object_unref (timezone_dialog);
181 }
182 
183 static void
184 timezone_entry_set_property (GObject *object,
185                              guint property_id,
186                              const GValue *value,
187                              GParamSpec *pspec)
188 {
189 	switch (property_id) {
190 		case PROP_TIMEZONE:
191 			e_timezone_entry_set_timezone (
192 				E_TIMEZONE_ENTRY (object),
193 				g_value_get_pointer (value));
194 			return;
195 	}
196 
197 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
198 }
199 
200 static void
201 timezone_entry_get_property (GObject *object,
202                              guint property_id,
203                              GValue *value,
204                              GParamSpec *pspec)
205 {
206 	switch (property_id) {
207 		case PROP_TIMEZONE:
208 			g_value_set_pointer (
209 				value, e_timezone_entry_get_timezone (
210 				E_TIMEZONE_ENTRY (object)));
211 			return;
212 	}
213 
214 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
215 }
216 
217 static gboolean
218 timezone_entry_mnemonic_activate (GtkWidget *widget,
219                                   gboolean group_cycling)
220 {
221 	ETimezoneEntryPrivate *priv;
222 
223 	priv = E_TIMEZONE_ENTRY_GET_PRIVATE (widget);
224 
225 	if (gtk_widget_get_can_focus (widget)) {
226 		if (priv->button != NULL)
227 			gtk_widget_grab_focus (priv->button);
228 	}
229 
230 	return TRUE;
231 }
232 
233 static gboolean
234 timezone_entry_focus (GtkWidget *widget,
235                       GtkDirectionType direction)
236 {
237 	ETimezoneEntryPrivate *priv;
238 
239 	priv = E_TIMEZONE_ENTRY_GET_PRIVATE (widget);
240 
241 	if (direction == GTK_DIR_TAB_FORWARD) {
242 		if (gtk_widget_has_focus (priv->entry))
243 			gtk_widget_grab_focus (priv->button);
244 		else if (gtk_widget_has_focus (priv->button))
245 			return FALSE;
246 		else if (gtk_widget_get_visible (priv->entry))
247 			gtk_widget_grab_focus (priv->entry);
248 		else
249 			gtk_widget_grab_focus (priv->button);
250 
251 	} else if (direction == GTK_DIR_TAB_BACKWARD) {
252 		if (gtk_widget_has_focus (priv->entry))
253 			return FALSE;
254 		else if (gtk_widget_has_focus (priv->button)) {
255 			if (gtk_widget_get_visible (priv->entry))
256 				gtk_widget_grab_focus (priv->entry);
257 			else
258 				return FALSE;
259 		} else
260 			gtk_widget_grab_focus (priv->button);
261 	} else
262 		return FALSE;
263 
264 	return TRUE;
265 }
266 
267 static void
268 e_timezone_entry_class_init (ETimezoneEntryClass *class)
269 {
270 	GObjectClass *object_class;
271 	GtkWidgetClass *widget_class;
272 
273 	g_type_class_add_private (class, sizeof (ETimezoneEntryPrivate));
274 
275 	object_class = G_OBJECT_CLASS (class);
276 	object_class->set_property = timezone_entry_set_property;
277 	object_class->get_property = timezone_entry_get_property;
278 
279 	widget_class = GTK_WIDGET_CLASS (class);
280 	widget_class->mnemonic_activate = timezone_entry_mnemonic_activate;
281 	widget_class->focus = timezone_entry_focus;
282 
283 	g_object_class_install_property (
284 		object_class,
285 		PROP_TIMEZONE,
286 		g_param_spec_pointer (
287 			"timezone",
288 			"Timezone",
289 			NULL,
290 			G_PARAM_READWRITE));
291 
292 	signals[CHANGED] = g_signal_new (
293 		"changed",
294 		G_TYPE_FROM_CLASS (object_class),
295 		G_SIGNAL_RUN_LAST,
296 		G_STRUCT_OFFSET (ETimezoneEntryClass, changed),
297 		NULL, NULL,
298 		g_cclosure_marshal_VOID__VOID,
299 		G_TYPE_NONE, 0);
300 }
301 
302 static void
303 e_timezone_entry_init (ETimezoneEntry *timezone_entry)
304 {
305 	AtkObject *a11y;
306 	GtkWidget *widget;
307 
308 	timezone_entry->priv = E_TIMEZONE_ENTRY_GET_PRIVATE (timezone_entry);
309 
310 	gtk_widget_set_can_focus (GTK_WIDGET (timezone_entry), TRUE);
311 
312 	widget  = gtk_entry_new ();
313 	gtk_editable_set_editable (GTK_EDITABLE (widget), FALSE);
314 	gtk_box_pack_start (GTK_BOX (timezone_entry), widget, TRUE, TRUE, 0);
315 	timezone_entry->priv->entry = widget;
316 	gtk_widget_show (widget);
317 
318 	g_signal_connect_swapped (
319 		widget, "changed",
320 		G_CALLBACK (timezone_entry_emit_changed), timezone_entry);
321 
322 	widget = gtk_button_new_with_label (_("Select..."));
323 	gtk_box_pack_start (GTK_BOX (timezone_entry), widget, FALSE, FALSE, 6);
324 	timezone_entry->priv->button = widget;
325 	gtk_widget_show (widget);
326 
327 	g_signal_connect_swapped (
328 		widget, "clicked",
329 		G_CALLBACK (timezone_entry_button_clicked_cb), timezone_entry);
330 
331 	a11y = gtk_widget_get_accessible (timezone_entry->priv->button);
332 	if (a11y != NULL)
333 		atk_object_set_name (a11y, _("Select Timezone"));
334 }
335 
336 GtkWidget *
337 e_timezone_entry_new (void)
338 {
339 	return g_object_new (E_TYPE_TIMEZONE_ENTRY, NULL);
340 }
341 
342 icaltimezone *
343 e_timezone_entry_get_timezone (ETimezoneEntry *timezone_entry)
344 {
345 	g_return_val_if_fail (E_IS_TIMEZONE_ENTRY (timezone_entry), NULL);
346 
347 	return timezone_entry->priv->timezone;
348 }
349 
350 void
351 e_timezone_entry_set_timezone (ETimezoneEntry *timezone_entry,
352                                icaltimezone *timezone)
353 {
354 	g_return_if_fail (E_IS_TIMEZONE_ENTRY (timezone_entry));
355 
356 	if (timezone_entry->priv->timezone == timezone)
357 		return;
358 
359 	timezone_entry->priv->timezone = timezone;
360 
361 	timezone_entry_update_entry (timezone_entry);
362 	timezone_entry_add_relation (timezone_entry);
363 
364 	g_object_notify (G_OBJECT (timezone_entry), "timezone");
365 }
366 
367 /* Sets the default timezone. If the current timezone matches this,
368  * then the entry field is hidden. This is useful since most people
369  * do not use timezones so it makes the user interface simpler. */
370 void
371 e_timezone_entry_set_default_timezone (ETimezoneEntry *timezone_entry,
372                                        icaltimezone *timezone)
373 {
374 	g_return_if_fail (E_IS_TIMEZONE_ENTRY (timezone_entry));
375 
376 	timezone_entry->priv->default_zone = timezone;
377 
378 	timezone_entry_update_entry (timezone_entry);
379 }