diff options
author | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2019-06-03 22:53:36 -0300 |
---|---|---|
committer | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2019-06-24 21:32:58 -0300 |
commit | e49ed1ed67d87a2f1a956699ae4fbbcee0eb51d5 (patch) | |
tree | 0a424e5f83e19b83a964499bf6b0544a8c9eec43 | |
parent | 9cc07c5786d10b296db8eaa0deff9722fe1e7d8b (diff) | |
download | gnome-calendar-e49ed1ed67d87a2f1a956699ae4fbbcee0eb51d5.tar.gz |
calendar-management: Move code to GcalNewCalendarPage
-rw-r--r-- | data/ui/calendar-management-dialog.ui | 216 | ||||
-rw-r--r-- | data/ui/new-calendar-page.ui | 208 | ||||
-rw-r--r-- | src/gui/calendar-management/gcal-calendar-management-dialog.c | 662 | ||||
-rw-r--r-- | src/gui/calendar-management/gcal-new-calendar-page.c | 485 |
4 files changed, 700 insertions, 871 deletions
diff --git a/data/ui/calendar-management-dialog.ui b/data/ui/calendar-management-dialog.ui index 6bbb1ed6..4955e1a2 100644 --- a/data/ui/calendar-management-dialog.ui +++ b/data/ui/calendar-management-dialog.ui @@ -28,117 +28,6 @@ <property name="vhomogeneous">False</property> <property name="transition_type">crossfade</property> <signal name="notify::visible-child-name" handler="stack_visible_child_name_changed" object="GcalCalendarManagementDialog" swapped="no"/> - <child> - <object class="GtkGrid" id="web_source_grid"> - <property name="visible">True</property> - <property name="border_width">18</property> - <property name="row_spacing">16</property> - <property name="column_spacing">12</property> - <child> - <object class="GtkLabel" id="web_description_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Enter the address of the calendar that you want to add. If the calendar belongs to one of your online accounts, you can add it through the <a href="GOA">online account settings</a>.</property> - <property name="use_markup">True</property> - <property name="wrap">True</property> - <property name="xalign">0</property> - <signal name="activate-link" handler="description_label_link_activated" object="GcalCalendarManagementDialog" swapped="no"/> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> - <property name="width">2</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="calendar_address_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Calendar Address</property> - <property name="xalign">1</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">1</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="calendar_address_entry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hexpand">True</property> - <signal name="notify::text" handler="url_entry_text_changed" object="GcalCalendarManagementDialog" swapped="no"/> - <signal name="activate" handler="calendar_address_activated" object="GcalCalendarManagementDialog" swapped="no"/> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">1</property> - </packing> - </child> - <child> - <object class="GtkRevealer" id="web_sources_revealer"> - <property name="transition_type">crossfade</property> - <property name="transition_duration">200</property> - <child> - <object class="GtkBox" id="web_sources_listbox_box"> - <property name="visible">True</property> - <property name="orientation">vertical</property> - <property name="spacing">6</property> - <child> - <object class="GtkLabel" id="web_sources_calendar_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Calendars</property> - <property name="xalign">0</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - </child> - <child> - <object class="GtkScrolledWindow" id="web_list_scrolledwindow"> - <property name="height_request">100</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hexpand">True</property> - <property name="vexpand">True</property> - <child> - <object class="GtkViewport" id="viewport"> - <property name="visible">True</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkListBox" id="web_sources_listbox"> - <property name="visible">True</property> - <property name="activate_on_single_click">False</property> - <property name="selection_mode">none</property> - <style> - <class name="calendar-list"/> - </style> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">2</property> - <property name="width">2</property> - </packing> - </child> - </object> - <packing> - <property name="name">create</property> - <property name="title" translatable="yes">Add Calendar</property> - <property name="position">2</property> - </packing> - </child> </object> </child> </object> @@ -196,109 +85,4 @@ </object> </child> </template> - <object class="GtkDialog" id="credentials_dialog"> - <property name="type_hint">dialog</property> - <property name="transient_for">GcalCalendarManagementDialog</property> - <child internal-child="vbox"> - <object class="GtkBox" id="credentials-dialog-vbox1"> - <property name="orientation">vertical</property> - <child> - <object class="GtkGrid" id="credentials_grid"> - <property name="visible">True</property> - <property name="hexpand">True</property> - <property name="border_width">12</property> - <property name="row_spacing">6</property> - <property name="column_spacing">12</property> - <child> - <object class="GtkLabel" id="credentials_user_dim_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">User</property> - <property name="xalign">1</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="credentials_password_dim_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Password</property> - <property name="xalign">1</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">1</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="credentials_user_entry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hexpand">True</property> - <signal name="activate" handler="credential_entry_activate" object="credentials_dialog" swapped="no"/> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">0</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="credentials_password_entry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hexpand">True</property> - <property name="visibility">False</property> - <signal name="activate" handler="credential_entry_activate" object="credentials_dialog" swapped="no"/> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">1</property> - </packing> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - <child type="titlebar"> - <object class="GtkHeaderBar" id="credentials_headerbar"> - <property name="visible">True</property> - <property name="title" translatable="yes">Enter your credentials</property> - <child> - <object class="GtkButton" id="credentials_cancel_button"> - <property name="label" translatable="yes">Cancel</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="clicked" handler="credential_button_clicked" object="GcalCalendarManagementDialog" swapped="no"/> - </object> - </child> - <child> - <object class="GtkButton" id="credentials_connect_button"> - <property name="label" translatable="yes">Connect</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="clicked" handler="credential_button_clicked" object="GcalCalendarManagementDialog" swapped="no"/> - <style> - <class name="suggested-action"/> - </style> - </object> - <packing> - <property name="pack_type">end</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> </interface> diff --git a/data/ui/new-calendar-page.ui b/data/ui/new-calendar-page.ui index b7cd5926..0f307796 100644 --- a/data/ui/new-calendar-page.ui +++ b/data/ui/new-calendar-page.ui @@ -2,5 +2,213 @@ <interface> <template class="GcalNewCalendarPage" parent="GtkBox"> <property name="visible">True</property> + <child> + <object class="GtkGrid"> + <property name="visible">True</property> + <property name="border_width">18</property> + <property name="row_spacing">16</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkLabel" id="web_description_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Enter the address of the calendar that you want to add. If the calendar belongs to one of your online accounts, you can add it through the <a href="GOA">online account settings</a>.</property> + <property name="use_markup">True</property> + <property name="wrap">True</property> + <property name="xalign">0</property> + <signal name="activate-link" handler="description_label_link_activated" object="GcalNewCalendarPage" swapped="no" /> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="calendar_address_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Calendar Address</property> + <property name="xalign">1</property> + <style> + <class name="dim-label" /> + </style> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="calendar_address_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <signal name="notify::text" handler="on_url_entry_text_changed_cb" object="GcalNewCalendarPage" swapped="no" /> + <signal name="activate" handler="on_calendar_address_activated_cb" object="GcalNewCalendarPage" swapped="no" /> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkRevealer" id="web_sources_revealer"> + <property name="transition_type">crossfade</property> + <property name="transition_duration">200</property> + <child> + <object class="GtkBox" id="web_sources_listbox_box"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="web_sources_calendar_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Calendars</property> + <property name="xalign">0</property> + <attributes> + <attribute name="weight" value="bold" /> + </attributes> + </object> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="height_request">100</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <child> + <object class="GtkViewport" id="viewport"> + <property name="visible">True</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkListBox" id="web_sources_listbox"> + <property name="visible">True</property> + <property name="activate_on_single_click">False</property> + <property name="selection_mode">none</property> + <style> + <class name="calendar-list" /> + </style> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + <property name="width">2</property> + </packing> + </child> + </object> + </child> </template> + + <!-- Credentials dialog --> + <object class="GtkDialog" id="credentials_dialog"> + <property name="type_hint">dialog</property> + <property name="transient_for">GcalNewCalendarPage</property> + <child type="titlebar"> + <object class="GtkHeaderBar" id="credentials_headerbar"> + <property name="visible">True</property> + <property name="title" translatable="yes">Enter your credentials</property> + <child> + <object class="GtkButton" id="credentials_cancel_button"> + <property name="label" translatable="yes">Cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <signal name="clicked" handler="on_credential_button_clicked_cb" object="GcalNewCalendarPage" swapped="no" /> + </object> + </child> + <child> + <object class="GtkButton" id="credentials_connect_button"> + <property name="label" translatable="yes">Connect</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <signal name="clicked" handler="on_credential_button_clicked_cb" object="GcalNewCalendarPage" swapped="no" /> + <style> + <class name="suggested-action" /> + </style> + </object> + <packing> + <property name="pack_type">end</property> + </packing> + </child> + </object> + </child> + <child internal-child="vbox"> + <object class="GtkBox" id="credentials-dialog-vbox1"> + <property name="orientation">vertical</property> + <child> + <object class="GtkGrid" id="credentials_grid"> + <property name="visible">True</property> + <property name="hexpand">True</property> + <property name="border_width">12</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkLabel" id="credentials_user_dim_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">User</property> + <property name="xalign">1</property> + <style> + <class name="dim-label" /> + </style> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="credentials_password_dim_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Password</property> + <property name="xalign">1</property> + <style> + <class name="dim-label" /> + </style> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="credentials_user_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <signal name="activate" handler="on_credential_entry_activate_cb" object="credentials_dialog" swapped="no" /> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="credentials_password_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="visibility">False</property> + <signal name="activate" handler="on_credential_entry_activate_cb" object="credentials_dialog" swapped="no" /> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </interface> diff --git a/src/gui/calendar-management/gcal-calendar-management-dialog.c b/src/gui/calendar-management/gcal-calendar-management-dialog.c index 905383ae..a36c57d9 100644 --- a/src/gui/calendar-management/gcal-calendar-management-dialog.c +++ b/src/gui/calendar-management/gcal-calendar-management-dialog.c @@ -63,31 +63,12 @@ struct _GcalCalendarManagementDialog GtkWidget *headerbar; GtkWidget *notebook; GtkWidget *stack; - GtkWidget *web_source_grid; - - /* new source details */ - GtkWidget *calendar_address_entry; - GtkWidget *web_sources_listbox; - GtkWidget *web_sources_revealer; - - /* credentials dialog */ - GtkWidget *credentials_cancel_button; - GtkWidget *credentials_connect_button; - GtkWidget *credentials_dialog; - GtkWidget *credentials_password_entry; - GtkWidget *credentials_user_entry; - - gint calendar_address_id; - gint validate_url_resource_id; /* flags */ GcalCalendarManagementDialogMode mode; ESource *source; - GList *remote_sources; - GcalCalendar *removed_calendar; ESource *old_default_source; GBinding *title_bind; - gboolean prompt_password; /* auxiliary */ GSimpleActionGroup *action_group; @@ -105,8 +86,6 @@ typedef enum GCAL_ACCOUNT_TYPE_NOT_SUPPORTED } GcalAccountType; -#define ENTRY_PROGRESS_TIMEOUT 100 - static void add_button_clicked (GtkWidget *button, gpointer user_data); @@ -126,18 +105,6 @@ static void calendar_visible_check_toggled (GObject *ob static void cancel_button_clicked (GtkWidget *button, gpointer user_data); -static void clear_pages (GcalCalendarManagementDialog *dialog); - -static void color_set (GtkColorButton *button, - gpointer user_data); - -static void default_check_toggled (GObject *object, - GParamSpec *pspec, - gpointer user_data); - -static gboolean description_label_link_activated (GtkWidget *widget, - gchar *uri, - gpointer user_data); static void on_file_activated (GSimpleAction *action, GVariant *param, @@ -155,22 +122,6 @@ static void response_signal (GtkDialog *di gint response_id, gpointer user_data); -static gboolean pulse_web_entry (GcalCalendarManagementDialog *dialog); - -static void url_entry_text_changed (GObject *object, - GParamSpec *pspec, - gpointer user_data); - -static gboolean validate_url_cb (GcalCalendarManagementDialog *dialog); - -static gint prompt_credentials (GcalCalendarManagementDialog *dialog, - gchar **username, - gchar **password); - -static void discover_sources_cb (GObject *source, - GAsyncResult *result, - gpointer user_data); - G_DEFINE_TYPE (GcalCalendarManagementDialog, gcal_calendar_management_dialog, GTK_TYPE_DIALOG) enum @@ -216,7 +167,7 @@ add_button_clicked (GtkWidget *button, gcal_calendar_management_dialog_set_mode (GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data), GCAL_CALENDAR_MANAGEMENT_MODE_NORMAL); } - +#if 0 if (self->remote_sources != NULL) { GList *l; @@ -232,6 +183,7 @@ add_button_clicked (GtkWidget *button, gcal_calendar_management_dialog_set_mode (GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data), GCAL_CALENDAR_MANAGEMENT_MODE_NORMAL); } +#endif } static void @@ -276,90 +228,7 @@ cancel_button_clicked (GtkWidget *button, { GcalCalendarManagementDialog *self = GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data); - /* Destroy the ongoing created source */ - g_clear_object (&self->source); - - /* Cleanup detected remote sources that weren't added */ - if (self->remote_sources != NULL) - { - g_list_free_full (self->remote_sources, g_object_unref); - self->remote_sources = NULL; - } - - gcal_calendar_management_dialog_set_mode (GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data), GCAL_CALENDAR_MANAGEMENT_MODE_NORMAL); -} - -static void -clear_pages (GcalCalendarManagementDialog *dialog) -{ - GList *list; - - gtk_entry_set_text (GTK_ENTRY (dialog->calendar_address_entry), ""); - gtk_widget_set_sensitive (dialog->add_button, FALSE); - - /* Remove discovered web sources (if any) */ - list = gtk_container_get_children (GTK_CONTAINER (dialog->web_sources_listbox)); - g_list_free_full (list, (GDestroyNotify) gtk_widget_destroy); - - gtk_revealer_set_reveal_child (GTK_REVEALER (dialog->web_sources_revealer), FALSE); - gtk_widget_hide (dialog->web_sources_revealer); -} - -static void -color_set (GtkColorButton *button, - gpointer user_data) -{ - GcalCalendarManagementDialog *self; - ESourceSelectable *extension; - GdkRGBA color; - - self = GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data); - gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (button), &color); - - extension = E_SOURCE_SELECTABLE (e_source_get_extension (self->source, E_SOURCE_EXTENSION_CALENDAR)); - e_source_selectable_set_color (extension, gdk_rgba_to_string (&color)); -} - -static void -default_check_toggled (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - GcalCalendarManagementDialog *self = GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data); - GcalManager *manager; - ESource *new_default_source; - - manager = gcal_context_get_manager (self->context); - - /* Retrieve the current default source */ - if (self->old_default_source == NULL) - { - GcalCalendar *default_calendar = gcal_manager_get_default_calendar (manager); - self->old_default_source = gcal_calendar_get_source (default_calendar); - } - - /** - * Keeps toggling between the - * current source and the previous - * default source. - */ - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (object))) - new_default_source = self->source; - else - new_default_source = self->old_default_source; - - gcal_manager_set_default_calendar (manager, - gcal_manager_get_calendar_from_source (manager, new_default_source)); -} - -static gboolean -description_label_link_activated (GtkWidget *widget, - gchar *uri, - gpointer user_data) -{ - GApplication *app = g_application_get_default (); - gcal_utils_launch_online_accounts_panel (g_application_get_dbus_connection (app), NULL, NULL); - return TRUE; + gcal_calendar_management_dialog_set_mode (self, GCAL_CALENDAR_MANAGEMENT_MODE_NORMAL); } static void @@ -378,7 +247,7 @@ response_signal (GtkDialog *dialog, gcal_manager_save_source (manager, self->source); g_clear_object (&self->source); } - +#if 0 /* Commit the new source; save the current page's source */ if (self->mode == GCAL_CALENDAR_MANAGEMENT_MODE_NORMAL && response_id == GTK_RESPONSE_APPLY && self->remote_sources != NULL) { @@ -398,43 +267,10 @@ response_signal (GtkDialog *dialog, g_list_free_full (self->remote_sources, g_object_unref); self->remote_sources = NULL; } - +#endif gtk_widget_hide (GTK_WIDGET (dialog)); } -#if 0 -static void -stack_visible_child_name_changed (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - GcalCalendarManagementDialog *self; - GcalCalendar *calendar; - GcalManager *manager; - GtkWidget *visible_child; - - self = GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data); - manager = gcal_context_get_manager (self->context); - calendar = gcal_manager_get_calendar_from_source (manager, self->source); - visible_child = gtk_stack_get_visible_child (GTK_STACK (object)); - - if (visible_child == self->main_scrolledwindow) - { - gtk_header_bar_set_title (GTK_HEADER_BAR (self->headerbar), _("Calendar Settings")); - gtk_header_bar_set_subtitle (GTK_HEADER_BAR (self->headerbar), NULL); - gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (self->headerbar), TRUE); - gtk_widget_set_visible (self->add_button, FALSE); - gtk_widget_set_visible (self->cancel_button, FALSE); - gtk_widget_set_visible (self->back_button, FALSE); - } -} -#endif - -/* calendar_path_to_name_suggestion: - * @file: a calendar file reference. - * - * Returns: (transfer full): A calendar name. - */ static gchar* calendar_path_to_name_suggestion (GFile *file) { @@ -507,62 +343,6 @@ calendar_file_selected (GtkFileChooser *button, gtk_widget_set_sensitive (self->add_button, TRUE); } -static gboolean -pulse_web_entry (GcalCalendarManagementDialog *dialog) -{ - gtk_entry_progress_pulse (GTK_ENTRY (dialog->calendar_address_entry)); - - dialog->calendar_address_id = g_timeout_add (ENTRY_PROGRESS_TIMEOUT, (GSourceFunc) pulse_web_entry, dialog); - - return FALSE; -} - -static void -url_entry_text_changed (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - GcalCalendarManagementDialog *self; - const gchar* text; - - self = GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data); - text = gtk_entry_get_text (GTK_ENTRY (self->calendar_address_entry)); - - if (self->calendar_address_id != 0) - { - g_source_remove (self->calendar_address_id); - self->calendar_address_id = 0; - - gtk_entry_set_progress_fraction (GTK_ENTRY (self->calendar_address_entry), 0); - } - - if (self->validate_url_resource_id != 0) - { - g_source_remove (self->validate_url_resource_id); - self->validate_url_resource_id = 0; - } - - if (g_utf8_strlen (text, -1) != 0) - { - /* Remove any previous unreleased resource */ - if (self->validate_url_resource_id != 0) - g_source_remove (self->validate_url_resource_id); - - /* - * At first, don't bother the user with - * the login prompt. Only prompt it when - * it fails. - */ - self->prompt_password = FALSE; - - self->validate_url_resource_id = g_timeout_add (500, (GSourceFunc) validate_url_cb, user_data); - } - else - { - gtk_entry_set_progress_fraction (GTK_ENTRY (self->calendar_address_entry), 0); - } -} - static void on_file_activated (GSimpleAction *action, GVariant *param, @@ -636,407 +416,6 @@ on_web_activated (GSimpleAction *action, } static void -calendar_address_activated (GtkEntry *entry, - gpointer user_data) -{ - g_assert (GCAL_IS_CALENDAR_MANAGEMENT_DIALOG (user_data)); - - validate_url_cb (GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data)); -} - -static gboolean -validate_url_cb (GcalCalendarManagementDialog *dialog) -{ - ESourceAuthentication *auth; - ENamedParameters *credentials; - ESourceExtension *ext; - ESourceWebdav *webdav; - ESource *source; - g_autoptr (SoupURI) soup_uri; - const gchar *uri; - const gchar *host, *path; - gboolean is_file; - - dialog->validate_url_resource_id = 0; - soup_uri = NULL; - host = path = NULL; - is_file = FALSE; - - /** - * Remove any reminescent ESources - * cached before. - */ - if (dialog->remote_sources != NULL) - { - g_list_free_full (dialog->remote_sources, g_object_unref); - dialog->remote_sources = NULL; - } - - /* Remove previous results */ - g_list_free_full (gtk_container_get_children (GTK_CONTAINER (dialog->web_sources_listbox)), - (GDestroyNotify) gtk_widget_destroy); - gtk_revealer_set_reveal_child (GTK_REVEALER (dialog->web_sources_revealer), FALSE); - - /* Clear the entry icon */ - gtk_entry_set_icon_from_icon_name (GTK_ENTRY (dialog->calendar_address_entry), GTK_ENTRY_ICON_SECONDARY, NULL); - - /* Get the hostname and file path from the server */ - uri = gtk_entry_get_text (GTK_ENTRY (dialog->calendar_address_entry)); - soup_uri = soup_uri_new (uri); - if (!soup_uri) - return FALSE; - - host = soup_uri_get_host (soup_uri); - path = soup_uri_get_path (soup_uri); - - if (soup_uri_get_scheme (soup_uri) == SOUP_URI_SCHEME_FILE) - is_file = TRUE; - - g_debug ("Detected host: '%s', path: '%s'", host, path); - - /** - * Create the new source and add the needed - * extensions. - */ - source = e_source_new (NULL, NULL, NULL); - e_source_set_parent (source, "webcal-stub"); - - ext = e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR); - e_source_backend_set_backend_name (E_SOURCE_BACKEND (ext), "webcal"); - - /* Authentication */ - auth = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); - e_source_authentication_set_host (auth, host); - - /* Webdav */ - webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); - e_source_webdav_set_soup_uri (webdav, soup_uri); - - /* - * If we're dealing with an absolute file path, - * there is no need to check the server for more - * sources. - */ - if (is_file) - { - /* Set the private source so it saves at closing */ - dialog->remote_sources = g_list_append (dialog->remote_sources, source); - - /* Update buttons */ - gtk_widget_set_sensitive (dialog->add_button, source != NULL); - - return FALSE; - } - - /* Pulse the entry while it performs the check */ - dialog->calendar_address_id = g_timeout_add (ENTRY_PROGRESS_TIMEOUT, (GSourceFunc) pulse_web_entry, dialog); - - /* - * Try to retrieve the sources without prompting - * username and password. If we get any error, - * then it prompts and retry. - */ - credentials = e_named_parameters_new (); - - if (!dialog->prompt_password) - { - g_debug ("Trying to connect without credentials..."); - - /* NULL credentials */ - e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_USERNAME, NULL); - e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_PASSWORD, NULL); - - e_webdav_discover_sources (source, - uri, - E_WEBDAV_DISCOVER_SUPPORTS_EVENTS, - credentials, - NULL, - discover_sources_cb, - dialog); - } - else - { - gint response; - gchar *user, *password; - - g_debug ("No credentials failed, retrying with user credentials..."); - - user = password = NULL; - response = prompt_credentials (dialog, &user, &password); - - /* - * User entered username and password, let's try - * with it. - */ - if (response == GTK_RESPONSE_OK) - { - /* User inputted credentials */ - e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_USERNAME, user); - e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_PASSWORD, password); - - e_webdav_discover_sources (source, - uri, - E_WEBDAV_DISCOVER_SUPPORTS_EVENTS, - credentials, - NULL, - discover_sources_cb, - dialog); - } - - g_free (user); - g_free (password); - } - - e_named_parameters_free (credentials); - - return FALSE; -} - -static void -credential_button_clicked (GtkWidget *button, - gpointer user_data) -{ - GcalCalendarManagementDialog *self = GCAL_CALENDAR_MANAGEMENT_DIALOG(user_data); - - if (button == self->credentials_cancel_button) - gtk_dialog_response (GTK_DIALOG (self->credentials_dialog), GTK_RESPONSE_CANCEL); - else - gtk_dialog_response (GTK_DIALOG (self->credentials_dialog), GTK_RESPONSE_OK); -} - -static void -credential_entry_activate (GtkEntry *entry, - gpointer user_data) -{ - gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK); -} - -static gint -prompt_credentials (GcalCalendarManagementDialog *dialog, - gchar **username, - gchar **password) -{ - gint response; - - /* Cleanup last credentials */ - gtk_entry_set_text (GTK_ENTRY (dialog->credentials_password_entry), ""); - gtk_entry_set_text (GTK_ENTRY (dialog->credentials_user_entry), ""); - - gtk_widget_grab_focus (dialog->credentials_user_entry); - - /* Show the dialog, then destroy it */ - response = gtk_dialog_run (GTK_DIALOG (dialog->credentials_dialog)); - - if (response == GTK_RESPONSE_OK) - { - if (username != NULL) - *username = g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->credentials_user_entry))); - - if (password != NULL) - *password = g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->credentials_password_entry))); - } - - gtk_widget_hide (dialog->credentials_dialog); - - return response; -} - -static ESource* -duplicate_source (ESource *source) -{ - ESourceExtension *ext; - ESource *new_source; - - g_assert (source && E_IS_SOURCE (source)); - - new_source = e_source_new (NULL, NULL, NULL); - e_source_set_parent (new_source, "local"); - - ext = e_source_get_extension (new_source, E_SOURCE_EXTENSION_CALENDAR); - e_source_backend_set_backend_name (E_SOURCE_BACKEND (ext), "local"); - - /* Copy Authentication data */ - if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) - { - ESourceAuthentication *new_auth, *parent_auth; - - parent_auth = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); - new_auth = e_source_get_extension (new_source, E_SOURCE_EXTENSION_AUTHENTICATION); - - e_source_authentication_set_host (new_auth, e_source_authentication_get_host (parent_auth)); - e_source_authentication_set_method (new_auth, e_source_authentication_get_method (parent_auth)); - e_source_authentication_set_port (new_auth, e_source_authentication_get_port (parent_auth)); - e_source_authentication_set_user (new_auth, e_source_authentication_get_user (parent_auth)); - e_source_authentication_set_proxy_uid (new_auth, e_source_authentication_get_proxy_uid (parent_auth)); - } - - /* Copy Webdav data */ - if (e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND)) - { - ESourceWebdav *new_webdav, *parent_webdav; - - parent_webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); - new_webdav = e_source_get_extension (new_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); - - e_source_webdav_set_display_name (new_webdav, e_source_webdav_get_display_name (parent_webdav)); - e_source_webdav_set_resource_path (new_webdav, e_source_webdav_get_resource_path (parent_webdav)); - e_source_webdav_set_resource_query (new_webdav, e_source_webdav_get_resource_query (parent_webdav)); - e_source_webdav_set_email_address (new_webdav, e_source_webdav_get_email_address (parent_webdav)); - e_source_webdav_set_ssl_trust (new_webdav, e_source_webdav_get_ssl_trust (parent_webdav)); - - e_source_set_parent (new_source, "webcal-stub"); - e_source_backend_set_backend_name (E_SOURCE_BACKEND (ext), "webcal"); - } - - return new_source; -} - -static void -check_activated_cb (GtkWidget *check, - GParamSpec *spec, - gpointer user_data) -{ - GcalCalendarManagementDialog *self; - GtkWidget *row; - ESource *source; - - self = GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data); - - row = gtk_widget_get_parent (check); - source = g_object_get_data (G_OBJECT (row), "source"); - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check))) - self->remote_sources = g_list_prepend (self->remote_sources, source); - else - self->remote_sources = g_list_remove (self->remote_sources, source); - - gtk_widget_set_sensitive (self->add_button, g_list_length (self->remote_sources) > 0); -} - -static void -discover_sources_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GcalCalendarManagementDialog *self; - GSList *discovered_sources, *user_addresses, *aux; - GError *error; - - self = GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data); - error = NULL; - - /* Stop the pulsing entry */ - if (self->calendar_address_id != 0) - { - gtk_entry_set_progress_fraction (GTK_ENTRY (self->calendar_address_entry), 0); - g_source_remove (self->calendar_address_id); - self->calendar_address_id = 0; - } - - if (!e_webdav_discover_sources_finish (E_SOURCE (source), result, NULL, NULL, &discovered_sources, &user_addresses, - &error)) - { - /* Don't add an source with errors */ - gtk_widget_set_sensitive (self->add_button, FALSE); - - /* - * If it's the first try and things went wrong, - * retry with the user credentials. Also, it - * checks for the error code, since we don't - * really want to retry things on unavailable - * servers. - */ - if (!self->prompt_password && - (error->code == 14 || - error->code == 401 || - error->code == 403 || - error->code == 405)) - { - self->prompt_password = TRUE; - - validate_url_cb (GCAL_CALENDAR_MANAGEMENT_DIALOG (user_data)); - } - else - { - g_debug ("Error: %s", error->message); - } - - g_error_free (error); - return; - } - - /* Add a success icon to the entry */ - gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->calendar_address_entry), GTK_ENTRY_ICON_SECONDARY, - "emblem-ok-symbolic"); - - /* Remove previous results */ - g_list_free_full (gtk_container_get_children (GTK_CONTAINER (self->web_sources_listbox)), - (GDestroyNotify) gtk_widget_destroy); - - /* Show the list of calendars */ - gtk_revealer_set_reveal_child (GTK_REVEALER (self->web_sources_revealer), TRUE); - gtk_widget_show (self->web_sources_revealer); - - /* TODO: show a list of calendars */ - for (aux = discovered_sources; aux != NULL; aux = aux->next) - { - g_autoptr (SoupURI) soup_uri = NULL; - EWebDAVDiscoveredSource *discovered_source; - const gchar *resource_path = NULL; - - discovered_source = aux->data; - - soup_uri = soup_uri_new (discovered_source->href); - - /* Get the new resource path from the uri */ - resource_path = soup_uri_get_path (soup_uri); - - if (soup_uri) - { - ESourceSelectable *selectable; - ESourceWebdav *webdav; - GtkWidget *row, *check; - ESource *new_source; - - - /* build up the new source */ - new_source = duplicate_source (E_SOURCE (source)); - e_source_set_display_name (E_SOURCE (new_source), discovered_source->display_name); - - webdav = e_source_get_extension (new_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); - e_source_webdav_set_resource_path (webdav, resource_path); - e_source_webdav_set_display_name (webdav, discovered_source->display_name); - - if (user_addresses) - e_source_webdav_set_email_address (webdav, user_addresses->data); - - /* Setup the color */ - selectable = e_source_get_extension (new_source, E_SOURCE_EXTENSION_CALENDAR); - e_source_selectable_set_color (selectable, discovered_source->color); - - /* create the new row */ - row = gtk_list_box_row_new (); - - check = gtk_check_button_new (); - gtk_button_set_label (GTK_BUTTON (check), discovered_source->display_name); - g_signal_connect (check, "notify::active", G_CALLBACK (check_activated_cb), user_data); - - gtk_container_add (GTK_CONTAINER (row), check); - gtk_container_add (GTK_CONTAINER (self->web_sources_listbox), row); - - g_object_set_data (G_OBJECT (row), "parent-source", source); - g_object_set_data (G_OBJECT (row), "source", new_source); - - gtk_widget_show_all (row); - } - } - - /* Free things up */ - e_webdav_discover_free_discovered_sources (discovered_sources); - g_slist_free_full (user_addresses, g_free); -} - -static void set_page (GcalCalendarManagementDialog *self, const gchar *page_name, gpointer page_data) @@ -1221,34 +600,17 @@ gcal_calendar_management_dialog_class_init (GcalCalendarManagementDialogClass *k gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, add_button); gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, back_button); - gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, calendar_address_entry); gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, cancel_button); - gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, credentials_cancel_button); - gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, credentials_connect_button); - gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, credentials_dialog); - gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, credentials_password_entry); - gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, credentials_user_entry); gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, headerbar); gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, stack); - gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, web_source_grid); - gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, web_sources_listbox); - gtk_widget_class_bind_template_child (widget_class, GcalCalendarManagementDialog, web_sources_revealer); gtk_widget_class_bind_template_callback (widget_class, add_button_clicked); gtk_widget_class_bind_template_callback (widget_class, action_widget_activated); gtk_widget_class_bind_template_callback (widget_class, back_button_clicked); - gtk_widget_class_bind_template_callback (widget_class, calendar_address_activated); gtk_widget_class_bind_template_callback (widget_class, calendar_file_selected); gtk_widget_class_bind_template_callback (widget_class, calendar_visible_check_toggled); gtk_widget_class_bind_template_callback (widget_class, cancel_button_clicked); - gtk_widget_class_bind_template_callback (widget_class, credential_button_clicked); - gtk_widget_class_bind_template_callback (widget_class, credential_entry_activate); - gtk_widget_class_bind_template_callback (widget_class, color_set); - gtk_widget_class_bind_template_callback (widget_class, default_check_toggled); - gtk_widget_class_bind_template_callback (widget_class, description_label_link_activated); gtk_widget_class_bind_template_callback (widget_class, response_signal); - //gtk_widget_class_bind_template_callback (widget_class, stack_visible_child_name_changed); - gtk_widget_class_bind_template_callback (widget_class, url_entry_text_changed); } static void @@ -1270,26 +632,19 @@ void gcal_calendar_management_dialog_set_mode (GcalCalendarManagementDialog *dialog, GcalCalendarManagementDialogMode mode) { - GcalCalendarManagementDialogMode previous_mode = dialog->mode; - - dialog->mode = mode; - - /* Cleanup old data */ - clear_pages (dialog); - switch (mode) { case GCAL_CALENDAR_MANAGEMENT_MODE_CREATE: gtk_header_bar_set_title (GTK_HEADER_BAR (dialog->headerbar), _("Add Calendar")); gtk_header_bar_set_subtitle (GTK_HEADER_BAR (dialog->headerbar), NULL); - gtk_stack_set_visible_child (GTK_STACK (dialog->stack), GTK_WIDGET (dialog->pages[GCAL_PAGE_EDIT_CALENDAR])); + gtk_stack_set_visible_child (GTK_STACK (dialog->stack), GTK_WIDGET (dialog->pages[GCAL_PAGE_NEW_CALENDAR])); break; case GCAL_CALENDAR_MANAGEMENT_MODE_CREATE_WEB: gtk_header_bar_set_title (GTK_HEADER_BAR (dialog->headerbar), _("Add Calendar")); gtk_header_bar_set_subtitle (GTK_HEADER_BAR (dialog->headerbar), NULL); gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (dialog->headerbar), FALSE); - gtk_stack_set_visible_child (GTK_STACK (dialog->stack), dialog->web_source_grid); + gtk_stack_set_visible_child (GTK_STACK (dialog->stack), GTK_WIDGET (dialog->pages[GCAL_PAGE_NEW_CALENDAR])); gtk_widget_set_visible (dialog->add_button, TRUE); gtk_widget_set_visible (dialog->cancel_button, TRUE); break; @@ -1310,9 +665,6 @@ gcal_calendar_management_dialog_set_mode (GcalCalendarManagementDialog *dial default: g_assert_not_reached (); } - - //if (previous_mode == mode) - // stack_visible_child_name_changed (G_OBJECT (dialog->stack), NULL, dialog); } /** diff --git a/src/gui/calendar-management/gcal-new-calendar-page.c b/src/gui/calendar-management/gcal-new-calendar-page.c index aab88eb1..04aaf3ec 100644 --- a/src/gui/calendar-management/gcal-new-calendar-page.c +++ b/src/gui/calendar-management/gcal-new-calendar-page.c @@ -24,15 +24,35 @@ #include "gcal-context.h" #include "gcal-calendar-management-page.h" +#include "gcal-debug.h" #include "gcal-new-calendar-page.h" +#define ENTRY_PROGRESS_TIMEOUT 100 // ms + struct _GcalNewCalendarPage { GtkBox parent; + GtkEntry *calendar_address_entry; + GtkWidget *credentials_cancel_button; + GtkWidget *credentials_connect_button; + GtkWidget *credentials_dialog; + GtkEntry *credentials_password_entry; + GtkEntry *credentials_user_entry; + GtkWidget *web_sources_listbox; + GtkWidget *web_sources_revealer; + + guint calendar_address_id; + gboolean prompt_password; + GList *remote_sources; + guint validate_url_resource_id; + GcalContext *context; }; + +static gboolean validate_url_cb (GcalNewCalendarPage *self); + static void gcal_calendar_management_page_iface_init (GcalCalendarManagementPageInterface *iface); G_DEFINE_TYPE_WITH_CODE (GcalNewCalendarPage, gcal_new_calendar_page, GTK_TYPE_BOX, @@ -47,6 +67,442 @@ enum }; /* + * Auxiliary methods + */ + +static ESource* +duplicate_source (ESource *source) +{ + ESourceExtension *ext; + ESource *new_source; + + g_assert (source && E_IS_SOURCE (source)); + + new_source = e_source_new (NULL, NULL, NULL); + e_source_set_parent (new_source, "local"); + + ext = e_source_get_extension (new_source, E_SOURCE_EXTENSION_CALENDAR); + e_source_backend_set_backend_name (E_SOURCE_BACKEND (ext), "local"); + + /* Copy Authentication data */ + if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) + { + ESourceAuthentication *new_auth, *parent_auth; + + parent_auth = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); + new_auth = e_source_get_extension (new_source, E_SOURCE_EXTENSION_AUTHENTICATION); + + e_source_authentication_set_host (new_auth, e_source_authentication_get_host (parent_auth)); + e_source_authentication_set_method (new_auth, e_source_authentication_get_method (parent_auth)); + e_source_authentication_set_port (new_auth, e_source_authentication_get_port (parent_auth)); + e_source_authentication_set_user (new_auth, e_source_authentication_get_user (parent_auth)); + e_source_authentication_set_proxy_uid (new_auth, e_source_authentication_get_proxy_uid (parent_auth)); + } + + /* Copy Webdav data */ + if (e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND)) + { + ESourceWebdav *new_webdav, *parent_webdav; + + parent_webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); + new_webdav = e_source_get_extension (new_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); + + e_source_webdav_set_display_name (new_webdav, e_source_webdav_get_display_name (parent_webdav)); + e_source_webdav_set_resource_path (new_webdav, e_source_webdav_get_resource_path (parent_webdav)); + e_source_webdav_set_resource_query (new_webdav, e_source_webdav_get_resource_query (parent_webdav)); + e_source_webdav_set_email_address (new_webdav, e_source_webdav_get_email_address (parent_webdav)); + e_source_webdav_set_ssl_trust (new_webdav, e_source_webdav_get_ssl_trust (parent_webdav)); + + e_source_set_parent (new_source, "webcal-stub"); + e_source_backend_set_backend_name (E_SOURCE_BACKEND (ext), "webcal"); + } + + return new_source; +} + +static gint +prompt_credentials (GcalNewCalendarPage *self, + gchar **username, + gchar **password) +{ + gint response; + + /* Cleanup last credentials */ + gtk_entry_set_text (self->credentials_password_entry, ""); + gtk_entry_set_text (self->credentials_user_entry, ""); + + gtk_widget_grab_focus (GTK_WIDGET (self->credentials_user_entry)); + + /* Show the dialog, then destroy it */ + response = gtk_dialog_run (GTK_DIALOG (self->credentials_dialog)); + + if (response == GTK_RESPONSE_OK) + { + if (username) + *username = g_strdup (gtk_entry_get_text (self->credentials_user_entry)); + + if (password) + *password = g_strdup (gtk_entry_get_text (self->credentials_password_entry)); + } + + gtk_widget_hide (self->credentials_dialog); + + return response; +} + + +/* + * Callbacks + */ + +static gboolean +pulse_web_entry (GcalNewCalendarPage *self) +{ + gtk_entry_progress_pulse (self->calendar_address_entry); + + self->calendar_address_id = g_timeout_add (ENTRY_PROGRESS_TIMEOUT, (GSourceFunc) pulse_web_entry, self); + + return G_SOURCE_CONTINUE; +} + +static void +on_check_activated_cb (GtkWidget *check, + GParamSpec *spec, + GcalNewCalendarPage *self) +{ + GtkWidget *row; + ESource *source; + + row = gtk_widget_get_parent (check); + source = g_object_get_data (G_OBJECT (row), "source"); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check))) + self->remote_sources = g_list_prepend (self->remote_sources, source); + else + self->remote_sources = g_list_remove (self->remote_sources, source); + + //gtk_widget_set_sensitive (self->add_button, g_list_length (self->remote_sources) > 0); +} + +static void +discover_sources_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GcalNewCalendarPage *self; + GSList *discovered_sources; + GSList *user_addresses; + GSList *aux; + GError *error; + + self = GCAL_NEW_CALENDAR_PAGE (user_data); + error = NULL; + + /* Stop the pulsing entry */ + if (self->calendar_address_id != 0) + { + gtk_entry_set_progress_fraction (GTK_ENTRY (self->calendar_address_entry), 0); + g_source_remove (self->calendar_address_id); + self->calendar_address_id = 0; + } + + if (!e_webdav_discover_sources_finish (E_SOURCE (source), result, NULL, NULL, &discovered_sources, &user_addresses, + &error)) + { + /* Don't add an source with errors */ + //gtk_widget_set_sensitive (self->add_button, FALSE); + + /* + * If it's the first try and things went wrong, retry with the user + * credentials. Also, it checks for the error code, since we don't + * really want to retry things on unavailable servers. + */ + if (!self->prompt_password && + (error->code == 14 || + error->code == 401 || + error->code == 403 || + error->code == 405)) + { + self->prompt_password = TRUE; + validate_url_cb (self); + } + else + { + g_debug ("Error: %s", error->message); + } + + g_error_free (error); + return; + } + + /* Add a success icon to the entry */ + gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->calendar_address_entry), GTK_ENTRY_ICON_SECONDARY, + "emblem-ok-symbolic"); + + /* Remove previous results */ + g_list_free_full (gtk_container_get_children (GTK_CONTAINER (self->web_sources_listbox)), + (GDestroyNotify) gtk_widget_destroy); + + /* Show the list of calendars */ + gtk_revealer_set_reveal_child (GTK_REVEALER (self->web_sources_revealer), TRUE); + gtk_widget_show (self->web_sources_revealer); + + /* TODO: show a list of calendars */ + for (aux = discovered_sources; aux != NULL; aux = aux->next) + { + g_autoptr (SoupURI) soup_uri = NULL; + EWebDAVDiscoveredSource *discovered_source; + const gchar *resource_path = NULL; + + discovered_source = aux->data; + + soup_uri = soup_uri_new (discovered_source->href); + + /* Get the new resource path from the uri */ + resource_path = soup_uri_get_path (soup_uri); + + if (soup_uri) + { + ESourceSelectable *selectable; + ESourceWebdav *webdav; + GtkWidget *row, *check; + ESource *new_source; + + + /* build up the new source */ + new_source = duplicate_source (E_SOURCE (source)); + e_source_set_display_name (E_SOURCE (new_source), discovered_source->display_name); + + webdav = e_source_get_extension (new_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); + e_source_webdav_set_resource_path (webdav, resource_path); + e_source_webdav_set_display_name (webdav, discovered_source->display_name); + + if (user_addresses) + e_source_webdav_set_email_address (webdav, user_addresses->data); + + /* Setup the color */ + selectable = e_source_get_extension (new_source, E_SOURCE_EXTENSION_CALENDAR); + e_source_selectable_set_color (selectable, discovered_source->color); + + /* create the new row */ + row = gtk_list_box_row_new (); + + check = gtk_check_button_new (); + gtk_button_set_label (GTK_BUTTON (check), discovered_source->display_name); + g_signal_connect (check, "notify::active", G_CALLBACK (on_check_activated_cb), self); + + gtk_container_add (GTK_CONTAINER (row), check); + gtk_container_add (GTK_CONTAINER (self->web_sources_listbox), row); + + g_object_set_data (G_OBJECT (row), "parent-source", source); + g_object_set_data (G_OBJECT (row), "source", new_source); + + gtk_widget_show_all (row); + } + } + + /* Free things up */ + e_webdav_discover_free_discovered_sources (discovered_sources); + g_slist_free_full (user_addresses, g_free); +} + +static gboolean +validate_url_cb (GcalNewCalendarPage *self) +{ + ESourceAuthentication *auth; + ENamedParameters *credentials; + ESourceExtension *ext; + ESourceWebdav *webdav; + ESource *source; + g_autoptr (SoupURI) soup_uri; + const gchar *uri; + const gchar *host, *path; + gboolean is_file; + + self->validate_url_resource_id = 0; + soup_uri = NULL; + host = path = NULL; + is_file = FALSE; + + /** + * Remove any reminescent ESources + * cached before. + */ + if (self->remote_sources) + { + g_list_free_full (self->remote_sources, g_object_unref); + self->remote_sources = NULL; + } + + /* Remove previous results */ + g_list_free_full (gtk_container_get_children (GTK_CONTAINER (self->web_sources_listbox)), + (GDestroyNotify) gtk_widget_destroy); + gtk_revealer_set_reveal_child (GTK_REVEALER (self->web_sources_revealer), FALSE); + + /* Clear the entry icon */ + gtk_entry_set_icon_from_icon_name (self->calendar_address_entry, GTK_ENTRY_ICON_SECONDARY, NULL); + + /* Get the hostname and file path from the server */ + uri = gtk_entry_get_text (self->calendar_address_entry); + soup_uri = soup_uri_new (uri); + if (!soup_uri) + return FALSE; + + host = soup_uri_get_host (soup_uri); + path = soup_uri_get_path (soup_uri); + + if (soup_uri_get_scheme (soup_uri) == SOUP_URI_SCHEME_FILE) + is_file = TRUE; + + g_debug ("Detected host: '%s', path: '%s'", host, path); + + /* Create the new source and add the needed extensions */ + source = e_source_new (NULL, NULL, NULL); + e_source_set_parent (source, "webcal-stub"); + + ext = e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR); + e_source_backend_set_backend_name (E_SOURCE_BACKEND (ext), "webcal"); + + /* Authentication */ + auth = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); + e_source_authentication_set_host (auth, host); + + /* Webdav */ + webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); + e_source_webdav_set_soup_uri (webdav, soup_uri); + + /* + * If we're dealing with an absolute file path, there is no need + * to check the server for more sources. + */ + if (is_file) + { + self->remote_sources = g_list_append (self->remote_sources, source); + //gtk_widget_set_sensitive (self->add_button, source != NULL); + + return FALSE; + } + + /* Pulse the entry while it performs the check */ + self->calendar_address_id = g_timeout_add (ENTRY_PROGRESS_TIMEOUT, (GSourceFunc) pulse_web_entry, self); + + /* + * Try to retrieve the sources without prompting + * username and password. If we get any error, + * then it prompts and retry. + */ + credentials = e_named_parameters_new (); + + if (!self->prompt_password) + { + g_debug ("Trying to connect without credentials..."); + + /* NULL credentials */ + e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_USERNAME, NULL); + e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_PASSWORD, NULL); + + e_webdav_discover_sources (source, + uri, + E_WEBDAV_DISCOVER_SUPPORTS_EVENTS, + credentials, + NULL, + discover_sources_cb, + self); + } + else + { + g_autofree gchar *password = NULL; + g_autofree gchar *user = NULL; + gint response; + + g_debug ("No credentials failed, retrying with user credentials..."); + + user = password = NULL; + response = prompt_credentials (self, &user, &password); + + if (response == GTK_RESPONSE_OK) + { + e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_USERNAME, user); + e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_PASSWORD, password); + + e_webdav_discover_sources (source, + uri, + E_WEBDAV_DISCOVER_SUPPORTS_EVENTS, + credentials, + NULL, + discover_sources_cb, + self); + } + } + + e_named_parameters_free (credentials); + + return FALSE; +} + +static void +on_calendar_address_activated_cb (GtkEntry *entry, + GcalNewCalendarPage *self) +{ + validate_url_cb (self); +} + +static void +on_credential_button_clicked_cb (GtkWidget *button, + GcalNewCalendarPage *self) +{ + if (button == self->credentials_cancel_button) + gtk_dialog_response (GTK_DIALOG (self->credentials_dialog), GTK_RESPONSE_CANCEL); + else + gtk_dialog_response (GTK_DIALOG (self->credentials_dialog), GTK_RESPONSE_OK); +} + +static void +on_credential_entry_activate_cb (GtkEntry *entry, + GtkDialog *dialog) +{ + gtk_dialog_response (dialog, GTK_RESPONSE_OK); +} + +static void +on_url_entry_text_changed_cb (GtkEntry *entry, + GParamSpec *pspec, + GcalNewCalendarPage *self) +{ + const gchar* text; + + GCAL_ENTRY; + + text = gtk_entry_get_text (entry); + + if (self->calendar_address_id != 0) + { + gtk_entry_set_progress_fraction (entry, 0); + g_clear_handle_id (&self->calendar_address_id, g_source_remove); + } + + if (self->validate_url_resource_id != 0) + g_clear_handle_id (&self->validate_url_resource_id, g_source_remove); + + if (g_utf8_strlen (text, -1) > 0) + { + /* + * At first, don't bother the user with the login prompt. Only prompt it when + * it fails. + */ + self->prompt_password = FALSE; + self->validate_url_resource_id = g_timeout_add (500, (GSourceFunc) validate_url_cb, self); + } + else + { + gtk_entry_set_progress_fraction (self->calendar_address_entry, 0); + } + + GCAL_EXIT; +} + + +/* * GcalCalendarManagementPage iface */ @@ -63,10 +519,25 @@ gcal_new_calendar_page_get_title (GcalCalendarManagementPage *page) } static void +gcal_new_calendar_page_deactivate (GcalCalendarManagementPage *page) +{ + GcalNewCalendarPage *self = GCAL_NEW_CALENDAR_PAGE (page); + + //g_clear_object (&self->source); + + if (self->remote_sources) + { + g_list_free_full (self->remote_sources, g_object_unref); + self->remote_sources = NULL; + } +} + +static void gcal_calendar_management_page_iface_init (GcalCalendarManagementPageInterface *iface) { iface->get_name = gcal_new_calendar_page_get_name; iface->get_title = gcal_new_calendar_page_get_title; + iface->deactivate = gcal_new_calendar_page_deactivate; } /* @@ -135,6 +606,20 @@ gcal_new_calendar_page_class_init (GcalNewCalendarPageClass *klass) g_object_class_override_property (object_class, PROP_CONTEXT, "context"); gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/new-calendar-page.ui"); + + gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, calendar_address_entry); + gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, credentials_cancel_button); + gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, credentials_connect_button); + gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, credentials_dialog); + gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, credentials_password_entry); + gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, credentials_user_entry); + gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, web_sources_listbox); + gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, web_sources_revealer); + + gtk_widget_class_bind_template_callback (widget_class, on_calendar_address_activated_cb); + gtk_widget_class_bind_template_callback (widget_class, on_credential_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, on_credential_entry_activate_cb); + gtk_widget_class_bind_template_callback (widget_class, on_url_entry_text_changed_cb); } static void |