/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Engrampa * * Copyright (C) 2001, 2003, 2005 Free Software Foundation, 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 Street #330, Boston, MA 02110-1301, USA. */ #include <config.h> #include <string.h> #include <gtk/gtk.h> #include "file-utils.h" #include "glib-utils.h" #include "gtk-utils.h" #include "main.h" #include "fr-window.h" #define TEMP_DOCS "temp_docs" enum { ICON_COLUMN, TEXT_COLUMN, DATA_COLUMN, N_COLUMNS }; typedef struct { FrWindow *window; GSettings *settings; GtkBuilder *builder; GtkWidget *dialog; GtkWidget *o_app_tree_view; GtkWidget *o_recent_tree_view; GtkWidget *o_app_entry; GtkWidget *o_del_button; GtkWidget *ok_button; GList *app_list; GList *file_list; GtkTreeModel *app_model; GtkTreeModel *recent_model; GtkWidget *last_clicked_list; } DialogData; /* called when the main dialog is closed. */ static void open_with__destroy_cb (GtkWidget *widget, DialogData *data) { if (data->app_list != NULL) g_list_free (data->app_list); if (data->file_list != NULL) path_list_free (data->file_list); g_object_unref (data->builder); g_object_unref (data->settings); g_free (data); } static void open_cb (GtkWidget *widget, gpointer callback_data) { DialogData *data = callback_data; const char *application; gboolean present = FALSE; char *command = NULL; GList *scan; char **editors; int i; application = gtk_entry_get_text (GTK_ENTRY (data->o_app_entry)); for (scan = data->app_list; scan; scan = scan->next) { GAppInfo *app = scan->data; if (strcmp (g_app_info_get_executable (app), application) == 0) { fr_window_open_files_with_application (data->window, data->file_list, app); gtk_widget_destroy (data->dialog); return; } } /* add the command to the editors list if not already present. */ editors = g_settings_get_strv (data->settings, PREF_GENERAL_EDITORS); for (i = 0; ! present && editors[i] != NULL; i++) { if (strcmp (editors[i], application) == 0) { command = g_strdup (editors[i]); present = TRUE; } } if (! present) { char **new_editors; new_editors = _g_strv_prepend (editors, g_strdup (application)); command = g_strdup (application); g_settings_set_strv (data->settings, PREF_GENERAL_EDITORS, (const gchar * const *) new_editors); g_strfreev (new_editors); } g_strfreev (editors); /* exec the application */ if (command != NULL) { fr_window_open_files_with_command (data->window, data->file_list, command); g_free (command); } gtk_widget_destroy (data->dialog); } static void app_list_selection_changed_cb (GtkTreeSelection *selection, gpointer p) { DialogData *data = p; GtkTreeIter iter; GAppInfo *app; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->o_app_tree_view)); if (selection == NULL) return; if (! gtk_tree_selection_get_selected (selection, NULL, &iter)) return; gtk_tree_model_get (data->app_model, &iter, DATA_COLUMN, &app, -1); _gtk_entry_set_locale_text (GTK_ENTRY (data->o_app_entry), g_app_info_get_executable (app)); data->last_clicked_list = data->o_app_tree_view; } static void app_activated_cb (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer callback_data) { DialogData *data = callback_data; GtkTreeIter iter; GAppInfo *app; if (! gtk_tree_model_get_iter (data->app_model, &iter, path)) return; gtk_tree_model_get (data->app_model, &iter, DATA_COLUMN, &app, -1); _gtk_entry_set_locale_text (GTK_ENTRY (data->o_app_entry), g_app_info_get_executable (app)); open_cb (NULL, data); } static void recent_list_selection_changed_cb (GtkTreeSelection *selection, gpointer p) { DialogData *data = p; GtkTreeIter iter; char *editor; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->o_recent_tree_view)); if (selection == NULL) return; if (! gtk_tree_selection_get_selected (selection, NULL, &iter)) return; gtk_tree_model_get (data->recent_model, &iter, 0, &editor, -1); _gtk_entry_set_locale_text (GTK_ENTRY (data->o_app_entry), editor); g_free (editor); data->last_clicked_list = data->o_recent_tree_view; } static void recent_activated_cb (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer callback_data) { DialogData *data = callback_data; GtkTreeIter iter; char *editor; if (! gtk_tree_model_get_iter (data->recent_model, &iter, path)) return; gtk_tree_model_get (data->recent_model, &iter, 0, &editor, -1); _gtk_entry_set_locale_text (GTK_ENTRY (data->o_app_entry), editor); g_free (editor); open_cb (NULL, data); } static void app_entry__changed_cb (GtkEditable *editable, gpointer user_data) { DialogData *data = user_data; const char *text; text = eat_void_chars (gtk_entry_get_text (GTK_ENTRY (data->o_app_entry))); gtk_widget_set_sensitive (data->ok_button, strlen (text) > 0); } static void delete_recent_cb (GtkWidget *widget, gpointer callback_data) { DialogData *data = callback_data; GtkTreeSelection *selection; GtkTreeIter iter; if (data->last_clicked_list == data->o_recent_tree_view) { char *editor; char **editors; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->o_recent_tree_view)); if (! gtk_tree_selection_get_selected (selection, NULL, &iter)) return; gtk_tree_model_get (data->recent_model, &iter, 0, &editor, -1); gtk_list_store_remove (GTK_LIST_STORE (data->recent_model), &iter); /**/ editors = g_settings_get_strv (data->settings, PREF_GENERAL_EDITORS); if (_g_strv_remove (editors, editor)) g_settings_set_strv (data->settings, PREF_GENERAL_EDITORS, (const gchar * const *) editors); g_strfreev (editors); g_free (editor); } else if (data->last_clicked_list == data->o_app_tree_view) { GAppInfo *app; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->o_app_tree_view)); if (! gtk_tree_selection_get_selected (selection, NULL, &iter)) return; gtk_tree_model_get (data->app_model, &iter, DATA_COLUMN, &app, -1); gtk_list_store_remove (GTK_LIST_STORE (data->app_model), &iter); if (g_app_info_can_remove_supports_type (app)) { const char *mime_type; mime_type = get_file_mime_type_for_path ((char*) data->file_list->data, FALSE); g_app_info_remove_supports_type (app, mime_type, NULL); } } } /* create the "open with" dialog. */ void dlg_open_with (FrWindow *window, GList *file_list) { DialogData *data; GAppInfo *app; GList *scan, *app_names = NULL; char **editors; int i; GtkWidget *cancel_button; GtkTreeIter iter; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkIconTheme *theme; int icon_size; if (file_list == NULL) return; data = g_new0 (DialogData, 1); data->settings = g_settings_new (ENGRAMPA_SCHEMA_GENERAL); data->builder = _gtk_builder_new_from_file ("open-with.ui"); if (data->builder == NULL) { g_free (data); return; } data->file_list = path_list_dup (file_list); data->window = window; /* Get the widgets. */ data->dialog = _gtk_builder_get_widget (data->builder, "open_with_dialog"); data->o_app_tree_view = _gtk_builder_get_widget (data->builder, "o_app_list_tree_view"); data->o_recent_tree_view = _gtk_builder_get_widget (data->builder, "o_recent_tree_view"); data->o_app_entry = _gtk_builder_get_widget (data->builder, "o_app_entry"); data->o_del_button = _gtk_builder_get_widget (data->builder, "o_del_button"); data->ok_button = _gtk_builder_get_widget (data->builder, "o_ok_button"); cancel_button = _gtk_builder_get_widget (data->builder, "o_cancel_button"); gtk_widget_set_sensitive (data->ok_button, FALSE); /* Set the signals handlers. */ g_signal_connect (G_OBJECT (data->dialog), "destroy", G_CALLBACK (open_with__destroy_cb), data); g_signal_connect (G_OBJECT (data->o_app_entry), "changed", G_CALLBACK (app_entry__changed_cb), data); g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (data->o_app_tree_view))), "changed", G_CALLBACK (app_list_selection_changed_cb), data); g_signal_connect (G_OBJECT (data->o_app_tree_view), "row_activated", G_CALLBACK (app_activated_cb), data); g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (data->o_recent_tree_view))), "changed", G_CALLBACK (recent_list_selection_changed_cb), data); g_signal_connect (G_OBJECT (data->o_recent_tree_view), "row_activated", G_CALLBACK (recent_activated_cb), data); g_signal_connect (G_OBJECT (data->ok_button), "clicked", G_CALLBACK (open_cb), data); g_signal_connect_swapped (G_OBJECT (cancel_button), "clicked", G_CALLBACK (gtk_widget_destroy), G_OBJECT (data->dialog)); g_signal_connect (G_OBJECT (data->o_del_button), "clicked", G_CALLBACK (delete_recent_cb), data); /* Set data. */ /* * registered applications list. */ data->app_list = NULL; for (scan = data->file_list; scan; scan = scan->next) { const char *mime_type; const char *name = scan->data; mime_type = get_file_mime_type_for_path (name, FALSE); if ((mime_type != NULL) && ! g_content_type_is_unknown (mime_type)) data->app_list = g_list_concat (data->app_list, g_app_info_get_all_for_type (mime_type)); } data->app_model = GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER)); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->app_model), TEXT_COLUMN, GTK_SORT_ASCENDING); gtk_tree_view_set_model (GTK_TREE_VIEW (data->o_app_tree_view), data->app_model); g_object_unref (G_OBJECT (data->app_model)); theme = gtk_icon_theme_get_default (); icon_size = get_folder_pixbuf_size_for_list (GTK_WIDGET (data->dialog)); for (scan = data->app_list; scan; scan = scan->next) { gboolean found; char *utf8_name; GdkPixbuf *icon_image = NULL; app = scan->data; found = FALSE; if (app_names != NULL) { GList *p; for (p = app_names; p && !found; p = p->next) if (strcmp ((char*)p->data, g_app_info_get_executable (app)) == 0) found = TRUE; } if (found) continue; app_names = g_list_prepend (app_names, (char*) g_app_info_get_executable (app)); utf8_name = g_locale_to_utf8 (g_app_info_get_name (app), -1, NULL, NULL, NULL); icon_image = get_icon_pixbuf (g_app_info_get_icon (app), icon_size, theme); gtk_list_store_append (GTK_LIST_STORE (data->app_model), &iter); gtk_list_store_set (GTK_LIST_STORE (data->app_model), &iter, ICON_COLUMN, icon_image, TEXT_COLUMN, utf8_name, DATA_COLUMN, app, -1); g_free (utf8_name); } column = gtk_tree_view_column_new (); renderer = gtk_cell_renderer_pixbuf_new (); gtk_tree_view_column_pack_start (column, renderer, FALSE); gtk_tree_view_column_set_attributes (column, renderer, "pixbuf", ICON_COLUMN, NULL); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (column, renderer, TRUE); gtk_tree_view_column_set_attributes (column, renderer, "text", TEXT_COLUMN, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (data->o_app_tree_view), column); if (app_names) g_list_free (app_names); /* * recent editors list. */ data->recent_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING)); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->recent_model), 0, GTK_SORT_ASCENDING); gtk_tree_view_set_model (GTK_TREE_VIEW (data->o_recent_tree_view), data->recent_model); g_object_unref (G_OBJECT (data->recent_model)); editors = g_settings_get_strv (data->settings, PREF_GENERAL_EDITORS); for (i = 0; editors[i] != NULL; i++) { gtk_list_store_append (GTK_LIST_STORE (data->recent_model), &iter); gtk_list_store_set (GTK_LIST_STORE (data->recent_model), &iter, 0, editors[i], -1); } g_strfreev (editors); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "text", 0, NULL); gtk_tree_view_column_set_sort_column_id (column, 0); gtk_tree_view_append_column (GTK_TREE_VIEW (data->o_recent_tree_view), column); /* Run dialog. */ gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (window)); gtk_window_set_modal (GTK_WINDOW (data->dialog), TRUE); gtk_widget_show_all (data->dialog); } void open_with_cb (GtkWidget *widget, void *callback_data) { FrWindow *window = callback_data; GList *file_list; file_list = fr_window_get_file_list_selection (window, FALSE, NULL); if (file_list == NULL) return; fr_window_open_files (window, file_list, TRUE); path_list_free (file_list); }