diff options
Diffstat (limited to 'modules/cal-config-google/e-google-chooser-dialog.c')
-rw-r--r-- | modules/cal-config-google/e-google-chooser-dialog.c | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/modules/cal-config-google/e-google-chooser-dialog.c b/modules/cal-config-google/e-google-chooser-dialog.c new file mode 100644 index 0000000000..acf11f2a9d --- /dev/null +++ b/modules/cal-config-google/e-google-chooser-dialog.c @@ -0,0 +1,387 @@ +/* + * e-google-chooser-dialog.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <webcal://www.gnu.org/licenses/> + * + */ + +#include "e-google-chooser-dialog.h" + +#include <config.h> +#include <glib/gi18n-lib.h> + +#define E_GOOGLE_CHOOSER_DIALOG_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_GOOGLE_CHOOSER_DIALOG, EGoogleChooserDialogPrivate)) + +struct _EGoogleChooserDialogPrivate { + EGoogleChooser *chooser; + GCancellable *cancellable; + + GtkWidget *info_bar; /* not referenced */ + GtkWidget *info_bar_label; /* not referenced */ +}; + +enum { + PROP_0, + PROP_CHOOSER +}; + +G_DEFINE_DYNAMIC_TYPE ( + EGoogleChooserDialog, + e_google_chooser_dialog, + GTK_TYPE_DIALOG) + +static void +google_chooser_dialog_populated_cb (EGoogleChooser *chooser, + GAsyncResult *result, + EGoogleChooserDialog *dialog) +{ + GdkWindow *window; + GError *error = NULL; + + e_google_chooser_populate_finish (chooser, result, &error); + + /* Ignore cancellations, and leave the mouse cursor alone + * since the GdkWindow may have already been destroyed. */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + goto exit; + + /* Reset the mouse cursor to normal. */ + window = gtk_widget_get_window (GTK_WIDGET (dialog)); + gdk_window_set_cursor (window, NULL); + + if (error != NULL) { + GtkLabel *label; + + label = GTK_LABEL (dialog->priv->info_bar_label); + gtk_label_set_text (label, error->message); + gtk_widget_show (dialog->priv->info_bar); + + g_error_free (error); + goto exit; + } + +exit: + g_object_unref (dialog); +} + +static void +google_chooser_dialog_row_activated_cb (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + GtkDialog *dialog) +{ + gtk_dialog_response (dialog, GTK_RESPONSE_APPLY); +} + +static void +google_chooser_dialog_selection_changed_cb (GtkTreeSelection *selection, + GtkDialog *dialog) +{ + gboolean sensitive; + + sensitive = (gtk_tree_selection_count_selected_rows (selection) > 0); + + gtk_dialog_set_response_sensitive ( + dialog, GTK_RESPONSE_APPLY, sensitive); +} + +static void +google_chooser_dialog_set_chooser (EGoogleChooserDialog *dialog, + EGoogleChooser *chooser) +{ + g_return_if_fail (E_IS_GOOGLE_CHOOSER (chooser)); + g_return_if_fail (dialog->priv->chooser == NULL); + + dialog->priv->chooser = g_object_ref_sink (chooser); +} + +static void +google_chooser_dialog_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CHOOSER: + google_chooser_dialog_set_chooser ( + E_GOOGLE_CHOOSER_DIALOG (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +google_chooser_dialog_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CHOOSER: + g_value_set_object ( + value, + e_google_chooser_dialog_get_chooser ( + E_GOOGLE_CHOOSER_DIALOG (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +google_chooser_dialog_dispose (GObject *object) +{ + EGoogleChooserDialogPrivate *priv; + + priv = E_GOOGLE_CHOOSER_DIALOG_GET_PRIVATE (object); + + if (priv->chooser != NULL) { + g_signal_handlers_disconnect_by_func ( + priv->chooser, google_chooser_dialog_row_activated_cb, + object); + g_object_unref (priv->chooser); + priv->chooser = NULL; + } + + if (priv->cancellable != NULL) { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_google_chooser_dialog_parent_class)->dispose (object); +} + +static void +google_chooser_dialog_constructed (GObject *object) +{ + EGoogleChooserDialog *dialog; + GtkTreeSelection *selection; + GtkWidget *container; + GtkWidget *widget; + GtkWidget *vbox; + const gchar *title; + + dialog = E_GOOGLE_CHOOSER_DIALOG (object); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_google_chooser_dialog_parent_class)-> + constructed (object); + + gtk_dialog_add_button ( + GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + + gtk_dialog_add_button ( + GTK_DIALOG (dialog), + GTK_STOCK_APPLY, GTK_RESPONSE_APPLY); + + gtk_dialog_set_default_response ( + GTK_DIALOG (dialog), GTK_RESPONSE_APPLY); + gtk_dialog_set_response_sensitive ( + GTK_DIALOG (dialog), GTK_RESPONSE_APPLY, FALSE); + + title = _("Choose a Calendar"); + gtk_window_set_title (GTK_WINDOW (dialog), title); + gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 400); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + + container = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + + widget = gtk_vbox_new (FALSE, 6); + gtk_container_set_border_width (GTK_CONTAINER (widget), 5); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + + container = vbox = widget; + + widget = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy ( + GTK_SCROLLED_WINDOW (widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type ( + GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = GTK_WIDGET (dialog->priv->chooser); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + g_signal_connect ( + widget, "row-activated", + G_CALLBACK (google_chooser_dialog_row_activated_cb), dialog); + + /* Build the info bar, but hide it initially. */ + + container = vbox; + + widget = gtk_info_bar_new (); + gtk_info_bar_set_message_type ( + GTK_INFO_BAR (widget), GTK_MESSAGE_WARNING); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + dialog->priv->info_bar = widget; /* do not reference */ + gtk_widget_hide (widget); + + container = gtk_info_bar_get_content_area (GTK_INFO_BAR (widget)); + + widget = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_image_new_from_stock ( + GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + dialog->priv->info_bar_label = widget; /* do not reference */ + gtk_widget_show (widget); + + /* Listen for tree view selection changes. */ + + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (dialog->priv->chooser)); + + g_signal_connect ( + selection, "changed", + G_CALLBACK (google_chooser_dialog_selection_changed_cb), + dialog); +} + +static void +google_chooser_dialog_realize (GtkWidget *widget) +{ + EGoogleChooserDialogPrivate *priv; + GdkCursor *cursor; + GdkWindow *window; + GdkDisplay *display; + + priv = E_GOOGLE_CHOOSER_DIALOG_GET_PRIVATE (widget); + + /* Chain up to parent's realize() method. */ + GTK_WIDGET_CLASS (e_google_chooser_dialog_parent_class)-> + realize (widget); + + g_return_if_fail (priv->cancellable == NULL); + priv->cancellable = g_cancellable_new (); + + /* Show a busy mouse cursor while populating. */ + window = gtk_widget_get_window (widget); + display = gtk_widget_get_display (widget); + cursor = gdk_cursor_new_for_display (display, GDK_WATCH); + gdk_window_set_cursor (window, cursor); + gdk_cursor_unref (cursor); + + e_google_chooser_populate ( + priv->chooser, priv->cancellable, (GAsyncReadyCallback) + google_chooser_dialog_populated_cb, g_object_ref (widget)); +} + +static void +google_chooser_dialog_response (GtkDialog *dialog, + gint response_id) +{ + EGoogleChooserDialogPrivate *priv; + + priv = E_GOOGLE_CHOOSER_DIALOG_GET_PRIVATE (dialog); + + if (response_id == GTK_RESPONSE_APPLY) + e_google_chooser_apply_selected (priv->chooser); +} + +static void +e_google_chooser_dialog_class_init (EGoogleChooserDialogClass *class) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkDialogClass *dialog_class; + + g_type_class_add_private (class, sizeof (EGoogleChooserDialogPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = google_chooser_dialog_set_property; + object_class->get_property = google_chooser_dialog_get_property; + object_class->dispose = google_chooser_dialog_dispose; + object_class->constructed = google_chooser_dialog_constructed; + + widget_class = GTK_WIDGET_CLASS (class); + widget_class->realize = google_chooser_dialog_realize; + + dialog_class = GTK_DIALOG_CLASS (class); + dialog_class->response = google_chooser_dialog_response; + + g_object_class_install_property ( + object_class, + PROP_CHOOSER, + g_param_spec_object ( + "chooser", + NULL, + NULL, + E_TYPE_GOOGLE_CHOOSER, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +e_google_chooser_dialog_class_finalize (EGoogleChooserDialogClass *class) +{ +} + +static void +e_google_chooser_dialog_init (EGoogleChooserDialog *dialog) +{ + dialog->priv = E_GOOGLE_CHOOSER_DIALOG_GET_PRIVATE (dialog); +} + +void +e_google_chooser_dialog_type_register (GTypeModule *type_module) +{ + /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration + * function, so we have to wrap it with a public function in + * order to register types from a separate compilation unit. */ + e_google_chooser_dialog_register_type (type_module); +} + +GtkWidget * +e_google_chooser_dialog_new (EGoogleChooser *chooser, + GtkWindow *parent) +{ + g_return_val_if_fail (E_IS_GOOGLE_CHOOSER (chooser), NULL); + g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL); + + return g_object_new ( + E_TYPE_GOOGLE_CHOOSER_DIALOG, + "chooser", chooser, "transient-for", parent, NULL); +} + +EGoogleChooser * +e_google_chooser_dialog_get_chooser (EGoogleChooserDialog *dialog) +{ + g_return_val_if_fail (E_IS_GOOGLE_CHOOSER_DIALOG (dialog), NULL); + + return dialog->priv->chooser; +} + |