/* sunone-subscription-dialog.c * * Copyright (C) 2002-2005 Sun Microsystems, Inc * * AUTHORS * Jack Jia * Harry Lu * Alfred Peng * Rodrigo Moya * */ #include "sunone-i18n.h" #include #include #include #include #include #include #include #include "sunone-subscription-dialog.h" extern char *evolution_dir; struct _SunOneSubscriptionDialogPrivate { SunOneFolderTree *tree; SunOneConnection *cnc; GList *matched_calids; SunOneConnectionPreferences *prefs; GHashTable *to_subscribe; GladeXML *xml; GtkWidget *main_table; GtkTreeView *subscriptions_tree; GtkWidget *search_field; GtkWidget *search_by; GtkWidget *search_string; GtkWidget *search_button; GtkWidget *search_clear; }; static void sunone_subscription_dialog_class_init (SunOneSubscriptionDialogClass *klass); static void sunone_subscription_dialog_init (SunOneSubscriptionDialog *object); static void sunone_subscription_dialog_dispose (GObject *object); static void sunone_subscription_dialog_finalize (GObject *object); static GObjectClass *parent_class = NULL; static void sunone_subscription_dialog_class_init (SunOneSubscriptionDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); parent_class = g_type_class_ref (GTK_TYPE_DIALOG); object_class->dispose = sunone_subscription_dialog_dispose; object_class->finalize = sunone_subscription_dialog_finalize; } static void refresh_table (SunOneSubscriptionDialog *dialog) { SunOneSubscriptionDialogPrivate *priv = dialog->priv; GtkListStore *subscriptions_model; GList *l; subscriptions_model = (GtkListStore *) gtk_tree_view_get_model (priv->subscriptions_tree); gtk_list_store_clear (subscriptions_model); for (l = priv->matched_calids; l != NULL; l = l->next) { SunOneCalendarProperties *calprops; GtkTreeIter iter; calprops = l->data; gtk_list_store_append (subscriptions_model, &iter); gtk_list_store_set (subscriptions_model, &iter, SUB_COLUMN, g_hash_table_lookup (priv->to_subscribe, calprops->relative_calid) != NULL, SUB_CALID_COLUMN, calprops->relative_calid, SUB_OWNER_COLUMN, calprops->primary_owner, SUB_DES_COLUMN, calprops->display_name, -1); } } static void free_matched_calids (SunOneSubscriptionDialogPrivate *priv) { if (priv->matched_calids) { g_list_foreach (priv->matched_calids, (GFunc) sunone_connection_free_calprops, NULL); g_list_free (priv->matched_calids); priv->matched_calids = NULL; } } static void clear_search_cb (GtkButton *button, gpointer user_data) { SunOneSubscriptionDialog *dialog = SUNONE_SUBSCRIPTION_DIALOG (user_data); SunOneSubscriptionDialogPrivate *priv = dialog->priv; g_return_if_fail (IS_SUNONE_SUBSCRIPTION_DIALOG (dialog)); gtk_combo_box_set_active ((GtkComboBox *) priv->search_by, CONTAINS); gtk_combo_box_set_active ((GtkComboBox *) priv->search_field, NAME_OR_ID); gtk_entry_set_text (GTK_ENTRY (priv->search_string), ""); /* refresh the list */ free_matched_calids (priv); refresh_table (dialog); } static void do_search_cb (GtkButton *button, gpointer user_data) { SunOneSubscriptionDialog *dialog = SUNONE_SUBSCRIPTION_DIALOG (user_data); SunOneSubscriptionDialogPrivate *priv = dialog->priv; GList *l; gint by, field; const char *str; g_return_if_fail (IS_SUNONE_SUBSCRIPTION_DIALOG (dialog)); /*free previous result*/ free_matched_calids (priv); /*do new search*/ by = gtk_combo_box_get_active ((GtkComboBox *) priv->search_by); field = gtk_combo_box_get_active ((GtkComboBox *) priv->search_field); str = gtk_entry_get_text (GTK_ENTRY (priv->search_string)); if (str && *str != 0) priv->matched_calids = sunone_connection_search_calids (priv->cnc, field, by, str); priv->prefs = sunone_connection_get_preferences (priv->cnc); if (priv->prefs) { for (l = priv->prefs->subscriptions; l != NULL; l = l->next) { SunOneCalendarSubscription *sub = l->data; g_hash_table_insert (priv->to_subscribe, g_strdup (sub->calid), g_strdup (sub->display_name ? sub->display_name : "")); } } refresh_table (dialog); } static void search_activated_cb (GtkComboBox *w, gpointer user_data) { SunOneSubscriptionDialog *dialog = SUNONE_SUBSCRIPTION_DIALOG (user_data); SunOneSubscriptionDialogPrivate *priv = dialog->priv; g_return_if_fail (IS_SUNONE_SUBSCRIPTION_DIALOG (dialog)); gtk_widget_set_sensitive (priv->search_button, TRUE); gtk_widget_grab_focus (priv->search_string); } static void subscribe_toggled (GtkCellRendererToggle *cell, gchar *path_str, gpointer data) { SunOneSubscriptionDialog *dialog = SUNONE_SUBSCRIPTION_DIALOG (data); SunOneSubscriptionDialogPrivate *priv = dialog->priv; SunOneCalendarProperties *calprops; GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path = gtk_tree_path_new_from_string (path_str); gboolean subscribe; gint row; GList *l; gpointer orig_key, orig_value; g_return_if_fail (IS_SUNONE_SUBSCRIPTION_DIALOG (dialog)); model = gtk_tree_view_get_model (priv->subscriptions_tree); gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, SUB_COLUMN, &subscribe, -1); row = gtk_tree_path_get_indices (path)[0]; gtk_tree_path_free (path); g_return_if_fail (row >= 0 && row < g_list_length (priv->matched_calids)); l = g_list_nth (priv->matched_calids, row); if (!l) return; calprops = l->data; /* don't allow subscription from default calendar */ if (!strcmp (calprops->relative_calid, priv->prefs->default_calendar)) return; if (!subscribe) { g_hash_table_insert (priv->to_subscribe, g_strdup (calprops->relative_calid), g_strdup (calprops->display_name ? calprops->display_name : "")); } else { if (g_hash_table_lookup_extended (priv->to_subscribe, calprops->relative_calid, &orig_key, &orig_value)) { g_hash_table_remove (priv->to_subscribe, calprops->relative_calid); g_free (orig_key); g_free (orig_value); } } subscribe = !subscribe; gtk_list_store_set (GTK_LIST_STORE (model), &iter, SUB_COLUMN, subscribe, -1); gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE); } static void sunone_subscription_dialog_init (SunOneSubscriptionDialog *object) { SunOneSubscriptionDialog *dialog = SUNONE_SUBSCRIPTION_DIALOG (object); SunOneSubscriptionDialogPrivate *priv; GtkWidget *label; dialog->priv = g_new0 (SunOneSubscriptionDialogPrivate, 1); priv = dialog->priv; priv->cnc = NULL; priv->matched_calids = NULL; priv->prefs = NULL; priv->to_subscribe = g_hash_table_new (g_str_hash, g_str_equal); /* load UI */ priv->xml = glade_xml_new (SUNONE_GLADEDIR "/sunone-subscription-dialog.glade", "subscription-main-table", NULL); if (!priv->xml) { label = gtk_label_new (_("Could not load permissions dialog UI")); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), label, TRUE, TRUE, 2); return; } priv->main_table = glade_xml_get_widget (priv->xml, "subscription-main-table"); gtk_widget_show (priv->main_table); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), priv->main_table, TRUE, TRUE, 2); priv->search_field = glade_xml_get_widget (priv->xml, "subscription-search-field"); gtk_combo_box_set_active ((GtkComboBox *) priv->search_field, 0); g_signal_connect ((GtkComboBox *) priv->search_field, "changed", G_CALLBACK (search_activated_cb), dialog); priv->search_by = glade_xml_get_widget (priv->xml, "subscription-search-by"); gtk_combo_box_set_active ((GtkComboBox *) priv->search_by, 0); g_signal_connect ((GtkComboBox *) priv->search_by, "changed", G_CALLBACK (search_activated_cb), dialog); priv->search_string = glade_xml_get_widget (priv->xml, "subscription-search-string"); g_signal_connect (G_OBJECT (priv->search_string), "changed", G_CALLBACK (search_activated_cb), dialog); g_signal_connect (G_OBJECT (priv->search_string), "activate", G_CALLBACK (do_search_cb), dialog); priv->search_button = glade_xml_get_widget (priv->xml, "subscription-search-button"); g_signal_connect (G_OBJECT (priv->search_button), "clicked", G_CALLBACK (do_search_cb), dialog); priv->search_clear = glade_xml_get_widget (priv->xml, "subscription-search-clear"); g_signal_connect (G_OBJECT (priv->search_clear), "clicked", G_CALLBACK (clear_search_cb), dialog); priv->subscriptions_tree = (GtkTreeView *)glade_xml_get_widget (priv->xml, "sub-treeview"); gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE); } static void free_to_subscribe_item (gpointer key, gpointer value, gpointer user_data) { g_free (key); g_free (value); } static void sunone_subscription_dialog_dispose (GObject *object) { SunOneSubscriptionDialog *dialog = SUNONE_SUBSCRIPTION_DIALOG (object); SunOneSubscriptionDialogPrivate *priv = dialog->priv; g_return_if_fail (IS_SUNONE_SUBSCRIPTION_DIALOG (dialog)); if (priv) { if (priv->tree) { g_object_unref (G_OBJECT (priv->tree)); priv->tree = NULL; } if (priv->cnc) { g_object_unref (G_OBJECT (priv->cnc)); priv->cnc = NULL; } if (priv->xml) { g_object_unref (G_OBJECT (priv->xml)); priv->xml = NULL; } if (priv->prefs) { sunone_connection_free_preferences (priv->prefs); priv->prefs = NULL; } if (priv->to_subscribe) { g_hash_table_foreach (priv->to_subscribe, (GHFunc) free_to_subscribe_item, NULL); g_hash_table_destroy (priv->to_subscribe); priv->to_subscribe = NULL; } if (priv->matched_calids) { g_list_foreach (priv->matched_calids, (GFunc) sunone_connection_free_calprops, NULL); g_list_free (priv->matched_calids); priv->matched_calids = NULL; } g_free (priv); dialog->priv = NULL; } if (G_OBJECT_CLASS (parent_class)->dispose) (* G_OBJECT_CLASS (parent_class)->dispose) (object); } static void sunone_subscription_dialog_finalize (GObject *object) { SunOneSubscriptionDialog *dialog = SUNONE_SUBSCRIPTION_DIALOG (object); g_return_if_fail (IS_SUNONE_SUBSCRIPTION_DIALOG (dialog)); if (G_OBJECT_CLASS (parent_class)->finalize) (* G_OBJECT_CLASS (parent_class)->finalize) (object); } G_DEFINE_TYPE (SunOneSubscriptionDialog, sunone_subscription_dialog, GTK_TYPE_DIALOG) static void add_subscription_from_hash (gpointer key, gpointer value, gpointer user_data) { SunOneConnectionPreferences *prefs = user_data; SunOneCalendarSubscription *sub; gchar *calid = key; gchar *display_name = value; sub = g_new0 (SunOneCalendarSubscription, 1); sub->calid = g_strdup (calid); sub->display_name = g_strdup (display_name); prefs->subscriptions = g_list_append (prefs->subscriptions, sub); } static void add_folder_hash (gpointer key, gpointer value, gpointer user_data) { SunOneSubscriptionDialog *dialog = SUNONE_SUBSCRIPTION_DIALOG (user_data); SunOneSubscriptionDialogPrivate *priv = dialog->priv; SunOneAccount *account; char *calid = key; char *display_name = value; account = sunone_folder_tree_get_account (priv->tree); if (!account) return; sunone_folder_tree_add_calendar (priv->tree, account, calid, display_name); } static void update_folder_tree (SunOneSubscriptionDialog *dialog, GList *old_subscriptions) { SunOneSubscriptionDialogPrivate *priv = dialog->priv; SunOneAccount *account; GList *l; gchar *calid_hash, *name_hash; account = sunone_folder_tree_get_account (priv->tree); if (!account) return; for (l = old_subscriptions; l != NULL; l = l->next) { SunOneCalendarSubscription *sub = l->data; if (g_hash_table_lookup_extended (priv->to_subscribe, sub->calid, (gpointer *)&calid_hash, (gpointer *)&name_hash)) { g_hash_table_remove (priv->to_subscribe, sub->calid); g_free (calid_hash); g_free (name_hash); /* found in both lists, so no changes */ continue; } /* not found in the new list, so remove it */ sunone_folder_tree_remove_calendar (priv->tree, account, sub->calid); } /* now, the left ones are new subscriptions */ g_hash_table_foreach (priv->to_subscribe, (GHFunc) add_folder_hash, dialog); sunone_folder_tree_sync (); } static void dialog_button_clicked_cb (GtkWidget *gdialog, gint response, gpointer user_data) { SunOneSubscriptionDialog *dialog = SUNONE_SUBSCRIPTION_DIALOG (gdialog); SunOneSubscriptionDialogPrivate *priv = dialog->priv; g_return_if_fail (IS_SUNONE_SUBSCRIPTION_DIALOG (dialog)); if (response == GTK_RESPONSE_OK) { guint rc; GList *old_subscriptions; gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE); gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL, FALSE); old_subscriptions = priv->prefs->subscriptions; priv->prefs->subscriptions = NULL; g_hash_table_foreach (priv->to_subscribe, (GHFunc) add_subscription_from_hash, priv->prefs); /* make sure we don't remove accidentally the default calendar */ if (!g_hash_table_lookup (priv->to_subscribe, priv->prefs->default_calendar)) { add_subscription_from_hash (priv->prefs->default_calendar, priv->prefs->default_calendar, priv->prefs); } /* send query to the server */ rc = sunone_connection_set_preferences (priv->cnc, priv->prefs); if (SUNONE_ERROR_IS_SUCCESSFUL (rc)) { update_folder_tree (dialog, old_subscriptions); g_list_foreach (old_subscriptions, (GFunc) sunone_connection_free_subscription, NULL); g_list_free (old_subscriptions); } else { g_list_foreach (old_subscriptions, (GFunc) sunone_connection_free_subscription, NULL); g_list_free (old_subscriptions); e_notice (GTK_WINDOW (dialog), GTK_MESSAGE_ERROR, _("Could not set preferences for this connection")); gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE); gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL, TRUE); return; } } gtk_widget_destroy (GTK_WIDGET (gdialog)); } static void load_subscriptions (SunOneSubscriptionDialog *dialog) { SunOneSubscriptionDialogPrivate *priv = dialog->priv; GtkListStore *subscriptions_model; GtkCellRenderer *renderer; /* create the Table and its model */ subscriptions_model = gtk_list_store_new (SUB_TREE_N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model (priv->subscriptions_tree, (GtkTreeModel *)subscriptions_model); renderer = gtk_cell_renderer_toggle_new(); g_signal_connect (renderer, "toggled", G_CALLBACK (subscribe_toggled), dialog); gtk_tree_view_insert_column_with_attributes (priv->subscriptions_tree, -1, _("Subscription"), renderer, "active", SUB_COLUMN, NULL); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_insert_column_with_attributes (priv->subscriptions_tree, -1, _("Calendar ID"), renderer, "text", SUB_CALID_COLUMN, NULL); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_insert_column_with_attributes (priv->subscriptions_tree, -1, _("Owner"), renderer, "text", SUB_OWNER_COLUMN, NULL); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_insert_column_with_attributes (priv->subscriptions_tree, -1, _("Description"), renderer, "text", SUB_DES_COLUMN, NULL); if (priv->matched_calids) refresh_table (dialog); } GtkWidget * sunone_subscription_dialog_new (SunOneFolderTree *tree, SunOneConnection *cnc) { SunOneSubscriptionDialogPrivate *priv; SunOneSubscriptionDialog *dialog; g_return_val_if_fail (IS_SUNONE_CONNECTION (cnc), NULL); g_return_val_if_fail (SUNONE_IS_FOLDER_TREE (tree), NULL); dialog = g_object_new (SUNONE_SUBSCRIPTION_DIALOG_TYPE, NULL); priv = dialog->priv; g_object_ref (tree); priv->tree = tree; g_object_ref (cnc); priv->cnc = cnc; gtk_window_set_title (GTK_WINDOW (dialog), _("Remote Calendar Subscriptions")); gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_OK, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE); gtk_widget_set_size_request (GTK_WIDGET (dialog), -1, 400); g_signal_connect (dialog, "response", G_CALLBACK (dialog_button_clicked_cb), NULL); load_subscriptions (dialog); return GTK_WIDGET (dialog); }