/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* importer.c * * Copyright (C) 2000 Helix Code, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * 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 * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Author: Iain Holmes */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "importer.h" #include "GNOME_Evolution_Importer.h" typedef struct _ImportDialogFilePage { GtkWidget *vbox; GtkWidget *filename; GtkWidget *filetype; GtkWidget *menu; gboolean need_filename; } ImportDialogFilePage; typedef struct _ImportData { GladeXML *wizard; GtkWidget *dialog; GtkWidget *druid; ImportDialogFilePage *filepage; GtkWidget *filedialog; GtkWidget *vbox; char *choosen_iid; } ImportData; /* Some HTML helper functions from mail/mail-config-gui.c */ static void html_size_req (GtkWidget *widget, GtkRequisition *requisition) { requisition->height = GTK_LAYOUT (widget)->height; } /* Returns a GtkHTML which is already inside a GtkScrolledWindow. If * @white is TRUE, the GtkScrolledWindow will be inside a GtkFrame. */ static GtkWidget * html_new (gboolean white) { GtkWidget *html, *scrolled, *frame; GtkStyle *style; html = gtk_html_new (); GTK_LAYOUT (html)->height = 0; gtk_signal_connect (GTK_OBJECT (html), "size_request", GTK_SIGNAL_FUNC (html_size_req), NULL); gtk_html_set_editable (GTK_HTML (html), FALSE); style = gtk_rc_get_style (html); if (style) { gtk_html_set_default_background_color (GTK_HTML (html), white ? &style->white: &style->bg[0]); } gtk_widget_set_sensitive (html, FALSE); scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_NEVER, GTK_POLICY_NEVER); gtk_container_add (GTK_CONTAINER (scrolled), html); if (white) { frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_add (GTK_CONTAINER (frame), scrolled); gtk_widget_show_all (frame); } else { gtk_widget_show_all (scrolled); } return html; } static void put_html (GtkHTML *html, const char *text) { GtkHTMLStream *handle; char *htmltext; htmltext = e_text_to_html (text, E_TEXT_TO_HTML_CONVERT_NL); handle = gtk_html_begin (html); gtk_html_write (html, handle, "", 12); gtk_html_write (html, handle, text, strlen (text)); gtk_html_write (html, handle, "", 14); g_free (htmltext); gtk_html_end (html, handle, GTK_HTML_STREAM_OK); } /* Importing functions */ /* Data to be passed around */ typedef struct _ImporterComponentData { EvolutionImporterClient *client; EvolutionImporterListener *listener; char *filename; GnomeDialog *dialog; GtkWidget *contents; int item; gboolean stop; gboolean destroyed; } ImporterComponentData; static gboolean importer_timeout_fn (gpointer data); static void import_cb (EvolutionImporterListener *listener, EvolutionImporterResult result, gboolean more_items, void *data) { ImporterComponentData *icd = (ImporterComponentData *) data; char *label; g_warning ("Recieved callback. Result: %d\tmore_items: %s", result, more_items ? "TRUE" : "FALSE"); if (icd->stop != TRUE) { if (result == EVOLUTION_IMPORTER_NOT_READY) { /* Importer isn't ready yet. Wait 5 seconds and try again. */ label = g_strdup_printf (_("Importing %s\nImporter not ready." "\nWaiting 5 seconds to retry."), icd->filename); gtk_label_set_text (GTK_LABEL (icd->contents), label); g_free (label); while (gtk_events_pending ()) gtk_main_iteration (); gtk_timeout_add (5000, importer_timeout_fn, data); return; } if (result == EVOLUTION_IMPORTER_BUSY) { gtk_timeout_add (5000, importer_timeout_fn, data); return; } if (more_items) { g_warning ("Processing...\n"); label = g_strdup_printf (_("Importing %s\nImporting item %d."), icd->filename, ++(icd->item)); gtk_label_set_text (GTK_LABEL (icd->contents), label); g_free (label); while (gtk_events_pending ()) gtk_main_iteration (); g_idle_add_full (G_PRIORITY_LOW, importer_timeout_fn, data, NULL); return; } } g_free (icd->filename); if (!icd->destroyed) gtk_object_destroy (GTK_OBJECT (icd->dialog)); bonobo_object_unref (BONOBO_OBJECT (icd->listener)); bonobo_object_unref (BONOBO_OBJECT (icd->client)); g_free (icd); } static gboolean importer_timeout_fn (gpointer data) { ImporterComponentData *icd = (ImporterComponentData *) data; char *label; g_warning ("Idle called"); label = g_strdup_printf (_("Importing %s\nImporting item %d."), icd->filename, icd->item); gtk_label_set_text (GTK_LABEL (icd->contents), label); g_free (label); while (gtk_events_pending ()) gtk_main_iteration (); evolution_importer_client_process_item (icd->client, icd->listener); return FALSE; } static void dialog_clicked_cb (GnomeDialog *dialog, int button_number, ImporterComponentData *icd) { if (button_number != 0) return; /* Interesting... */ icd->stop = TRUE; } static void dialog_destroy_cb (GtkObject *object, ImporterComponentData *icd) { icd->stop = TRUE; icd->destroyed = TRUE; } static char * get_iid_for_filetype (const char *filename) { OAF_ServerInfoList *info_list; CORBA_Environment ev; GList *can_handle = NULL; char *ret_iid; int i, len = 0; CORBA_exception_init (&ev); info_list = oaf_query ("repo_ids.has ('IDL:GNOME/Evolution/Importer:1.0')", NULL, &ev); for (i = 0; i < info_list->_length; i++) { CORBA_Environment ev2; CORBA_Object importer; const OAF_ServerInfo *info; info = info_list->_buffer + i; CORBA_exception_init (&ev2); importer = oaf_activate_from_id ((char *) info->iid, 0, NULL, &ev2); if (ev2._major != CORBA_NO_EXCEPTION) { g_warning ("Error activating %s", info->iid); CORBA_exception_free (&ev2); continue; } if (GNOME_Evolution_Importer_supportFormat (importer, filename, &ev2)) { can_handle = g_list_prepend (can_handle, g_strdup (info->iid)); len++; } bonobo_object_release_unref (importer, &ev2); CORBA_exception_free (&ev2); } if (len == 1) { ret_iid = can_handle->data; g_list_free (can_handle); return ret_iid; } else if (len > 1) { /* FIXME: Some way to choose between multiple iids */ /* FIXME: Free stuff */ g_warning ("Multiple iids can support"); ret_iid = can_handle->data; g_list_free (can_handle); return ret_iid; } else { return NULL; } } static void start_import (const char *filename, const char *iid) { ImporterComponentData *icd; char *label; char *real_iid; if (iid == NULL || strcmp (iid, "Automatic") == 0) { /* Work out the component to use */ real_iid = get_iid_for_filetype (filename); } else { real_iid = g_strdup (iid); } g_print ("Importing with: %s\n", real_iid); if (real_iid == NULL) return; icd = g_new (ImporterComponentData, 1); icd->stop = FALSE; icd->destroyed = FALSE; icd->dialog = GNOME_DIALOG (gnome_dialog_new (_("Importing"), GNOME_STOCK_BUTTON_CANCEL, NULL)); gtk_signal_connect (GTK_OBJECT (icd->dialog), "clicked", GTK_SIGNAL_FUNC (dialog_clicked_cb), icd); gtk_signal_connect (GTK_OBJECT (icd->dialog), "destroy", GTK_SIGNAL_FUNC (dialog_destroy_cb), icd); label = g_strdup_printf (_("Importing %s.\nStarting %s"), filename, real_iid); icd->contents = gtk_label_new (label); g_free (label); gtk_box_pack_start (GTK_BOX (icd->dialog->vbox), icd->contents, TRUE, TRUE, 0); gtk_widget_show_all (GTK_WIDGET (icd->dialog)); while (gtk_events_pending ()) gtk_main_iteration (); icd->client = evolution_importer_client_new_from_id (real_iid); g_free (real_iid); if (evolution_importer_client_load_file (icd->client, filename) == FALSE) { label = g_strdup_printf (_("Error loading %s"), filename); gtk_label_set_text (GTK_LABEL (icd->contents), label); g_free (label); while (gtk_events_pending ()) gtk_main_iteration (); bonobo_object_unref (BONOBO_OBJECT (icd->client)); gtk_object_unref (GTK_OBJECT (icd->dialog)); g_free (icd); } icd->filename = g_strdup (filename); icd->item = 1; label = g_strdup_printf (_("Importing %s\nImporting item 1."), filename); gtk_label_set_text (GTK_LABEL (icd->contents), label); g_free (label); while (gtk_events_pending ()) gtk_main_iteration (); icd->listener = evolution_importer_listener_new (import_cb, icd); evolution_importer_client_process_item (icd->client, icd->listener); } static void filename_changed (GtkEntry *entry, ImportData *data) { ImportDialogFilePage *page; char *filename; page = data->filepage; filename = gtk_entry_get_text (entry); if (filename != NULL && *filename != '\0') page->need_filename = FALSE; else page->need_filename = TRUE; gnome_druid_set_buttons_sensitive (GNOME_DRUID (data->druid), TRUE, !page->need_filename, TRUE); } static const char * get_name_from_component_info (const OAF_ServerInfo *info) { OAF_Property *property; const char *name; property = oaf_server_info_prop_find ((OAF_ServerInfo *) info, "evolution:menu-name"); if (property == NULL || property->v._d != OAF_P_STRING) return NULL; name = property->v._u.value_string; return name; } static void item_selected (GtkWidget *item, ImportData *data) { char *iid; g_free (data->choosen_iid); iid = gtk_object_get_data (GTK_OBJECT (item), "oafiid"); g_print ("iid: %s\n", iid); if (iid == NULL) data->choosen_iid = g_strdup ("Automatic"); else data->choosen_iid = g_strdup (iid); } static GtkWidget * create_plugin_menu (ImportData *data) { OAF_ServerInfoList *info_list; CORBA_Environment ev; int i; GtkWidget *menu; GtkWidget *item; menu = gtk_menu_new (); item = gtk_menu_item_new_with_label (_("Automatic")); gtk_object_set_data_full (GTK_OBJECT (item), "oafiid", g_strdup ("Automatic"), g_free); gtk_menu_append (GTK_MENU (menu), item); CORBA_exception_init (&ev); info_list = oaf_query ("repo_ids.has ('IDL:GNOME/Evolution/Importer:1.0')", NULL, &ev); for (i = 0; i < info_list->_length; i++) { const OAF_ServerInfo *info; char *name = NULL; info = info_list->_buffer + i; name = g_strdup (get_name_from_component_info (info)); if (name == NULL) { name = g_strdup (info->iid); } item = gtk_menu_item_new_with_label (name); g_free (name); gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (item_selected), data); gtk_object_set_data_full (GTK_OBJECT (item), "oafiid", g_strdup (info->iid), g_free); gtk_menu_append (GTK_MENU (menu), item); } return menu; } static ImportDialogFilePage * importer_file_page_new (ImportData *data) { ImportDialogFilePage *page; GtkWidget *table, *label; int row = 0; page = g_new0 (ImportDialogFilePage, 1); page->vbox = gtk_vbox_new (FALSE, 5); page->need_filename = TRUE; table = gtk_table_new (2, 2, FALSE); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_table_set_col_spacings (GTK_TABLE (table), 10); gtk_container_set_border_width (GTK_CONTAINER (table), 8); gtk_box_pack_start (GTK_BOX (page->vbox), table, TRUE, TRUE, 0); label = gtk_label_new (_("Filename:")); gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0); gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); page->filename = gnome_file_entry_new (NULL, _("Select a file")); gtk_signal_connect (GTK_OBJECT (gnome_file_entry_gtk_entry (GNOME_FILE_ENTRY (page->filename))), "changed", GTK_SIGNAL_FUNC (filename_changed), data); gtk_table_attach (GTK_TABLE (table), page->filename, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, 0, 0, 0); row++; label = gtk_label_new (_("File type:")); gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0); gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); page->filetype = gtk_option_menu_new (); page->menu = create_plugin_menu (data); gtk_option_menu_set_menu (GTK_OPTION_MENU (page->filetype), page->menu); gtk_table_attach (GTK_TABLE (table), page->filetype, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, 0, 0, 0); gtk_widget_show_all (table); return page; } static void import_druid_cancel (GnomeDruid *druid, ImportData *data) { gtk_widget_destroy (GTK_WIDGET (data->dialog)); } static void import_druid_destroy (GtkObject *object, ImportData *data) { gtk_object_unref (GTK_OBJECT (data->wizard)); g_free (data->choosen_iid); g_free (data); } static void import_druid_finish (GnomeDruidPage *page, GnomeDruid *druid, ImportData *data) { char *filename; char *iid; filename = g_strdup (gtk_entry_get_text (GTK_ENTRY (gnome_file_entry_gtk_entry (GNOME_FILE_ENTRY (data->filepage->filename))))); iid = g_strdup (data->choosen_iid); gtk_widget_destroy (data->dialog); start_import (filename, iid); g_free (filename); g_free (iid); } static gboolean prepare_file_page (GnomeDruidPage *page, GnomeDruid *druid, ImportData *data) { g_print ("Prepare thyself\n"); gnome_druid_set_buttons_sensitive (druid, TRUE, !data->filepage->need_filename, TRUE); return FALSE; } void show_import_wizard (void) { ImportData *data = g_new0 (ImportData, 1); GnomeDruidPageStart *start; GnomeDruidPageFinish *finish; GtkWidget *html; data->wizard = glade_xml_new (EVOLUTION_GLADEDIR "/import.glade", NULL); data->dialog = glade_xml_get_widget (data->wizard, "importwizard"); gtk_window_set_wmclass (GTK_WINDOW (data->dialog), "importdruid", "Evolution:shell"); data->druid = glade_xml_get_widget (data->wizard, "druid1"); gtk_signal_connect (GTK_OBJECT (data->druid), "cancel", GTK_SIGNAL_FUNC (import_druid_cancel), data); start = GNOME_DRUID_PAGE_START (glade_xml_get_widget (data->wizard, "page1")); data->filedialog = glade_xml_get_widget (data->wizard, "page2"); gtk_signal_connect (GTK_OBJECT (data->filedialog), "prepare", GTK_SIGNAL_FUNC (prepare_file_page), data); finish = GNOME_DRUID_PAGE_FINISH (glade_xml_get_widget (data->wizard, "page3")); data->filepage = importer_file_page_new (data); data->vbox = data->filepage->vbox; html = html_new (TRUE); put_html (GTK_HTML (html), _("Choose the file that you want to import into Evolution," "and select what type of file it is from the list.\n\n" "You can select \"Automatic\" if you do not know, and" "Evolution will attempt to work it out.")); gtk_box_pack_start (GTK_BOX (data->vbox), html->parent->parent, FALSE, TRUE, 0); gtk_box_reorder_child (GTK_BOX (data->vbox), html->parent->parent, 0); gtk_box_pack_start (GTK_BOX (GNOME_DRUID_PAGE_STANDARD (data->filedialog)->vbox), data->vbox, TRUE, TRUE, 0); /* Finish page */ gtk_signal_connect (GTK_OBJECT (finish), "finish", GTK_SIGNAL_FUNC (import_druid_finish), data); gtk_signal_connect (GTK_OBJECT (data->dialog), "destroy", GTK_SIGNAL_FUNC (import_druid_destroy), data); gtk_widget_show_all (data->dialog); }