diff options
Diffstat (limited to 'capplets/file-types/file-types-capplet-dialogs.c')
-rw-r--r-- | capplets/file-types/file-types-capplet-dialogs.c | 690 |
1 files changed, 381 insertions, 309 deletions
diff --git a/capplets/file-types/file-types-capplet-dialogs.c b/capplets/file-types/file-types-capplet-dialogs.c index 8af403ea7..c554c72b1 100644 --- a/capplets/file-types/file-types-capplet-dialogs.c +++ b/capplets/file-types/file-types-capplet-dialogs.c @@ -35,7 +35,9 @@ #include <libgnomevfs/gnome-vfs-mime-handlers.h> #include <libgnomevfs/gnome-vfs-application-registry.h> #include <libgnomevfs/gnome-vfs-mime-info.h> +#include <libgnomevfs/gnome-vfs-utils.h> +#include "libuuid/uuid.h" #include "nautilus-mime-type-capplet.h" #include "nautilus-mime-type-capplet-dialogs.h" @@ -67,7 +69,8 @@ static edit_dialog_details *edit_component_details = NULL; static void show_new_application_window (GtkWidget *button, GtkWidget *list); static void show_edit_application_window (GtkWidget *button, GtkWidget *list); static void delete_selected_application (GtkWidget *button, GtkWidget *list); -static void add_item_to_application_list (GtkWidget *list, const char *name, const char *mime_type, int position); +static void add_item_to_application_list (GtkWidget *list, const char *id, const char *name, const char *mime_type, + gboolean user_owned, int position); static void find_message_label_callback (GtkWidget *widget, gpointer callback_data); static void find_message_label (GtkWidget *widget, const char *message); @@ -139,12 +142,73 @@ application_button_toggled_callback (GtkToggleButton *button, gpointer user_data } static void +insert_item (GtkList *list_widget, GtkListItem *item, int position) +{ + GList *singleton_list; + + g_assert (GTK_IS_LIST (list_widget)); + g_assert (GTK_IS_LIST_ITEM (item)); + + /* Due to GTK inheritance stupidity, the "Add" signal, which we + * rely on for widget sensitivity updates, is not sent if you + * use the GtkList API to add items. So when we add new items, + * which always go at the end, we must use the GtkContainer API. + */ + if (position < 0) { + gtk_container_add (GTK_CONTAINER (list_widget), GTK_WIDGET (item)); + } else { + singleton_list = g_list_prepend (NULL, item); + gtk_list_insert_items (list_widget, singleton_list, position); + /* This looks like a leak of a singleton_list, but believe it or not + * gtk_list takes ownership of the list of items. + */ + } +} + +static GtkListItem * +create_application_list_item (const char *id, const char *name, const char *mime_type, + gboolean user_owned, GList *short_list) +{ + GtkWidget *list_item; + GtkWidget *hbox, *check_button, *label; + + list_item = gtk_list_item_new (); + + hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); + gtk_container_add (GTK_CONTAINER (list_item), hbox); + + check_button = gtk_check_button_new (); + gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); + + label = gtk_label_new (name); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + gtk_widget_show_all (list_item); + + /* Save ID and mime type*/ + gtk_object_set_data_full (GTK_OBJECT (check_button), "application_id", g_strdup (id), g_free); + gtk_object_set_data_full (GTK_OBJECT (check_button), "mime_type", g_strdup (mime_type), g_free); + gtk_object_set_data_full (GTK_OBJECT (list_item), "application_id", g_strdup (id), g_free); + gtk_object_set_data_full (GTK_OBJECT (list_item), "mime_type", g_strdup (mime_type), g_free); + gtk_object_set_data (GTK_OBJECT (list_item), "user_owned", GINT_TO_POINTER(user_owned)); + + /* Check and see if component is in preferred list */ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), + application_is_in_list (id, short_list)); + + /* Connect to toggled signal */ + gtk_signal_connect (GTK_OBJECT (check_button), "toggled", + GTK_SIGNAL_FUNC (application_button_toggled_callback), NULL); + + return GTK_LIST_ITEM (list_item); +} + +static void populate_default_applications_list (GtkWidget *list, const char *mime_type) { GList *short_list, *app_list, *list_element; GnomeVFSMimeApplication *application; - GtkWidget *button, *list_item; - GtkWidget *hbox, *label; + GtkListItem *list_item; /* Get the application short list */ short_list = gnome_vfs_mime_get_short_list_applications (mime_type); @@ -156,43 +220,20 @@ populate_default_applications_list (GtkWidget *list, const char *mime_type) application = list_element->data; /* Create list item */ - list_item = gtk_list_item_new (); - - /* Create check button */ - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_container_add (GTK_CONTAINER (list_item), hbox); - - button = gtk_check_button_new (); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); - - label = gtk_label_new (application->name); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - /* Add list item to list */ - gtk_container_add (GTK_CONTAINER (list), list_item); + list_item = create_application_list_item (application->id, application->name, + mime_type, + gnome_vfs_application_is_user_owned_application (application), + short_list); - /* Save ID and mime type*/ - gtk_object_set_data_full (GTK_OBJECT (button), "application_id", g_strdup (application->id), g_free); - gtk_object_set_data_full (GTK_OBJECT (button), "mime_type", g_strdup (mime_type), g_free); - gtk_object_set_data_full (GTK_OBJECT (list_item), "application_id", g_strdup (application->id), g_free); - gtk_object_set_data_full (GTK_OBJECT (list_item), "mime_type", g_strdup (mime_type), g_free); + insert_item (GTK_LIST (list), list_item, -1); - /* Check and see if component is in preferred list */ - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), - application_is_in_list (application->id, short_list)); - - /* Connect to toggled signal */ - gtk_signal_connect (GTK_OBJECT (button), "toggled", - GTK_SIGNAL_FUNC (application_button_toggled_callback), NULL); - } + } gnome_vfs_mime_application_list_free (app_list); } - if (short_list != NULL) { - gnome_vfs_mime_application_list_free (short_list); - } + gnome_vfs_mime_application_list_free (short_list); } @@ -314,11 +355,17 @@ check_button_status (GtkList *list, GtkWidget *widget, ButtonHolder *button_hold gtk_widget_set_sensitive (button_holder->delete_button, FALSE); gtk_widget_set_sensitive (button_holder->edit_button, FALSE); } else { - gtk_widget_set_sensitive (button_holder->delete_button, TRUE); gtk_widget_set_sensitive (button_holder->edit_button, TRUE); } } +static void +update_delete_button (GtkList *list, GtkWidget *widget, ButtonHolder *button_holder) +{ + gtk_widget_set_sensitive (button_holder->delete_button, + GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "user_owned"))); +} + /* * initialize_edit_applications_dialog @@ -342,6 +389,8 @@ initialize_edit_applications_dialog (const char *mime_type) NULL, NULL); + /* FIXME: dialog should be parented on Control Center window */ + gtk_container_set_border_width (GTK_CONTAINER (edit_application_details->window), GNOME_PAD); gtk_window_set_policy (GTK_WINDOW (edit_application_details->window), FALSE, TRUE, FALSE); gtk_window_set_default_size (GTK_WINDOW (edit_application_details->window), @@ -357,7 +406,7 @@ initialize_edit_applications_dialog (const char *mime_type) main_vbox = GNOME_DIALOG (edit_application_details->window)->vbox; /* Add label */ - label_text = g_strdup_printf (_("Select applications to appear in menu for mime type \"%s\""), mime_type); + label_text = g_strdup_printf (_("Select applications to appear in menu for MIME type \"%s\""), mime_type); label = gtk_label_new (label_text); g_free (label_text); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); @@ -403,11 +452,12 @@ initialize_edit_applications_dialog (const char *mime_type) /* Watch container so we can update buttons */ gtk_signal_connect (GTK_OBJECT (list), "add", check_button_status, button_holder); gtk_signal_connect_full (GTK_OBJECT (list), "remove", check_button_status, NULL, button_holder, - g_free, FALSE, FALSE); + g_free, FALSE, FALSE); + gtk_signal_connect (GTK_OBJECT (list), "select_child", update_delete_button, button_holder); - populate_default_applications_list (list, mime_type); - gtk_widget_show_all (main_vbox); + + populate_default_applications_list (list, mime_type); } @@ -447,7 +497,7 @@ initialize_edit_components_dialog (const char *mime_type) main_vbox = GNOME_DIALOG (edit_component_details->window)->vbox; /* Add label */ - label_text = g_strdup_printf (_("Select views to appear in menu for mime type \"%s\""), mime_type); + label_text = g_strdup_printf (_("Select views to appear in menu for MIME type \"%s\""), mime_type); label = gtk_label_new (label_text); g_free (label_text); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); @@ -482,19 +532,13 @@ show_edit_applications_dialog (const char *mime_type) if (edit_application_details == NULL) { initialize_edit_applications_dialog (mime_type); } - - switch(gnome_dialog_run (GNOME_DIALOG (edit_application_details->window))) { - case 0: - nautilus_mime_type_capplet_update_application_info (mime_type); - /* Delete the dialog so the lists are repopulated on next lauch */ - gtk_widget_destroy (edit_application_details->window); - break; - - case 1: - /* Delete the dialog so the lists are repopulated on next lauch */ - gtk_widget_destroy (edit_application_details->window); - break; - } + + /* FIXME: This is a modal dialog with no Cancel button, so the close box + * has to do the same thing as the OK button, which is pretty darn confusing. + * It would be better to make it modeless someday. + */ + gnome_dialog_run_and_close (GNOME_DIALOG (edit_application_details->window)); + nautilus_mime_type_capplet_update_application_info (mime_type); } @@ -511,18 +555,13 @@ show_edit_components_dialog (const char *mime_type) initialize_edit_components_dialog (mime_type); } - switch(gnome_dialog_run (GNOME_DIALOG (edit_component_details->window))) { - case 0: - nautilus_mime_type_capplet_update_viewer_info (mime_type); - /* Delete the dialog so the lists are repopulated on next lauch */ - gtk_widget_destroy (edit_component_details->window); - break; - - case 1: - /* Delete the dialog so the lists are repopulated on next lauch */ - gtk_widget_destroy (edit_component_details->window); - break; - } + /* FIXME: This is a modal dialog with no Cancel button, so the close box + * has to do the same thing as the OK button, which is pretty darn confusing. + * It would be better to make it modeless someday. + */ + gnome_dialog_run_and_close (GNOME_DIALOG (edit_component_details->window)); + + nautilus_mime_type_capplet_update_viewer_info (mime_type); } @@ -688,6 +727,30 @@ display_upper_case_dialog (void) gnome_dialog_run_and_close (dialog); } +/* Do some basic validation of the text entry and enable the OK button if the text is + * determined to be a valid string. + */ +static void +validate_text_and_update_button (GtkEntry *entry, gpointer data) +{ + char *text, *token; + gboolean sensitize; + + sensitize = TRUE; + + text = gtk_entry_get_text (entry); + if (text == NULL) { + sensitize = FALSE; + } else { + token = strtok (text, " "); + if (token == NULL || strlen (token) <= 0) { + /* Entered text is invalid as best as we can detect. */ + sensitize = FALSE; + } + } + + gtk_widget_set_sensitive (GTK_WIDGET (data), sensitize); +} char * nautilus_mime_type_capplet_show_new_mime_window (void) @@ -696,8 +759,6 @@ nautilus_mime_type_capplet_show_new_mime_window (void) GtkWidget *mime_entry; GtkWidget *label; GtkWidget *desc_entry; - GtkWidget *hbox; - GtkWidget *vbox; const char *description; char *mime_type, *tmp_str, c; gboolean upper_case_alert; @@ -705,70 +766,62 @@ nautilus_mime_type_capplet_show_new_mime_window (void) mime_type = NULL; upper_case_alert = FALSE; - dialog = gnome_dialog_new (_("Add Mime Type"), GNOME_STOCK_BUTTON_OK, + dialog = gnome_dialog_new (_("Add MIME Type"), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_set_default (GNOME_DIALOG (dialog), 1); - label = gtk_label_new (_("Add a new Mime Type\n" - "For example: image/tiff; text/x-scheme")); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0); - label = gtk_label_new (_("Mime Type:")); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + label = gtk_label_new (_("New MIME type (e.g. image/x-thumper):")); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), label, TRUE, TRUE, 0); + mime_entry = gtk_entry_new (); - gtk_box_pack_start (GTK_BOX (hbox), mime_entry, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), mime_entry, TRUE, TRUE, 0); - - vbox = gtk_vbox_new (FALSE, GNOME_PAD_SMALL); - gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), vbox, FALSE, FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (vbox), GNOME_PAD_SMALL); - label = gtk_label_new (_("Type in a description for this mime-type.")); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("Description:")), FALSE, FALSE, 0); + label = gtk_label_new (_("Description (e.g. Thumper image):")); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), label, TRUE, TRUE, 0); + desc_entry = gtk_entry_new (); - gtk_box_pack_start (GTK_BOX (hbox), desc_entry, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), desc_entry, TRUE, TRUE, 0); + /* Set up text entry validation signal */ + gtk_signal_connect (GTK_OBJECT (mime_entry), "changed", + GTK_SIGNAL_FUNC (validate_text_and_update_button), GNOME_DIALOG (dialog)->buttons->data); - gnome_dialog_set_close (GNOME_DIALOG (dialog), FALSE); + /* Set initial OK button state to desensitized */ + gtk_widget_set_sensitive (GTK_WIDGET (GNOME_DIALOG (dialog)->buttons->data), FALSE); + + /* Set focus to text entry widget */ + gtk_widget_grab_focus (mime_entry); gtk_widget_show_all (GNOME_DIALOG (dialog)->vbox); - switch (gnome_dialog_run (GNOME_DIALOG (dialog))) { - case 0: - mime_type = g_strdup (gtk_entry_get_text (GTK_ENTRY (mime_entry))); - g_assert (mime_type != NULL); - - /* Handle illegal mime types as best we can */ - for (tmp_str = mime_type; (c = *tmp_str) != '\0'; tmp_str++) { - if (isascii (c) && isupper (c)) { - *tmp_str = tolower (c); - upper_case_alert = TRUE; - } - } - - description = gtk_entry_get_text (GTK_ENTRY (desc_entry)); - - /* Add new mime type here */ - if (strlen (mime_type) > 3) { - gnome_vfs_mime_set_value (mime_type, - "description", - description); + if (gnome_dialog_run (GNOME_DIALOG (dialog)) == GNOME_OK) { + mime_type = g_strdup (gtk_entry_get_text (GTK_ENTRY (mime_entry))); + g_assert (mime_type != NULL); + + /* Handle illegal mime types as best we can */ + for (tmp_str = mime_type; (c = *tmp_str) != '\0'; tmp_str++) { + if (isascii ((guchar) c) && isupper ((guchar) c)) { + *tmp_str = tolower (c); + upper_case_alert = TRUE; } - /* Fall through to close dialog */ - break; - - case 1: - default: - break; + } + + description = gtk_entry_get_text (GTK_ENTRY (desc_entry)); + + /* Add new mime type here */ + if (strlen (mime_type) > 3) { + /* This call creates the key */ + gnome_vfs_mime_set_registered_type_key (mime_type, + "description", + description); + + /* Ths call sets the user information */ + gnome_vfs_mime_set_value (mime_type, + "description", + description); + } } gnome_dialog_close (GNOME_DIALOG (dialog)); @@ -793,6 +846,13 @@ add_extension_clicked (GtkWidget *widget, gpointer data) extension_list = GTK_LIST (data); new_extension = nautilus_mime_type_capplet_show_new_extension_window (); + + /* Filter out bogus extensions */ + if (new_extension == NULL || strlen (new_extension) <= 0 || new_extension[0] == ' ') { + g_free (new_extension); + return; + } + new_list_item = gtk_list_item_new_with_label (new_extension); gtk_widget_show (new_list_item); @@ -874,14 +934,16 @@ get_extensions_from_gtk_list (GtkList *list) } char * -nautilus_mime_type_capplet_show_change_extension_window (const char *mime_type) +nautilus_mime_type_capplet_show_change_extension_window (const char *mime_type, gboolean *new_list) { GtkWidget *dialog; GtkWidget *hbox; GtkWidget *button; GtkWidget *list; - char *extensions_list; + char *extensions_list_str; + *new_list = FALSE; + dialog = gnome_dialog_new (_("File Extensions "), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, @@ -933,7 +995,6 @@ nautilus_mime_type_capplet_show_change_extension_window (const char *mime_type) extensions_list = gnome_vfs_mime_get_extensions_list (mime_type); - if (extensions_list != NULL) { widget_list = NULL; for (temp = extensions_list; temp != NULL; temp = temp->next) { @@ -950,22 +1011,21 @@ nautilus_mime_type_capplet_show_change_extension_window (const char *mime_type) gtk_widget_show_all (GNOME_DIALOG (dialog)->vbox); - switch (gnome_dialog_run (GNOME_DIALOG (dialog))) { - case 0: - extensions_list = get_extensions_from_gtk_list (GTK_LIST (list)); - if (extensions_list == NULL) { - extensions_list = g_strdup (""); - } - break; - case 1: - default: - extensions_list = g_strdup (""); - break; - } + extensions_list_str = NULL; + if (gnome_dialog_run (GNOME_DIALOG (dialog)) == GNOME_OK) { + *new_list = TRUE; + extensions_list_str = get_extensions_from_gtk_list (GTK_LIST (list)); + if (extensions_list_str == NULL) { + extensions_list_str = g_strdup (""); + } + } + if (extensions_list_str == NULL) { + extensions_list_str = g_strdup (""); + } gnome_dialog_close (GNOME_DIALOG (dialog)); - return extensions_list; + return extensions_list_str; } @@ -982,7 +1042,9 @@ nautilus_mime_type_capplet_show_new_extension_window (void) GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_set_default (GNOME_DIALOG (dialog), 0); gnome_dialog_set_close (GNOME_DIALOG (dialog), FALSE); - label = gtk_label_new (_("Type in the extensions for this mime-type.\nFor example: .html, .htm")); + label = gtk_label_new (_("Type in the extensions for this mime-type (without dot).\n" + "You can enter several extensions seperated by a space,\n" + "for example: html htm")); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); @@ -998,17 +1060,13 @@ nautilus_mime_type_capplet_show_new_extension_window (void) gtk_widget_show_all (GNOME_DIALOG (dialog)->vbox); /* Set focus to text entry widget */ - gtk_window_set_focus (GTK_WINDOW (dialog), mime_entry); + gtk_widget_grab_focus (mime_entry); - new_extension = g_strdup (""); - switch (gnome_dialog_run (GNOME_DIALOG (dialog))) { - case 0: - new_extension = g_strdup (gtk_entry_get_text (GTK_ENTRY (mime_entry))); - case 1: - break; - default: - break; - } + if (gnome_dialog_run (GNOME_DIALOG (dialog)) == GNOME_OK) { + new_extension = g_strdup (gtk_entry_get_text (GTK_ENTRY (mime_entry))); + } else { + new_extension = g_strdup (""); + } gnome_dialog_close (GNOME_DIALOG (dialog)); @@ -1020,17 +1078,19 @@ nautilus_mime_type_capplet_show_new_extension_window (void) * Create or update a GnomeVFSMimeApplication and register * it with the mime database. */ -static void +static char * add_or_update_application (GtkWidget *list, const char *name, const char *command, gboolean multiple, gboolean expects_uris, gboolean update) { GnomeVFSMimeApplication app, *original; const char *mime_type; - + uuid_t app_uuid; + char app_uuid_string[100]; + /* Check for empty strings. Command can be empty. */ if (name[0] == '\0') { - return; + return NULL; } mime_type = nautilus_mime_type_capplet_get_selected_item_mime_type (); @@ -1039,7 +1099,11 @@ add_or_update_application (GtkWidget *list, const char *name, const char *comman /* It's ok to cast, we don't modify the application * structure and thus the name/command, this should really * use the application registry explicitly */ - app.id = (char *)name; + + /* Generate unique application id */ + uuid_generate(app_uuid); + uuid_unparse(app_uuid, app_uuid_string); + app.id = app_uuid_string; app.name = (char *)name; app.command = (char *)command; app.can_open_multiple_files = multiple; @@ -1049,7 +1113,7 @@ add_or_update_application (GtkWidget *list, const char *name, const char *comman app.requires_terminal = FALSE; if (update) { - original = gnome_vfs_mime_application_new_from_id (name); + original = gnome_vfs_mime_application_new_from_id (app.id); if (original == NULL) { const char *original_id; GList *selection; @@ -1059,20 +1123,20 @@ add_or_update_application (GtkWidget *list, const char *name, const char *comman /* If there isn't a selection we cannot allow an edit */ selection = GTK_LIST (list)->selection; if (selection == NULL || g_list_length (selection) <= 0) { - return; + return NULL; } /* Get application id and info */ item = GTK_LIST_ITEM (selection->data); if (item == NULL) { - return; + return NULL; } original_id = gtk_object_get_data (GTK_OBJECT (item), "application_id"); if (original_id == NULL) { - return; + return NULL; } - + /* Remove original application data */ gnome_vfs_application_registry_remove_mime_type (original_id, mime_type); gnome_vfs_application_registry_sync (); @@ -1083,77 +1147,122 @@ add_or_update_application (GtkWidget *list, const char *name, const char *comman gtk_container_remove (GTK_CONTAINER (list), GTK_WIDGET (item)); /* Add new widget and restore position */ - add_item_to_application_list (list, name, mime_type, position); + add_item_to_application_list (list, original_id, name, mime_type, + gnome_vfs_application_is_user_owned_application (original), + position); } } gnome_vfs_application_registry_save_mime_application (&app); - gnome_vfs_application_registry_add_mime_type (name, mime_type); + gnome_vfs_application_registry_add_mime_type (app.id, mime_type); gnome_vfs_application_registry_sync (); gnome_vfs_mime_add_application_to_short_list (mime_type, app.id); + + return g_strdup (app.id); } static void -add_item_to_application_list (GtkWidget *list, const char *name, const char *mime_type, int position) +add_item_to_application_list (GtkWidget *list, const char *id, const char *name, const char *mime_type, + gboolean user_owned, int position) { - GtkWidget *check_button, *list_item, *hbox, *label; - - /* Create list item */ - list_item = gtk_list_item_new (); - - /* Create check button */ - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_container_add (GTK_CONTAINER (list_item), hbox); - - check_button = gtk_check_button_new (); - gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); + GtkListItem *list_item; + GList *short_list; - label = gtk_label_new (name); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - /* Add list item to list */ - if (position == -1) { - gtk_container_add (GTK_CONTAINER (list), list_item); - } else { - GList *items; - items = g_list_alloc (); - items->data = list_item; - gtk_list_insert_items (GTK_LIST (list), items, position); - gtk_list_select_child (GTK_LIST (list), list_item); + short_list = gnome_vfs_mime_get_short_list_applications (mime_type); + list_item = create_application_list_item (id, name, mime_type, user_owned, short_list); + gnome_vfs_mime_application_list_free (short_list); + + insert_item (GTK_LIST (list), list_item, position); + gtk_list_select_child (GTK_LIST (list), GTK_WIDGET (list_item)); +} + +static gboolean +handle_invalid_application_input (GtkWindow *parent_window, const char *name, const char *command) +{ + char *message; + char *stripped_name; + GnomeDialog *error_dialog; + gboolean error_in_name; + + message = NULL; + error_in_name = FALSE; + + stripped_name = g_strstrip (g_strdup (name)); + + if (strlen (stripped_name) == 0) { + message = g_strdup (_("You must enter a name.")); + error_in_name = TRUE; + } else if (strlen (command) == 0) { + message = g_strdup (_("You must enter a command.")); + } else if (!gnome_vfs_is_executable_command_string (command)) { + if (command[0] == '/') { + /* FIXME: Should strip parameters off before using in this message. */ + /* FIXME: Should use separate messages for doesn't exist/isn't executable. */ + /* Both of these FIXMEs would need to handle quoting to work correctly, + * since otherwise a space might be part of path or separator before parameters. + */ + /* FIXME: Should use some line-wrapping technology a la nautilus-stock-dialogs.c */ + message = g_strdup_printf + (_("\"%s\" does not exist or is not executable.\n" + "Check your spelling and make sure you have\n" + "the right permissions to execute this file."), command); + } else { + /* FIXME: Should strip parameters off before using in this message */ + message = g_strdup_printf + (_("The command \"%s\" cannot be found.\n" + "You must use a command that can work from any command line."), command); + } } - - gtk_widget_show_all (list); - - /* Save ID and mime type*/ - gtk_object_set_data_full (GTK_OBJECT (check_button), "application_id", g_strdup (name), g_free); - gtk_object_set_data_full (GTK_OBJECT (check_button), "mime_type", g_strdup (mime_type), g_free); - gtk_object_set_data_full (GTK_OBJECT (list_item), "application_id", g_strdup (name), g_free); - gtk_object_set_data_full (GTK_OBJECT (list_item), "mime_type", g_strdup (mime_type), g_free); - /* Check and see if component is in preferred list */ - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), TRUE); + g_free (stripped_name); + + if (message != NULL) { + error_dialog = GNOME_DIALOG (gnome_error_dialog_parented (message, + parent_window)); + gtk_window_set_title (GTK_WINDOW (error_dialog), + error_in_name + ? _("Bad Application Name") + : _("Bad Application Command")); + + gnome_dialog_run (error_dialog); + g_free (message); + + return TRUE; + } - /* Connect to toggled signal */ - gtk_signal_connect (GTK_OBJECT (check_button), "toggled", - GTK_SIGNAL_FUNC (application_button_toggled_callback), NULL); + return FALSE; } + static void -show_new_application_window (GtkWidget *button, GtkWidget *list) +run_edit_or_new_application_dialog (const char *mime_type, GtkWidget *list, GnomeVFSMimeApplication *application) { - GtkWidget *app_entry, *command_entry; GtkWidget *dialog; + GtkWidget *app_entry, *command_entry; GtkWidget *label; GtkWidget *behavior_frame, *frame_vbox; GtkWidget *multiple_check_box, *uri_check_box; GtkWidget *table; - char *name, *command, *mime_type; - gboolean multiple, uri; - - dialog = gnome_dialog_new (_("New Application"), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); - + gboolean initial_toggle_state; + const char *name; + const char *command; + int dialog_result; + gboolean entry_validated; + char *invalid_entry_message, *app_id; + + g_assert (mime_type != NULL || application != NULL); + g_assert (GTK_IS_WIDGET (list)); + + dialog = gnome_dialog_new ( + application == NULL + ? _("Add Application") + : _("Edit Application"), + GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); + + /* FIXME: Dialog should be parented on Edit Applications dialog */ + /* Create table */ - table = gtk_table_new (3, 2, FALSE); + table = gtk_table_new (4, 2, FALSE); gtk_container_add (GTK_CONTAINER (GNOME_DIALOG (dialog)->vbox), table); gtk_table_set_row_spacings (GTK_TABLE (table), GNOME_PAD_SMALL); gtk_table_set_col_spacings (GTK_TABLE (table), GNOME_PAD_SMALL); @@ -1161,21 +1270,26 @@ show_new_application_window (GtkWidget *button, GtkWidget *list) /* Application Name label and entry */ label = gtk_label_new (_("Application Name:")); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_table_attach_defaults ( GTK_TABLE (table), label, 0, 1, 0, 1); + gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1); app_entry = gtk_entry_new (); gtk_table_attach_defaults ( GTK_TABLE (table), app_entry, 1, 2, 0, 1); + if (application != NULL) { + gtk_entry_set_text (GTK_ENTRY (app_entry), application->name); + } /* Application Command label and entry */ label = gtk_label_new (_("Application Command:")); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_table_attach_defaults ( GTK_TABLE (table), label, 0, 1, 1, 2); + gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2); command_entry = gtk_entry_new (); - gtk_table_attach_defaults ( GTK_TABLE (table), command_entry, 1, 2, 1, 2); - + gtk_table_attach_defaults (GTK_TABLE (table), command_entry, 1, 2, 1, 2); + if (application != NULL) { + gtk_entry_set_text (GTK_ENTRY (command_entry), application->command); + } + /* Open Behavior frame */ - /* FIXME bugzilla.eazel.com 6066: Need to add expected uri schemes */ behavior_frame = gtk_frame_new (_("Open Behavior")); gtk_table_attach_defaults ( GTK_TABLE (table), behavior_frame, 0, 2, 2, 3); @@ -1184,52 +1298,70 @@ show_new_application_window (GtkWidget *button, GtkWidget *list) multiple_check_box = gtk_check_button_new_with_label (_("Can open multiple files")); gtk_box_pack_start (GTK_BOX (frame_vbox), multiple_check_box, FALSE, FALSE, 0); + initial_toggle_state = application == NULL + ? FALSE + : application->can_open_multiple_files; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (multiple_check_box), initial_toggle_state); - uri_check_box = gtk_check_button_new_with_label (_("Expects URIs as arguments")); + /* FIXME bugzilla.eazel.com 6066: This needs to be three options now: "yes", "no", and "use uris for non-file locations" */ + uri_check_box = gtk_check_button_new_with_label (_("Can open from URI")); gtk_box_pack_start (GTK_BOX (frame_vbox), uri_check_box, FALSE, FALSE, 0); - - + initial_toggle_state = application == NULL + ? FALSE + : application->expects_uris; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uri_check_box), initial_toggle_state); + + gtk_widget_show_all (GNOME_DIALOG (dialog)->vbox); /* Set focus to text entry widget */ - gtk_window_set_focus (GTK_WINDOW (dialog), app_entry); + gtk_widget_grab_focus (app_entry); + + do { + dialog_result = gnome_dialog_run (GNOME_DIALOG (dialog)); + entry_validated = FALSE; - switch (gnome_dialog_run (GNOME_DIALOG (dialog))) { - case 0: + if (dialog_result == GNOME_OK) { name = gtk_entry_get_text (GTK_ENTRY (app_entry)); command = gtk_entry_get_text (GTK_ENTRY (command_entry)); - multiple = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (multiple_check_box)); - uri = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uri_check_box)); - - if (strlen (name) > 0 && strlen (command) > 0) { - mime_type = gtk_object_get_data (GTK_OBJECT (button), "mime_type"); - add_or_update_application (list, - gtk_entry_get_text (GTK_ENTRY (app_entry)), - gtk_entry_get_text (GTK_ENTRY (command_entry)), - - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (multiple_check_box)), - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uri_check_box)), - FALSE); - add_item_to_application_list (list, name, mime_type, -1); + + invalid_entry_message = NULL; + + if (!handle_invalid_application_input (GTK_WINDOW (dialog), name, command)) { + entry_validated = TRUE; + app_id = add_or_update_application (list, + name, + command, + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (multiple_check_box)), + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uri_check_box)), + application != NULL); + if (application == NULL && app_id != NULL) { + add_item_to_application_list (list, app_id, name, mime_type, TRUE, -1); + } + g_free (app_id); } - case 1: - gtk_widget_destroy (dialog); - break; - - default: - break; - } + } + } while (dialog_result == GNOME_OK && !entry_validated); + + /* FIXME: Close box is treated like Cancel, which loses user changes silently. + * Would be better to either do nothing at all (force use of OK or Cancel) or + * even put up a little dialog telling them they have to use OK or Cancel. + * Too bad we can't prevent the close box from appearing. Window Managers suck. + */ + if (dialog_result >= 0) { + gnome_dialog_close (GNOME_DIALOG (dialog)); + } } static void +show_new_application_window (GtkWidget *button, GtkWidget *list) +{ + run_edit_or_new_application_dialog (gtk_object_get_data (GTK_OBJECT (button), "mime_type"), list, NULL); +} + +static void show_edit_application_window (GtkWidget *button, GtkWidget *list) { - GtkWidget *app_entry, *command_entry; - GtkWidget *dialog; - GtkWidget *label; - GtkWidget *behavior_frame, *frame_vbox; - GtkWidget *multiple_check_box, *uri_check_box; - GtkWidget *table; GList *selection; const char *id; GnomeVFSMimeApplication *application; @@ -1257,78 +1389,16 @@ show_edit_application_window (GtkWidget *button, GtkWidget *list) return; } - dialog = gnome_dialog_new (_("Edit Application"), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); - - /* Create table */ - table = gtk_table_new (4, 2, FALSE); - gtk_container_add (GTK_CONTAINER (GNOME_DIALOG (dialog)->vbox), table); - gtk_table_set_row_spacings (GTK_TABLE (table), GNOME_PAD_SMALL); - gtk_table_set_col_spacings (GTK_TABLE (table), GNOME_PAD_SMALL); - - /* Application Name label and entry */ - label = gtk_label_new (_("Application Name:")); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1); - - app_entry = gtk_entry_new (); - gtk_table_attach_defaults ( GTK_TABLE (table), app_entry, 1, 2, 0, 1); - gtk_entry_set_text (GTK_ENTRY (app_entry), application->name); + run_edit_or_new_application_dialog (NULL, list, application); - /* Application Command label and entry */ - label = gtk_label_new (_("Application Command:")); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2); - - command_entry = gtk_entry_new (); - gtk_entry_set_text (GTK_ENTRY (command_entry), application->command); - gtk_table_attach_defaults (GTK_TABLE (table), command_entry, 1, 2, 1, 2); - - /* Open Behavior frame */ - behavior_frame = gtk_frame_new (_("Open Behavior")); - gtk_table_attach_defaults ( GTK_TABLE (table), behavior_frame, 0, 2, 2, 3); - - frame_vbox = gtk_vbox_new (FALSE, GNOME_PAD_SMALL); - gtk_container_add (GTK_CONTAINER (behavior_frame), frame_vbox); - - multiple_check_box = gtk_check_button_new_with_label (_("Can open multiple files")); - gtk_box_pack_start (GTK_BOX (frame_vbox), multiple_check_box, FALSE, FALSE, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (multiple_check_box), application->can_open_multiple_files); - - /* FIXME bugzilla.eazel.com 6066: This needs to be three options now: "yes", "no", and "use uris for non-file locations" */ - uri_check_box = gtk_check_button_new_with_label (_("Can open from URI")); - gtk_box_pack_start (GTK_BOX (frame_vbox), uri_check_box, FALSE, FALSE, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uri_check_box), application->expects_uris); - - - gtk_widget_show_all (GNOME_DIALOG (dialog)->vbox); - - /* Set focus to text entry widget */ - gtk_window_set_focus (GTK_WINDOW (dialog), app_entry); - - switch (gnome_dialog_run (GNOME_DIALOG (dialog))) { - case 0: - add_or_update_application (list, - gtk_entry_get_text (GTK_ENTRY (app_entry)), - gtk_entry_get_text (GTK_ENTRY (command_entry)), - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (multiple_check_box)), - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uri_check_box)), - TRUE); - - case 1: - gnome_vfs_mime_application_free (application); - gtk_widget_destroy (dialog); - break; - - default: - break; - } + gnome_vfs_mime_application_free (application); } static void delete_selected_application (GtkWidget *button, GtkWidget *list) { GtkListItem *item; - const char *mime_type, *name; + const char *mime_type, *id; GList *selection; /* Get selected list item */ @@ -1342,14 +1412,16 @@ delete_selected_application (GtkWidget *button, GtkWidget *list) return; } - name = gtk_object_get_data (GTK_OBJECT (item), "application_id"); + g_return_if_fail (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (item), "user_owned"))); + + id = gtk_object_get_data (GTK_OBJECT (item), "application_id"); mime_type = gtk_object_get_data (GTK_OBJECT (item), "mime_type"); - /* Remove mime data */ - if (name != NULL && mime_type != NULL) { - gnome_vfs_application_registry_remove_mime_type (name, mime_type); + /* Remove application if it is user owned */ + if (id != NULL && mime_type != NULL) { + gnome_vfs_application_registry_remove_mime_type (id, mime_type); gnome_vfs_application_registry_sync (); - gnome_vfs_mime_remove_application_from_short_list (mime_type, name); + gnome_vfs_mime_remove_application_from_short_list (mime_type, id); } /* Remove widget from list */ |