Updated Hungarian translation
[evolution.git] / e-util / e-proxy-preferences.c
blobf3c478792c31937de60bbf59db8905ee7da7d3dd
1 /*
2 * e-proxy-preferences.c
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 /**
19 * SECTION: e-proxy-preferences
20 * @include: e-util/e-util.h
21 * @short_description: Manage network proxy preferences
23 * #EProxyPreferences is the main widget for displaying network proxy
24 * preferences. A link button toggles between a basic mode (for most
25 * users) and advanced mode. Basic mode only shows proxy details for
26 * the built-in proxy profile, which all new accounts use by default.
27 * Advanced mode reveals a sidebar of proxy profiles, allowing users
28 * to create or delete custom profiles and apply them to particular
29 * accounts.
30 **/
32 #include "e-proxy-preferences.h"
34 #include <config.h>
35 #include <glib/gi18n-lib.h>
37 #include <e-util/e-proxy-editor.h>
38 #include <e-util/e-proxy-link-selector.h>
39 #include <e-util/e-proxy-selector.h>
41 #define E_PROXY_PREFERENCES_GET_PRIVATE(obj) \
42 (G_TYPE_INSTANCE_GET_PRIVATE \
43 ((obj), E_TYPE_PROXY_PREFERENCES, EProxyPreferencesPrivate))
45 /* Rate-limit committing proxy changes to the registry. */
46 #define COMMIT_DELAY_SECS 2
48 struct _EProxyPreferencesPrivate {
49 ESourceRegistry *registry;
50 gulong source_changed_handler_id;
52 /* The widgets are not referenced. */
53 GtkWidget *proxy_selector;
54 GtkWidget *proxy_editor;
55 GtkWidget *toplevel;
57 gulong toplevel_notify_id;
59 GMutex commit_lock;
60 guint commit_timeout_id;
61 GHashTable *commit_sources;
63 gboolean show_advanced;
66 enum {
67 PROP_0,
68 PROP_REGISTRY,
69 PROP_SHOW_ADVANCED
72 /* Forward Declarations */
73 static void proxy_preferences_commit_changes
74 (EProxyPreferences *preferences);
75 static void proxy_preferences_toplevel_notify_visible_cb
76 (GtkWidget *widget,
77 GParamSpec *param,
78 EProxyPreferences *preferences);
80 G_DEFINE_TYPE (
81 EProxyPreferences,
82 e_proxy_preferences,
83 GTK_TYPE_BOX)
85 static gboolean
86 proxy_preferences_commit_timeout_cb (gpointer user_data)
88 EProxyPreferences *preferences = user_data;
90 proxy_preferences_commit_changes (preferences);
92 return FALSE;
95 static void
96 proxy_preferences_commit_stash (EProxyPreferences *preferences,
97 ESource *source,
98 gboolean start_timeout)
100 gboolean commit_now = FALSE;
102 g_mutex_lock (&preferences->priv->commit_lock);
104 g_hash_table_replace (
105 preferences->priv->commit_sources,
106 e_source_dup_uid (source),
107 e_weak_ref_new (source));
109 if (preferences->priv->commit_timeout_id > 0) {
110 g_source_remove (preferences->priv->commit_timeout_id);
111 preferences->priv->commit_timeout_id = 0;
114 if (start_timeout) {
115 if (!preferences->priv->toplevel) {
116 GtkWidget *toplevel;
118 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (preferences));
120 if (toplevel) {
121 g_object_weak_ref (G_OBJECT (toplevel),
122 (GWeakNotify) g_nullify_pointer, &preferences->priv->toplevel);
124 preferences->priv->toplevel_notify_id = g_signal_connect (
125 toplevel, "notify::visible",
126 G_CALLBACK (proxy_preferences_toplevel_notify_visible_cb), preferences);
128 preferences->priv->toplevel = toplevel;
130 if (!gtk_widget_get_visible (toplevel)) {
131 start_timeout = FALSE;
132 commit_now = TRUE;
138 if (start_timeout) {
139 preferences->priv->commit_timeout_id =
140 e_named_timeout_add_seconds (
141 COMMIT_DELAY_SECS,
142 proxy_preferences_commit_timeout_cb,
143 preferences);
146 g_mutex_unlock (&preferences->priv->commit_lock);
148 if (commit_now)
149 e_proxy_preferences_submit (preferences);
152 static GList *
153 proxy_preferences_commit_claim (EProxyPreferences *preferences)
155 GQueue queue = G_QUEUE_INIT;
156 GList *list, *link;
158 g_mutex_lock (&preferences->priv->commit_lock);
160 if (preferences->priv->commit_timeout_id > 0) {
161 g_source_remove (preferences->priv->commit_timeout_id);
162 preferences->priv->commit_timeout_id = 0;
165 /* Returns a list of GWeakRefs which may hold an ESource. */
166 list = g_hash_table_get_values (preferences->priv->commit_sources);
168 for (link = list; link != NULL; link = g_list_next (link)) {
169 ESource *source;
171 source = g_weak_ref_get ((GWeakRef *) link->data);
172 if (source != NULL)
173 g_queue_push_tail (&queue, source);
176 g_list_free (list);
178 g_hash_table_remove_all (preferences->priv->commit_sources);
180 g_mutex_unlock (&preferences->priv->commit_lock);
182 return g_queue_peek_head_link (&queue);
185 static gboolean
186 proxy_preferences_activate_link_cb (GtkLinkButton *button,
187 EProxyPreferences *preferences)
189 EProxySelector *selector;
191 selector = E_PROXY_SELECTOR (preferences->priv->proxy_selector);
193 if (e_proxy_preferences_get_show_advanced (preferences)) {
194 /* Basic mode always shows the built-in proxy profile. */
195 e_proxy_preferences_set_show_advanced (preferences, FALSE);
196 e_proxy_selector_set_selected (selector, NULL);
197 } else {
198 e_proxy_preferences_set_show_advanced (preferences, TRUE);
201 return TRUE;
204 static gboolean
205 proxy_preferences_switch_to_label (GBinding *binding,
206 const GValue *source_value,
207 GValue *target_value,
208 gpointer user_data)
210 const gchar *string;
212 if (g_value_get_boolean (source_value))
213 string = _("Switch to Basic Proxy Preferences");
214 else
215 string = _("Switch to Advanced Proxy Preferences");
217 g_value_set_string (target_value, string);
219 return TRUE;
222 static gboolean
223 proxy_preferences_source_to_display_name (GBinding *binding,
224 const GValue *source_value,
225 GValue *target_value,
226 gpointer user_data)
228 ESource *source;
229 gchar *display_name;
231 source = g_value_get_object (source_value);
232 g_return_val_if_fail (source != NULL, FALSE);
234 display_name = e_source_dup_display_name (source);
235 g_value_take_string (target_value, display_name);
237 return TRUE;
240 static void
241 proxy_preferences_write_done_cb (GObject *source_object,
242 GAsyncResult *result,
243 gpointer user_data)
245 ESource *source;
246 EProxyPreferences *preferences;
247 GError *error = NULL;
249 source = E_SOURCE (source_object);
250 preferences = E_PROXY_PREFERENCES (user_data);
252 e_source_write_finish (source, result, &error);
254 /* FIXME Display the error in an alert sink. */
255 if (error != NULL) {
256 g_warning ("%s: %s", G_STRFUNC, error->message);
257 g_error_free (error);
260 g_object_unref (preferences);
263 static void
264 proxy_preferences_commit_changes (EProxyPreferences *preferences)
266 GList *list, *link;
268 list = proxy_preferences_commit_claim (preferences);
270 for (link = list; link != NULL; link = g_list_next (link)) {
271 e_source_write (
272 E_SOURCE (link->data), NULL,
273 proxy_preferences_write_done_cb,
274 g_object_ref (preferences));
277 g_list_free_full (list, (GDestroyNotify) g_object_unref);
280 static void
281 proxy_preferences_toplevel_notify_visible_cb (GtkWidget *widget,
282 GParamSpec *param,
283 EProxyPreferences *preferences)
285 g_return_if_fail (GTK_IS_WIDGET (widget));
286 g_return_if_fail (E_IS_PROXY_PREFERENCES (preferences));
288 /* The toplevel widget was hidden, save anything pending immediately */
289 if (!gtk_widget_get_visible (widget))
290 e_proxy_preferences_submit (preferences);
293 static void
294 proxy_preferences_source_changed_cb (ESourceRegistry *registry,
295 ESource *source,
296 EProxyPreferences *preferences)
298 if (e_source_has_extension (source, E_SOURCE_EXTENSION_PROXY))
299 proxy_preferences_commit_stash (preferences, source, TRUE);
302 static void
303 proxy_preferences_set_registry (EProxyPreferences *preferences,
304 ESourceRegistry *registry)
306 gulong handler_id;
308 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
309 g_return_if_fail (preferences->priv->registry == NULL);
311 preferences->priv->registry = g_object_ref (registry);
313 handler_id = g_signal_connect (
314 registry, "source-changed",
315 G_CALLBACK (proxy_preferences_source_changed_cb), preferences);
316 preferences->priv->source_changed_handler_id = handler_id;
319 static void
320 proxy_preferences_set_property (GObject *object,
321 guint property_id,
322 const GValue *value,
323 GParamSpec *pspec)
325 switch (property_id) {
326 case PROP_REGISTRY:
327 proxy_preferences_set_registry (
328 E_PROXY_PREFERENCES (object),
329 g_value_get_object (value));
330 return;
332 case PROP_SHOW_ADVANCED:
333 e_proxy_preferences_set_show_advanced (
334 E_PROXY_PREFERENCES (object),
335 g_value_get_boolean (value));
336 return;
339 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
342 static void
343 proxy_preferences_get_property (GObject *object,
344 guint property_id,
345 GValue *value,
346 GParamSpec *pspec)
348 switch (property_id) {
349 case PROP_REGISTRY:
350 g_value_set_object (
351 value,
352 e_proxy_preferences_get_registry (
353 E_PROXY_PREFERENCES (object)));
354 return;
356 case PROP_SHOW_ADVANCED:
357 g_value_set_boolean (
358 value,
359 e_proxy_preferences_get_show_advanced (
360 E_PROXY_PREFERENCES (object)));
361 return;
364 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
367 static void
368 proxy_preferences_dispose (GObject *object)
370 EProxyPreferencesPrivate *priv;
372 priv = E_PROXY_PREFERENCES_GET_PRIVATE (object);
374 if (priv->toplevel) {
375 g_object_weak_unref (G_OBJECT (priv->toplevel),
376 (GWeakNotify) g_nullify_pointer, &priv->toplevel);
378 if (priv->toplevel_notify_id) {
379 g_signal_handler_disconnect (priv->toplevel, priv->toplevel_notify_id);
380 priv->toplevel_notify_id = 0;
383 priv->toplevel = NULL;
386 if (priv->source_changed_handler_id > 0) {
387 g_signal_handler_disconnect (
388 priv->registry,
389 priv->source_changed_handler_id);
390 priv->source_changed_handler_id = 0;
393 if (priv->commit_timeout_id > 0) {
394 g_source_remove (priv->commit_timeout_id);
395 priv->commit_timeout_id = 0;
397 /* Make sure the changes are committed, or at least its write invoked */
398 proxy_preferences_commit_changes (E_PROXY_PREFERENCES (object));
401 g_clear_object (&priv->registry);
403 g_hash_table_remove_all (priv->commit_sources);
405 /* Chain up to parent's dispose() method. */
406 G_OBJECT_CLASS (e_proxy_preferences_parent_class)->dispose (object);
409 static void
410 proxy_preferences_finalize (GObject *object)
412 EProxyPreferencesPrivate *priv;
414 priv = E_PROXY_PREFERENCES_GET_PRIVATE (object);
416 g_mutex_clear (&priv->commit_lock);
417 g_hash_table_destroy (priv->commit_sources);
419 /* Chain up to parent's finalize() method. */
420 G_OBJECT_CLASS (e_proxy_preferences_parent_class)->finalize (object);
423 static void
424 proxy_preferences_constructed (GObject *object)
426 EProxyPreferences *preferences;
427 ESourceRegistry *registry;
428 GtkWidget *widget;
429 GtkWidget *container;
430 GtkWidget *container2;
431 PangoAttribute *attr;
432 PangoAttrList *attr_list;
433 GList *list;
434 const gchar *extension_name;
435 gboolean show_advanced;
437 /* Chain up to parent's constructed() method. */
438 G_OBJECT_CLASS (e_proxy_preferences_parent_class)->constructed (object);
440 preferences = E_PROXY_PREFERENCES (object);
441 registry = e_proxy_preferences_get_registry (preferences);
443 gtk_orientable_set_orientation (
444 GTK_ORIENTABLE (preferences), GTK_ORIENTATION_VERTICAL);
445 gtk_box_set_spacing (GTK_BOX (preferences), 12);
447 widget = gtk_grid_new ();
448 gtk_grid_set_row_spacing (GTK_GRID (widget), 12);
449 gtk_grid_set_column_spacing (GTK_GRID (widget), 12);
450 gtk_box_pack_start (GTK_BOX (preferences), widget, TRUE, TRUE, 0);
451 gtk_widget_show (widget);
453 container = widget;
455 widget = e_proxy_selector_new (registry);
456 gtk_widget_set_vexpand (widget, TRUE);
457 gtk_widget_set_size_request (widget, 200, -1);
458 gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 1, 3);
459 preferences->priv->proxy_selector = widget; /* do not reference */
461 g_object_bind_property (
462 preferences, "show-advanced",
463 widget, "visible",
464 G_BINDING_SYNC_CREATE);
466 attr_list = pango_attr_list_new ();
467 attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
468 pango_attr_list_insert (attr_list, attr);
470 widget = gtk_label_new ("");
471 gtk_widget_set_hexpand (widget, TRUE);
472 gtk_widget_set_valign (widget, GTK_ALIGN_START);
473 gtk_label_set_attributes (GTK_LABEL (widget), attr_list);
474 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
475 gtk_grid_attach (GTK_GRID (container), widget, 1, 0, 1, 1);
476 gtk_widget_show (widget);
478 g_object_bind_property_full (
479 preferences->priv->proxy_selector, "selected",
480 widget, "label",
481 G_BINDING_SYNC_CREATE,
482 proxy_preferences_source_to_display_name,
483 NULL, NULL, NULL);
485 pango_attr_list_unref (attr_list);
487 widget = e_proxy_editor_new (registry);
488 gtk_widget_set_margin_left (widget, 12);
489 gtk_widget_set_valign (widget, GTK_ALIGN_START);
490 gtk_grid_attach (GTK_GRID (container), widget, 1, 1, 1, 1);
491 preferences->priv->proxy_editor = widget; /* do not reference */
492 gtk_widget_show (widget);
494 g_object_bind_property (
495 preferences->priv->proxy_selector, "selected",
496 widget, "source",
497 G_BINDING_SYNC_CREATE);
499 widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
500 gtk_widget_set_margin_left (widget, 12);
501 gtk_widget_set_vexpand (widget, TRUE);
502 gtk_grid_attach (GTK_GRID (container), widget, 1, 2, 1, 1);
503 gtk_widget_show (widget);
505 container = widget;
507 /* Nested containers to control multiple levels of visibility. */
509 widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
510 gtk_widget_set_vexpand (widget, TRUE);
511 gtk_container_add (GTK_CONTAINER (container), widget);
513 g_object_bind_property (
514 preferences, "show-advanced",
515 widget, "visible",
516 G_BINDING_SYNC_CREATE);
518 container = widget;
520 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
521 gtk_container_add (GTK_CONTAINER (container), widget);
523 container = widget;
525 widget = gtk_label_new (
526 _("Apply custom proxy settings to these accounts:"));
527 gtk_widget_set_halign (widget, GTK_ALIGN_START);
528 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
529 gtk_widget_show (widget);
531 widget = gtk_scrolled_window_new (NULL, NULL);
532 gtk_scrolled_window_set_policy (
533 GTK_SCROLLED_WINDOW (widget),
534 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
535 gtk_scrolled_window_set_shadow_type (
536 GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
537 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
538 gtk_widget_show (widget);
540 container2 = widget;
542 widget = e_proxy_link_selector_new (registry);
543 gtk_container_add (GTK_CONTAINER (container2), widget);
544 gtk_widget_show (widget);
546 g_object_bind_property (
547 preferences->priv->proxy_selector, "selected",
548 widget, "target-source",
549 G_BINDING_SYNC_CREATE);
551 /* This is bound to the GtkBox created above. */
552 g_object_bind_property (
553 widget, "show-toggles",
554 container, "visible",
555 G_BINDING_SYNC_CREATE);
557 widget = gtk_link_button_new ("");
558 gtk_widget_set_halign (widget, GTK_ALIGN_START);
559 gtk_widget_set_tooltip_markup (
560 widget, _(
561 "<b>Advanced Proxy Preferences</b> lets you "
562 "define alternate network proxies and apply "
563 "them to specific accounts"));
564 gtk_box_pack_start (GTK_BOX (preferences), widget, FALSE, FALSE, 0);
565 gtk_widget_show (widget);
567 g_object_bind_property_full (
568 preferences, "show-advanced",
569 widget, "label",
570 G_BINDING_SYNC_CREATE,
571 proxy_preferences_switch_to_label,
572 NULL, NULL, NULL);
574 g_object_bind_property (
575 preferences, "show-advanced",
576 widget, "has-tooltip",
577 G_BINDING_SYNC_CREATE |
578 G_BINDING_INVERT_BOOLEAN);
580 g_signal_connect (
581 widget, "activate-link",
582 G_CALLBACK (proxy_preferences_activate_link_cb),
583 preferences);
585 extension_name = E_SOURCE_EXTENSION_PROXY;
586 list = e_source_registry_list_sources (registry, extension_name);
587 show_advanced = (g_list_length (list) > 1);
588 g_list_free_full (list, (GDestroyNotify) g_object_unref);
590 /* Switch to advanced mode if there are multiple proxy profiles. */
591 e_proxy_preferences_set_show_advanced (preferences, show_advanced);
594 static void
595 e_proxy_preferences_class_init (EProxyPreferencesClass *class)
597 GObjectClass *object_class;
599 g_type_class_add_private (class, sizeof (EProxyPreferencesPrivate));
601 object_class = G_OBJECT_CLASS (class);
602 object_class->set_property = proxy_preferences_set_property;
603 object_class->get_property = proxy_preferences_get_property;
604 object_class->dispose = proxy_preferences_dispose;
605 object_class->finalize = proxy_preferences_finalize;
606 object_class->constructed = proxy_preferences_constructed;
608 g_object_class_install_property (
609 object_class,
610 PROP_REGISTRY,
611 g_param_spec_object (
612 "registry",
613 "Registry",
614 "Data source registry",
615 E_TYPE_SOURCE_REGISTRY,
616 G_PARAM_READWRITE |
617 G_PARAM_CONSTRUCT_ONLY |
618 G_PARAM_STATIC_STRINGS));
620 g_object_class_install_property (
621 object_class,
622 PROP_SHOW_ADVANCED,
623 g_param_spec_boolean (
624 "show-advanced",
625 "Show Advanced",
626 "Show advanced proxy preferences",
627 FALSE,
628 G_PARAM_READWRITE |
629 G_PARAM_STATIC_STRINGS));
632 static void
633 e_proxy_preferences_init (EProxyPreferences *preferences)
635 GHashTable *commit_sources;
637 /* Keys are UIDs, values are allocated GWeakRefs. */
638 commit_sources = g_hash_table_new_full (
639 (GHashFunc) g_str_hash,
640 (GEqualFunc) g_str_equal,
641 (GDestroyNotify) g_free,
642 (GDestroyNotify) e_weak_ref_free);
644 preferences->priv = E_PROXY_PREFERENCES_GET_PRIVATE (preferences);
646 g_mutex_init (&preferences->priv->commit_lock);
647 preferences->priv->commit_sources = commit_sources;
651 * e_proxy_preferences_new:
652 * @registry: an #ESourceRegistry
654 * Creates a new #EProxyPreferences widget using #ESource instances in
655 * @registry.
657 * Returns: a new #EProxyPreferences
659 GtkWidget *
660 e_proxy_preferences_new (ESourceRegistry *registry)
662 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
664 return g_object_new (
665 E_TYPE_PROXY_PREFERENCES,
666 "registry", registry, NULL);
670 * e_proxy_preferences_submit:
671 * @preferences: an #EProxyPreferences
673 * Writes the displayed proxy profile details to the #ESource being edited,
674 * and submits the changes to the registry service asynchronously.
676 * Normally changes are submitted to the registry service automatically
677 * after a brief delay, but changes may sometimes need to be submitted
678 * explicitly such as when the top-level window is closing.
680 void
681 e_proxy_preferences_submit (EProxyPreferences *preferences)
683 EProxyEditor *proxy_editor;
684 ESource *source;
686 g_return_if_fail (E_IS_PROXY_PREFERENCES (preferences));
688 proxy_editor = E_PROXY_EDITOR (preferences->priv->proxy_editor);
690 /* Save user changes to the proxy source. */
691 e_proxy_editor_save (proxy_editor);
693 /* This part normally happens from a "source-changed"
694 * signal handler, but we can't wait for that here. */
695 source = e_proxy_editor_ref_source (proxy_editor);
696 proxy_preferences_commit_stash (preferences, source, FALSE);
697 g_object_unref (source);
699 /* Commit any pending changes immediately. */
700 proxy_preferences_commit_changes (preferences);
704 * e_proxy_preferences_get_registry:
705 * @preferences: an #EProxyPreferences
707 * Returns the #ESourceRegistry passed to e_proxy_preferences_new().
709 * Returns: an #ESourceRegistry
711 ESourceRegistry *
712 e_proxy_preferences_get_registry (EProxyPreferences *preferences)
714 g_return_val_if_fail (E_IS_PROXY_PREFERENCES (preferences), NULL);
716 return preferences->priv->registry;
720 * e_proxy_preferences_get_show_advanced:
721 * @preferences: an #EProxyPreferences
723 * Returns whether @preferences is currently in advanced mode.
725 * Returns: whether advanced proxy preferences are visible
727 gboolean
728 e_proxy_preferences_get_show_advanced (EProxyPreferences *preferences)
730 g_return_val_if_fail (E_IS_PROXY_PREFERENCES (preferences), FALSE);
732 return preferences->priv->show_advanced;
736 * e_proxy_preferences_set_show_advanced:
737 * @preferences: an #EProxyPreferences
738 * @show_advanced: whether to show advanced proxy preferences
740 * Switches @preferences to advanced mode if @show_advanced is %TRUE,
741 * or to basic mode if @show_advanced is %FALSE.
743 void
744 e_proxy_preferences_set_show_advanced (EProxyPreferences *preferences,
745 gboolean show_advanced)
747 g_return_if_fail (E_IS_PROXY_PREFERENCES (preferences));
749 if (show_advanced == preferences->priv->show_advanced)
750 return;
752 preferences->priv->show_advanced = show_advanced;
754 g_object_notify (G_OBJECT (preferences), "show-advanced");