/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Engrampa * * Copyright (C) 2007 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. * * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include "actions.h" #include "dlg-batch-add.h" #include "dlg-delete.h" #include "dlg-extract.h" #include "dlg-open-with.h" #include "dlg-ask-password.h" #include "dlg-package-installer.h" #include "dlg-update.h" #include "eggtreemultidnd.h" #include "fr-marshal.h" #include "fr-list-model.h" #include "fr-archive.h" #include "fr-error.h" #include "fr-window.h" #include "file-data.h" #include "file-utils.h" #include "glib-utils.h" #include "fr-init.h" #include "gtk-utils.h" #include "open-file.h" #include "typedefs.h" #include "ui.h" #ifdef __GNUC__ #define UNUSED_VARIABLE __attribute__ ((unused)) #else #define UNUSED_VARIABLE #endif #define LAST_OUTPUT_DIALOG_NAME "last-output" #define ACTIVITY_DELAY 100 #define ACTIVITY_PULSE_STEP (0.033) #define PROGRESS_TIMEOUT_MSECS 5000 #define PROGRESS_DIALOG_DEFAULT_WIDTH 500 #define PROGRESS_BAR_HEIGHT 10 #undef LOG_PROGRESS #define HIDE_PROGRESS_TIMEOUT_MSECS 500 #define DEFAULT_NAME_COLUMN_WIDTH 250 #define OTHER_COLUMNS_WIDTH 100 #define FILE_LIST_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR #define BAD_CHARS "/\\*" static GHashTable *tree_pixbuf_hash = NULL; static GtkIconTheme *icon_theme = NULL; static int file_list_icon_size = 0; #define XDS_FILENAME "xds.txt" #define MAX_XDS_ATOM_VAL_LEN 4096 #define XDS_ATOM gdk_atom_intern ("XdndDirectSave0", FALSE) #define TEXT_ATOM gdk_atom_intern ("text/plain", FALSE) #define XFR_ATOM gdk_atom_intern ("XdndEngrampa0", FALSE) #define FR_CLIPBOARD (gdk_atom_intern_static_string ("_RNGRAMPA_SPECIAL_CLIPBOARD")) #define FR_SPECIAL_URI_LIST (gdk_atom_intern_static_string ("application/engrampa-uri-list")) static GtkTargetEntry clipboard_targets[] = { { "application/engrampa-uri-list", 0, 1 } }; static GtkTargetEntry target_table[] = { { "XdndEngrampa0", 0, 0 }, { "text/uri-list", 0, 1 }, }; static GtkTargetEntry folder_tree_targets[] = { { "XdndEngrampa0", 0, 0 }, { "XdndDirectSave0", 0, 2 } }; typedef struct { FrBatchActionType type; void * data; GFreeFunc free_func; } FRBatchAction; typedef struct { guint converting : 1; char *temp_dir; FrArchive *new_archive; char *password; gboolean encrypt_header; guint volume_size; char *new_file; } FRConvertData; typedef enum { FR_CLIPBOARD_OP_CUT, FR_CLIPBOARD_OP_COPY } FRClipboardOp; typedef struct { GList *file_list; char *extract_to_dir; char *base_dir; gboolean skip_older; FrOverwrite overwrite; gboolean junk_paths; char *password; gboolean extract_here; gboolean ask_to_open_destination; } ExtractData; typedef enum { FR_WINDOW_AREA_MENUBAR, FR_WINDOW_AREA_TOOLBAR, FR_WINDOW_AREA_LOCATIONBAR, FR_WINDOW_AREA_CONTENTS, FR_WINDOW_AREA_FILTERBAR, FR_WINDOW_AREA_STATUSBAR, } FrWindowArea; typedef enum { DIALOG_RESPONSE_NONE = 1, DIALOG_RESPONSE_OPEN_ARCHIVE, DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER, DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER_AND_QUIT, DIALOG_RESPONSE_QUIT } DialogResponse; /* -- FrClipboardData -- */ typedef struct { int refs; char *archive_filename; char *archive_password; FRClipboardOp op; char *base_dir; GList *files; char *tmp_dir; char *current_dir; } FrClipboardData; static FrClipboardData* fr_clipboard_data_new (void) { FrClipboardData *data; data = g_new0 (FrClipboardData, 1); data->refs = 1; return data; } static FrClipboardData * fr_clipboard_data_ref (FrClipboardData *clipboard_data) { clipboard_data->refs++; return clipboard_data; } static void fr_clipboard_data_unref (FrClipboardData *clipboard_data) { if (clipboard_data == NULL) return; if (--clipboard_data->refs > 0) return; g_free (clipboard_data->archive_filename); g_free (clipboard_data->archive_password); g_free (clipboard_data->base_dir); g_free (clipboard_data->tmp_dir); g_free (clipboard_data->current_dir); g_list_free_full (clipboard_data->files, g_free); g_free (clipboard_data); } static void fr_clipboard_data_set_password (FrClipboardData *clipboard_data, const char *password) { if (clipboard_data->archive_password != password) g_free (clipboard_data->archive_password); if (password != NULL) clipboard_data->archive_password = g_strdup (password); } /**/ enum { ARCHIVE_LOADED, PROGRESS, READY, LAST_SIGNAL }; static GtkApplicationWindowClass *parent_class = NULL; static guint fr_window_signals[LAST_SIGNAL] = { 0 }; struct _FrWindowPrivateData { GtkWidget *layout; GtkWidget *contents; GtkWidget *list_view; GtkListStore *list_store; GtkWidget *tree_view; GtkTreeStore *tree_store; GtkWidget *toolbar; GtkWidget *statusbar; GtkWidget *progress_bar; GtkWidget *location_bar; GtkWidget *location_entry; GtkWidget *location_label; GtkWidget *filter_bar; GtkWidget *filter_entry; GtkWidget *paned; GtkWidget *sidepane; GtkTreePath *list_hover_path; GtkTreeViewColumn *filename_column; gboolean filter_mode; gint current_view_length; guint help_message_cid; guint list_info_cid; guint progress_cid; GtkWidget * up_arrows[5]; GtkWidget * down_arrows[5]; FrAction action; gboolean archive_present; gboolean archive_new; /* A new archive has been created * but it doesn't contain any * file yet. The real file will * be created only when the user * adds some file to the * archive.*/ char * archive_uri; char * open_default_dir; /* default directory to be used * in the Open dialog. */ char * add_default_dir; /* default directory to be used * in the Add dialog. */ char * extract_default_dir; /* default directory to be used * in the Extract dialog. */ gboolean freeze_default_dir; gboolean asked_for_password; gboolean ask_to_open_destination_after_extraction; gboolean destroy_with_error_dialog; FRBatchAction current_batch_action; gboolean give_focus_to_the_list; gboolean single_click; GtkTreePath *path_clicked; FrWindowSortMethod sort_method; GtkSortType sort_type; char * last_location; gboolean view_folders; FrWindowListMode list_mode; FrWindowListMode last_list_mode; GList * history; GList * history_current; char * password; char * password_for_paste; gboolean encrypt_header; FrCompression compression; guint volume_size; guint activity_timeout_handle; /* activity timeout * handle. */ gint activity_ref; /* when > 0 some activity * is present. */ guint update_timeout_handle; /* update file list * timeout handle. */ FRConvertData convert_data; gboolean stoppable; gboolean closing; FrClipboardData *clipboard_data; FrClipboardData *copy_data; FrArchive *copy_from_archive; GtkActionGroup *actions; GtkWidget *file_popup_menu; GtkWidget *folder_popup_menu; GtkWidget *sidebar_folder_popup_menu; /* dragged files data */ char *drag_destination_folder; char *drag_base_dir; GError *drag_error; GList *drag_file_list; /* the list of files we are * dragging*/ /* progress dialog data */ GtkWidget *progress_dialog; GtkWidget *pd_action; GtkWidget *pd_message; GtkWidget *pd_progress_bar; GtkWidget *pd_cancel_button; GtkWidget *pd_close_button; GtkWidget *pd_open_archive_button; GtkWidget *pd_open_destination_button; GtkWidget *pd_open_destination_and_quit_button; GtkWidget *pd_quit_button; GtkWidget *pd_state_button; //Switch state, pause state or start state GtkWidget *pd_icon; gboolean progress_pulse; guint progress_timeout; /* Timeout to display the progress dialog. */ guint hide_progress_timeout; /* Timeout to hide the progress dialog. */ char *pd_last_archive; char *working_archive; double pd_last_fraction; char *pd_last_message; gboolean use_progress_dialog; /* update dialog data */ gpointer update_dialog; GList *open_files; /* batch mode data */ gboolean batch_mode; /* whether we are in a non interactive * mode. */ GList *batch_action_list; /* FRBatchAction * elements */ GList *batch_action; /* current action. */ char *batch_title; /* misc */ GSettings *settings_listing; GSettings *settings_ui; GSettings *settings_general; GSettings *settings_dialogs; GSettings *settings_caja; gulong theme_changed_handler_id; gboolean non_interactive; char *extract_here_dir; gboolean extract_interact_use_default_dir; gboolean update_dropped_files; gboolean batch_adding_one_file; GtkWindow *load_error_parent_window; gboolean showing_error_dialog; GtkWindow *error_dialog_parent; }; /* -- fr_window_free_private_data -- */ static void fr_window_free_batch_data (FrWindow *window) { GList *scan; for (scan = window->priv->batch_action_list; scan; scan = scan->next) { FRBatchAction *adata = scan->data; if ((adata->data != NULL) && (adata->free_func != NULL)) (*adata->free_func) (adata->data); g_free (adata); } g_list_free (window->priv->batch_action_list); window->priv->batch_action_list = NULL; window->priv->batch_action = NULL; g_free (window->priv->batch_title); window->priv->batch_title = NULL; } static void gh_unref_pixbuf (gpointer key, gpointer value, gpointer user_data) { g_object_unref (value); } static void fr_window_clipboard_remove_file_list (FrWindow *window, GList *file_list) { GList *scan1; if (window->priv->copy_data == NULL) return; if (file_list == NULL) { fr_clipboard_data_unref (window->priv->copy_data); window->priv->copy_data = NULL; return; } for (scan1 = file_list; scan1; scan1 = scan1->next) { const char *name1 = scan1->data; GList *scan2; for (scan2 = window->priv->copy_data->files; scan2;) { const char *name2 = scan2->data; if (strcmp (name1, name2) == 0) { GList *tmp = scan2->next; window->priv->copy_data->files = g_list_remove_link (window->priv->copy_data->files, scan2); g_free (scan2->data); g_list_free (scan2); scan2 = tmp; } else scan2 = scan2->next; } } if (window->priv->copy_data->files == NULL) { fr_clipboard_data_unref (window->priv->copy_data); window->priv->copy_data = NULL; } } static void fr_window_history_clear (FrWindow *window) { if (window->priv->history != NULL) path_list_free (window->priv->history); window->priv->history = NULL; window->priv->history_current = NULL; g_free (window->priv->last_location); window->priv->last_location = NULL; } static void fr_window_free_open_files (FrWindow *window) { GList *scan; for (scan = window->priv->open_files; scan; scan = scan->next) { OpenFile *file = scan->data; if (file->monitor != NULL) g_file_monitor_cancel (file->monitor); open_file_free (file); } g_list_free (window->priv->open_files); window->priv->open_files = NULL; } static void fr_window_convert_data_free (FrWindow *window, gboolean all) { if (all) { g_free (window->priv->convert_data.new_file); window->priv->convert_data.new_file = NULL; } window->priv->convert_data.converting = FALSE; if (window->priv->convert_data.temp_dir != NULL) { g_free (window->priv->convert_data.temp_dir); window->priv->convert_data.temp_dir = NULL; } if (window->priv->convert_data.new_archive != NULL) { g_object_unref (window->priv->convert_data.new_archive); window->priv->convert_data.new_archive = NULL; } if (window->priv->convert_data.password != NULL) { g_free (window->priv->convert_data.password); window->priv->convert_data.password = NULL; } } static void fr_window_free_private_data (FrWindow *window) { if (window->priv->update_timeout_handle != 0) { g_source_remove (window->priv->update_timeout_handle); window->priv->update_timeout_handle = 0; } while (window->priv->activity_ref > 0) fr_window_stop_activity_mode (window); if (window->priv->progress_timeout != 0) { g_source_remove (window->priv->progress_timeout); window->priv->progress_timeout = 0; } if (window->priv->hide_progress_timeout != 0) { g_source_remove (window->priv->hide_progress_timeout); window->priv->hide_progress_timeout = 0; } if (window->priv->theme_changed_handler_id != 0) g_signal_handler_disconnect (icon_theme, window->priv->theme_changed_handler_id); fr_window_history_clear (window); g_free (window->priv->open_default_dir); g_free (window->priv->add_default_dir); g_free (window->priv->extract_default_dir); g_free (window->priv->archive_uri); g_free (window->priv->working_archive); g_free (window->priv->password); g_free (window->priv->password_for_paste); g_object_unref (window->priv->list_store); if (window->priv->clipboard_data != NULL) { fr_clipboard_data_unref (window->priv->clipboard_data); window->priv->clipboard_data = NULL; } if (window->priv->copy_data != NULL) { fr_clipboard_data_unref (window->priv->copy_data); window->priv->copy_data = NULL; } if (window->priv->copy_from_archive != NULL) { g_object_unref (window->priv->copy_from_archive); window->priv->copy_from_archive = NULL; } fr_window_free_open_files (window); fr_window_convert_data_free (window, TRUE); g_clear_error (&window->priv->drag_error); path_list_free (window->priv->drag_file_list); window->priv->drag_file_list = NULL; if (window->priv->file_popup_menu != NULL) { gtk_widget_destroy (window->priv->file_popup_menu); window->priv->file_popup_menu = NULL; } if (window->priv->folder_popup_menu != NULL) { gtk_widget_destroy (window->priv->folder_popup_menu); window->priv->folder_popup_menu = NULL; } if (window->priv->sidebar_folder_popup_menu != NULL) { gtk_widget_destroy (window->priv->sidebar_folder_popup_menu); window->priv->sidebar_folder_popup_menu = NULL; } g_free (window->priv->last_location); fr_window_free_batch_data (window); fr_window_reset_current_batch_action (window); g_free (window->priv->pd_last_archive); g_free (window->priv->pd_last_message); g_free (window->priv->extract_here_dir); g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_SORT_METHOD, window->priv->sort_method); g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_SORT_TYPE, window->priv->sort_type); g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_LIST_MODE, window->priv->last_list_mode); _g_object_unref (window->priv->settings_listing); _g_object_unref (window->priv->settings_ui); _g_object_unref (window->priv->settings_general); _g_object_unref (window->priv->settings_dialogs); if (window->priv->settings_caja) _g_object_unref (window->priv->settings_caja); } static void fr_window_finalize (GObject *object) { FrWindow *window = FR_WINDOW (object); fr_window_free_open_files (window); if (window->archive != NULL) { g_object_unref (window->archive); window->archive = NULL; } if (window->priv != NULL) { fr_window_free_private_data (window); g_free (window->priv); window->priv = NULL; } if (gtk_application_get_windows (GTK_APPLICATION (g_application_get_default ())) == NULL) { if (tree_pixbuf_hash != NULL) { g_hash_table_foreach (tree_pixbuf_hash, gh_unref_pixbuf, NULL); g_hash_table_destroy (tree_pixbuf_hash); tree_pixbuf_hash = NULL; } } G_OBJECT_CLASS (parent_class)->finalize (object); } static gboolean close__step2 (gpointer data) { gtk_widget_destroy (GTK_WIDGET (data)); return FALSE; } void fr_window_close (FrWindow *window) { if (window->priv->activity_ref > 0) return; window->priv->closing = TRUE; if (gtk_widget_get_realized (GTK_WIDGET (window))) { int width, height; width = gtk_widget_get_allocated_width (GTK_WIDGET (window)); height = gtk_widget_get_allocated_height (GTK_WIDGET (window)); g_settings_set_int (window->priv->settings_ui, PREF_UI_WINDOW_WIDTH, width); g_settings_set_int (window->priv->settings_ui, PREF_UI_WINDOW_HEIGHT, height); width = gtk_paned_get_position (GTK_PANED (window->priv->paned)); if (width > 0) g_settings_set_int (window->priv->settings_ui, PREF_UI_SIDEBAR_WIDTH, width); width = gtk_tree_view_column_get_width (window->priv->filename_column); if (width > 0) g_settings_set_int (window->priv->settings_listing, PREF_LISTING_NAME_COLUMN_WIDTH, width); } g_idle_add (close__step2, window); } static void fr_window_class_init (FrWindowClass *class) { GObjectClass *gobject_class; parent_class = g_type_class_peek_parent (class); fr_window_signals[ARCHIVE_LOADED] = g_signal_new ("archive-loaded", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (FrWindowClass, archive_loaded), NULL, NULL, fr_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); fr_window_signals[PROGRESS] = g_signal_new ("progress", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (FrWindowClass, progress), NULL, NULL, fr_marshal_VOID__DOUBLE_STRING, G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_STRING); fr_window_signals[READY] = g_signal_new ("ready", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (FrWindowClass, ready), NULL, NULL, fr_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); gobject_class = (GObjectClass*) class; gobject_class->finalize = fr_window_finalize; } static void fr_window_update_paste_command_sensitivity (FrWindow *, GtkClipboard *); static void clipboard_owner_change_cb (GtkClipboard *clipboard, GdkEvent *event, gpointer user_data) { fr_window_update_paste_command_sensitivity ((FrWindow *) user_data, clipboard); } static void fr_window_realized (GtkWidget *window, gpointer *data) { GtkClipboard *clipboard; clipboard = gtk_widget_get_clipboard (window, FR_CLIPBOARD); g_signal_connect (clipboard, "owner_change", G_CALLBACK (clipboard_owner_change_cb), window); } static void fr_window_unrealized (GtkWidget *window, gpointer *data) { GtkClipboard *clipboard; clipboard = gtk_widget_get_clipboard (window, FR_CLIPBOARD); g_signal_handlers_disconnect_by_func (clipboard, G_CALLBACK (clipboard_owner_change_cb), window); } static void fr_window_init (FrWindow *window) { GtkStyleContext *context; window->priv = g_new0 (FrWindowPrivateData, 1); window->priv->update_dropped_files = FALSE; window->priv->filter_mode = FALSE; window->priv->batch_title = NULL; window->priv->use_progress_dialog = TRUE; window->priv->batch_title = NULL; context = gtk_widget_get_style_context (GTK_WIDGET (window)); gtk_style_context_add_class (context, "engrampa-window"); g_signal_connect (window, "realize", G_CALLBACK (fr_window_realized), NULL); g_signal_connect (window, "unrealize", G_CALLBACK (fr_window_unrealized), NULL); } GType fr_window_get_type (void) { static GType type = 0; if (! type) { GTypeInfo type_info = { sizeof (FrWindowClass), NULL, NULL, (GClassInitFunc) fr_window_class_init, NULL, NULL, sizeof (FrWindow), 0, (GInstanceInitFunc) fr_window_init, NULL }; type = g_type_register_static (GTK_TYPE_APPLICATION_WINDOW, "FrWindow", &type_info, 0); } return type; } /* -- window history -- */ #if 0 static void fr_window_history_print (FrWindow *window) { GList *list; debug (DEBUG_INFO, "history:\n"); for (list = window->priv->history; list; list = list->next) g_print ("\t%s %s\n", (char*) list->data, (list == window->priv->history_current)? "<-": ""); g_print ("\n"); } #endif static void fr_window_history_add (FrWindow *window, const char *path) { if ((window->priv->history_current == NULL) || (g_strcmp0 (path, window->priv->history_current->data) != 0)) { GList *scan; GList *new_current = NULL; /* search the path in the history */ for (scan = window->priv->history_current; scan; scan = scan->next) { char *path_in_history = scan->data; if (g_strcmp0 (path, path_in_history) == 0) { new_current = scan; break; } } if (new_current != NULL) { window->priv->history_current = new_current; } else { /* remove all the paths after the current position */ for (scan = window->priv->history; scan && (scan != window->priv->history_current); /* void */) { GList *next = scan->next; window->priv->history = g_list_remove_link (window->priv->history, scan); path_list_free (scan); scan = next; } window->priv->history = g_list_prepend (window->priv->history, g_strdup (path)); window->priv->history_current = window->priv->history; } } } static void fr_window_history_pop (FrWindow *window) { GList *first; if (window->priv->history == NULL) return; first = window->priv->history; window->priv->history = g_list_remove_link (window->priv->history, first); if (window->priv->history_current == first) window->priv->history_current = window->priv->history; g_free (first->data); g_list_free (first); } /* -- window_update_file_list -- */ static GPtrArray * fr_window_get_current_dir_list (FrWindow *window) { GPtrArray *files; guint i; files = g_ptr_array_sized_new (128); for (i = 0; i < window->archive->command->files->len; i++) { FileData *fdata = g_ptr_array_index (window->archive->command->files, i); if (fdata->list_name == NULL) continue; g_ptr_array_add (files, fdata); } return files; } static gint sort_by_name (gconstpointer ptr1, gconstpointer ptr2) { FileData *fdata1 = *((FileData **) ptr1); FileData *fdata2 = *((FileData **) ptr2); if (file_data_is_dir (fdata1) != file_data_is_dir (fdata2)) { if (file_data_is_dir (fdata1)) return -1; else return 1; } return strcmp (fdata1->sort_key, fdata2->sort_key); } static gint sort_by_size (gconstpointer ptr1, gconstpointer ptr2) { FileData *fdata1 = *((FileData **) ptr1); FileData *fdata2 = *((FileData **) ptr2); if (file_data_is_dir (fdata1) != file_data_is_dir (fdata2)) { if (file_data_is_dir (fdata1)) return -1; else return 1; } else if (file_data_is_dir (fdata1) && file_data_is_dir (fdata2)) { if (fdata1->dir_size > fdata2->dir_size) return 1; else return -1; } if (fdata1->size == fdata2->size) return sort_by_name (ptr1, ptr2); else if (fdata1->size > fdata2->size) return 1; else return -1; } static gint sort_by_type (gconstpointer ptr1, gconstpointer ptr2) { FileData *fdata1 = *((FileData **) ptr1); FileData *fdata2 = *((FileData **) ptr2); int result; char *desc1, *desc2; if (file_data_is_dir (fdata1) != file_data_is_dir (fdata2)) { if (file_data_is_dir (fdata1)) return -1; else return 1; } else if (file_data_is_dir (fdata1) && file_data_is_dir (fdata2)) return sort_by_name (ptr1, ptr2); desc1 = g_content_type_get_description (fdata1->content_type); desc2 = g_content_type_get_description (fdata2->content_type); result = strcasecmp (desc1, desc2); g_free (desc1); g_free (desc2); if (result == 0) return sort_by_name (ptr1, ptr2); else return result; } static gint sort_by_time (gconstpointer ptr1, gconstpointer ptr2) { FileData *fdata1 = *((FileData **) ptr1); FileData *fdata2 = *((FileData **) ptr2); if (file_data_is_dir (fdata1) != file_data_is_dir (fdata2)) { if (file_data_is_dir (fdata1)) return -1; else return 1; } else if (file_data_is_dir (fdata1) && file_data_is_dir (fdata2)) return sort_by_name (ptr1, ptr2); if (fdata1->modified == fdata2->modified) return sort_by_name (ptr1, ptr2); else if (fdata1->modified > fdata2->modified) return 1; else return -1; } static gint sort_by_path (gconstpointer ptr1, gconstpointer ptr2) { FileData *fdata1 = *((FileData **) ptr1); FileData *fdata2 = *((FileData **) ptr2); int result; if (file_data_is_dir (fdata1) != file_data_is_dir (fdata2)) { if (file_data_is_dir (fdata1)) return -1; else return 1; } else if (file_data_is_dir (fdata1) && file_data_is_dir (fdata2)) return sort_by_name (ptr1, ptr2); /* 2 files */ result = strcasecmp (fdata1->path, fdata2->path); if (result == 0) return sort_by_name (ptr1, ptr2); else return result; } static guint64 get_dir_size (FrWindow *window, const char *current_dir, const char *name) { guint64 size; char *dirname; int dirname_l; guint i; dirname = g_strconcat (current_dir, name, "/", NULL); dirname_l = strlen (dirname); size = 0; for (i = 0; i < window->archive->command->files->len; i++) { FileData *fd = g_ptr_array_index (window->archive->command->files, i); if (strncmp (dirname, fd->full_path, dirname_l) == 0) size += fd->size; } g_free (dirname); return size; } static gboolean file_data_respects_filter (FrWindow *window, FileData *fdata) { const char *filter; filter = gtk_entry_get_text (GTK_ENTRY (window->priv->filter_entry)); if ((fdata == NULL) || (filter == NULL) || (*filter == '\0')) return TRUE; if (fdata->dir || (fdata->name == NULL)) return FALSE; return strncasecmp (fdata->name, filter, strlen (filter)) == 0; } static gboolean compute_file_list_name (FrWindow *window, FileData *fdata, const char *current_dir, size_t current_dir_len, GHashTable *names_hash, gboolean *different_name) { register char *scan, *end; *different_name = FALSE; if (! file_data_respects_filter (window, fdata)) return FALSE; if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) { if (!(fdata->dir)) file_data_set_list_name (fdata, fdata->name); return FALSE; } if (strncmp (fdata->full_path, current_dir, current_dir_len) != 0) { *different_name = TRUE; return FALSE; } if (strlen (fdata->full_path) == current_dir_len) return FALSE; scan = fdata->full_path + current_dir_len; end = strchr (scan, '/'); if ((end == NULL) && ! fdata->dir) { /* file */ file_data_set_list_name (fdata, scan); } else { /* folder */ char *dir_name; if (end != NULL) dir_name = g_strndup (scan, end - scan); else dir_name = g_strdup (scan); /* avoid to insert duplicated folders */ if (g_hash_table_lookup (names_hash, dir_name) != NULL) { g_free (dir_name); return FALSE; } g_hash_table_insert (names_hash, dir_name, GINT_TO_POINTER (1)); if ((end != NULL) && (*(end + 1) != '\0')) fdata->list_dir = TRUE; file_data_set_list_name (fdata, dir_name); fdata->dir_size = get_dir_size (window, current_dir, dir_name); } return TRUE; } static void fr_window_compute_list_names (FrWindow *window, GPtrArray *files) { const char *current_dir; size_t current_dir_len; GHashTable *names_hash; guint i; gboolean visible_list_started = FALSE; gboolean visible_list_completed = FALSE; gboolean different_name; current_dir = fr_window_get_current_location (window); current_dir_len = strlen (current_dir); names_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (i = 0; i < files->len; i++) { FileData *fdata = g_ptr_array_index (files, i); file_data_set_list_name (fdata, NULL); fdata->list_dir = FALSE; /* the files array is sorted by path, when the visible list * is started and we find a path that doesn't match the * current_dir path, the following files can't match * the current_dir path. */ if (visible_list_completed) continue; if (compute_file_list_name (window, fdata, current_dir, current_dir_len, names_hash, &different_name)) { visible_list_started = TRUE; } else if (visible_list_started && different_name) visible_list_completed = TRUE; } g_hash_table_destroy (names_hash); } static gboolean fr_window_dir_exists_in_archive (FrWindow *window, const char *dir_name) { int dir_name_len; guint i; if (dir_name == NULL) return FALSE; dir_name_len = strlen (dir_name); if (dir_name_len == 0) return TRUE; if (strcmp (dir_name, "/") == 0) return TRUE; for (i = 0; i < window->archive->command->files->len; i++) { FileData *fdata = g_ptr_array_index (window->archive->command->files, i); if (strncmp (dir_name, fdata->full_path, dir_name_len) == 0) { return TRUE; } else if (fdata->dir && (fdata->full_path[strlen (fdata->full_path) -1] != '/') && (strncmp (dir_name, fdata->full_path, dir_name_len - 1) == 0)) { return TRUE; } } return FALSE; } static char * get_parent_dir (const char *current_dir) { char *dir; char *new_dir; char *retval; if (current_dir == NULL) return NULL; if (strcmp (current_dir, "/") == 0) return g_strdup ("/"); dir = g_strdup (current_dir); dir[strlen (dir) - 1] = 0; new_dir = remove_level_from_path (dir); g_free (dir); if (new_dir[strlen (new_dir) - 1] == '/') retval = new_dir; else { retval = g_strconcat (new_dir, "/", NULL); g_free (new_dir); } return retval; } static void fr_window_update_statusbar_list_info (FrWindow *window); static GdkPixbuf * get_mime_type_icon (const char *mime_type) { GdkPixbuf *pixbuf = NULL; pixbuf = g_hash_table_lookup (tree_pixbuf_hash, mime_type); if (pixbuf != NULL) { g_object_ref (G_OBJECT (pixbuf)); return pixbuf; } pixbuf = get_mime_type_pixbuf (mime_type, file_list_icon_size, icon_theme); if (pixbuf == NULL) return NULL; pixbuf = gdk_pixbuf_copy (pixbuf); g_hash_table_insert (tree_pixbuf_hash, (gpointer) mime_type, pixbuf); g_object_ref (G_OBJECT (pixbuf)); return pixbuf; } static GdkPixbuf * get_icon (FileData *fdata) { const char *content_type; if (file_data_is_dir (fdata)) content_type = MIME_TYPE_DIRECTORY; else content_type = fdata->content_type; return get_mime_type_icon (content_type); } static GdkPixbuf * get_emblem (FileData *fdata) { if (! fdata->encrypted) return NULL; return get_mime_type_icon ("emblem-nowrite"); } static int get_column_from_sort_method (FrWindowSortMethod sort_method) { switch (sort_method) { case FR_WINDOW_SORT_BY_NAME: return COLUMN_NAME; case FR_WINDOW_SORT_BY_SIZE: return COLUMN_SIZE; case FR_WINDOW_SORT_BY_TYPE: return COLUMN_TYPE; case FR_WINDOW_SORT_BY_TIME: return COLUMN_TIME; case FR_WINDOW_SORT_BY_PATH: return COLUMN_PATH; default: break; } return COLUMN_NAME; } static int get_sort_method_from_column (int column_id) { switch (column_id) { case COLUMN_NAME: return FR_WINDOW_SORT_BY_NAME; case COLUMN_SIZE: return FR_WINDOW_SORT_BY_SIZE; case COLUMN_TYPE: return FR_WINDOW_SORT_BY_TYPE; case COLUMN_TIME: return FR_WINDOW_SORT_BY_TIME; case COLUMN_PATH: return FR_WINDOW_SORT_BY_PATH; default: break; } return FR_WINDOW_SORT_BY_NAME; } static void add_selected_from_list_view (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GList **list = data; FileData *fdata; gtk_tree_model_get (model, iter, COLUMN_FILE_DATA, &fdata, -1); *list = g_list_prepend (*list, fdata); } static void add_selected_from_tree_view (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GList **list = data; char *dir_path; gtk_tree_model_get (model, iter, TREE_COLUMN_PATH, &dir_path, -1); *list = g_list_prepend (*list, dir_path); } static void add_selected_fd (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GList **list = data; FileData *fdata; gtk_tree_model_get (model, iter, COLUMN_FILE_DATA, &fdata, -1); if (! fdata->list_dir) *list = g_list_prepend (*list, fdata); } static GList * get_selection_as_fd (FrWindow *window) { GtkTreeSelection *selection; GList *list = NULL; if (! gtk_widget_get_realized (window->priv->list_view)) return NULL; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)); if (selection == NULL) return NULL; gtk_tree_selection_selected_foreach (selection, add_selected_fd, &list); return list; } static void fr_window_update_statusbar_list_info (FrWindow *window) { char *info, *archive_info, *selected_info; char *size_txt, *sel_size_txt; gulong tot_n = 0; gulong sel_n = 0; goffset tot_size = 0; goffset sel_size = 0; GList *scan; if (window == NULL) return; if ((window->archive == NULL) || (window->archive->command == NULL)) { gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar), window->priv->list_info_cid); return; } if (window->priv->archive_present) { GPtrArray *files = fr_window_get_current_dir_list (window); guint i; for (i = 0; i < files->len; i++) { FileData *fd = g_ptr_array_index (files, i); tot_n++; if (! file_data_is_dir (fd)) tot_size += fd->size; else tot_size += fd->dir_size; } g_ptr_array_free (files, TRUE); } if (window->priv->archive_present) { GList *selection = get_selection_as_fd (window); for (scan = selection; scan; scan = scan->next) { FileData *fd = scan->data; sel_n++; if (! file_data_is_dir (fd)) sel_size += fd->size; } g_list_free (selection); } size_txt = g_format_size (tot_size); sel_size_txt = g_format_size (sel_size); if (tot_n == 0) archive_info = g_strdup (""); else archive_info = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%lu object (%s)", "%lu objects (%s)", tot_n), tot_n, size_txt); if (sel_n == 0) selected_info = g_strdup (""); else selected_info = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%lu object selected (%s)", "%lu objects selected (%s)", sel_n), sel_n, sel_size_txt); info = g_strconcat (archive_info, ((sel_n == 0) ? NULL : ", "), selected_info, NULL); gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar), window->priv->list_info_cid, info); g_free (size_txt); g_free (sel_size_txt); g_free (archive_info); g_free (selected_info); g_free (info); } static void fr_window_populate_file_list (FrWindow *window, GPtrArray *files) { guint i; gtk_list_store_clear (window->priv->list_store); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); for (i = 0; i < files->len; i++) { FileData *fdata = g_ptr_array_index (files, i); GtkTreeIter iter; GdkPixbuf *icon, *emblem; char *utf8_name; if (fdata->list_name == NULL) continue; gtk_list_store_append (window->priv->list_store, &iter); icon = get_icon (fdata); utf8_name = g_filename_display_name (fdata->list_name); emblem = get_emblem (fdata); if (file_data_is_dir (fdata)) { char *utf8_path; char *tmp; char *s_size; char *s_time; if (fdata->list_dir) tmp = remove_ending_separator (fr_window_get_current_location (window)); else tmp = remove_level_from_path (fdata->path); utf8_path = g_filename_display_name (tmp); g_free (tmp); s_size = g_format_size (fdata->dir_size); if (fdata->list_dir) { s_time = g_strdup (""); } else { GDateTime *date_time; date_time = g_date_time_new_from_unix_local (fdata->modified); s_time = g_date_time_format (date_time, _("%d %B %Y, %H:%M")); g_date_time_unref (date_time); } gtk_list_store_set (window->priv->list_store, &iter, COLUMN_FILE_DATA, fdata, COLUMN_ICON, icon, COLUMN_NAME, utf8_name, COLUMN_EMBLEM, emblem, COLUMN_TYPE, _("Folder"), COLUMN_SIZE, s_size, COLUMN_TIME, s_time, COLUMN_PATH, utf8_path, -1); g_free (utf8_path); g_free (s_size); g_free (s_time); } else { GDateTime *date_time; char *utf8_path; char *s_size; char *s_time; char *desc; utf8_path = g_filename_display_name (fdata->path); s_size = g_format_size (fdata->size); date_time = g_date_time_new_from_unix_local (fdata->modified); s_time = g_date_time_format (date_time, _("%d %B %Y, %H:%M")); g_date_time_unref (date_time); desc = g_content_type_get_description (fdata->content_type); gtk_list_store_set (window->priv->list_store, &iter, COLUMN_FILE_DATA, fdata, COLUMN_ICON, icon, COLUMN_NAME, utf8_name, COLUMN_EMBLEM, emblem, COLUMN_TYPE, desc, COLUMN_SIZE, s_size, COLUMN_TIME, s_time, COLUMN_PATH, utf8_path, -1); g_free (utf8_path); g_free (s_size); g_free (s_time); g_free (desc); } g_free (utf8_name); if (icon != NULL) g_object_unref (icon); if (emblem != NULL) g_object_unref (emblem); } gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store), get_column_from_sort_method (window->priv->sort_method), window->priv->sort_type); fr_window_update_statusbar_list_info (window); fr_window_stop_activity_mode (window); } static int path_compare (gconstpointer a, gconstpointer b) { char *path_a = *((char**) a); char *path_b = *((char**) b); return strcmp (path_a, path_b); } static gboolean get_tree_iter_from_path (FrWindow *window, const char *path, GtkTreeIter *parent, GtkTreeIter *iter) { gboolean result = FALSE; if (! gtk_tree_model_iter_children (GTK_TREE_MODEL (window->priv->tree_store), iter, parent)) return FALSE; do { GtkTreeIter tmp; char *iter_path; if (get_tree_iter_from_path (window, path, iter, &tmp)) { *iter = tmp; return TRUE; } gtk_tree_model_get (GTK_TREE_MODEL (window->priv->tree_store), iter, TREE_COLUMN_PATH, &iter_path, -1); if ((iter_path != NULL) && (strcmp (path, iter_path) == 0)) { result = TRUE; g_free (iter_path); break; } g_free (iter_path); } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (window->priv->tree_store), iter)); return result; } static void set_sensitive (FrWindow *window, const char *action_name, gboolean sensitive) { GtkAction *action; action = gtk_action_group_get_action (window->priv->actions, action_name); g_object_set (action, "sensitive", sensitive, NULL); } static void fr_window_update_current_location (FrWindow *window) { const char *current_dir = fr_window_get_current_location (window); char *path; GtkTreeIter iter; if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) { gtk_widget_hide (window->priv->location_bar); return; } gtk_widget_show (window->priv->location_bar); gtk_entry_set_text (GTK_ENTRY (window->priv->location_entry), window->priv->archive_present? current_dir: ""); set_sensitive (window, "GoBack", window->priv->archive_present && (current_dir != NULL) && (window->priv->history_current != NULL) && (window->priv->history_current->next != NULL)); set_sensitive (window, "GoForward", window->priv->archive_present && (current_dir != NULL) && (window->priv->history_current != NULL) && (window->priv->history_current->prev != NULL)); set_sensitive (window, "GoUp", window->priv->archive_present && (current_dir != NULL) && (strcmp (current_dir, "/") != 0)); set_sensitive (window, "GoHome", window->priv->archive_present); gtk_widget_set_sensitive (window->priv->location_entry, window->priv->archive_present); gtk_widget_set_sensitive (window->priv->location_label, window->priv->archive_present); gtk_widget_set_sensitive (window->priv->filter_entry, window->priv->archive_present); #if 0 fr_window_history_print (window); #endif path = remove_ending_separator (current_dir); if (get_tree_iter_from_path (window, path, NULL, &iter)) { GtkTreeSelection *selection; GtkTreePath *t_path; t_path = gtk_tree_model_get_path (GTK_TREE_MODEL (window->priv->tree_store), &iter); gtk_tree_view_expand_to_path (GTK_TREE_VIEW (window->priv->tree_view), t_path); gtk_tree_path_free (t_path); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view)); gtk_tree_selection_select_iter (selection, &iter); } g_free (path); } static void fr_window_update_dir_tree (FrWindow *window) { GPtrArray *dirs; GHashTable *dir_cache; guint i; GdkPixbuf *icon; gtk_tree_store_clear (window->priv->tree_store); if (! window->priv->view_folders || ! window->priv->archive_present || (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT)) { gtk_widget_set_sensitive (window->priv->tree_view, FALSE); gtk_widget_hide (window->priv->sidepane); return; } else { gtk_widget_set_sensitive (window->priv->tree_view, TRUE); if (! gtk_widget_get_visible (window->priv->sidepane)) gtk_widget_show_all (window->priv->sidepane); } if (gtk_widget_get_realized (window->priv->tree_view)) gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (window->priv->tree_view), 0, 0); /**/ dirs = g_ptr_array_sized_new (128); dir_cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); for (i = 0; i < window->archive->command->files->len; i++) { FileData *fdata = g_ptr_array_index (window->archive->command->files, i); char *dir; if (gtk_entry_get_text (GTK_ENTRY (window->priv->filter_entry)) != NULL) { if (! file_data_respects_filter (window, fdata)) continue; } if (fdata->dir) dir = remove_ending_separator (fdata->full_path); else dir = remove_level_from_path (fdata->full_path); while ((dir != NULL) && (strcmp (dir, "/") != 0)) { char *new_dir; if (g_hash_table_lookup (dir_cache, dir) != NULL) break; new_dir = dir; g_ptr_array_add (dirs, new_dir); g_hash_table_replace (dir_cache, new_dir, "1"); dir = remove_level_from_path (new_dir); } g_free (dir); } g_hash_table_destroy (dir_cache); g_ptr_array_sort (dirs, path_compare); dir_cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) gtk_tree_path_free); /**/ icon = get_mime_type_icon (MIME_TYPE_ARCHIVE); { GtkTreeIter node; char *uri; char *name; uri = g_file_get_uri (window->archive->file); name = g_uri_display_basename (uri); gtk_tree_store_append (window->priv->tree_store, &node, NULL); gtk_tree_store_set (window->priv->tree_store, &node, TREE_COLUMN_ICON, icon, TREE_COLUMN_NAME, name, TREE_COLUMN_PATH, "/", TREE_COLUMN_WEIGHT, PANGO_WEIGHT_BOLD, -1); g_hash_table_replace (dir_cache, "/", gtk_tree_model_get_path (GTK_TREE_MODEL (window->priv->tree_store), &node)); g_free (name); g_free (uri); } g_object_unref (icon); /**/ icon = get_mime_type_icon (MIME_TYPE_DIRECTORY); for (i = 0; i < dirs->len; i++) { char *dir = g_ptr_array_index (dirs, i); char *parent_dir; GtkTreePath *parent_path; GtkTreeIter parent; GtkTreeIter node; parent_dir = remove_level_from_path (dir); if (parent_dir == NULL) continue; parent_path = g_hash_table_lookup (dir_cache, parent_dir); gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->tree_store), &parent, parent_path); gtk_tree_store_append (window->priv->tree_store, &node, &parent); gtk_tree_store_set (window->priv->tree_store, &node, TREE_COLUMN_ICON, icon, TREE_COLUMN_NAME, file_name_from_path (dir), TREE_COLUMN_PATH, dir, TREE_COLUMN_WEIGHT, PANGO_WEIGHT_NORMAL, -1); g_hash_table_replace (dir_cache, dir, gtk_tree_model_get_path (GTK_TREE_MODEL (window->priv->tree_store), &node)); g_free (parent_dir); } g_hash_table_destroy (dir_cache); if (icon != NULL) g_object_unref (icon); g_ptr_array_free (dirs, TRUE); fr_window_update_current_location (window); } static void fr_window_update_filter_bar_visibility (FrWindow *window) { const char *filter; filter = gtk_entry_get_text (GTK_ENTRY (window->priv->filter_entry)); if ((filter == NULL) || (*filter == '\0')) gtk_widget_hide (window->priv->filter_bar); else gtk_widget_show (window->priv->filter_bar); } static void fr_window_update_file_list (FrWindow *window, gboolean update_view) { GPtrArray *files; gboolean free_files = FALSE; if (gtk_widget_get_realized (window->priv->list_view)) gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (window->priv->list_view), 0, 0); if (! window->priv->archive_present || window->priv->archive_new) { if (update_view) gtk_list_store_clear (window->priv->list_store); window->priv->current_view_length = 0; if (window->priv->archive_new) { gtk_widget_set_sensitive (window->priv->list_view, TRUE); gtk_widget_show_all (gtk_widget_get_parent (window->priv->list_view)); } else { gtk_widget_set_sensitive (window->priv->list_view, FALSE); gtk_widget_hide (gtk_widget_get_parent (window->priv->list_view)); } return; } else { gtk_widget_set_sensitive (window->priv->list_view, TRUE); gtk_widget_show_all (gtk_widget_get_parent (window->priv->list_view)); } if (window->priv->give_focus_to_the_list) { gtk_widget_grab_focus (window->priv->list_view); window->priv->give_focus_to_the_list = FALSE; } /**/ fr_window_start_activity_mode (window); if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) { fr_window_compute_list_names (window, window->archive->command->files); files = window->archive->command->files; free_files = FALSE; } else { char *current_dir = g_strdup (fr_window_get_current_location (window)); while (! fr_window_dir_exists_in_archive (window, current_dir)) { char *tmp; fr_window_history_pop (window); tmp = get_parent_dir (current_dir); g_free (current_dir); current_dir = tmp; fr_window_history_add (window, current_dir); } g_free (current_dir); fr_window_compute_list_names (window, window->archive->command->files); files = fr_window_get_current_dir_list (window); free_files = TRUE; } if (files != NULL) window->priv->current_view_length = files->len; else window->priv->current_view_length = 0; if (update_view) fr_window_populate_file_list (window, files); if (free_files) g_ptr_array_free (files, TRUE); } void fr_window_update_list_order (FrWindow *window) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store), get_column_from_sort_method (window->priv->sort_method), window->priv->sort_type); } static void fr_window_update_title (FrWindow *window) { if (! window->priv->archive_present) gtk_window_set_title (GTK_WINDOW (window), _("Archive Manager")); else { char *title; char *name; name = g_uri_display_basename (fr_window_get_archive_uri (window)); title = g_strdup_printf ("%s %s", name, window->archive->read_only ? _("[read only]") : ""); gtk_window_set_title (GTK_WINDOW (window), title); g_free (title); g_free (name); } } static void check_whether_has_a_dir (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { gboolean *has_a_dir = data; FileData *fdata; gtk_tree_model_get (model, iter, COLUMN_FILE_DATA, &fdata, -1); if (file_data_is_dir (fdata)) *has_a_dir = TRUE; } static gboolean selection_has_a_dir (FrWindow *window) { GtkTreeSelection *selection; gboolean has_a_dir = FALSE; if (! gtk_widget_get_realized (window->priv->list_view)) return FALSE; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)); if (selection == NULL) return FALSE; gtk_tree_selection_selected_foreach (selection, check_whether_has_a_dir, &has_a_dir); return has_a_dir; } static void set_active (FrWindow *window, const char *action_name, gboolean is_active) { GtkAction *action; action = gtk_action_group_get_action (window->priv->actions, action_name); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), is_active); } static void fr_window_update_paste_command_sensitivity (FrWindow *window, GtkClipboard *clipboard) { gboolean running; gboolean no_archive; gboolean ro; gboolean compr_file; if (window->priv->closing) return; if (clipboard == NULL) clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), FR_CLIPBOARD); running = window->priv->activity_ref > 0; no_archive = (window->archive == NULL) || ! window->priv->archive_present; ro = ! no_archive && window->archive->read_only; compr_file = ! no_archive && window->archive->is_compressed_file; set_sensitive (window, "Paste", ! no_archive && ! ro && ! running && ! compr_file && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT) && gtk_clipboard_wait_is_target_available (clipboard, FR_SPECIAL_URI_LIST)); } static void fr_window_update_sensitivity (FrWindow *window) { gboolean no_archive; gboolean ro; gboolean file_op; gboolean running; gboolean compr_file; gboolean sel_not_null; gboolean one_file_selected; gboolean dir_selected; int n_selected; if (window->priv->batch_mode) return; running = window->priv->activity_ref > 0; no_archive = (window->archive == NULL) || ! window->priv->archive_present; ro = ! no_archive && window->archive->read_only; file_op = ! no_archive && ! window->priv->archive_new && ! running; compr_file = ! no_archive && window->archive->is_compressed_file; n_selected = fr_window_get_n_selected_files (window); sel_not_null = n_selected > 0; one_file_selected = n_selected == 1; dir_selected = selection_has_a_dir (window); set_sensitive (window, "AddFiles", ! no_archive && ! ro && ! running && ! compr_file); set_sensitive (window, "AddFiles_Toolbar", ! no_archive && ! ro && ! running && ! compr_file); set_sensitive (window, "AddFolder", ! no_archive && ! ro && ! running && ! compr_file); set_sensitive (window, "AddFolder_Toolbar", ! no_archive && ! ro && ! running && ! compr_file); set_sensitive (window, "Copy", ! no_archive && ! ro && ! running && ! compr_file && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT)); set_sensitive (window, "Cut", ! no_archive && ! ro && ! running && ! compr_file && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT)); set_sensitive (window, "Delete", ! no_archive && ! ro && ! window->priv->archive_new && ! running && ! compr_file); set_sensitive (window, "DeselectAll", ! no_archive && sel_not_null); set_sensitive (window, "Extract", file_op); set_sensitive (window, "Extract_Toolbar", file_op); set_sensitive (window, "Find", ! no_archive); set_sensitive (window, "LastOutput", ((window->archive != NULL) && (window->archive->process != NULL) && (window->archive->process->out.raw != NULL))); set_sensitive (window, "New", ! running); set_sensitive (window, "Open", ! running); set_sensitive (window, "Open_Toolbar", ! running); set_sensitive (window, "OpenSelection", file_op && sel_not_null && ! dir_selected); set_sensitive (window, "OpenFolder", file_op && one_file_selected && dir_selected); set_sensitive (window, "Password", ! running && (window->priv->asked_for_password || (! no_archive && window->archive->command->propPassword))); set_sensitive (window, "Properties", file_op); set_sensitive (window, "Close", !running || window->priv->stoppable); set_sensitive (window, "Reload", ! (no_archive || running)); set_sensitive (window, "Rename", ! no_archive && ! ro && ! running && ! compr_file && one_file_selected); set_sensitive (window, "SaveAs", ! no_archive && ! compr_file && ! running); set_sensitive (window, "SelectAll", ! no_archive); set_sensitive (window, "Stop", running && window->priv->stoppable); set_sensitive (window, "TestArchive", ! no_archive && ! running && window->archive->command->propTest); set_sensitive (window, "ViewSelection", file_op && one_file_selected && ! dir_selected); set_sensitive (window, "ViewSelection_Toolbar", file_op && one_file_selected && ! dir_selected); if (window->priv->progress_dialog != NULL) gtk_dialog_set_response_sensitive (GTK_DIALOG (window->priv->progress_dialog), GTK_RESPONSE_OK, running && window->priv->stoppable); fr_window_update_paste_command_sensitivity (window, NULL); set_sensitive (window, "SelectAll", (window->priv->current_view_length > 0) && (window->priv->current_view_length != n_selected)); set_sensitive (window, "DeselectAll", n_selected > 0); set_sensitive (window, "OpenRecent", ! running); set_sensitive (window, "OpenRecent_Toolbar", ! running); set_sensitive (window, "ViewFolders", (window->priv->list_mode == FR_WINDOW_LIST_MODE_AS_DIR)); set_sensitive (window, "ViewAllFiles", ! window->priv->filter_mode); set_sensitive (window, "ViewAsFolder", ! window->priv->filter_mode); } static gboolean location_entry_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, FrWindow *window) { if ((event->keyval == GDK_KEY_Return) || (event->keyval == GDK_KEY_KP_Enter) || (event->keyval == GDK_KEY_ISO_Enter)) { fr_window_go_to_location (window, gtk_entry_get_text (GTK_ENTRY (window->priv->location_entry)), FALSE); } return FALSE; } static gboolean real_close_progress_dialog (gpointer data) { FrWindow *window = data; if (window->priv->hide_progress_timeout != 0) { g_source_remove (window->priv->hide_progress_timeout); window->priv->hide_progress_timeout = 0; } if (window->priv->progress_dialog != NULL) gtk_widget_hide (window->priv->progress_dialog); return FALSE; } static void close_suspend_process(FrWindow *window) { if (window->archive->process != NULL) { start_close_suspend_process(window->archive->process); } } static void close_progress_dialog (FrWindow *window, gboolean close_now) { if (window->priv->progress_timeout != 0) { g_source_remove (window->priv->progress_timeout); window->priv->progress_timeout = 0; } if (! window->priv->batch_mode && gtk_widget_get_mapped (GTK_WIDGET (window))) gtk_widget_hide (window->priv->progress_bar); if (window->priv->progress_dialog == NULL) return; if (close_now) { if (window->priv->hide_progress_timeout != 0) { g_source_remove (window->priv->hide_progress_timeout); window->priv->hide_progress_timeout = 0; } real_close_progress_dialog (window); } else { if (window->priv->hide_progress_timeout != 0) return; window->priv->hide_progress_timeout = g_timeout_add (HIDE_PROGRESS_TIMEOUT_MSECS, real_close_progress_dialog, window); } close_suspend_process(window); } static gboolean progress_dialog_delete_event (GtkWidget *caller, GdkEvent *event, FrWindow *window) { if (window->priv->stoppable) { activate_action_stop (NULL, window); close_progress_dialog (window, TRUE); } return TRUE; } static void open_folder (GtkWindow *parent, const char *folder) { GError *error = NULL; if (folder == NULL) return; if (! gtk_show_uri_on_window (parent, folder, GDK_CURRENT_TIME, &error)) { GtkWidget *d; char *utf8_name; char *message; utf8_name = g_filename_display_name (folder); message = g_strdup_printf (_("Could not display the folder \"%s\""), utf8_name); g_free (utf8_name); d = _gtk_error_dialog_new (parent, GTK_DIALOG_MODAL, NULL, message, "%s", error->message); gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy (d); g_free (message); g_clear_error (&error); } } static void fr_window_view_extraction_destination_folder (FrWindow *window) { open_folder (GTK_WINDOW (window), fr_archive_get_last_extraction_destination (window->archive)); } static void change_button_label (FrWindow *window, GtkWidget *button) { const gchar *state; state = gtk_button_get_label (GTK_BUTTON (button)); if (g_strrstr (_("_Pause"), state) != NULL) { gtk_widget_set_visible (window->priv->pd_progress_bar, FALSE); fr_command_message (window->archive->command, _("Process paused")); gtk_button_set_label (GTK_BUTTON (button), _("_Resume")); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_icon_name ("media-playback-start", GTK_ICON_SIZE_BUTTON)); } else { gtk_widget_set_visible (window->priv->pd_progress_bar, TRUE); fr_command_message (window->archive->command, _("Please wait…")); gtk_button_set_label (GTK_BUTTON(button), _("_Pause")); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_icon_name ("media-playback-pause", GTK_ICON_SIZE_BUTTON)); } } static void fr_state_switch (FrWindow *window) { if ((window->archive->process != NULL) && ((start_switch_state (window->archive->process) == 0))) { change_button_label (window, window->priv->pd_state_button); } } static void progress_dialog_response (GtkDialog *dialog, int response_id, FrWindow *window) { GtkWidget *new_window; switch (response_id) { case GTK_RESPONSE_CANCEL: if (window->priv->stoppable) { activate_action_stop (NULL, window); close_progress_dialog (window, TRUE); } break; case GTK_RESPONSE_CLOSE: close_progress_dialog (window, TRUE); break; case DIALOG_RESPONSE_OPEN_ARCHIVE: new_window = fr_window_new (); gtk_widget_show (new_window); fr_window_archive_open (FR_WINDOW (new_window), window->priv->convert_data.new_file, GTK_WINDOW (new_window)); close_progress_dialog (window, TRUE); break; case DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER: fr_window_view_extraction_destination_folder (window); close_progress_dialog (window, TRUE); break; case DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER_AND_QUIT: fr_window_view_extraction_destination_folder (window); close_progress_dialog (window, TRUE); fr_window_close (window); break; case DIALOG_RESPONSE_QUIT: fr_window_close (window); break; case GTK_RESPONSE_ACCEPT: fr_state_switch (window); break; default: break; } } static char* get_action_description (FrAction action, const char *uri) { char *basename; char *message; basename = (uri != NULL) ? g_uri_display_basename (uri) : NULL; message = NULL; switch (action) { case FR_ACTION_CREATING_NEW_ARCHIVE: /* Translators: %s is a filename */ message = g_strdup_printf (_("Creating \"%s\""), basename); break; case FR_ACTION_LOADING_ARCHIVE: /* Translators: %s is a filename */ message = g_strdup_printf (_("Loading \"%s\""), basename); break; case FR_ACTION_LISTING_CONTENT: /* Translators: %s is a filename */ message = g_strdup_printf (_("Reading \"%s\""), basename); break; case FR_ACTION_DELETING_FILES: /* Translators: %s is a filename */ message = g_strdup_printf (_("Deleting files from \"%s\""), basename); break; case FR_ACTION_TESTING_ARCHIVE: /* Translators: %s is a filename */ message = g_strdup_printf (_("Testing \"%s\""), basename); break; case FR_ACTION_GETTING_FILE_LIST: message = g_strdup (_("Getting the file list")); break; case FR_ACTION_COPYING_FILES_FROM_REMOTE: /* Translators: %s is a filename */ message = g_strdup_printf (_("Copying the files to add to \"%s\""), basename); break; case FR_ACTION_ADDING_FILES: /* Translators: %s is a filename */ message = g_strdup_printf (_("Adding files to \"%s\""), basename); break; case FR_ACTION_EXTRACTING_FILES: /* Translators: %s is a filename */ message = g_strdup_printf (_("Extracting files from \"%s\""), basename); break; case FR_ACTION_COPYING_FILES_TO_REMOTE: message = g_strdup (_("Copying the extracted files to the destination")); break; case FR_ACTION_CREATING_ARCHIVE: /* Translators: %s is a filename */ message = g_strdup_printf (_("Creating \"%s\""), basename); break; case FR_ACTION_SAVING_REMOTE_ARCHIVE: /* Translators: %s is a filename */ message = g_strdup_printf (_("Saving \"%s\""), basename); break; case FR_ACTION_NONE: break; } g_free (basename); return message; } static void progress_dialog_update_action_description (FrWindow *window) { const char *current_archive; char *description; char *description_markup; if (window->priv->progress_dialog == NULL) return; if (window->priv->convert_data.converting) current_archive = window->priv->convert_data.new_file; else if (window->priv->working_archive != NULL) current_archive = window->priv->working_archive; else current_archive = window->priv->archive_uri; g_free (window->priv->pd_last_archive); window->priv->pd_last_archive = NULL; if (current_archive != NULL) window->priv->pd_last_archive = g_strdup (current_archive); description = get_action_description (window->priv->action, window->priv->pd_last_archive); description_markup = g_markup_printf_escaped ("%s", description); gtk_label_set_markup (GTK_LABEL (window->priv->pd_action), description_markup); g_free (description_markup); g_free (description); } static gboolean fr_window_working_archive_cb (FrCommand *command, const char *archive_filename, FrWindow *window) { g_free (window->priv->working_archive); if (archive_filename != NULL) window->priv->working_archive = g_strdup (archive_filename); else window->priv->working_archive = NULL; progress_dialog_update_action_description (window); return TRUE; } static gboolean fr_window_message_cb (FrCommand *command, const char *msg, FrWindow *window) { if (window->priv->pd_last_message != msg) { g_free (window->priv->pd_last_message); window->priv->pd_last_message = g_strdup (msg); } if (window->priv->progress_dialog == NULL) return TRUE; if (msg != NULL) { while (*msg == ' ') msg++; if (*msg == 0) msg = NULL; } if (msg != NULL) { char *utf8_msg; if (! g_utf8_validate (msg, -1, NULL)) utf8_msg = g_locale_to_utf8 (msg, -1 , 0, 0, 0); else utf8_msg = g_strdup (msg); if (utf8_msg == NULL) return TRUE; if (g_utf8_validate (utf8_msg, -1, NULL)) gtk_label_set_text (GTK_LABEL (window->priv->pd_message), utf8_msg); g_free (window->priv->pd_last_message); window->priv->pd_last_message = g_strdup (utf8_msg); g_signal_emit (G_OBJECT (window), fr_window_signals[PROGRESS], 0, window->priv->pd_last_fraction, window->priv->pd_last_message); #ifdef LOG_PROGRESS g_print ("message > %s\n", utf8_msg); #endif g_free (utf8_msg); } else gtk_label_set_text (GTK_LABEL (window->priv->pd_message), ""); progress_dialog_update_action_description (window); return TRUE; } static GtkWidget* dialog_add_button_with_icon_name (GtkDialog *dialog, const gchar *button_text, const gchar *icon_name, gint response_id) { GtkWidget *button; button = gtk_button_new_with_mnemonic (button_text); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON)); gtk_button_set_use_underline (GTK_BUTTON (button), TRUE); gtk_style_context_add_class (gtk_widget_get_style_context (button), "text-button"); gtk_widget_set_can_default (button, TRUE); gtk_widget_show (button); gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, response_id); return button; } static void create_the_progress_dialog (FrWindow *window) { GtkWindow *parent; GtkDialogFlags flags; GtkDialog *d; GtkWidget *hbox; GtkWidget *vbox; GtkWidget *progress_vbox; GtkWidget *lbl; PangoAttrList *attr_list; GdkPixbuf *icon; if (window->priv->progress_dialog != NULL) return; flags = GTK_DIALOG_DESTROY_WITH_PARENT; if (window->priv->batch_mode) { parent = NULL; } else { parent = GTK_WINDOW (window); flags |= GTK_DIALOG_MODAL; } window->priv->progress_dialog = gtk_dialog_new_with_buttons ((window->priv->batch_mode ? window->priv->batch_title : NULL), parent, flags, NULL, NULL); window->priv->pd_quit_button = dialog_add_button_with_icon_name (GTK_DIALOG (window->priv->progress_dialog), _("_Quit"), "application-exit", DIALOG_RESPONSE_QUIT); window->priv->pd_open_archive_button = gtk_dialog_add_button (GTK_DIALOG (window->priv->progress_dialog), _("_Open the Archive"), DIALOG_RESPONSE_OPEN_ARCHIVE); window->priv->pd_open_destination_button = gtk_dialog_add_button (GTK_DIALOG (window->priv->progress_dialog), _("_Show the Files"), DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER); window->priv->pd_open_destination_and_quit_button = gtk_dialog_add_button (GTK_DIALOG (window->priv->progress_dialog), _("Show the _Files and Quit"), DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER_AND_QUIT); window->priv->pd_close_button = dialog_add_button_with_icon_name (GTK_DIALOG (window->priv->progress_dialog), _("_Close"), "window-close", GTK_RESPONSE_CLOSE); window->priv->pd_cancel_button = dialog_add_button_with_icon_name (GTK_DIALOG (window->priv->progress_dialog), _("_Cancel"), "process-stop", GTK_RESPONSE_CANCEL); /*add start button default suspend*/ window->priv->pd_state_button = dialog_add_button_with_icon_name (GTK_DIALOG (window->priv->progress_dialog), _("_Pause"), "media-playback-pause", GTK_RESPONSE_ACCEPT); d = GTK_DIALOG (window->priv->progress_dialog); gtk_window_set_resizable (GTK_WINDOW (d), TRUE); gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_OK); gtk_window_set_default_size (GTK_WINDOW (d), PROGRESS_DIALOG_DEFAULT_WIDTH, -1); /* Main */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 24); gtk_container_set_border_width (GTK_CONTAINER (hbox), 6); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (d)), hbox, FALSE, FALSE, 10); icon = get_mime_type_pixbuf ("package-x-generic", _gtk_widget_lookup_for_size (GTK_WIDGET (window), GTK_ICON_SIZE_DIALOG), NULL); window->priv->pd_icon = gtk_image_new_from_pixbuf (icon); g_object_unref (icon); gtk_widget_set_valign (window->priv->pd_icon, GTK_ALIGN_START); gtk_box_pack_start (GTK_BOX (hbox), window->priv->pd_icon, FALSE, FALSE, 0); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); /* action description */ lbl = window->priv->pd_action = gtk_label_new (""); gtk_widget_set_halign (lbl, GTK_ALIGN_START); gtk_widget_set_valign (lbl, GTK_ALIGN_START); gtk_widget_set_hexpand (lbl, TRUE); gtk_widget_set_vexpand (lbl, TRUE); gtk_widget_set_margin_bottom (lbl, 12); gtk_label_set_xalign (GTK_LABEL (lbl), 0.0); gtk_label_set_ellipsize (GTK_LABEL (lbl), PANGO_ELLIPSIZE_END); gtk_box_pack_start (GTK_BOX (vbox), lbl, TRUE, TRUE, 0); /* archive name */ g_free (window->priv->pd_last_archive); window->priv->pd_last_archive = NULL; if (window->priv->archive_uri != NULL) window->priv->pd_last_archive = g_strdup (window->priv->archive_uri); /* progress and details */ progress_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_widget_set_valign (progress_vbox, GTK_ALIGN_START); gtk_widget_set_hexpand (progress_vbox, TRUE); gtk_widget_set_vexpand (progress_vbox, TRUE); gtk_widget_set_margin_bottom (progress_vbox, 6); gtk_box_pack_start (GTK_BOX (vbox), progress_vbox, TRUE, TRUE, 0); /* progress bar */ window->priv->pd_progress_bar = gtk_progress_bar_new (); gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR (window->priv->pd_progress_bar), ACTIVITY_PULSE_STEP); gtk_box_pack_start (GTK_BOX (progress_vbox), window->priv->pd_progress_bar, TRUE, TRUE, 0); /* details label */ lbl = window->priv->pd_message = gtk_label_new (""); attr_list = pango_attr_list_new (); pango_attr_list_insert (attr_list, pango_attr_size_new (9000)); gtk_label_set_attributes (GTK_LABEL (lbl), attr_list); pango_attr_list_unref (attr_list); gtk_label_set_xalign (GTK_LABEL (lbl), 0.0); gtk_label_set_ellipsize (GTK_LABEL (lbl), PANGO_ELLIPSIZE_END); gtk_box_pack_start (GTK_BOX (progress_vbox), lbl, TRUE, TRUE, 0); gtk_widget_show_all (hbox); progress_dialog_update_action_description (window); /* signals */ g_signal_connect (G_OBJECT (window->priv->progress_dialog), "response", G_CALLBACK (progress_dialog_response), window); g_signal_connect (G_OBJECT (window->priv->progress_dialog), "delete_event", G_CALLBACK (progress_dialog_delete_event), window); } static gboolean display_progress_dialog (gpointer data) { FrWindow *window = data; if (window->priv->progress_timeout != 0) g_source_remove (window->priv->progress_timeout); if (window->priv->use_progress_dialog && (window->priv->progress_dialog != NULL)) { gtk_dialog_set_response_sensitive (GTK_DIALOG (window->priv->progress_dialog), GTK_RESPONSE_OK, window->priv->stoppable); if (! window->priv->non_interactive) gtk_widget_show (GTK_WIDGET (window)); gtk_widget_hide (window->priv->progress_bar); gtk_widget_show (window->priv->progress_dialog); fr_window_message_cb (NULL, window->priv->pd_last_message, window); } window->priv->progress_timeout = 0; return FALSE; } static void open_progress_dialog (FrWindow *window, gboolean open_now) { if (window->priv->hide_progress_timeout != 0) { g_source_remove (window->priv->hide_progress_timeout); window->priv->hide_progress_timeout = 0; } if (open_now) { if (window->priv->progress_timeout != 0) g_source_remove (window->priv->progress_timeout); window->priv->progress_timeout = 0; } if ((window->priv->progress_timeout != 0) || ((window->priv->progress_dialog != NULL) && gtk_widget_get_visible (window->priv->progress_dialog))) return; if (! window->priv->batch_mode && ! open_now) gtk_widget_show (window->priv->progress_bar); create_the_progress_dialog (window); gtk_widget_show (window->priv->pd_cancel_button); gtk_widget_show (window->priv->pd_state_button); gtk_widget_hide (window->priv->pd_open_archive_button); gtk_widget_hide (window->priv->pd_open_destination_button); gtk_widget_hide (window->priv->pd_open_destination_and_quit_button); gtk_widget_hide (window->priv->pd_quit_button); gtk_widget_hide (window->priv->pd_close_button); if (open_now) display_progress_dialog (window); else window->priv->progress_timeout = g_timeout_add (PROGRESS_TIMEOUT_MSECS, display_progress_dialog, window); } static gboolean fr_window_progress_cb (FrArchive *archive, double fraction, FrWindow *window) { window->priv->progress_pulse = (fraction < 0.0); if (! window->priv->progress_pulse) { fraction = CLAMP (fraction, 0.0, 1.0); if (window->priv->progress_dialog != NULL) gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->pd_progress_bar), fraction); gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->progress_bar), fraction); if ((archive != NULL) && (archive->command != NULL) && (archive->command->n_files > 0)) { char *message = NULL; gulong remaining_files; remaining_files = (gulong) (archive->command->n_files - archive->command->n_file + 1); switch (window->priv->action) { case FR_ACTION_ADDING_FILES: case FR_ACTION_EXTRACTING_FILES: case FR_ACTION_DELETING_FILES: message = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%lu file remaining", "%lu files remaining", remaining_files), remaining_files); break; default: break; } if (message != NULL) fr_command_message (archive->command, message); } window->priv->pd_last_fraction = fraction; g_signal_emit (G_OBJECT (window), fr_window_signals[PROGRESS], 0, window->priv->pd_last_fraction, window->priv->pd_last_message); #ifdef LOG_PROGRESS g_print ("progress > %2.2f\n", fraction); #endif } return TRUE; } static void open_progress_dialog_with_open_destination (FrWindow *window) { window->priv->ask_to_open_destination_after_extraction = FALSE; if (window->priv->hide_progress_timeout != 0) { g_source_remove (window->priv->hide_progress_timeout); window->priv->hide_progress_timeout = 0; } if (window->priv->progress_timeout != 0) { g_source_remove (window->priv->progress_timeout); window->priv->progress_timeout = 0; } create_the_progress_dialog (window); gtk_widget_hide (window->priv->pd_cancel_button); gtk_widget_hide (window->priv->pd_state_button); gtk_widget_hide (window->priv->pd_open_archive_button); gtk_widget_show (window->priv->pd_open_destination_button); gtk_widget_show (window->priv->pd_open_destination_and_quit_button); gtk_widget_show (window->priv->pd_quit_button); gtk_widget_show (window->priv->pd_close_button); display_progress_dialog (window); fr_window_progress_cb (NULL, 1.0, window); fr_window_message_cb (NULL, _("Extraction completed successfully"), window); } static void open_progress_dialog_with_open_archive (FrWindow *window) { if (window->priv->hide_progress_timeout != 0) { g_source_remove (window->priv->hide_progress_timeout); window->priv->hide_progress_timeout = 0; } if (window->priv->progress_timeout != 0) { g_source_remove (window->priv->progress_timeout); window->priv->progress_timeout = 0; } create_the_progress_dialog (window); gtk_widget_hide (window->priv->pd_cancel_button); gtk_widget_hide (window->priv->pd_state_button); gtk_widget_hide (window->priv->pd_open_destination_button); gtk_widget_hide (window->priv->pd_open_destination_and_quit_button); gtk_widget_show (window->priv->pd_open_archive_button); gtk_widget_show (window->priv->pd_close_button); display_progress_dialog (window); fr_window_progress_cb (NULL, 1.0, window); fr_window_message_cb (NULL, _("Archive created successfully"), window); } void fr_window_push_message (FrWindow *window, const char *msg) { if (! gtk_widget_get_mapped (GTK_WIDGET (window))) return; gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar), window->priv->progress_cid, msg); } void fr_window_pop_message (FrWindow *window) { if (! gtk_widget_get_mapped (GTK_WIDGET (window))) return; gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar), window->priv->progress_cid); if (window->priv->progress_dialog != NULL) gtk_label_set_text (GTK_LABEL (window->priv->pd_message), ""); } static void action_started (FrArchive *archive, FrAction action, gpointer data) { FrWindow *window = data; char *message; window->priv->action = action; fr_window_start_activity_mode (window); #ifdef MATE_ENABLE_DEBUG debug (DEBUG_INFO, "%s [START] (FR::Window)\n", get_action_name (action)); #endif message = get_action_description (action, window->priv->pd_last_archive); fr_window_push_message (window, message); g_free (message); switch (action) { case FR_ACTION_EXTRACTING_FILES: open_progress_dialog (window, window->priv->ask_to_open_destination_after_extraction || window->priv->convert_data.converting || window->priv->batch_mode); break; default: open_progress_dialog (window, window->priv->batch_mode); break; } if (archive->command != NULL) { fr_command_progress (archive->command, -1.0); fr_command_message (archive->command, _("Please wait…")); } } static void fr_window_add_to_recent_list (FrWindow *window, char *uri) { if (window->priv->batch_mode) return; if (is_temp_dir (uri)) return; if (window->archive->content_type != NULL) { GtkRecentData *recent_data; recent_data = g_new0 (GtkRecentData, 1); recent_data->mime_type = g_content_type_get_mime_type (window->archive->content_type); recent_data->app_name = "Engrampa"; recent_data->app_exec = "engrampa"; gtk_recent_manager_add_full (gtk_recent_manager_get_default (), uri, recent_data); g_free (recent_data->mime_type); g_free (recent_data); } else gtk_recent_manager_add_item (gtk_recent_manager_get_default (), uri); } static void fr_window_remove_from_recent_list (FrWindow *window, char *filename) { if (filename != NULL) gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), filename, NULL); } static void error_dialog_response_cb (GtkDialog *dialog, gint arg1, gpointer user_data) { FrWindow *window = user_data; GtkWindow *dialog_parent = window->priv->error_dialog_parent; window->priv->showing_error_dialog = FALSE; window->priv->error_dialog_parent = NULL; if ((dialog_parent != NULL) && (gtk_widget_get_toplevel (GTK_WIDGET (dialog_parent)) != (GtkWidget*) dialog_parent)) gtk_window_set_modal (dialog_parent, TRUE); gtk_widget_destroy (GTK_WIDGET (dialog)); if (window->priv->destroy_with_error_dialog) gtk_widget_destroy (GTK_WIDGET (window)); } static void fr_window_show_error_dialog (FrWindow *window, GtkWidget *dialog, GtkWindow *dialog_parent, const char *details) { if (window->priv->batch_mode && ! window->priv->use_progress_dialog) { GError *error; error = g_error_new_literal (FR_ERROR, FR_PROC_ERROR_GENERIC, details ? details : _("Command exited abnormally.")); g_signal_emit (window, fr_window_signals[READY], 0, error); gtk_widget_destroy (GTK_WIDGET (window)); return; } close_progress_dialog (window, TRUE); if (window->priv->batch_mode) fr_window_destroy_with_error_dialog (window); if (dialog_parent != NULL) gtk_window_set_modal (dialog_parent, FALSE); g_signal_connect (dialog, "response", G_CALLBACK (error_dialog_response_cb), window); gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); gtk_widget_show (dialog); window->priv->showing_error_dialog = TRUE; window->priv->error_dialog_parent = dialog_parent; } void fr_window_destroy_with_error_dialog (FrWindow *window) { window->priv->destroy_with_error_dialog = TRUE; } static gboolean handle_errors (FrWindow *window, FrArchive *archive, FrAction action, FrProcError *error) { if (error->type == FR_PROC_ERROR_ASK_PASSWORD) { close_progress_dialog (window, TRUE); dlg_ask_password (window); return FALSE; } else if (error->type == FR_PROC_ERROR_UNSUPPORTED_FORMAT) { close_progress_dialog (window, TRUE); dlg_package_installer (window, archive, action); return FALSE; } #if 0 else if (error->type == FR_PROC_ERROR_BAD_CHARSET) { close_progress_dialog (window, TRUE); /* dlg_ask_archive_charset (window); FIXME: implement after feature freeze */ return FALSE; } #endif else if (error->type == FR_PROC_ERROR_STOPPED) { /* nothing */ } else if (error->type != FR_PROC_ERROR_NONE) { char *msg = NULL; char *utf8_name; char *details = NULL; GtkWindow *dialog_parent; GtkWidget *dialog; FrProcess *process = archive->process; GList *output = NULL; if (window->priv->batch_mode) { dialog_parent = NULL; window->priv->load_error_parent_window = NULL; } else { dialog_parent = (GtkWindow *) window; if (window->priv->load_error_parent_window == NULL) window->priv->load_error_parent_window = (GtkWindow *) window; } if ((action == FR_ACTION_LISTING_CONTENT) || (action == FR_ACTION_LOADING_ARCHIVE)) fr_window_archive_close (window); switch (action) { case FR_ACTION_CREATING_NEW_ARCHIVE: dialog_parent = window->priv->load_error_parent_window; msg = _("Could not create the archive"); break; case FR_ACTION_EXTRACTING_FILES: case FR_ACTION_COPYING_FILES_TO_REMOTE: msg = _("An error occurred while extracting files."); break; case FR_ACTION_LOADING_ARCHIVE: dialog_parent = window->priv->load_error_parent_window; utf8_name = g_uri_display_basename (window->priv->archive_uri); msg = g_strdup_printf (_("Could not open \"%s\""), utf8_name); g_free (utf8_name); break; case FR_ACTION_LISTING_CONTENT: msg = _("An error occurred while loading the archive."); break; case FR_ACTION_DELETING_FILES: msg = _("An error occurred while deleting files from the archive."); break; case FR_ACTION_ADDING_FILES: case FR_ACTION_GETTING_FILE_LIST: case FR_ACTION_COPYING_FILES_FROM_REMOTE: msg = _("An error occurred while adding files to the archive."); break; case FR_ACTION_TESTING_ARCHIVE: msg = _("An error occurred while testing archive."); break; case FR_ACTION_SAVING_REMOTE_ARCHIVE: msg = _("An error occurred while saving the archive."); break; default: msg = _("An error occurred."); break; } switch (error->type) { case FR_PROC_ERROR_COMMAND_NOT_FOUND: details = _("Command not found."); break; case FR_PROC_ERROR_EXITED_ABNORMALLY: details = _("Command exited abnormally."); break; case FR_PROC_ERROR_SPAWN: details = error->gerror->message; break; default: if (error->gerror != NULL) details = error->gerror->message; else details = NULL; break; } if (error->type != FR_PROC_ERROR_GENERIC) output = (process->err.raw != NULL) ? process->err.raw : process->out.raw; dialog = _gtk_error_dialog_new (dialog_parent, 0, output, msg, ((details != NULL) ? "%s" : NULL), details); fr_window_show_error_dialog (window, dialog, dialog_parent, details); return FALSE; } return TRUE; } static void convert__action_performed (FrArchive *archive, FrAction action, FrProcError *error, gpointer data) { FrWindow *window = data; #ifdef MATE_ENABLE_DEBUG debug (DEBUG_INFO, "%s [CONVERT::DONE] (FR::Window)\n", get_action_name (action)); #endif if ((action == FR_ACTION_GETTING_FILE_LIST) || (action == FR_ACTION_ADDING_FILES)) { fr_window_stop_activity_mode (window); fr_window_pop_message (window); close_progress_dialog (window, FALSE); } if (action != FR_ACTION_ADDING_FILES) return; handle_errors (window, archive, action, error); if (error->type == FR_PROC_ERROR_NONE) open_progress_dialog_with_open_archive (window); remove_local_directory (window->priv->convert_data.temp_dir); fr_window_convert_data_free (window, FALSE); fr_window_update_sensitivity (window); fr_window_update_statusbar_list_info (window); } static void fr_window_exec_next_batch_action (FrWindow *window); static void action_performed (FrArchive *archive, FrAction action, FrProcError *error, gpointer data) { FrWindow *window = data; gboolean continue_batch = FALSE; char *archive_dir; gboolean temp_dir; #ifdef MATE_ENABLE_DEBUG debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", get_action_name (action)); #endif fr_window_stop_activity_mode (window); fr_window_pop_message (window); continue_batch = handle_errors (window, archive, action, error); if ((error->type == FR_PROC_ERROR_ASK_PASSWORD) || (error->type == FR_PROC_ERROR_UNSUPPORTED_FORMAT) /*|| (error->type == FR_PROC_ERROR_BAD_CHARSET)*/) { return; } switch (action) { case FR_ACTION_CREATING_NEW_ARCHIVE: case FR_ACTION_CREATING_ARCHIVE: close_progress_dialog (window, FALSE); if (error->type != FR_PROC_ERROR_STOPPED) { fr_window_history_clear (window); fr_window_go_to_location (window, "/", TRUE); fr_window_update_dir_tree (window); fr_window_update_title (window); fr_window_update_sensitivity (window); } break; case FR_ACTION_LOADING_ARCHIVE: close_progress_dialog (window, FALSE); if (error->type != FR_PROC_ERROR_NONE) { fr_window_remove_from_recent_list (window, window->priv->archive_uri); if (window->priv->non_interactive) { fr_window_archive_close (window); fr_window_stop_batch (window); } } else { fr_window_add_to_recent_list (window, window->priv->archive_uri); if (! window->priv->non_interactive) gtk_window_present (GTK_WINDOW (window)); } continue_batch = FALSE; g_signal_emit (window, fr_window_signals[ARCHIVE_LOADED], 0, error->type == FR_PROC_ERROR_NONE); break; case FR_ACTION_LISTING_CONTENT: /* update the uri because multi-volume archives can have * a different name after loading. */ g_free (window->priv->archive_uri); window->priv->archive_uri = g_file_get_uri (window->archive->file); close_progress_dialog (window, FALSE); if (error->type != FR_PROC_ERROR_NONE) { fr_window_remove_from_recent_list (window, window->priv->archive_uri); fr_window_archive_close (window); fr_window_set_password (window, NULL); break; } archive_dir = remove_level_from_path (window->priv->archive_uri); temp_dir = is_temp_dir (archive_dir); if (! window->priv->archive_present) { window->priv->archive_present = TRUE; fr_window_history_clear (window); fr_window_history_add (window, "/"); if (! temp_dir) { fr_window_set_open_default_dir (window, archive_dir); fr_window_set_add_default_dir (window, archive_dir); if (! window->priv->freeze_default_dir) fr_window_set_extract_default_dir (window, archive_dir, FALSE); } window->priv->archive_new = FALSE; } g_free (archive_dir); if (! temp_dir) fr_window_add_to_recent_list (window, window->priv->archive_uri); fr_window_update_title (window); fr_window_go_to_location (window, fr_window_get_current_location (window), TRUE); fr_window_update_dir_tree (window); if (! window->priv->batch_mode && window->priv->non_interactive) gtk_window_present (GTK_WINDOW (window)); break; case FR_ACTION_DELETING_FILES: close_progress_dialog (window, FALSE); if (error->type != FR_PROC_ERROR_STOPPED) fr_window_archive_reload (window); return; case FR_ACTION_ADDING_FILES: close_progress_dialog (window, FALSE); /* update the uri because multi-volume archives can have * a different name after creation. */ g_free (window->priv->archive_uri); window->priv->archive_uri = g_file_get_uri (window->archive->file); if (error->type == FR_PROC_ERROR_NONE) { if (window->priv->archive_new) window->priv->archive_new = FALSE; fr_window_add_to_recent_list (window, window->priv->archive_uri); } if (! window->priv->batch_mode && (error->type != FR_PROC_ERROR_STOPPED)) { fr_window_archive_reload (window); return; } break; case FR_ACTION_TESTING_ARCHIVE: close_progress_dialog (window, FALSE); if (error->type == FR_PROC_ERROR_NONE) fr_window_view_last_output (window, _("Test Result")); return; case FR_ACTION_EXTRACTING_FILES: if (error->type != FR_PROC_ERROR_NONE) { if (window->priv->convert_data.converting) { remove_local_directory (window->priv->convert_data.temp_dir); fr_window_convert_data_free (window, TRUE); } break; } if (window->priv->convert_data.converting) { char *source_dir; source_dir = g_filename_to_uri (window->priv->convert_data.temp_dir, NULL, NULL); fr_archive_add_with_wildcard ( window->priv->convert_data.new_archive, "*", NULL, NULL, source_dir, NULL, FALSE, TRUE, window->priv->convert_data.password, window->priv->convert_data.encrypt_header, window->priv->compression, window->priv->convert_data.volume_size); g_free (source_dir); } else { if (window->priv->ask_to_open_destination_after_extraction) open_progress_dialog_with_open_destination (window); else close_progress_dialog (window, FALSE); } break; default: close_progress_dialog (window, FALSE); continue_batch = FALSE; break; } if (window->priv->batch_action == NULL) { fr_window_update_sensitivity (window); fr_window_update_statusbar_list_info (window); } if (continue_batch) { if (error->type != FR_PROC_ERROR_NONE) fr_window_stop_batch (window); else fr_window_exec_next_batch_action (window); } } /* -- selections -- */ #undef DEBUG_GET_DIR_LIST_FROM_PATH static GList * get_dir_list_from_path (FrWindow *window, char *path) { char *dirname; int dirname_l; GList *list = NULL; guint i; if (path[strlen (path) - 1] != '/') dirname = g_strconcat (path, "/", NULL); else dirname = g_strdup (path); dirname_l = strlen (dirname); for (i = 0; i < window->archive->command->files->len; i++) { FileData *fd = g_ptr_array_index (window->archive->command->files, i); gboolean matches = FALSE; #ifdef DEBUG_GET_DIR_LIST_FROM_PATH g_print ("%s <=> %s (%d)\n", dirname, fd->full_path, dirname_l); #endif if (fd->dir) { int full_path_l = strlen (fd->full_path); if ((full_path_l == dirname_l - 1) && (strncmp (dirname, fd->full_path, full_path_l) == 0)) /* example: dirname is '/path/to/dir/' and fd->full_path is '/path/to/dir' */ matches = TRUE; else if (strcmp (dirname, fd->full_path) == 0) matches = TRUE; } if (! matches && strncmp (dirname, fd->full_path, dirname_l) == 0) { matches = TRUE; } if (matches) { #ifdef DEBUG_GET_DIR_LIST_FROM_PATH g_print ("`-> OK\n"); #endif list = g_list_prepend (list, g_strdup (fd->original_path)); } } g_free (dirname); return g_list_reverse (list); } static GList * get_dir_list_from_file_data (FrWindow *window, FileData *fdata) { char *dirname; GList *list; dirname = g_strconcat (fr_window_get_current_location (window), fdata->list_name, NULL); list = get_dir_list_from_path (window, dirname); g_free (dirname); return list; } GList * fr_window_get_file_list_selection (FrWindow *window, gboolean recursive, gboolean *has_dirs) { GtkTreeSelection *selection; GList *selections = NULL, *list, *scan; g_return_val_if_fail (window != NULL, NULL); if (has_dirs != NULL) *has_dirs = FALSE; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)); if (selection == NULL) return NULL; gtk_tree_selection_selected_foreach (selection, add_selected_from_list_view, &selections); list = NULL; for (scan = selections; scan; scan = scan->next) { FileData *fd = scan->data; if (!fd) continue; if (file_data_is_dir (fd)) { if (has_dirs != NULL) *has_dirs = TRUE; if (recursive) list = g_list_concat (list, get_dir_list_from_file_data (window, fd)); } else list = g_list_prepend (list, g_strdup (fd->original_path)); } if (selections) g_list_free (selections); return g_list_reverse (list); } GList * fr_window_get_folder_tree_selection (FrWindow *window, gboolean recursive, gboolean *has_dirs) { GtkTreeSelection *tree_selection; GList *selections, *list, *scan; g_return_val_if_fail (window != NULL, NULL); if (has_dirs != NULL) *has_dirs = FALSE; tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view)); if (tree_selection == NULL) return NULL; selections = NULL; gtk_tree_selection_selected_foreach (tree_selection, add_selected_from_tree_view, &selections); if (selections == NULL) return NULL; if (has_dirs != NULL) *has_dirs = TRUE; list = NULL; for (scan = selections; scan; scan = scan->next) { char *path = scan->data; if (recursive) list = g_list_concat (list, get_dir_list_from_path (window, path)); } path_list_free (selections); return g_list_reverse (list); } GList * fr_window_get_file_list_from_path_list (FrWindow *window, GList *path_list, gboolean *has_dirs) { GtkTreeModel *model; GList *selections, *list, *scan; g_return_val_if_fail (window != NULL, NULL); model = GTK_TREE_MODEL (window->priv->list_store); selections = NULL; if (has_dirs != NULL) *has_dirs = FALSE; for (scan = path_list; scan; scan = scan->next) { GtkTreeRowReference *reference = scan->data; GtkTreePath *path; GtkTreeIter iter; FileData *fdata; path = gtk_tree_row_reference_get_path (reference); if (path == NULL) continue; if (! gtk_tree_model_get_iter (model, &iter, path)) continue; gtk_tree_model_get (model, &iter, COLUMN_FILE_DATA, &fdata, -1); selections = g_list_prepend (selections, fdata); } list = NULL; for (scan = selections; scan; scan = scan->next) { FileData *fd = scan->data; if (!fd) continue; if (file_data_is_dir (fd)) { if (has_dirs != NULL) *has_dirs = TRUE; list = g_list_concat (list, get_dir_list_from_file_data (window, fd)); } else list = g_list_prepend (list, g_strdup (fd->original_path)); } if (selections != NULL) g_list_free (selections); return g_list_reverse (list); } GList * fr_window_get_file_list_pattern (FrWindow *window, const char *pattern) { GRegex **regexps; GList *list; guint i; g_return_val_if_fail (window != NULL, NULL); regexps = search_util_get_regexps (pattern, G_REGEX_CASELESS); list = NULL; for (i = 0; i < window->archive->command->files->len; i++) { FileData *fd = g_ptr_array_index (window->archive->command->files, i); char *utf8_name; /* FIXME: only files in the current location ? */ if (fd == NULL) continue; utf8_name = g_filename_to_utf8 (fd->name, -1, NULL, NULL, NULL); if (match_regexps (regexps, utf8_name, 0)) list = g_list_prepend (list, g_strdup (fd->original_path)); g_free (utf8_name); } free_regexps (regexps); return g_list_reverse (list); } static GList * fr_window_get_file_list (FrWindow *window) { GList *list; guint i; g_return_val_if_fail (window != NULL, NULL); list = NULL; for (i = 0; i < window->archive->command->files->len; i++) { FileData *fd = g_ptr_array_index (window->archive->command->files, i); list = g_list_prepend (list, g_strdup (fd->original_path)); } return g_list_reverse (list); } int fr_window_get_n_selected_files (FrWindow *window) { return gtk_tree_selection_count_selected_rows (gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view))); } /**/ static int dir_tree_button_press_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) { FrWindow *window = data; GtkTreeSelection *selection; if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->tree_view))) return FALSE; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view)); if (selection == NULL) return FALSE; if ((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) { GtkTreePath *path; GtkTreeIter iter; if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->tree_view), (int) event->x, (int) event->y, &path, NULL, NULL, NULL)) { if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->tree_store), &iter, path)) { gtk_tree_path_free (path); return FALSE; } gtk_tree_path_free (path); if (! gtk_tree_selection_iter_is_selected (selection, &iter)) { gtk_tree_selection_unselect_all (selection); gtk_tree_selection_select_iter (selection, &iter); } gtk_menu_popup_at_pointer (GTK_MENU (window->priv->sidebar_folder_popup_menu), (const GdkEvent*) event); } else gtk_tree_selection_unselect_all (selection); return TRUE; } else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 8)) { fr_window_go_back (window); return TRUE; } else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 9)) { fr_window_go_forward (window); return TRUE; } return FALSE; } static FileData * fr_window_get_selected_item_from_file_list (FrWindow *window) { GtkTreeSelection *tree_selection; GList *selection; FileData *fdata = NULL; g_return_val_if_fail (window != NULL, NULL); tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)); if (tree_selection == NULL) return NULL; selection = NULL; gtk_tree_selection_selected_foreach (tree_selection, add_selected_from_list_view, &selection); if ((selection == NULL) || (selection->next != NULL)) { /* return NULL if the selection contains more than one entry. */ g_list_free (selection); return NULL; } fdata = file_data_copy (selection->data); g_list_free (selection); return fdata; } static char * fr_window_get_selected_folder_in_tree_view (FrWindow *window) { GtkTreeSelection *tree_selection; GList *selections; char *path = NULL; g_return_val_if_fail (window != NULL, NULL); tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view)); if (tree_selection == NULL) return NULL; selections = NULL; gtk_tree_selection_selected_foreach (tree_selection, add_selected_from_tree_view, &selections); if (selections != NULL) { path = selections->data; g_list_free (selections); } return path; } void fr_window_current_folder_activated (FrWindow *window, gboolean from_sidebar) { char *dir_path; if (! from_sidebar) { FileData *fdata; char *dir_name; fdata = fr_window_get_selected_item_from_file_list (window); if ((fdata == NULL) || ! file_data_is_dir (fdata)) { file_data_free (fdata); return; } dir_name = g_strdup (fdata->list_name); dir_path = g_strconcat (fr_window_get_current_location (window), dir_name, "/", NULL); g_free (dir_name); file_data_free (fdata); } else dir_path = fr_window_get_selected_folder_in_tree_view (window); fr_window_go_to_location (window, dir_path, FALSE); g_free (dir_path); } static gboolean row_activated_cb (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) { FrWindow *window = data; FileData *fdata; GtkTreeIter iter; if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store), &iter, path)) return FALSE; gtk_tree_model_get (GTK_TREE_MODEL (window->priv->list_store), &iter, COLUMN_FILE_DATA, &fdata, -1); if (! file_data_is_dir (fdata)) { GList *list = g_list_prepend (NULL, fdata->original_path); fr_window_open_files (window, list, FALSE); g_list_free (list); } else if (window->priv->list_mode == FR_WINDOW_LIST_MODE_AS_DIR) { char *new_dir; new_dir = g_strconcat (fr_window_get_current_location (window), fdata->list_name, "/", NULL); fr_window_go_to_location (window, new_dir, FALSE); g_free (new_dir); } return FALSE; } static int file_button_press_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) { FrWindow *window = data; GtkTreeSelection *selection; if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view))) return FALSE; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)); if (selection == NULL) return FALSE; if (window->priv->path_clicked != NULL) { gtk_tree_path_free (window->priv->path_clicked); window->priv->path_clicked = NULL; } if ((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) { GtkTreePath *path; GtkTreeIter iter; int n_selected; if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->list_view), (int) event->x, (int) event->y, &path, NULL, NULL, NULL)) { if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store), &iter, path)) { gtk_tree_path_free (path); return FALSE; } gtk_tree_path_free (path); if (! gtk_tree_selection_iter_is_selected (selection, &iter)) { gtk_tree_selection_unselect_all (selection); gtk_tree_selection_select_iter (selection, &iter); } } else gtk_tree_selection_unselect_all (selection); n_selected = fr_window_get_n_selected_files (window); if ((n_selected == 1) && selection_has_a_dir (window)) gtk_menu_popup_at_pointer (GTK_MENU (window->priv->folder_popup_menu), (const GdkEvent*) event); else gtk_menu_popup_at_pointer (GTK_MENU (window->priv->file_popup_menu), (const GdkEvent*) event); return TRUE; } else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 1)) { GtkTreePath *path = NULL; if (! gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->list_view), (int) event->x, (int) event->y, &path, NULL, NULL, NULL)) { gtk_tree_selection_unselect_all (selection); } if (window->priv->path_clicked != NULL) { gtk_tree_path_free (window->priv->path_clicked); window->priv->path_clicked = NULL; } if (path != NULL) { window->priv->path_clicked = gtk_tree_path_copy (path); gtk_tree_path_free (path); } return FALSE; } else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 8)) { // go back fr_window_go_back (window); return TRUE; } else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 9)) { // go forward fr_window_go_forward (window); return TRUE; } return FALSE; } static int file_button_release_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) { FrWindow *window = data; GtkTreeSelection *selection; if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view))) return FALSE; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)); if (selection == NULL) return FALSE; if (window->priv->path_clicked == NULL) return FALSE; if ((event->type == GDK_BUTTON_RELEASE) && (event->button == 1) && (window->priv->path_clicked != NULL)) { GtkTreePath *path = NULL; if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->list_view), (int) event->x, (int) event->y, &path, NULL, NULL, NULL)) { if ((gtk_tree_path_compare (window->priv->path_clicked, path) == 0) && window->priv->single_click && ! ((event->state & GDK_CONTROL_MASK) || (event->state & GDK_SHIFT_MASK))) { gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE); gtk_tree_view_row_activated (GTK_TREE_VIEW (widget), path, NULL); } } if (path != NULL) gtk_tree_path_free (path); } if (window->priv->path_clicked != NULL) { gtk_tree_path_free (window->priv->path_clicked); window->priv->path_clicked = NULL; } return FALSE; } static gboolean file_motion_notify_callback (GtkWidget *widget, GdkEventMotion *event, gpointer user_data) { FrWindow *window = user_data; GdkCursor *cursor; GtkTreePath *last_hover_path; GdkDisplay *display; GtkTreeIter iter; if (! window->priv->single_click) return FALSE; if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view))) return FALSE; last_hover_path = window->priv->list_hover_path; gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), (int) event->x, (int) event->y, &window->priv->list_hover_path, NULL, NULL, NULL); display = gtk_widget_get_display (GTK_WIDGET (widget)); if (window->priv->list_hover_path != NULL) cursor = gdk_cursor_new_for_display (display, GDK_HAND2); else cursor = NULL; gdk_window_set_cursor (event->window, cursor); /* only redraw if the hover row has changed */ if (!(last_hover_path == NULL && window->priv->list_hover_path == NULL) && (!(last_hover_path != NULL && window->priv->list_hover_path != NULL) || gtk_tree_path_compare (last_hover_path, window->priv->list_hover_path))) { if (last_hover_path) { gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store), &iter, last_hover_path); gtk_tree_model_row_changed (GTK_TREE_MODEL (window->priv->list_store), last_hover_path, &iter); } if (window->priv->list_hover_path) { gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store), &iter, window->priv->list_hover_path); gtk_tree_model_row_changed (GTK_TREE_MODEL (window->priv->list_store), window->priv->list_hover_path, &iter); } } gtk_tree_path_free (last_hover_path); return FALSE; } static gboolean file_leave_notify_callback (GtkWidget *widget, GdkEventCrossing *event, gpointer user_data) { FrWindow *window = user_data; GtkTreeIter iter; if (window->priv->single_click && (window->priv->list_hover_path != NULL)) { gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store), &iter, window->priv->list_hover_path); gtk_tree_model_row_changed (GTK_TREE_MODEL (window->priv->list_store), window->priv->list_hover_path, &iter); gtk_tree_path_free (window->priv->list_hover_path); window->priv->list_hover_path = NULL; } return FALSE; } /* -- drag and drop -- */ static GList * get_uri_list_from_selection_data (char *uri_list) { GList *list = NULL; char **uris; int i; if (uri_list == NULL) return NULL; uris = g_uri_list_extract_uris (uri_list); for (i = 0; uris[i] != NULL; i++) list = g_list_prepend (list, g_strdup (uris[i])); g_strfreev (uris); return g_list_reverse (list); } static gboolean fr_window_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data) { FrWindow *window = user_data; if ((gtk_drag_get_source_widget (context) == window->priv->list_view) || (gtk_drag_get_source_widget (context) == window->priv->tree_view)) { gdk_drag_status (context, 0, time); return FALSE; } return TRUE; } static void fr_window_paste_from_clipboard_data (FrWindow *window, FrClipboardData *data); static FrClipboardData* get_clipboard_data_from_selection_data (FrWindow *window, const char *data) { FrClipboardData *clipboard_data; char **uris; int i; clipboard_data = fr_clipboard_data_new (); uris = g_strsplit (data, "\r\n", -1); clipboard_data->archive_filename = g_strdup (uris[0]); if (window->priv->password_for_paste != NULL) clipboard_data->archive_password = g_strdup (window->priv->password_for_paste); else if (strcmp (uris[1], "") != 0) clipboard_data->archive_password = g_strdup (uris[1]); clipboard_data->op = (strcmp (uris[2], "copy") == 0) ? FR_CLIPBOARD_OP_COPY : FR_CLIPBOARD_OP_CUT; clipboard_data->base_dir = g_strdup (uris[3]); for (i = 4; uris[i] != NULL; i++) if (uris[i][0] != '\0') clipboard_data->files = g_list_prepend (clipboard_data->files, g_strdup (uris[i])); clipboard_data->files = g_list_reverse (clipboard_data->files); g_strfreev (uris); return clipboard_data; } static void fr_window_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time, gpointer extra_data) { FrWindow *window = extra_data; GList *list; gboolean one_file; gboolean is_an_archive; debug (DEBUG_INFO, "::DragDataReceived -->\n"); if ((gtk_drag_get_source_widget (context) == window->priv->list_view) || (gtk_drag_get_source_widget (context) == window->priv->tree_view)) { gtk_drag_finish (context, FALSE, FALSE, time); return; } if (! ((gtk_selection_data_get_length (data) >= 0) && (gtk_selection_data_get_format (data) == 8))) { gtk_drag_finish (context, FALSE, FALSE, time); return; } if (window->priv->activity_ref > 0) { gtk_drag_finish (context, FALSE, FALSE, time); return; } gtk_drag_finish (context, TRUE, FALSE, time); if (gtk_selection_data_get_target (data) == XFR_ATOM) { FrClipboardData *dnd_data; dnd_data = get_clipboard_data_from_selection_data (window, (char*) gtk_selection_data_get_data (data)); dnd_data->current_dir = g_strdup (fr_window_get_current_location (window)); fr_window_paste_from_clipboard_data (window, dnd_data); return; } list = get_uri_list_from_selection_data ((char*) gtk_selection_data_get_data (data)); if (list == NULL) { GtkWidget *d; d = _gtk_error_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL, NULL, _("Could not perform the operation"), NULL); gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy(d); return; } one_file = (list->next == NULL); if (one_file) is_an_archive = uri_is_archive (list->data); else is_an_archive = FALSE; if (window->priv->archive_present && (window->archive != NULL) && ! window->archive->read_only && ! window->archive->is_compressed_file) { if (one_file && is_an_archive) { GtkWidget *d; gint r; d = _gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL, "dialog-question", _("Do you want to add this file to the current archive or open it as a new archive?"), NULL, "gtk-cancel", GTK_RESPONSE_CANCEL, "gtk-add", 0, "gtk-open", 1, NULL); gtk_dialog_set_default_response (GTK_DIALOG (d), 2); r = gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy (GTK_WIDGET (d)); if (r == 0) /* Add */ fr_window_archive_add_dropped_items (window, list, FALSE); else if (r == 1) /* Open */ fr_window_archive_open (window, list->data, GTK_WINDOW (window)); } else fr_window_archive_add_dropped_items (window, list, FALSE); } else { if (one_file && is_an_archive) fr_window_archive_open (window, list->data, GTK_WINDOW (window)); else { GtkWidget *d; int r; d = _gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL, "dialog-question", _("Do you want to create a new archive with these files?"), NULL, "gtk-cancel", GTK_RESPONSE_CANCEL, _("Create _Archive"), GTK_RESPONSE_YES, NULL); gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_YES); r = gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy (GTK_WIDGET (d)); if (r == GTK_RESPONSE_YES) { char *first_item; char *folder; char *local_path = NULL; char *utf8_path = NULL; const char *archive_name; fr_window_free_batch_data (window); fr_window_append_batch_action (window, FR_BATCH_ACTION_ADD, path_list_dup (list), (GFreeFunc) path_list_free); first_item = (char*) list->data; folder = remove_level_from_path (first_item); if (folder != NULL) fr_window_set_open_default_dir (window, folder); if ((list->next != NULL) && (folder != NULL)) { archive_name = file_name_from_path (folder); } else { if (uri_is_local (first_item)) { local_path = g_filename_from_uri (first_item, NULL, NULL); if (local_path) utf8_path = g_filename_to_utf8 (local_path, -1, NULL, NULL, NULL); if (!utf8_path) utf8_path= g_strdup (first_item); g_free (local_path); } else { utf8_path = g_strdup (first_item); } archive_name = file_name_from_path (utf8_path); } show_new_archive_dialog (window, archive_name); g_free (utf8_path); g_free (folder); } } } path_list_free (list); debug (DEBUG_INFO, "::DragDataReceived <--\n"); } static gboolean file_list_drag_begin (GtkWidget *widget, GdkDragContext *context, gpointer data) { FrWindow *window = data; debug (DEBUG_INFO, "::DragBegin -->\n"); if (window->priv->activity_ref > 0) return FALSE; g_free (window->priv->drag_destination_folder); window->priv->drag_destination_folder = NULL; g_free (window->priv->drag_base_dir); window->priv->drag_base_dir = NULL; gdk_property_change (gdk_drag_context_get_source_window (context), XDS_ATOM, TEXT_ATOM, 8, GDK_PROP_MODE_REPLACE, (guchar *) XDS_FILENAME, strlen (XDS_FILENAME)); return TRUE; } static void file_list_drag_end (GtkWidget *widget, GdkDragContext *context, gpointer data) { FrWindow *window = data; debug (DEBUG_INFO, "::DragEnd -->\n"); gdk_property_delete (gdk_drag_context_get_source_window (context), XDS_ATOM); if (window->priv->drag_error != NULL) { _gtk_error_dialog_run (GTK_WINDOW (window), _("Extraction not performed"), "%s", window->priv->drag_error->message); g_clear_error (&window->priv->drag_error); } else if (window->priv->drag_destination_folder != NULL) { fr_window_archive_extract (window, window->priv->drag_file_list, window->priv->drag_destination_folder, window->priv->drag_base_dir, FALSE, FR_OVERWRITE_ASK, FALSE, FALSE); path_list_free (window->priv->drag_file_list); window->priv->drag_file_list = NULL; } debug (DEBUG_INFO, "::DragEnd <--\n"); } /* The following three functions taken from bugzilla * (http://bugzilla.mate.org/attachment.cgi?id=49362&action=view) * Author: Christian Neumair * Copyright: 2005 Free Software Foundation, Inc * License: GPL */ static char * get_xds_atom_value (GdkDragContext *context) { gint actual_length; char *data; char *ret = NULL; g_return_val_if_fail (context != NULL, NULL); g_return_val_if_fail (gdk_drag_context_get_source_window (context) != NULL, NULL); if (gdk_property_get (gdk_drag_context_get_source_window (context), XDS_ATOM, TEXT_ATOM, 0, MAX_XDS_ATOM_VAL_LEN, FALSE, NULL, NULL, &actual_length, (unsigned char **) &data)) { /* add not included \0 to the end of the string */ ret = g_strndup ((gchar *) data, actual_length); g_free (data); } return ret; } static gboolean context_offers_target (GdkDragContext *context, GdkAtom target) { return (g_list_find (gdk_drag_context_list_targets (context), target) != NULL); } static gboolean caja_xds_dnd_is_valid_xds_context (GdkDragContext *context) { char *tmp; gboolean ret; g_return_val_if_fail (context != NULL, FALSE); tmp = NULL; if (context_offers_target (context, XDS_ATOM)) { tmp = get_xds_atom_value (context); } ret = (tmp != NULL); g_free (tmp); return ret; } static char * get_selection_data_from_clipboard_data (FrWindow *window, FrClipboardData *data) { GString *list; char *local_filename; GList *scan; list = g_string_new (NULL); local_filename = g_file_get_uri (window->archive->local_copy); g_string_append (list, local_filename); g_free (local_filename); g_string_append (list, "\r\n"); if (window->priv->password != NULL) g_string_append (list, window->priv->password); g_string_append (list, "\r\n"); g_string_append (list, (data->op == FR_CLIPBOARD_OP_COPY) ? "copy" : "cut"); g_string_append (list, "\r\n"); g_string_append (list, data->base_dir); g_string_append (list, "\r\n"); for (scan = data->files; scan; scan = scan->next) { g_string_append (list, scan->data); g_string_append (list, "\r\n"); } return g_string_free (list, FALSE); } static gboolean fr_window_folder_tree_drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data) { FrWindow *window = user_data; GList *file_list; char *destination; char *destination_folder; debug (DEBUG_INFO, "::DragDataGet -->\n"); if (window->priv->activity_ref > 0) return FALSE; file_list = fr_window_get_folder_tree_selection (window, TRUE, NULL); if (file_list == NULL) return FALSE; if (gtk_selection_data_get_target (selection_data) == XFR_ATOM) { FrClipboardData *tmp; char *data; tmp = fr_clipboard_data_new (); tmp->files = file_list; tmp->op = FR_CLIPBOARD_OP_COPY; tmp->base_dir = g_strdup (fr_window_get_current_location (window)); data = get_selection_data_from_clipboard_data (window, tmp); gtk_selection_data_set (selection_data, XFR_ATOM, 8, (guchar *) data, strlen (data)); fr_clipboard_data_unref (tmp); g_free (data); return TRUE; } if (! caja_xds_dnd_is_valid_xds_context (context)) return FALSE; destination = get_xds_atom_value (context); g_return_val_if_fail (destination != NULL, FALSE); destination_folder = remove_level_from_path (destination); g_free (destination); /* check whether the extraction can be performed in the destination * folder */ g_clear_error (&window->priv->drag_error); if (! check_permissions (destination_folder, R_OK | W_OK)) { char *destination_folder_display_name; destination_folder_display_name = g_filename_display_name (destination_folder); window->priv->drag_error = g_error_new (FR_ERROR, 0, _("You don't have the right permissions to extract archives in the folder \"%s\""), destination_folder_display_name); g_free (destination_folder_display_name); } if (window->priv->drag_error == NULL) { g_free (window->priv->drag_destination_folder); g_free (window->priv->drag_base_dir); path_list_free (window->priv->drag_file_list); window->priv->drag_destination_folder = g_strdup (destination_folder); window->priv->drag_base_dir = fr_window_get_selected_folder_in_tree_view (window); window->priv->drag_file_list = file_list; } g_free (destination_folder); /* sends back the response */ gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (guchar *) ((window->priv->drag_error == NULL) ? "S" : "E"), 1); debug (DEBUG_INFO, "::DragDataGet <--\n"); return TRUE; } gboolean fr_window_file_list_drag_data_get (FrWindow *window, GdkDragContext *context, GtkSelectionData *selection_data, GList *path_list) { char *destination; char *destination_folder; debug (DEBUG_INFO, "::DragDataGet -->\n"); if (window->priv->path_clicked != NULL) { gtk_tree_path_free (window->priv->path_clicked); window->priv->path_clicked = NULL; } if (window->priv->activity_ref > 0) return FALSE; if (gtk_selection_data_get_target (selection_data) == XFR_ATOM) { FrClipboardData *tmp; char *data; tmp = fr_clipboard_data_new (); tmp->files = fr_window_get_file_list_selection (window, TRUE, NULL); tmp->op = FR_CLIPBOARD_OP_COPY; tmp->base_dir = g_strdup (fr_window_get_current_location (window)); data = get_selection_data_from_clipboard_data (window, tmp); gtk_selection_data_set (selection_data, XFR_ATOM, 8, (guchar *) data, strlen (data)); fr_clipboard_data_unref (tmp); g_free (data); return TRUE; } if (! caja_xds_dnd_is_valid_xds_context (context)) return FALSE; destination = get_xds_atom_value (context); g_return_val_if_fail (destination != NULL, FALSE); destination_folder = remove_level_from_path (destination); g_free (destination); /* check whether the extraction can be performed in the destination * folder */ g_clear_error (&window->priv->drag_error); if (! check_permissions (destination_folder, R_OK | W_OK)) { char *destination_folder_display_name; destination_folder_display_name = g_filename_display_name (destination_folder); window->priv->drag_error = g_error_new (FR_ERROR, 0, _("You don't have the right permissions to extract archives in the folder \"%s\""), destination_folder_display_name); g_free (destination_folder_display_name); } if (window->priv->drag_error == NULL) { g_free (window->priv->drag_destination_folder); g_free (window->priv->drag_base_dir); path_list_free (window->priv->drag_file_list); window->priv->drag_destination_folder = g_strdup (destination_folder); window->priv->drag_base_dir = g_strdup (fr_window_get_current_location (window)); window->priv->drag_file_list = fr_window_get_file_list_from_path_list (window, path_list, NULL); } g_free (destination_folder); /* sends back the response */ gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (guchar *) ((window->priv->drag_error == NULL) ? "S" : "E"), 1); debug (DEBUG_INFO, "::DragDataGet <--\n"); return TRUE; } /* -- window_new -- */ static void fr_window_deactivate_filter (FrWindow *window) { window->priv->filter_mode = FALSE; window->priv->list_mode = window->priv->last_list_mode; gtk_entry_set_text (GTK_ENTRY (window->priv->filter_entry), ""); fr_window_update_filter_bar_visibility (window); gtk_list_store_clear (window->priv->list_store); fr_window_update_columns_visibility (window); fr_window_update_file_list (window, TRUE); fr_window_update_dir_tree (window); fr_window_update_current_location (window); } static gboolean key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data) { FrWindow *window = data; gboolean retval = FALSE; gboolean alt; if (gtk_widget_has_focus (window->priv->location_entry)) return FALSE; if (gtk_widget_has_focus (window->priv->filter_entry)) { switch (event->keyval) { case GDK_KEY_Escape: fr_window_deactivate_filter (window); retval = TRUE; break; default: break; } return retval; } alt = (event->state & GDK_MOD1_MASK) == GDK_MOD1_MASK; switch (event->keyval) { case GDK_KEY_Escape: activate_action_stop (NULL, window); if (window->priv->filter_mode) fr_window_deactivate_filter (window); retval = TRUE; break; case GDK_KEY_F10: if (event->state & GDK_SHIFT_MASK) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)); if (selection == NULL) return FALSE; gtk_menu_popup_at_pointer (GTK_MENU (window->priv->file_popup_menu), (const GdkEvent*) event); retval = TRUE; } break; case GDK_KEY_Up: case GDK_KEY_KP_Up: if (alt) { fr_window_go_up_one_level (window); retval = TRUE; } break; case GDK_KEY_BackSpace: fr_window_go_up_one_level (window); retval = TRUE; break; case GDK_KEY_Right: case GDK_KEY_KP_Right: if (alt) { fr_window_go_forward (window); retval = TRUE; } break; case GDK_KEY_Left: case GDK_KEY_KP_Left: if (alt) { fr_window_go_back (window); retval = TRUE; } break; case GDK_KEY_Home: case GDK_KEY_KP_Home: if (alt) { fr_window_go_to_location (window, "/", FALSE); retval = TRUE; } break; default: break; } return retval; } static gboolean dir_tree_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data) { FrWindow *window = user_data; GtkTreeIter iter; if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { char *path; gtk_tree_model_get (GTK_TREE_MODEL (window->priv->tree_store), &iter, TREE_COLUMN_PATH, &path, -1); fr_window_go_to_location (window, path, FALSE); g_free (path); } return FALSE; } static gboolean selection_changed_cb (GtkTreeSelection *selection, gpointer user_data) { FrWindow *window = user_data; fr_window_update_statusbar_list_info (window); fr_window_update_sensitivity (window); return FALSE; } static void fr_window_delete_event_cb (GtkWidget *caller, GdkEvent *event, FrWindow *window) { fr_window_close (window); } static gboolean is_single_click_policy (FrWindow *window) { gboolean result = FALSE; if (window->priv->settings_caja) { char *value; value = g_settings_get_string (window->priv->settings_caja, CAJA_CLICK_POLICY); result = (value != NULL) && (strncmp (value, "single", 6) == 0); g_free (value); } return result; } static void filename_cell_data_func (GtkTreeViewColumn *column, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, FrWindow *window) { char *text; PangoUnderline underline; gtk_tree_model_get (model, iter, COLUMN_NAME, &text, -1); if (window->priv->single_click) { GtkTreePath *path; path = gtk_tree_model_get_path (model, iter); if ((window->priv->list_hover_path == NULL) || gtk_tree_path_compare (path, window->priv->list_hover_path)) underline = PANGO_UNDERLINE_NONE; else underline = PANGO_UNDERLINE_SINGLE; gtk_tree_path_free (path); } else underline = PANGO_UNDERLINE_NONE; g_object_set (G_OBJECT (renderer), "text", text, "underline", underline, NULL); g_free (text); } static void add_dir_tree_columns (FrWindow *window, GtkTreeView *treeview) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; GValue value = { 0, }; /* First column. */ column = gtk_tree_view_column_new (); gtk_tree_view_column_set_title (column, _("Folders")); /* icon */ renderer = gtk_cell_renderer_pixbuf_new (); gtk_tree_view_column_pack_start (column, renderer, FALSE); gtk_tree_view_column_set_attributes (column, renderer, "pixbuf", TREE_COLUMN_ICON, NULL); /* name */ renderer = gtk_cell_renderer_text_new (); g_value_init (&value, PANGO_TYPE_ELLIPSIZE_MODE); g_value_set_enum (&value, PANGO_ELLIPSIZE_END); g_object_set_property (G_OBJECT (renderer), "ellipsize", &value); g_value_unset (&value); gtk_tree_view_column_pack_start (column, renderer, TRUE); gtk_tree_view_column_set_attributes (column, renderer, "text", TREE_COLUMN_NAME, "weight", TREE_COLUMN_WEIGHT, NULL); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_column_set_sort_column_id (column, TREE_COLUMN_NAME); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); } static void add_file_list_columns (FrWindow *window, GtkTreeView *treeview) { static const char *titles[] = {NC_("File", "Size"), NC_("File", "Type"), NC_("File", "Date Modified"), NC_("File", "Location")}; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GValue value = { 0, }; int i, j, w; /* First column. */ window->priv->filename_column = column = gtk_tree_view_column_new (); gtk_tree_view_column_set_title (column, C_("File", "Name")); /* emblem */ renderer = gtk_cell_renderer_pixbuf_new (); gtk_tree_view_column_pack_end (column, renderer, FALSE); gtk_tree_view_column_set_attributes (column, renderer, "pixbuf", COLUMN_EMBLEM, NULL); /* icon */ renderer = gtk_cell_renderer_pixbuf_new (); gtk_tree_view_column_pack_start (column, renderer, FALSE); gtk_tree_view_column_set_attributes (column, renderer, "pixbuf", COLUMN_ICON, NULL); /* name */ window->priv->single_click = is_single_click_policy (window); renderer = gtk_cell_renderer_text_new (); g_value_init (&value, PANGO_TYPE_ELLIPSIZE_MODE); g_value_set_enum (&value, PANGO_ELLIPSIZE_END); g_object_set_property (G_OBJECT (renderer), "ellipsize", &value); g_value_unset (&value); gtk_tree_view_column_pack_start (column, renderer, TRUE); gtk_tree_view_column_set_attributes (column, renderer, "text", COLUMN_NAME, NULL); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED); w = g_settings_get_int (window->priv->settings_listing, PREF_LISTING_NAME_COLUMN_WIDTH); if (w <= 0) w = DEFAULT_NAME_COLUMN_WIDTH; gtk_tree_view_column_set_fixed_width (column, w); gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME); gtk_tree_view_column_set_cell_data_func (column, renderer, (GtkTreeCellDataFunc) filename_cell_data_func, window, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); /* Other columns */ for (j = 0, i = COLUMN_SIZE; i < NUMBER_OF_COLUMNS; i++, j++) { GValue value_oc = { 0, }; renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (g_dpgettext2 (NULL, "File", titles[j]), renderer, "text", i, NULL); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width (column, OTHER_COLUMNS_WIDTH); gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_column_set_sort_column_id (column, i); g_value_init (&value_oc, PANGO_TYPE_ELLIPSIZE_MODE); g_value_set_enum (&value_oc, PANGO_ELLIPSIZE_END); g_object_set_property (G_OBJECT (renderer), "ellipsize", &value_oc); g_value_unset (&value_oc); gtk_tree_view_append_column (treeview, column); } } static int name_column_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { FileData *fdata1, *fdata2; gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1); gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1); return sort_by_name (&fdata1, &fdata2); } static int size_column_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { FileData *fdata1, *fdata2; gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1); gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1); return sort_by_size (&fdata1, &fdata2); } static int type_column_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { FileData *fdata1, *fdata2; gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1); gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1); return sort_by_type (&fdata1, &fdata2); } static int time_column_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { FileData *fdata1, *fdata2; gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1); gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1); return sort_by_time (&fdata1, &fdata2); } static int path_column_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { FileData *fdata1, *fdata2; gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1); gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1); return sort_by_path (&fdata1, &fdata2); } static int no_sort_column_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { return -1; } static void sort_column_changed_cb (GtkTreeSortable *sortable, gpointer user_data) { FrWindow *window = user_data; GtkSortType order; int column_id; if (! gtk_tree_sortable_get_sort_column_id (sortable, &column_id, &order)) return; window->priv->sort_method = get_sort_method_from_column (column_id); window->priv->sort_type = order; /*set_active (window, get_action_from_sort_method (window->priv->sort_method), TRUE); set_active (window, "SortReverseOrder", (window->priv->sort_type == GTK_SORT_DESCENDING));*/ } static gboolean fr_window_show_cb (GtkWidget *widget, FrWindow *window) { fr_window_update_current_location (window); set_active (window, "ViewToolbar", g_settings_get_boolean (window->priv->settings_ui, PREF_UI_VIEW_TOOLBAR)); set_active (window, "ViewStatusbar", g_settings_get_boolean (window->priv->settings_ui, PREF_UI_VIEW_STATUSBAR)); window->priv->view_folders = g_settings_get_boolean (window->priv->settings_ui, PREF_UI_VIEW_FOLDERS); set_active (window, "ViewFolders", window->priv->view_folders); fr_window_update_filter_bar_visibility (window); return TRUE; } /* preferences changes notification callbacks */ static void pref_history_len_changed (GSettings *settings, const char *key, gpointer user_data) { FrWindow *window = user_data; int limit; GtkAction *action; limit = g_settings_get_int (settings, PREF_UI_HISTORY_LEN); action = gtk_action_group_get_action (window->priv->actions, "OpenRecent"); gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (action), limit); action = gtk_action_group_get_action (window->priv->actions, "OpenRecent_Toolbar"); gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (action), limit); } static void pref_view_toolbar_changed (GSettings *settings, const char *key, gpointer user_data) { FrWindow *window = user_data; fr_window_set_toolbar_visibility (window, g_settings_get_boolean (settings, key)); } static void pref_view_statusbar_changed (GSettings *settings, const char *key, gpointer user_data) { FrWindow *window = user_data; fr_window_set_statusbar_visibility (window, g_settings_get_boolean (settings, key)); } static void pref_view_folders_changed (GSettings *settings, const char *key, gpointer user_data) { FrWindow *window = user_data; fr_window_set_folders_visibility (window, g_settings_get_boolean (settings, key)); } static void pref_show_field_changed (GSettings *settings, const char *key, gpointer user_data) { FrWindow *window = user_data; fr_window_update_columns_visibility (window); } static void pref_click_policy_changed (GSettings *settings, const char *key, gpointer user_data) { FrWindow *window = user_data; GdkWindow *win = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view)); GdkDisplay *display; window->priv->single_click = is_single_click_policy (window); gdk_window_set_cursor (win, NULL); display = gtk_widget_get_display (GTK_WIDGET (window->priv->list_view)); if (display != NULL) gdk_display_flush (display); } static void pref_use_mime_icons_changed (GSettings *settings, const char *key, gpointer user_data) { FrWindow *window = user_data; if (tree_pixbuf_hash != NULL) { g_hash_table_foreach (tree_pixbuf_hash, gh_unref_pixbuf, NULL); g_hash_table_destroy (tree_pixbuf_hash); tree_pixbuf_hash = g_hash_table_new (g_str_hash, g_str_equal); } fr_window_update_file_list (window, FALSE); fr_window_update_dir_tree (window); } static void theme_changed_cb (GtkIconTheme *theme, FrWindow *window) { file_list_icon_size = _gtk_widget_lookup_for_size (GTK_WIDGET (window), FILE_LIST_ICON_SIZE); if (tree_pixbuf_hash != NULL) { g_hash_table_foreach (tree_pixbuf_hash, gh_unref_pixbuf, NULL); g_hash_table_destroy (tree_pixbuf_hash); tree_pixbuf_hash = g_hash_table_new (g_str_hash, g_str_equal); } fr_window_update_file_list (window, TRUE); fr_window_update_dir_tree (window); } static gboolean fr_window_stoppable_cb (FrCommand *command, gboolean stoppable, FrWindow *window) { window->priv->stoppable = stoppable; set_sensitive (window, "Stop", stoppable); if (window->priv->progress_dialog != NULL) gtk_dialog_set_response_sensitive (GTK_DIALOG (window->priv->progress_dialog), GTK_RESPONSE_OK, stoppable); return TRUE; } static gboolean fr_window_fake_load (FrArchive *archive, gpointer data) { /* fake loads are disabled to allow exact progress dialogs (#153281) */ return FALSE; #if 0 FrWindow *window = data; gboolean add_after_opening = FALSE; gboolean extract_after_opening = FALSE; GList *scan; /* fake loads are used only in batch mode to avoid unnecessary * archive loadings. */ if (! window->priv->batch_mode) return FALSE; /* Check whether there is an ADD or EXTRACT action in the batch list. */ for (scan = window->priv->batch_action; scan; scan = scan->next) { FRBatchAction *action; action = (FRBatchAction *) scan->data; if (action->type == FR_BATCH_ACTION_ADD) { add_after_opening = TRUE; break; } if ((action->type == FR_BATCH_ACTION_EXTRACT) || (action->type == FR_BATCH_ACTION_EXTRACT_HERE) || (action->type == FR_BATCH_ACTION_EXTRACT_INTERACT)) { extract_after_opening = TRUE; break; } } /* use fake load when in batch mode and the archive type supports all * of the required features */ return (window->priv->batch_mode && ! (add_after_opening && window->priv->update_dropped_files && ! archive->command->propAddCanUpdate) && ! (add_after_opening && ! window->priv->update_dropped_files && ! archive->command->propAddCanReplace) && ! (extract_after_opening && !archive->command->propCanExtractAll)); #endif } static void menu_item_select_cb (GtkMenuItem *proxy, FrWindow *window) { GtkAction *action; char *message; action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (proxy)); g_return_if_fail (action != NULL); g_object_get (G_OBJECT (action), "tooltip", &message, NULL); if (message) { gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar), window->priv->help_message_cid, message); g_free (message); } } static void menu_item_deselect_cb (GtkMenuItem *proxy, FrWindow *window) { gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar), window->priv->help_message_cid); } static void disconnect_proxy_cb (GtkUIManager *manager, GtkAction *action, GtkWidget *proxy, FrWindow *window) { if (GTK_IS_MENU_ITEM (proxy)) { g_signal_handlers_disconnect_by_func (proxy, G_CALLBACK (menu_item_select_cb), window); g_signal_handlers_disconnect_by_func (proxy, G_CALLBACK (menu_item_deselect_cb), window); } } static void connect_proxy_cb (GtkUIManager *manager, GtkAction *action, GtkWidget *proxy, FrWindow *window) { if (GTK_IS_MENU_ITEM (proxy)) { g_signal_connect (proxy, "select", G_CALLBACK (menu_item_select_cb), window); g_signal_connect (proxy, "deselect", G_CALLBACK (menu_item_deselect_cb), window); } } static void view_as_radio_action (GtkAction *action, GtkRadioAction *current, gpointer data) { FrWindow *window = data; fr_window_set_list_mode (window, gtk_radio_action_get_current_value (current)); } static void sort_by_radio_action (GtkAction *action, GtkRadioAction *current, gpointer data) { FrWindow *window = data; window->priv->sort_method = gtk_radio_action_get_current_value (current); window->priv->sort_type = GTK_SORT_ASCENDING; fr_window_update_list_order (window); } static void recent_chooser_item_activated_cb (GtkRecentChooser *chooser, FrWindow *window) { char *uri; uri = gtk_recent_chooser_get_current_uri (chooser); if (uri != NULL) { fr_window_archive_open (window, uri, GTK_WINDOW (window)); g_free (uri); } } static void fr_window_init_recent_chooser (FrWindow *window, GtkRecentChooser *chooser) { GtkRecentFilter *filter; int i; g_return_if_fail (chooser != NULL); filter = gtk_recent_filter_new (); gtk_recent_filter_set_name (filter, _("All archives")); for (i = 0; open_type[i] != -1; i++) gtk_recent_filter_add_mime_type (filter, mime_type_desc[open_type[i]].mime_type); gtk_recent_filter_add_application (filter, "Engrampa"); gtk_recent_chooser_add_filter (chooser, filter); gtk_recent_chooser_set_local_only (chooser, FALSE); gtk_recent_chooser_set_limit (chooser, g_settings_get_int (window->priv->settings_ui, PREF_UI_HISTORY_LEN)); gtk_recent_chooser_set_show_not_found (chooser, TRUE); gtk_recent_chooser_set_sort_type (chooser, GTK_RECENT_SORT_MRU); g_signal_connect (G_OBJECT (chooser), "item_activated", G_CALLBACK (recent_chooser_item_activated_cb), window); } static void close_sidepane_button_clicked_cb (GtkButton *button, FrWindow *window) { fr_window_set_folders_visibility (window, FALSE); } static void fr_window_activate_filter (FrWindow *window) { GtkTreeView *tree_view = GTK_TREE_VIEW (window->priv->list_view); GtkTreeViewColumn *column; fr_window_update_filter_bar_visibility (window); window->priv->list_mode = FR_WINDOW_LIST_MODE_FLAT; gtk_list_store_clear (window->priv->list_store); column = gtk_tree_view_get_column (tree_view, 4); gtk_tree_view_column_set_visible (column, TRUE); fr_window_update_file_list (window, TRUE); fr_window_update_dir_tree (window); fr_window_update_current_location (window); } static void filter_entry_activate_cb (GtkEntry *entry, FrWindow *window) { fr_window_activate_filter (window); } static void filter_entry_icon_release_cb (GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEventButton *event, gpointer user_data) { FrWindow *window = FR_WINDOW (user_data); if ((event->button == 1) && (icon_pos == GTK_ENTRY_ICON_SECONDARY)) fr_window_deactivate_filter (window); } static void fr_window_attach (FrWindow *window, GtkWidget *child, FrWindowArea area) { int position; g_return_if_fail (window != NULL); g_return_if_fail (FR_IS_WINDOW (window)); g_return_if_fail (child != NULL); g_return_if_fail (GTK_IS_WIDGET (child)); switch (area) { case FR_WINDOW_AREA_MENUBAR: position = 0; break; case FR_WINDOW_AREA_TOOLBAR: position = 1; break; case FR_WINDOW_AREA_LOCATIONBAR: position = 2; break; case FR_WINDOW_AREA_CONTENTS: position = 3; if (window->priv->contents != NULL) gtk_widget_destroy (window->priv->contents); window->priv->contents = child; gtk_widget_set_vexpand (child, TRUE); break; case FR_WINDOW_AREA_FILTERBAR: position = 4; break; case FR_WINDOW_AREA_STATUSBAR: position = 5; break; default: g_critical ("%s: area not recognized!", G_STRFUNC); return; break; } gtk_widget_set_hexpand (child, TRUE); gtk_grid_attach (GTK_GRID (window->priv->layout), child, 0, position, 1, 1); } static void set_action_important (GtkUIManager *ui, const char *action_name) { GtkAction *action; action = gtk_ui_manager_get_action (ui, action_name); g_object_set (action, "is_important", TRUE, NULL); g_object_unref (action); } static void fr_window_construct (FrWindow *window) { GtkWidget *menubar; GtkWidget *toolbar; GtkWidget *list_scrolled_window; GtkWidget *location_box; GtkStatusbar *statusbar; GtkWidget *statusbar_box; GtkWidget *filter_box; GtkWidget *tree_scrolled_window; GtkWidget *sidepane_title; GtkWidget *sidepane_title_box; GtkWidget *sidepane_title_label; GtkWidget *close_sidepane_button; GtkTreeSelection *selection; GtkActionGroup *actions; GtkAction *action; GtkUIManager *ui; GError *error = NULL; GSettingsSchemaSource *schema_source; GSettingsSchema *caja_schema; /* data common to all windows. */ if (tree_pixbuf_hash == NULL) tree_pixbuf_hash = g_hash_table_new (g_str_hash, g_str_equal); if (icon_theme == NULL) icon_theme = gtk_icon_theme_get_default (); /* Create the settings objects */ window->priv->settings_listing = g_settings_new (ENGRAMPA_SCHEMA_LISTING); window->priv->settings_ui = g_settings_new (ENGRAMPA_SCHEMA_UI); window->priv->settings_general = g_settings_new (ENGRAMPA_SCHEMA_GENERAL); window->priv->settings_dialogs = g_settings_new (ENGRAMPA_SCHEMA_DIALOGS); schema_source = g_settings_schema_source_get_default (); caja_schema = g_settings_schema_source_lookup (schema_source, CAJA_SCHEMA, FALSE); if (caja_schema) { window->priv->settings_caja = g_settings_new (CAJA_SCHEMA); g_settings_schema_unref (caja_schema); } /* Create the application. */ window->priv->layout = gtk_grid_new (); gtk_container_add (GTK_CONTAINER (window), window->priv->layout); gtk_widget_show (window->priv->layout); gtk_window_set_title (GTK_WINDOW (window), _("Archive Manager")); g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (fr_window_delete_event_cb), window); g_signal_connect (G_OBJECT (window), "show", G_CALLBACK (fr_window_show_cb), window); window->priv->theme_changed_handler_id = g_signal_connect (icon_theme, "changed", G_CALLBACK (theme_changed_cb), window); file_list_icon_size = _gtk_widget_lookup_for_size (GTK_WIDGET (window), FILE_LIST_ICON_SIZE); gtk_window_set_default_size (GTK_WINDOW (window), g_settings_get_int (window->priv->settings_ui, PREF_UI_WINDOW_WIDTH), g_settings_get_int (window->priv->settings_ui, PREF_UI_WINDOW_HEIGHT)); gtk_drag_dest_set (GTK_WIDGET (window), GTK_DEST_DEFAULT_ALL, target_table, G_N_ELEMENTS (target_table), GDK_ACTION_COPY); g_signal_connect (G_OBJECT (window), "drag_data_received", G_CALLBACK (fr_window_drag_data_received), window); g_signal_connect (G_OBJECT (window), "drag_motion", G_CALLBACK (fr_window_drag_motion), window); g_signal_connect (G_OBJECT (window), "key_press_event", G_CALLBACK (key_press_cb), window); /* Initialize Data. */ window->archive = fr_archive_new (); g_signal_connect (G_OBJECT (window->archive), "start", G_CALLBACK (action_started), window); g_signal_connect (G_OBJECT (window->archive), "done", G_CALLBACK (action_performed), window); g_signal_connect (G_OBJECT (window->archive), "progress", G_CALLBACK (fr_window_progress_cb), window); g_signal_connect (G_OBJECT (window->archive), "message", G_CALLBACK (fr_window_message_cb), window); g_signal_connect (G_OBJECT (window->archive), "stoppable", G_CALLBACK (fr_window_stoppable_cb), window); g_signal_connect (G_OBJECT (window->archive), "working_archive", G_CALLBACK (fr_window_working_archive_cb), window); fr_archive_set_fake_load_func (window->archive, fr_window_fake_load, window); window->priv->sort_method = g_settings_get_enum (window->priv->settings_listing, PREF_LISTING_SORT_METHOD); window->priv->sort_type = g_settings_get_enum (window->priv->settings_listing, PREF_LISTING_SORT_TYPE); window->priv->list_mode = window->priv->last_list_mode = g_settings_get_enum (window->priv->settings_listing, PREF_LISTING_LIST_MODE); g_settings_set_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_PATH, (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT)); window->priv->history = NULL; window->priv->history_current = NULL; window->priv->action = FR_ACTION_NONE; window->priv->open_default_dir = g_strdup (get_home_uri ()); window->priv->add_default_dir = g_strdup (get_home_uri ()); window->priv->extract_default_dir = g_strdup (get_home_uri ()); window->priv->give_focus_to_the_list = FALSE; window->priv->activity_ref = 0; window->priv->activity_timeout_handle = 0; window->priv->update_timeout_handle = 0; window->priv->archive_present = FALSE; window->priv->archive_new = FALSE; window->priv->archive_uri = NULL; window->priv->drag_destination_folder = NULL; window->priv->drag_base_dir = NULL; window->priv->drag_error = NULL; window->priv->drag_file_list = NULL; window->priv->batch_mode = FALSE; window->priv->batch_action_list = NULL; window->priv->batch_action = NULL; window->priv->extract_interact_use_default_dir = FALSE; window->priv->non_interactive = FALSE; window->priv->password = NULL; window->priv->compression = g_settings_get_enum (window->priv->settings_general, PREF_GENERAL_COMPRESSION_LEVEL); window->priv->encrypt_header = g_settings_get_boolean (window->priv->settings_general, PREF_GENERAL_ENCRYPT_HEADER); window->priv->volume_size = 0; window->priv->convert_data.converting = FALSE; window->priv->convert_data.temp_dir = NULL; window->priv->convert_data.new_archive = NULL; window->priv->convert_data.password = NULL; window->priv->convert_data.encrypt_header = FALSE; window->priv->convert_data.volume_size = 0; window->priv->stoppable = TRUE; window->priv->batch_adding_one_file = FALSE; window->priv->path_clicked = NULL; window->priv->current_view_length = 0; window->priv->current_batch_action.type = FR_BATCH_ACTION_NONE; window->priv->current_batch_action.data = NULL; window->priv->current_batch_action.free_func = NULL; window->priv->pd_last_archive = NULL; window->priv->pd_last_message = NULL; window->priv->pd_last_fraction = 0.0; /* Create the widgets. */ /* * File list. */ window->priv->list_store = fr_list_model_new (NUMBER_OF_COLUMNS, G_TYPE_POINTER, GDK_TYPE_PIXBUF, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); g_object_set_data (G_OBJECT (window->priv->list_store), "FrWindow", window); window->priv->list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window->priv->list_store)); add_file_list_columns (window, GTK_TREE_VIEW (window->priv->list_view)); gtk_tree_view_set_enable_search (GTK_TREE_VIEW (window->priv->list_view), TRUE); gtk_tree_view_set_search_column (GTK_TREE_VIEW (window->priv->list_view), COLUMN_NAME); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store), COLUMN_NAME, name_column_sort_func, NULL, NULL); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store), COLUMN_SIZE, size_column_sort_func, NULL, NULL); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store), COLUMN_TYPE, type_column_sort_func, NULL, NULL); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store), COLUMN_TIME, time_column_sort_func, NULL, NULL); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store), COLUMN_PATH, path_column_sort_func, NULL, NULL); gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (window->priv->list_store), no_sort_column_sort_func, NULL, NULL); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); g_signal_connect (selection, "changed", G_CALLBACK (selection_changed_cb), window); g_signal_connect (G_OBJECT (window->priv->list_view), "row_activated", G_CALLBACK (row_activated_cb), window); g_signal_connect (G_OBJECT (window->priv->list_view), "button_press_event", G_CALLBACK (file_button_press_cb), window); g_signal_connect (G_OBJECT (window->priv->list_view), "button_release_event", G_CALLBACK (file_button_release_cb), window); g_signal_connect (G_OBJECT (window->priv->list_view), "motion_notify_event", G_CALLBACK (file_motion_notify_callback), window); g_signal_connect (G_OBJECT (window->priv->list_view), "leave_notify_event", G_CALLBACK (file_leave_notify_callback), window); g_signal_connect (G_OBJECT (window->priv->list_store), "sort_column_changed", G_CALLBACK (sort_column_changed_cb), window); g_signal_connect (G_OBJECT (window->priv->list_view), "drag_begin", G_CALLBACK (file_list_drag_begin), window); g_signal_connect (G_OBJECT (window->priv->list_view), "drag_end", G_CALLBACK (file_list_drag_end), window); egg_tree_multi_drag_add_drag_support (GTK_TREE_VIEW (window->priv->list_view)); list_scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (list_scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (list_scrolled_window), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (list_scrolled_window), window->priv->list_view); /* filter bar */ window->priv->filter_bar = filter_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_container_set_border_width (GTK_CONTAINER (filter_box), 3); fr_window_attach (FR_WINDOW (window), window->priv->filter_bar, FR_WINDOW_AREA_FILTERBAR); gtk_box_pack_start (GTK_BOX (filter_box), gtk_label_new (_("Find:")), FALSE, FALSE, 0); /* * filter entry */ window->priv->filter_entry = GTK_WIDGET (gtk_entry_new ()); gtk_entry_set_icon_from_icon_name (GTK_ENTRY (window->priv->filter_entry), GTK_ENTRY_ICON_SECONDARY, "edit-clear"); gtk_widget_set_size_request (window->priv->filter_entry, 300, -1); gtk_box_pack_start (GTK_BOX (filter_box), window->priv->filter_entry, FALSE, FALSE, 6); g_signal_connect (G_OBJECT (window->priv->filter_entry), "activate", G_CALLBACK (filter_entry_activate_cb), window); g_signal_connect (G_OBJECT (window->priv->filter_entry), "icon-release", G_CALLBACK (filter_entry_icon_release_cb), window); gtk_widget_show_all (filter_box); /* tree view */ window->priv->tree_store = gtk_tree_store_new (TREE_NUMBER_OF_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING, PANGO_TYPE_WEIGHT); window->priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window->priv->tree_store)); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (window->priv->tree_view), FALSE); add_dir_tree_columns (window, GTK_TREE_VIEW (window->priv->tree_view)); g_signal_connect (G_OBJECT (window->priv->tree_view), "button_press_event", G_CALLBACK (dir_tree_button_press_cb), window); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view)); g_signal_connect (selection, "changed", G_CALLBACK (dir_tree_selection_changed_cb), window); g_signal_connect (G_OBJECT (window->priv->tree_view), "drag_begin", G_CALLBACK (file_list_drag_begin), window); g_signal_connect (G_OBJECT (window->priv->tree_view), "drag_end", G_CALLBACK (file_list_drag_end), window); g_signal_connect (G_OBJECT (window->priv->tree_view), "drag_data_get", G_CALLBACK (fr_window_folder_tree_drag_data_get), window); gtk_drag_source_set (window->priv->tree_view, GDK_BUTTON1_MASK, folder_tree_targets, G_N_ELEMENTS (folder_tree_targets), GDK_ACTION_COPY); tree_scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (tree_scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (tree_scrolled_window), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (tree_scrolled_window), window->priv->tree_view); /* side pane */ window->priv->sidepane = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); sidepane_title = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (sidepane_title), GTK_SHADOW_ETCHED_IN); sidepane_title_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_set_border_width (GTK_CONTAINER (sidepane_title_box), 2); gtk_container_add (GTK_CONTAINER (sidepane_title), sidepane_title_box); sidepane_title_label = gtk_label_new (_("Folders")); gtk_label_set_xalign (GTK_LABEL (sidepane_title_label), 0.0); gtk_box_pack_start (GTK_BOX (sidepane_title_box), sidepane_title_label, TRUE, TRUE, 0); close_sidepane_button = gtk_button_new (); gtk_container_add (GTK_CONTAINER (close_sidepane_button), gtk_image_new_from_icon_name ("window-close", GTK_ICON_SIZE_MENU)); gtk_button_set_relief (GTK_BUTTON (close_sidepane_button), GTK_RELIEF_NONE); gtk_widget_set_tooltip_text (close_sidepane_button, _("Close the folders pane")); g_signal_connect (close_sidepane_button, "clicked", G_CALLBACK (close_sidepane_button_clicked_cb), window); gtk_box_pack_end (GTK_BOX (sidepane_title_box), close_sidepane_button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (window->priv->sidepane), sidepane_title, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (window->priv->sidepane), tree_scrolled_window, TRUE, TRUE, 0); /* main content */ window->priv->paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); gtk_paned_pack1 (GTK_PANED (window->priv->paned), window->priv->sidepane, FALSE, TRUE); gtk_paned_pack2 (GTK_PANED (window->priv->paned), list_scrolled_window, TRUE, TRUE); gtk_paned_set_position (GTK_PANED (window->priv->paned), g_settings_get_int (window->priv->settings_ui, PREF_UI_SIDEBAR_WIDTH)); fr_window_attach (FR_WINDOW (window), window->priv->paned, FR_WINDOW_AREA_CONTENTS); gtk_widget_show_all (window->priv->paned); /* Build the menu and the toolbar. */ ui = gtk_ui_manager_new (); window->priv->actions = actions = gtk_action_group_new ("Actions"); /* open recent toolbar item action */ action = g_object_new (GTK_TYPE_RECENT_ACTION, "name", "OpenRecent", /* Translators: this is the label for the "open recent file" sub-menu. */ "label", _("Open _Recent"), "tooltip", _("Open a recently used archive"), "stock-id", "gtk-open", NULL); fr_window_init_recent_chooser (window, GTK_RECENT_CHOOSER (action)); gtk_action_group_add_action (actions, action); g_object_unref (action); /* open recent toolbar item action */ action = g_object_new (GTK_TYPE_RECENT_ACTION, "name", "OpenRecent_Toolbar", "label", _("Open"), "tooltip", _("Open a recently used archive"), "stock-id", "gtk-open", "is-important", TRUE, NULL); fr_window_init_recent_chooser (window, GTK_RECENT_CHOOSER (action)); g_signal_connect (action, "activate", G_CALLBACK (activate_action_open), window); gtk_action_group_add_action (actions, action); g_object_unref (action); /* other actions */ gtk_action_group_set_translation_domain (actions, NULL); gtk_action_group_add_actions (actions, action_entries, n_action_entries, window); gtk_action_group_add_toggle_actions (actions, action_toggle_entries, n_action_toggle_entries, window); gtk_action_group_add_radio_actions (actions, view_as_entries, n_view_as_entries, window->priv->list_mode, G_CALLBACK (view_as_radio_action), window); gtk_action_group_add_radio_actions (actions, sort_by_entries, n_sort_by_entries, window->priv->sort_type, G_CALLBACK (sort_by_radio_action), window); g_signal_connect (ui, "connect_proxy", G_CALLBACK (connect_proxy_cb), window); g_signal_connect (ui, "disconnect_proxy", G_CALLBACK (disconnect_proxy_cb), window); gtk_ui_manager_insert_action_group (ui, actions, 0); gtk_window_add_accel_group (GTK_WINDOW (window), gtk_ui_manager_get_accel_group (ui)); /* Add a hidden short cut Ctrl-Q for power users */ gtk_accel_group_connect (gtk_ui_manager_get_accel_group (ui), GDK_KEY_q, GDK_CONTROL_MASK, 0, g_cclosure_new_swap (G_CALLBACK (fr_window_close), window, NULL)); if (! gtk_ui_manager_add_ui_from_resource (ui, ENGRAMPA_RESOURCE_UI_PATH G_DIR_SEPARATOR_S "menus-toolbars.ui", &error)) { g_message ("building menus failed: %s", error->message); g_error_free (error); } menubar = gtk_ui_manager_get_widget (ui, "/MenuBar"); fr_window_attach (FR_WINDOW (window), menubar, FR_WINDOW_AREA_MENUBAR); gtk_widget_show (menubar); window->priv->toolbar = toolbar = gtk_ui_manager_get_widget (ui, "/ToolBar"); gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), TRUE); gtk_style_context_add_class (gtk_widget_get_style_context (toolbar), GTK_STYLE_CLASS_PRIMARY_TOOLBAR); set_action_important (ui, "/ToolBar/Extract_Toolbar"); /* location bar */ window->priv->location_bar = gtk_ui_manager_get_widget (ui, "/LocationBar"); gtk_toolbar_set_show_arrow (GTK_TOOLBAR (window->priv->location_bar), FALSE); gtk_toolbar_set_style (GTK_TOOLBAR (window->priv->location_bar), GTK_TOOLBAR_BOTH_HORIZ); gtk_style_context_add_class (gtk_widget_get_style_context (window->priv->location_bar), GTK_STYLE_CLASS_TOOLBAR); set_action_important (ui, "/LocationBar/GoBack"); /* current location */ location_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); /* Translators: after the colon there is a folder name. */ window->priv->location_label = gtk_label_new_with_mnemonic (_("_Location:")); gtk_box_pack_start (GTK_BOX (location_box), window->priv->location_label, FALSE, FALSE, 5); window->priv->location_entry = gtk_entry_new (); gtk_entry_set_icon_from_icon_name (GTK_ENTRY (window->priv->location_entry), GTK_ENTRY_ICON_PRIMARY, "folder"); gtk_box_pack_start (GTK_BOX (location_box), window->priv->location_entry, TRUE, TRUE, 5); g_signal_connect (G_OBJECT (window->priv->location_entry), "key_press_event", G_CALLBACK (location_entry_key_press_event_cb), window); { GtkToolItem *tool_item; tool_item = gtk_separator_tool_item_new (); gtk_widget_show_all (GTK_WIDGET (tool_item)); gtk_toolbar_insert (GTK_TOOLBAR (window->priv->location_bar), tool_item, -1); tool_item = gtk_tool_item_new (); gtk_tool_item_set_expand (tool_item, TRUE); gtk_container_add (GTK_CONTAINER (tool_item), location_box); gtk_widget_show_all (GTK_WIDGET (tool_item)); gtk_toolbar_insert (GTK_TOOLBAR (window->priv->location_bar), tool_item, -1); } fr_window_attach (FR_WINDOW (window), window->priv->location_bar, FR_WINDOW_AREA_LOCATIONBAR); if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) gtk_widget_hide (window->priv->location_bar); else gtk_widget_show (window->priv->location_bar); /**/ fr_window_attach (FR_WINDOW (window), window->priv->toolbar, FR_WINDOW_AREA_TOOLBAR); if (g_settings_get_boolean (window->priv->settings_ui, PREF_UI_VIEW_TOOLBAR)) gtk_widget_show (toolbar); else gtk_widget_hide (toolbar); window->priv->file_popup_menu = gtk_ui_manager_get_widget (ui, "/FilePopupMenu"); window->priv->folder_popup_menu = gtk_ui_manager_get_widget (ui, "/FolderPopupMenu"); window->priv->sidebar_folder_popup_menu = gtk_ui_manager_get_widget (ui, "/SidebarFolderPopupMenu"); /* Create the statusbar. */ window->priv->statusbar = gtk_statusbar_new (); window->priv->help_message_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->priv->statusbar), "help_message"); window->priv->list_info_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->priv->statusbar), "list_info"); window->priv->progress_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->priv->statusbar), "progress"); statusbar = GTK_STATUSBAR (window->priv->statusbar); /*reduce size of statusbar */ gtk_widget_set_margin_top (GTK_WIDGET (statusbar), 0); gtk_widget_set_margin_bottom (GTK_WIDGET (statusbar), 0); statusbar_box = gtk_statusbar_get_message_area (statusbar); gtk_box_set_homogeneous (GTK_BOX (statusbar_box), FALSE); gtk_box_set_spacing (GTK_BOX (statusbar_box), 4); gtk_box_set_child_packing (GTK_BOX (statusbar_box), gtk_statusbar_get_message_area (statusbar), TRUE, TRUE, 0, GTK_PACK_START ); window->priv->progress_bar = gtk_progress_bar_new (); gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR (window->priv->progress_bar), ACTIVITY_PULSE_STEP); gtk_widget_set_size_request (window->priv->progress_bar, -1, PROGRESS_BAR_HEIGHT); { GtkWidget *vbox; vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start (GTK_BOX (statusbar_box), vbox, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), window->priv->progress_bar, TRUE, TRUE, 1); gtk_widget_show (vbox); } gtk_widget_show (statusbar_box); fr_window_attach (FR_WINDOW (window), window->priv->statusbar, FR_WINDOW_AREA_STATUSBAR); if (g_settings_get_boolean (window->priv->settings_ui, PREF_UI_VIEW_STATUSBAR)) gtk_widget_show (window->priv->statusbar); else gtk_widget_hide (window->priv->statusbar); /**/ fr_window_update_title (window); fr_window_update_sensitivity (window); fr_window_update_file_list (window, FALSE); fr_window_update_dir_tree (window); fr_window_update_current_location (window); fr_window_update_columns_visibility (window); /* Add notification callbacks. */ g_signal_connect (window->priv->settings_ui, "changed::" PREF_UI_HISTORY_LEN, G_CALLBACK (pref_history_len_changed), window); g_signal_connect (window->priv->settings_ui, "changed::" PREF_UI_VIEW_TOOLBAR, G_CALLBACK (pref_view_toolbar_changed), window); g_signal_connect (window->priv->settings_ui, "changed::" PREF_UI_VIEW_STATUSBAR, G_CALLBACK (pref_view_statusbar_changed), window); g_signal_connect (window->priv->settings_ui, "changed::" PREF_UI_VIEW_FOLDERS, G_CALLBACK (pref_view_folders_changed), window); g_signal_connect (window->priv->settings_listing, "changed::" PREF_LISTING_SHOW_TYPE, G_CALLBACK (pref_show_field_changed), window); g_signal_connect (window->priv->settings_listing, "changed::" PREF_LISTING_SHOW_SIZE, G_CALLBACK (pref_show_field_changed), window); g_signal_connect (window->priv->settings_listing, "changed::" PREF_LISTING_SHOW_TIME, G_CALLBACK (pref_show_field_changed), window); g_signal_connect (window->priv->settings_listing, "changed::" PREF_LISTING_SHOW_PATH, G_CALLBACK (pref_show_field_changed), window); g_signal_connect (window->priv->settings_listing, "changed::" PREF_LISTING_USE_MIME_ICONS, G_CALLBACK (pref_use_mime_icons_changed), window); if (window->priv->settings_caja) g_signal_connect (window->priv->settings_caja, "changed::" CAJA_CLICK_POLICY, G_CALLBACK (pref_click_policy_changed), window); /* Give focus to the list. */ gtk_widget_grab_focus (window->priv->list_view); } GtkWidget * fr_window_new (void) { GtkWidget *window; window = g_object_new (FR_TYPE_WINDOW, "application", g_application_get_default (), NULL); fr_window_construct ((FrWindow*) window); return window; } static void fr_window_set_archive_uri (FrWindow *window, const char *uri) { if (window->priv->archive_uri != NULL) g_free (window->priv->archive_uri); window->priv->archive_uri = g_strdup (uri); } gboolean fr_window_archive_new (FrWindow *window, const char *uri) { g_return_val_if_fail (window != NULL, FALSE); if (! fr_archive_create (window->archive, uri)) { GtkWindow *file_sel = g_object_get_data (G_OBJECT (window), "fr_file_sel"); window->priv->load_error_parent_window = file_sel; fr_archive_action_completed (window->archive, FR_ACTION_CREATING_NEW_ARCHIVE, FR_PROC_ERROR_GENERIC, _("Archive type not supported.")); return FALSE; } fr_window_set_archive_uri (window, uri); window->priv->archive_present = TRUE; window->priv->archive_new = TRUE; fr_archive_action_completed (window->archive, FR_ACTION_CREATING_NEW_ARCHIVE, FR_PROC_ERROR_NONE, NULL); return TRUE; } FrWindow * fr_window_archive_open (FrWindow *current_window, const char *uri, GtkWindow *parent) { FrWindow *window = current_window; if (current_window->priv->archive_present) window = (FrWindow *) fr_window_new (); g_return_val_if_fail (window != NULL, FALSE); fr_window_archive_close (window); fr_window_set_archive_uri (window, uri); window->priv->archive_present = FALSE; window->priv->give_focus_to_the_list = TRUE; window->priv->load_error_parent_window = parent; fr_window_set_current_batch_action (window, FR_BATCH_ACTION_LOAD, g_strdup (window->priv->archive_uri), (GFreeFunc) g_free); fr_archive_load (window->archive, window->priv->archive_uri, window->priv->password); return window; } void fr_window_archive_close (FrWindow *window) { g_return_if_fail (window != NULL); if (! window->priv->archive_new && ! window->priv->archive_present) return; fr_window_free_open_files (window); fr_clipboard_data_unref (window->priv->copy_data); window->priv->copy_data = NULL; fr_window_set_password (window, NULL); fr_window_set_volume_size(window, 0); fr_window_history_clear (window); window->priv->archive_new = FALSE; window->priv->archive_present = FALSE; fr_window_update_title (window); fr_window_update_sensitivity (window); fr_window_update_file_list (window, FALSE); fr_window_update_dir_tree (window); fr_window_update_current_location (window); fr_window_update_statusbar_list_info (window); } const char * fr_window_get_archive_uri (FrWindow *window) { g_return_val_if_fail (window != NULL, NULL); return window->priv->archive_uri; } const char * fr_window_get_paste_archive_uri (FrWindow *window) { g_return_val_if_fail (window != NULL, NULL); if (window->priv->clipboard_data != NULL) return window->priv->clipboard_data->archive_filename; else return NULL; } gboolean fr_window_archive_is_present (FrWindow *window) { g_return_val_if_fail (window != NULL, FALSE); return window->priv->archive_present; } typedef struct { char *uri; char *password; gboolean encrypt_header; guint volume_size; } SaveAsData; static SaveAsData * save_as_data_new (const char *uri, const char *password, gboolean encrypt_header, guint volume_size) { SaveAsData *sdata; sdata = g_new0 (SaveAsData, 1); if (uri != NULL) sdata->uri = g_strdup (uri); if (password != NULL) sdata->password = g_strdup (password); sdata->encrypt_header = encrypt_header; sdata->volume_size = volume_size; return sdata; } static void save_as_data_free (SaveAsData *sdata) { if (sdata == NULL) return; g_free (sdata->uri); g_free (sdata->password); g_free (sdata); } void fr_window_archive_save_as (FrWindow *window, const char *uri, const char *password, gboolean encrypt_header, guint volume_size) { g_return_if_fail (window != NULL); g_return_if_fail (uri != NULL); g_return_if_fail (window->archive != NULL); fr_window_convert_data_free (window, TRUE); window->priv->convert_data.new_file = g_strdup (uri); /* create the new archive */ window->priv->convert_data.new_archive = fr_archive_new (); if (! fr_archive_create (window->priv->convert_data.new_archive, uri)) { GtkWidget *d; char *utf8_name; char *message; utf8_name = g_uri_display_basename (uri); message = g_strdup_printf (_("Could not save the archive \"%s\""), utf8_name); g_free (utf8_name); d = _gtk_error_dialog_new (GTK_WINDOW (window), GTK_DIALOG_DESTROY_WITH_PARENT, NULL, message, "%s", _("Archive type not supported.")); gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy (d); g_free (message); g_object_unref (window->priv->convert_data.new_archive); window->priv->convert_data.new_archive = NULL; return; } g_return_if_fail (window->priv->convert_data.new_archive->command != NULL); if (password != NULL) { window->priv->convert_data.password = g_strdup (password); window->priv->convert_data.encrypt_header = encrypt_header; } else window->priv->convert_data.encrypt_header = FALSE; window->priv->convert_data.volume_size = volume_size; fr_window_set_current_batch_action (window, FR_BATCH_ACTION_SAVE_AS, save_as_data_new (uri, password, encrypt_header, volume_size), (GFreeFunc) save_as_data_free); g_signal_connect (G_OBJECT (window->priv->convert_data.new_archive), "start", G_CALLBACK (action_started), window); g_signal_connect (G_OBJECT (window->priv->convert_data.new_archive), "done", G_CALLBACK (convert__action_performed), window); g_signal_connect (G_OBJECT (window->priv->convert_data.new_archive), "progress", G_CALLBACK (fr_window_progress_cb), window); g_signal_connect (G_OBJECT (window->priv->convert_data.new_archive), "message", G_CALLBACK (fr_window_message_cb), window); g_signal_connect (G_OBJECT (window->priv->convert_data.new_archive), "stoppable", G_CALLBACK (fr_window_stoppable_cb), window); window->priv->convert_data.converting = TRUE; window->priv->convert_data.temp_dir = get_temp_work_dir (NULL); fr_process_clear (window->archive->process); fr_archive_extract_to_local (window->archive, NULL, window->priv->convert_data.temp_dir, NULL, TRUE, FALSE, FALSE, window->priv->password); fr_process_start (window->archive->process); } void fr_window_archive_reload (FrWindow *window) { g_return_if_fail (window != NULL); if (window->priv->activity_ref > 0) return; if (window->priv->archive_new) return; fr_archive_reload (window->archive, window->priv->password); } /**/ void fr_window_archive_add_files (FrWindow *window, GList *file_list, /* GFile list */ gboolean update) { GFile *base; char *base_dir; int base_len; GList *files = NULL; GList *scan; char *base_uri; base = g_file_get_parent ((GFile *) file_list->data); base_dir = g_file_get_path (base); base_len = 0; if (strcmp (base_dir, "/") != 0) base_len = strlen (base_dir); for (scan = file_list; scan; scan = scan->next) { GFile *file = scan->data; char *path; char *rel_path; path = g_file_get_path (file); rel_path = g_strdup (path + base_len + 1); files = g_list_prepend (files, rel_path); g_free (path); } base_uri = g_file_get_uri (base); fr_archive_add_files (window->archive, files, base_uri, fr_window_get_current_location (window), update, window->priv->password, window->priv->encrypt_header, window->priv->compression, window->priv->volume_size); g_free (base_uri); path_list_free (files); g_free (base_dir); g_object_unref (base); } void fr_window_archive_add_with_wildcard (FrWindow *window, const char *include_files, const char *exclude_files, const char *exclude_folders, const char *base_dir, const char *dest_dir, gboolean update, gboolean follow_links) { fr_archive_add_with_wildcard (window->archive, include_files, exclude_files, exclude_folders, base_dir, (dest_dir == NULL)? fr_window_get_current_location (window): dest_dir, update, follow_links, window->priv->password, window->priv->encrypt_header, window->priv->compression, window->priv->volume_size); } void fr_window_archive_add_directory (FrWindow *window, const char *directory, const char *base_dir, const char *dest_dir, gboolean update) { fr_archive_add_directory (window->archive, directory, base_dir, (dest_dir == NULL)? fr_window_get_current_location (window): dest_dir, update, window->priv->password, window->priv->encrypt_header, window->priv->compression, window->priv->volume_size); } void fr_window_archive_add_items (FrWindow *window, GList *item_list, const char *base_dir, const char *dest_dir, gboolean update) { fr_archive_add_items (window->archive, item_list, base_dir, (dest_dir == NULL)? fr_window_get_current_location (window): dest_dir, update, window->priv->password, window->priv->encrypt_header, window->priv->compression, window->priv->volume_size); } void fr_window_archive_add_dropped_items (FrWindow *window, GList *item_list, gboolean update) { fr_archive_add_dropped_items (window->archive, item_list, fr_window_get_current_location (window), fr_window_get_current_location (window), update, window->priv->password, window->priv->encrypt_header, window->priv->compression, window->priv->volume_size); } void fr_window_archive_remove (FrWindow *window, GList *file_list) { fr_window_clipboard_remove_file_list (window, file_list); fr_process_clear (window->archive->process); fr_archive_remove (window->archive, file_list, window->priv->compression); fr_process_start (window->archive->process); } /* -- window_archive_extract -- */ static ExtractData* extract_data_new (GList *file_list, const char *extract_to_dir, const char *base_dir, gboolean skip_older, FrOverwrite overwrite, gboolean junk_paths, gboolean extract_here, gboolean ask_to_open_destination) { ExtractData *edata; edata = g_new0 (ExtractData, 1); edata->file_list = path_list_dup (file_list); if (extract_to_dir != NULL) edata->extract_to_dir = g_strdup (extract_to_dir); edata->skip_older = skip_older; edata->overwrite = overwrite; edata->junk_paths = junk_paths; if (base_dir != NULL) edata->base_dir = g_strdup (base_dir); edata->extract_here = extract_here; edata->ask_to_open_destination = ask_to_open_destination; return edata; } static ExtractData* extract_to_data_new (const char *extract_to_dir) { return extract_data_new (NULL, extract_to_dir, NULL, FALSE, TRUE, FALSE, FALSE, FALSE); } static void extract_data_free (ExtractData *edata) { g_return_if_fail (edata != NULL); path_list_free (edata->file_list); g_free (edata->extract_to_dir); g_free (edata->base_dir); g_free (edata); } static gboolean archive_is_encrypted (FrWindow *window, GList *file_list) { gboolean encrypted = FALSE; if (file_list == NULL) { guint i; for (i = 0; ! encrypted && i < window->archive->command->files->len; i++) { FileData *fdata = g_ptr_array_index (window->archive->command->files, i); if (fdata->encrypted) encrypted = TRUE; } } else { GHashTable *file_hash; guint i; GList *scan; file_hash = g_hash_table_new (g_str_hash, g_str_equal); for (i = 0; i < window->archive->command->files->len; i++) { FileData *fdata = g_ptr_array_index (window->archive->command->files, i); g_hash_table_insert (file_hash, fdata->original_path, fdata); } for (scan = file_list; ! encrypted && scan; scan = scan->next) { char *filename = scan->data; FileData *fdata; fdata = g_hash_table_lookup (file_hash, filename); g_return_val_if_fail (fdata != NULL, FALSE); if (fdata->encrypted) encrypted = TRUE; } g_hash_table_destroy (file_hash); } return encrypted; } void fr_window_archive_extract_here (FrWindow *window, gboolean skip_older, FrOverwrite overwrite, gboolean junk_paths) { ExtractData *edata; edata = extract_data_new (NULL, NULL, NULL, skip_older, overwrite, junk_paths, TRUE, FALSE); fr_window_set_current_batch_action (window, FR_BATCH_ACTION_EXTRACT, edata, (GFreeFunc) extract_data_free); if (archive_is_encrypted (window, NULL) && (window->priv->password == NULL)) { dlg_ask_password (window); return; } window->priv->ask_to_open_destination_after_extraction = edata->ask_to_open_destination; fr_process_clear (window->archive->process); if (fr_archive_extract_here (window->archive, edata->skip_older, edata->overwrite, edata->junk_paths, window->priv->password)) { fr_process_start (window->archive->process); } } /* -- fr_window_archive_extract -- */ typedef struct { FrWindow *window; ExtractData *edata; GList *current_file; gboolean extract_all; } OverwriteData; #define _FR_RESPONSE_OVERWRITE_YES_ALL 100 #define _FR_RESPONSE_OVERWRITE_YES 101 #define _FR_RESPONSE_OVERWRITE_NO 102 static void _fr_window_archive_extract_from_edata (FrWindow *window, ExtractData *edata) { window->priv->ask_to_open_destination_after_extraction = edata->ask_to_open_destination; fr_process_clear (window->archive->process); fr_archive_extract (window->archive, edata->file_list, edata->extract_to_dir, edata->base_dir, edata->skip_older, edata->overwrite == FR_OVERWRITE_YES, edata->junk_paths, window->priv->password); fr_process_start (window->archive->process); } static void _fr_window_ask_overwrite_dialog (OverwriteData *odata); static void overwrite_dialog_response_cb (GtkDialog *dialog, int response_id, gpointer user_data) { OverwriteData *odata = user_data; gboolean do_not_extract = FALSE; switch (response_id) { case _FR_RESPONSE_OVERWRITE_YES_ALL: odata->edata->overwrite = FR_OVERWRITE_YES; break; case _FR_RESPONSE_OVERWRITE_YES: odata->current_file = odata->current_file->next; break; case _FR_RESPONSE_OVERWRITE_NO: { /* remove the file from the list to extract */ GList *next = odata->current_file->next; odata->edata->file_list = g_list_remove_link (odata->edata->file_list, odata->current_file); path_list_free (odata->current_file); odata->current_file = next; odata->extract_all = FALSE; } break; case GTK_RESPONSE_DELETE_EVENT: case GTK_RESPONSE_CANCEL: do_not_extract = TRUE; break; default: break; } gtk_widget_destroy (GTK_WIDGET (dialog)); if (do_not_extract) { fr_window_stop_batch (odata->window); g_free (odata); return; } _fr_window_ask_overwrite_dialog (odata); } static void _fr_window_ask_overwrite_dialog (OverwriteData *odata) { while ((odata->edata->overwrite == FR_OVERWRITE_ASK) && (odata->current_file != NULL)) { const char *base_name; char *e_base_name; char *dest_uri; GFile *file; GFileInfo *info; GFileType file_type; base_name = _g_path_get_base_name ((char *) odata->current_file->data, odata->edata->base_dir, odata->edata->junk_paths); e_base_name = g_uri_escape_string (base_name, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE); dest_uri = g_strdup_printf ("%s/%s", odata->edata->extract_to_dir, e_base_name); file = g_file_new_for_uri (dest_uri); info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); g_free (dest_uri); g_free (e_base_name); if (info == NULL) { g_object_unref (file); odata->current_file = odata->current_file->next; continue; } file_type = g_file_info_get_file_type (info); if ((file_type != G_FILE_TYPE_UNKNOWN) && (file_type != G_FILE_TYPE_DIRECTORY)) { char *msg; GFile *parent; char *parent_name; char *details; GtkWidget *d; msg = g_strdup_printf (_("Replace file \"%s\"?"), g_file_info_get_display_name (info)); parent = g_file_get_parent (file); parent_name = g_file_get_parse_name (parent); details = g_strdup_printf (_("Another file with the same name already exists in \"%s\"."), parent_name); d = _gtk_message_dialog_new (GTK_WINDOW (odata->window), GTK_DIALOG_MODAL, "dialog-question", msg, details, "gtk-cancel", GTK_RESPONSE_CANCEL, _("Replace _All"), _FR_RESPONSE_OVERWRITE_YES_ALL, _("_Skip"), _FR_RESPONSE_OVERWRITE_NO, _("_Replace"), _FR_RESPONSE_OVERWRITE_YES, NULL); gtk_dialog_set_default_response (GTK_DIALOG (d), _FR_RESPONSE_OVERWRITE_YES); g_signal_connect (d, "response", G_CALLBACK (overwrite_dialog_response_cb), odata); gtk_widget_show (d); g_free (parent_name); g_object_unref (parent); g_object_unref (info); g_object_unref (file); return; } else odata->current_file = odata->current_file->next; g_object_unref (info); g_object_unref (file); } if (odata->edata->file_list != NULL) { /* speed optimization: passing NULL when extracting all the * files is faster if the command supports the * propCanExtractAll property. */ if (odata->extract_all) { path_list_free (odata->edata->file_list); odata->edata->file_list = NULL; } odata->edata->overwrite = FR_OVERWRITE_YES; _fr_window_archive_extract_from_edata (odata->window, odata->edata); } else { GtkWidget *d; d = _gtk_message_dialog_new (GTK_WINDOW (odata->window), 0, "dialog-warning", _("Extraction not performed"), NULL, "gtk-ok", GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_OK); fr_window_show_error_dialog (odata->window, d, GTK_WINDOW (odata->window), _("Extraction not performed")); fr_window_stop_batch (odata->window); } g_free (odata); } void fr_window_archive_extract (FrWindow *window, GList *file_list, const char *extract_to_dir, const char *base_dir, gboolean skip_older, FrOverwrite overwrite, gboolean junk_paths, gboolean ask_to_open_destination) { ExtractData *edata; gboolean do_not_extract = FALSE; GError *error = NULL; edata = extract_data_new (file_list, extract_to_dir, base_dir, skip_older, overwrite, junk_paths, FALSE, ask_to_open_destination); fr_window_set_current_batch_action (window, FR_BATCH_ACTION_EXTRACT, edata, (GFreeFunc) extract_data_free); if (archive_is_encrypted (window, edata->file_list) && (window->priv->password == NULL)) { dlg_ask_password (window); return; } if (! uri_is_dir (edata->extract_to_dir)) { /* There is nothing to ask if the destination doesn't exist. */ if (edata->overwrite == FR_OVERWRITE_ASK) edata->overwrite = FR_OVERWRITE_YES; if (! ForceDirectoryCreation) { GtkWidget *d; int r; char *folder_name; char *msg; folder_name = g_filename_display_name (edata->extract_to_dir); msg = g_strdup_printf (_("Destination folder \"%s\" does not exist.\n\nDo you want to create it?"), folder_name); g_free (folder_name); d = _gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL, "dialog-question", msg, NULL, "gtk-cancel", GTK_RESPONSE_CANCEL, _("Create _Folder"), GTK_RESPONSE_YES, NULL); gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_YES); r = gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy (GTK_WIDGET (d)); g_free (msg); if (r != GTK_RESPONSE_YES) do_not_extract = TRUE; } if (! do_not_extract && ! ensure_dir_exists (edata->extract_to_dir, 0755, &error)) { GtkWidget *d; char *details; details = g_strdup_printf (_("Could not create the destination folder: %s."), error->message); d = _gtk_error_dialog_new (GTK_WINDOW (window), 0, NULL, _("Extraction not performed"), "%s", details); g_clear_error (&error); fr_window_show_error_dialog (window, d, GTK_WINDOW (window), details); fr_window_stop_batch (window); g_free (details); return; } } if (do_not_extract) { GtkWidget *d; d = _gtk_message_dialog_new (GTK_WINDOW (window), 0, "dialog-warning", _("Extraction not performed"), NULL, "gtk-ok", GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_OK); fr_window_show_error_dialog (window, d, GTK_WINDOW (window), _("Extraction not performed")); fr_window_stop_batch (window); return; } if (edata->overwrite == FR_OVERWRITE_ASK) { OverwriteData *odata; odata = g_new0 (OverwriteData, 1); odata->window = window; odata->edata = edata; odata->extract_all = (edata->file_list == NULL) || (g_list_length (edata->file_list) == window->archive->command->files->len); if (edata->file_list == NULL) edata->file_list = fr_window_get_file_list (window); odata->current_file = odata->edata->file_list; _fr_window_ask_overwrite_dialog (odata); } else _fr_window_archive_extract_from_edata (window, edata); } void fr_window_archive_test (FrWindow *window) { fr_window_set_current_batch_action (window, FR_BATCH_ACTION_TEST, NULL, NULL); fr_archive_test (window->archive, window->priv->password); } void fr_window_set_password (FrWindow *window, const char *password) { g_return_if_fail (window != NULL); if (window->priv->password != NULL) { g_free (window->priv->password); window->priv->password = NULL; } if ((password != NULL) && (password[0] != '\0')) window->priv->password = g_strdup (password); } void fr_window_set_password_for_paste (FrWindow *window, const char *password) { g_return_if_fail (window != NULL); if (window->priv->password_for_paste != NULL) { g_free (window->priv->password_for_paste); window->priv->password_for_paste = NULL; } if ((password != NULL) && (password[0] != '\0')) window->priv->password_for_paste = g_strdup (password); } const char * fr_window_get_password (FrWindow *window) { g_return_val_if_fail (window != NULL, NULL); return window->priv->password; } void fr_window_set_encrypt_header (FrWindow *window, gboolean encrypt_header) { g_return_if_fail (window != NULL); window->priv->encrypt_header = encrypt_header; } gboolean fr_window_get_encrypt_header (FrWindow *window) { return window->priv->encrypt_header; } void fr_window_set_compression (FrWindow *window, FrCompression compression) { g_return_if_fail (window != NULL); window->priv->compression = compression; } FrCompression fr_window_get_compression (FrWindow *window) { return window->priv->compression; } void fr_window_set_volume_size (FrWindow *window, guint volume_size) { g_return_if_fail (window != NULL); window->priv->volume_size = volume_size; } guint fr_window_get_volume_size (FrWindow *window) { return window->priv->volume_size; } void fr_window_go_to_location (FrWindow *window, const char *path, gboolean force_update) { char *dir; g_return_if_fail (window != NULL); g_return_if_fail (path != NULL); if (force_update) { g_free (window->priv->last_location); window->priv->last_location = NULL; } if (path[strlen (path) - 1] != '/') dir = g_strconcat (path, "/", NULL); else dir = g_strdup (path); if ((window->priv->last_location == NULL) || (strcmp (window->priv->last_location, dir) != 0)) { g_free (window->priv->last_location); window->priv->last_location = dir; fr_window_history_add (window, dir); fr_window_update_file_list (window, TRUE); fr_window_update_current_location (window); } else g_free (dir); } const char * fr_window_get_current_location (FrWindow *window) { if (window->priv->history_current == NULL) { fr_window_history_add (window, "/"); return window->priv->history_current->data; } else return (const char*) window->priv->history_current->data; } void fr_window_go_up_one_level (FrWindow *window) { char *parent_dir; g_return_if_fail (window != NULL); parent_dir = get_parent_dir (fr_window_get_current_location (window)); fr_window_go_to_location (window, parent_dir, FALSE); g_free (parent_dir); } void fr_window_go_back (FrWindow *window) { g_return_if_fail (window != NULL); if (window->priv->history == NULL) return; if (window->priv->history_current == NULL) return; if (window->priv->history_current->next == NULL) return; window->priv->history_current = window->priv->history_current->next; fr_window_go_to_location (window, window->priv->history_current->data, FALSE); } void fr_window_go_forward (FrWindow *window) { g_return_if_fail (window != NULL); if (window->priv->history == NULL) return; if (window->priv->history_current == NULL) return; if (window->priv->history_current->prev == NULL) return; window->priv->history_current = window->priv->history_current->prev; fr_window_go_to_location (window, window->priv->history_current->data, FALSE); } void fr_window_set_list_mode (FrWindow *window, FrWindowListMode list_mode) { g_return_if_fail (window != NULL); window->priv->list_mode = window->priv->last_list_mode = list_mode; if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) { fr_window_history_clear (window); fr_window_history_add (window, "/"); } g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_LIST_MODE, window->priv->last_list_mode); g_settings_set_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_PATH, (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT)); fr_window_update_file_list (window, TRUE); fr_window_update_dir_tree (window); fr_window_update_current_location (window); } GtkTreeModel * fr_window_get_list_store (FrWindow *window) { return GTK_TREE_MODEL (window->priv->list_store); } void fr_window_find (FrWindow *window) { window->priv->filter_mode = TRUE; gtk_widget_show (window->priv->filter_bar); gtk_widget_grab_focus (window->priv->filter_entry); } void fr_window_select_all (FrWindow *window) { gtk_tree_selection_select_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view))); } void fr_window_unselect_all (FrWindow *window) { gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view))); } void fr_window_set_sort_type (FrWindow *window, GtkSortType sort_type) { window->priv->sort_type = sort_type; fr_window_update_list_order (window); } void fr_window_stop (FrWindow *window) { if (! window->priv->stoppable) return; if (window->priv->activity_ref > 0) fr_archive_stop (window->archive); if (window->priv->convert_data.converting) fr_window_convert_data_free (window, TRUE); } /* -- start/stop activity mode -- */ static int activity_cb (gpointer data) { FrWindow *window = data; if ((window->priv->pd_progress_bar != NULL) && window->priv->progress_pulse) gtk_progress_bar_pulse (GTK_PROGRESS_BAR (window->priv->pd_progress_bar)); if (window->priv->progress_pulse) gtk_progress_bar_pulse (GTK_PROGRESS_BAR (window->priv->progress_bar)); return TRUE; } void fr_window_start_activity_mode (FrWindow *window) { g_return_if_fail (window != NULL); if (window->priv->activity_ref++ > 0) return; window->priv->activity_timeout_handle = g_timeout_add (ACTIVITY_DELAY, activity_cb, window); fr_window_update_sensitivity (window); } void fr_window_stop_activity_mode (FrWindow *window) { g_return_if_fail (window != NULL); if (window->priv->activity_ref == 0) return; window->priv->activity_ref--; if (window->priv->activity_ref > 0) return; if (window->priv->activity_timeout_handle == 0) return; g_source_remove (window->priv->activity_timeout_handle); window->priv->activity_timeout_handle = 0; if (! gtk_widget_get_realized (GTK_WIDGET (window))) return; if (window->priv->progress_dialog != NULL) gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->pd_progress_bar), 0.0); if (! window->priv->batch_mode) { if (window->priv->progress_bar != NULL) gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->progress_bar), 0.0); fr_window_update_sensitivity (window); } } static gboolean last_output_window__unrealize_cb (GtkWidget *widget, gpointer data) { pref_util_save_window_geometry (GTK_WINDOW (widget), LAST_OUTPUT_DIALOG_NAME); return FALSE; } static void fr_window_view_last_output_print(GtkTextBuffer *text_buffer, GtkTextIter *iter, GList *scan) { for (; scan; scan = scan->next) { char *line = scan->data; char *utf8_line; gsize bytes_written; utf8_line = g_locale_to_utf8 (line, -1, NULL, &bytes_written, NULL); gtk_text_buffer_insert_with_tags_by_name (text_buffer, iter, utf8_line, bytes_written, "monospace", NULL); g_free (utf8_line); gtk_text_buffer_insert (text_buffer, iter, "\n", 1); } } void fr_window_view_last_output (FrWindow *window, const char *title) { GtkWidget *dialog; GtkWidget *vbox; GtkWidget *text_view; GtkWidget *scrolled; GtkTextBuffer *text_buffer; GtkTextIter iter; if (title == NULL) title = _("Last Output"); dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW (window), GTK_DIALOG_DESTROY_WITH_PARENT, "gtk-close", GTK_RESPONSE_CLOSE, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE); gtk_widget_set_size_request (dialog, 500, 300); /* Add text */ scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_ETCHED_IN); text_buffer = gtk_text_buffer_new (NULL); gtk_text_buffer_create_tag (text_buffer, "monospace", "family", "monospace", NULL); text_view = gtk_text_view_new_with_buffer (text_buffer); g_object_unref (text_buffer); gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE); gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE); /**/ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); gtk_container_add (GTK_CONTAINER (scrolled), text_view); gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0); gtk_widget_show_all (vbox); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), vbox, TRUE, TRUE, 0); /* signals */ g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (gtk_widget_destroy), NULL); g_signal_connect (G_OBJECT (dialog), "unrealize", G_CALLBACK (last_output_window__unrealize_cb), NULL); gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 0); /* Show STDOUT of process */ fr_window_view_last_output_print(text_buffer, &iter, window->archive->process->out.raw); /* Show STDERR of process */ fr_window_view_last_output_print(text_buffer, &iter, window->archive->process->err.raw); /**/ pref_util_restore_window_geometry (GTK_WINDOW (dialog), LAST_OUTPUT_DIALOG_NAME); } /* -- fr_window_rename_selection -- */ typedef struct { char *path_to_rename; char *old_name; char *new_name; char *current_dir; gboolean is_dir; gboolean dir_in_archive; char *original_path; } RenameData; static RenameData* rename_data_new (const char *path_to_rename, const char *old_name, const char *new_name, const char *current_dir, gboolean is_dir, gboolean dir_in_archive, const char *original_path) { RenameData *rdata; rdata = g_new0 (RenameData, 1); rdata->path_to_rename = g_strdup (path_to_rename); if (old_name != NULL) rdata->old_name = g_strdup (old_name); if (new_name != NULL) rdata->new_name = g_strdup (new_name); if (current_dir != NULL) rdata->current_dir = g_strdup (current_dir); rdata->is_dir = is_dir; rdata->dir_in_archive = dir_in_archive; if (original_path != NULL) rdata->original_path = g_strdup (original_path); return rdata; } static void rename_data_free (RenameData *rdata) { g_return_if_fail (rdata != NULL); g_free (rdata->path_to_rename); g_free (rdata->old_name); g_free (rdata->new_name); g_free (rdata->current_dir); g_free (rdata->original_path); g_free (rdata); } static void rename_selection (FrWindow *window, const char *path_to_rename, const char *old_name, const char *new_name, const char *current_dir, gboolean is_dir, gboolean dir_in_archive, const char *original_path) { FrArchive *archive = window->archive; RenameData *rdata; char *tmp_dir; GList *file_list; gboolean added_dir; char *new_dirname; GList *new_file_list; GList *scan; rdata = rename_data_new (path_to_rename, old_name, new_name, current_dir, is_dir, dir_in_archive, original_path); fr_window_set_current_batch_action (window, FR_BATCH_ACTION_RENAME, rdata, (GFreeFunc) rename_data_free); fr_process_clear (archive->process); tmp_dir = get_temp_work_dir (NULL); if (is_dir) file_list = get_dir_list_from_path (window, rdata->path_to_rename); else file_list = g_list_append (NULL, g_strdup (rdata->path_to_rename)); fr_archive_extract_to_local (archive, file_list, tmp_dir, NULL, FALSE, TRUE, FALSE, window->priv->password); /* temporarily add the dir to rename to the list if it's stored in the * archive, this way it will be removed from the archive... */ added_dir = FALSE; if (is_dir && dir_in_archive && ! g_list_find_custom (file_list, original_path, (GCompareFunc) strcmp)) { file_list = g_list_prepend (file_list, g_strdup (original_path)); added_dir = TRUE; } fr_archive_remove (archive, file_list, window->priv->compression); fr_window_clipboard_remove_file_list (window, file_list); /* ...and remove it from the list again */ if (added_dir) { GList *tmp; tmp = file_list; file_list = g_list_remove_link (file_list, tmp); g_free (tmp->data); g_list_free (tmp); } /* rename the files. */ new_dirname = g_build_filename (rdata->current_dir + 1, rdata->new_name, "/", NULL); new_file_list = NULL; if (rdata->is_dir) { char *old_path; char *new_path; old_path = g_build_filename (tmp_dir, rdata->current_dir, rdata->old_name, NULL); new_path = g_build_filename (tmp_dir, rdata->current_dir, rdata->new_name, NULL); fr_process_begin_command (archive->process, "mv"); fr_process_add_arg (archive->process, "-f"); fr_process_add_arg (archive->process, old_path); fr_process_add_arg (archive->process, new_path); fr_process_end_command (archive->process); g_free (old_path); g_free (new_path); } for (scan = file_list; scan; scan = scan->next) { const char *current_dir_relative = rdata->current_dir + 1; const char *filename = (char*) scan->data; char *old_path = NULL, *common = NULL, *new_path = NULL; char *new_filename; old_path = g_build_filename (tmp_dir, filename, NULL); if (strlen (filename) > (strlen (rdata->current_dir) + strlen (rdata->old_name))) common = g_strdup (filename + strlen (rdata->current_dir) + strlen (rdata->old_name)); new_path = g_build_filename (tmp_dir, rdata->current_dir, rdata->new_name, common, NULL); if (! rdata->is_dir) { fr_process_begin_command (archive->process, "mv"); fr_process_add_arg (archive->process, "-f"); fr_process_add_arg (archive->process, old_path); fr_process_add_arg (archive->process, new_path); fr_process_end_command (archive->process); } new_filename = g_build_filename (current_dir_relative, rdata->new_name, common, NULL); new_file_list = g_list_prepend (new_file_list, new_filename); g_free (old_path); g_free (common); g_free (new_path); } new_file_list = g_list_reverse (new_file_list); /* FIXME: this is broken for tar archives. if (is_dir && dir_in_archive && ! g_list_find_custom (new_file_list, new_dirname, (GCompareFunc) strcmp)) new_file_list = g_list_prepend (new_file_list, g_build_filename (rdata->current_dir + 1, rdata->new_name, NULL)); */ fr_archive_add (archive, new_file_list, tmp_dir, NULL, FALSE, FALSE, window->priv->password, window->priv->encrypt_header, window->priv->compression, window->priv->volume_size); g_free (new_dirname); path_list_free (new_file_list); path_list_free (file_list); /* remove the tmp dir */ fr_process_begin_command (archive->process, "rm"); fr_process_set_working_dir (archive->process, g_get_tmp_dir ()); fr_process_set_sticky (archive->process, TRUE); fr_process_add_arg (archive->process, "-rf"); fr_process_add_arg (archive->process, tmp_dir); fr_process_end_command (archive->process); fr_process_start (archive->process); g_free (tmp_dir); } static gboolean valid_name (const char *new_name, const char *old_name, char **reason) { char *utf8_new_name; gboolean retval = TRUE; new_name = eat_spaces (new_name); utf8_new_name = g_filename_display_name (new_name); if (*new_name == '\0') { /* Translators: the name references to a filename. This message can appear when renaming a file. */ *reason = g_strdup (_("New name is void, please type a name.")); retval = FALSE; } else if (strcmp (new_name, old_name) == 0) { /* Translators: the name references to a filename. This message can appear when renaming a file. */ *reason = g_strdup (_("New name is the same as old one, please type other name.")); retval = FALSE; } else if (strchrs (new_name, BAD_CHARS)) { /* Translators: the %s references to a filename. This message can appear when renaming a file. */ *reason = g_strdup_printf (_("Name \"%s\" is not valid because it contains at least one of the following characters: %s, please type other name."), utf8_new_name, BAD_CHARS); retval = FALSE; } g_free (utf8_new_name); return retval; } static gboolean name_is_present (FrWindow *window, const char *current_dir, const char *new_name, char **reason) { gboolean retval = FALSE; guint i; char *new_filename; int new_filename_l; *reason = NULL; new_filename = g_build_filename (current_dir, new_name, NULL); new_filename_l = strlen (new_filename); for (i = 0; i < window->archive->command->files->len; i++) { FileData *fdata = g_ptr_array_index (window->archive->command->files, i); const char *filename = fdata->full_path; if ((strncmp (filename, new_filename, new_filename_l) == 0) && ((filename[new_filename_l] == '\0') || (filename[new_filename_l] == G_DIR_SEPARATOR))) { char *utf8_name = g_filename_display_name (new_name); if (filename[new_filename_l] == G_DIR_SEPARATOR) *reason = g_strdup_printf (_("A folder named \"%s\" already exists.\n\n%s"), utf8_name, _("Please use a different name.")); else *reason = g_strdup_printf (_("A file named \"%s\" already exists.\n\n%s"), utf8_name, _("Please use a different name.")); retval = TRUE; break; } } g_free (new_filename); return retval; } void fr_window_rename_selection (FrWindow *window, gboolean from_sidebar) { char *path_to_rename; char *parent_dir; char *old_name; gboolean renaming_dir = FALSE; gboolean dir_in_archive = FALSE; char *original_path = NULL; char *utf8_old_name; char *utf8_new_name; if (from_sidebar) { path_to_rename = fr_window_get_selected_folder_in_tree_view (window); if (path_to_rename == NULL) return; parent_dir = remove_level_from_path (path_to_rename); old_name = g_strdup (file_name_from_path (path_to_rename)); renaming_dir = TRUE; } else { FileData *selected_item; selected_item = fr_window_get_selected_item_from_file_list (window); if (selected_item == NULL) return; renaming_dir = file_data_is_dir (selected_item); dir_in_archive = selected_item->dir; original_path = g_strdup (selected_item->original_path); if (renaming_dir && ! dir_in_archive) { parent_dir = g_strdup (fr_window_get_current_location (window)); old_name = g_strdup (selected_item->list_name); path_to_rename = g_build_filename (parent_dir, old_name, NULL); } else { if (renaming_dir) { path_to_rename = remove_ending_separator (selected_item->full_path); parent_dir = remove_level_from_path (path_to_rename); } else { path_to_rename = g_strdup (selected_item->original_path); parent_dir = remove_level_from_path (selected_item->full_path); } old_name = g_strdup (selected_item->name); } file_data_free (selected_item); } retry__rename_selection: utf8_old_name = g_locale_to_utf8 (old_name, -1 ,0 ,0 ,0); utf8_new_name = _gtk_request_dialog_run (GTK_WINDOW (window), (GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL), _("Rename"), (renaming_dir ? _("_New folder name:") : _("_New file name:")), utf8_old_name, 1024, _("_Cancel"), _("_Rename")); g_free (utf8_old_name); if (utf8_new_name != NULL) { char *new_name; char *reason = NULL; new_name = g_filename_from_utf8 (utf8_new_name, -1, 0, 0, 0); g_free (utf8_new_name); if (! valid_name (new_name, old_name, &reason)) { char *utf8_name = g_filename_display_name (new_name); GtkWidget *dlg; dlg = _gtk_error_dialog_new (GTK_WINDOW (window), GTK_DIALOG_DESTROY_WITH_PARENT, NULL, (renaming_dir ? _("Could not rename the folder") : _("Could not rename the file")), "%s", reason); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); g_free (reason); g_free (utf8_name); g_free (new_name); goto retry__rename_selection; } if (name_is_present (window, parent_dir, new_name, &reason)) { GtkWidget *dlg; dlg = _gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL, "dialog-question", (renaming_dir ? _("Could not rename the folder") : _("Could not rename the file")), reason, "gtk-close", GTK_RESPONSE_OK, NULL); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); g_free (reason); g_free (new_name); goto retry__rename_selection; } rename_selection (window, path_to_rename, old_name, new_name, parent_dir, renaming_dir, dir_in_archive, original_path); g_free (new_name); } g_free (old_name); g_free (parent_dir); g_free (path_to_rename); g_free (original_path); } static void fr_clipboard_get (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer user_data_or_owner) { FrWindow *window = user_data_or_owner; char *data; if (gtk_selection_data_get_target (selection_data) != FR_SPECIAL_URI_LIST) return; data = get_selection_data_from_clipboard_data (window, window->priv->copy_data); gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (guchar *) data, strlen (data)); g_free (data); } static void fr_clipboard_clear (GtkClipboard *clipboard, gpointer user_data_or_owner) { FrWindow *window = user_data_or_owner; if (window->priv->copy_data != NULL) { fr_clipboard_data_unref (window->priv->copy_data); window->priv->copy_data = NULL; } } GList * fr_window_get_selection (FrWindow *window, gboolean from_sidebar, char **return_base_dir) { GList *files; char *base_dir; if (from_sidebar) { char *selected_folder; char *parent_folder; files = fr_window_get_folder_tree_selection (window, TRUE, NULL); selected_folder = fr_window_get_selected_folder_in_tree_view (window); parent_folder = remove_level_from_path (selected_folder); if (parent_folder == NULL) base_dir = g_strdup ("/"); else if (parent_folder[strlen (parent_folder) - 1] == '/') base_dir = g_strdup (parent_folder); else base_dir = g_strconcat (parent_folder, "/", NULL); g_free (selected_folder); g_free (parent_folder); } else { files = fr_window_get_file_list_selection (window, TRUE, NULL); base_dir = g_strdup (fr_window_get_current_location (window)); } if (return_base_dir) *return_base_dir = base_dir; else g_free (base_dir); return files; } static void fr_window_copy_or_cut_selection (FrWindow *window, FRClipboardOp op, gboolean from_sidebar) { GList *files; char *base_dir; GtkClipboard *clipboard; files = fr_window_get_selection (window, from_sidebar, &base_dir); if (window->priv->copy_data != NULL) fr_clipboard_data_unref (window->priv->copy_data); window->priv->copy_data = fr_clipboard_data_new (); window->priv->copy_data->files = files; window->priv->copy_data->op = op; window->priv->copy_data->base_dir = base_dir; clipboard = gtk_clipboard_get (FR_CLIPBOARD); gtk_clipboard_set_with_owner (clipboard, clipboard_targets, G_N_ELEMENTS (clipboard_targets), fr_clipboard_get, fr_clipboard_clear, G_OBJECT (window)); fr_window_update_sensitivity (window); } void fr_window_copy_selection (FrWindow *window, gboolean from_sidebar) { fr_window_copy_or_cut_selection (window, FR_CLIPBOARD_OP_COPY, from_sidebar); } void fr_window_cut_selection (FrWindow *window, gboolean from_sidebar) { fr_window_copy_or_cut_selection (window, FR_CLIPBOARD_OP_CUT, from_sidebar); } static gboolean always_fake_load (FrArchive *archive, gpointer data) { return TRUE; } static void add_pasted_files (FrWindow *window, FrClipboardData *data) { const char *current_dir_relative = data->current_dir + 1; GList *scan; GList *new_file_list = NULL; if (window->priv->password_for_paste != NULL) { g_free (window->priv->password_for_paste); window->priv->password_for_paste = NULL; } fr_process_clear (window->archive->process); for (scan = data->files; scan; scan = scan->next) { const char *old_name = (char*) scan->data; char *new_name = g_build_filename (current_dir_relative, old_name + strlen (data->base_dir) - 1, NULL); /* skip folders */ if ((strcmp (old_name, new_name) != 0) && (old_name[strlen (old_name) - 1] != '/')) { fr_process_begin_command (window->archive->process, "mv"); fr_process_set_working_dir (window->archive->process, data->tmp_dir); fr_process_add_arg (window->archive->process, "-f"); if (old_name[0] == '/') old_name = old_name + 1; fr_process_add_arg (window->archive->process, old_name); fr_process_add_arg (window->archive->process, new_name); fr_process_end_command (window->archive->process); } new_file_list = g_list_prepend (new_file_list, new_name); } fr_archive_add (window->archive, new_file_list, data->tmp_dir, NULL, FALSE, FALSE, window->priv->password, window->priv->encrypt_header, window->priv->compression, window->priv->volume_size); path_list_free (new_file_list); /* remove the tmp dir */ fr_process_begin_command (window->archive->process, "rm"); fr_process_set_working_dir (window->archive->process, g_get_tmp_dir ()); fr_process_set_sticky (window->archive->process, TRUE); fr_process_add_arg (window->archive->process, "-rf"); fr_process_add_arg (window->archive->process, data->tmp_dir); fr_process_end_command (window->archive->process); fr_process_start (window->archive->process); } static void copy_from_archive_action_performed_cb (FrArchive *archive, FrAction action, FrProcError *error, gpointer data) { FrWindow *window = data; gboolean UNUSED_VARIABLE continue_batch = FALSE; #ifdef MATE_ENABLE_DEBUG debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", get_action_name (action)); #endif fr_window_stop_activity_mode (window); fr_window_pop_message (window); close_progress_dialog (window, FALSE); if (error->type == FR_PROC_ERROR_ASK_PASSWORD) { dlg_ask_password_for_paste_operation (window); return; } (void) handle_errors (window, archive, action, error); if (error->type != FR_PROC_ERROR_NONE) { fr_clipboard_data_unref (window->priv->clipboard_data); window->priv->clipboard_data = NULL; return; } switch (action) { case FR_ACTION_LISTING_CONTENT: fr_process_clear (window->priv->copy_from_archive->process); fr_archive_extract_to_local (window->priv->copy_from_archive, window->priv->clipboard_data->files, window->priv->clipboard_data->tmp_dir, NULL, FALSE, TRUE, FALSE, window->priv->clipboard_data->archive_password); fr_process_start (window->priv->copy_from_archive->process); break; case FR_ACTION_EXTRACTING_FILES: if (window->priv->clipboard_data->op == FR_CLIPBOARD_OP_CUT) { fr_process_clear (window->priv->copy_from_archive->process); fr_archive_remove (window->priv->copy_from_archive, window->priv->clipboard_data->files, window->priv->compression); fr_process_start (window->priv->copy_from_archive->process); } else add_pasted_files (window, window->priv->clipboard_data); break; case FR_ACTION_DELETING_FILES: add_pasted_files (window, window->priv->clipboard_data); break; default: break; } } static void fr_window_paste_from_clipboard_data (FrWindow *window, FrClipboardData *data) { const char *current_dir_relative; GHashTable *created_dirs; GList *scan; if (window->priv->password_for_paste != NULL) fr_clipboard_data_set_password (data, window->priv->password_for_paste); if (window->priv->clipboard_data != data) { fr_clipboard_data_unref (window->priv->clipboard_data); window->priv->clipboard_data = data; } fr_window_set_current_batch_action (window, FR_BATCH_ACTION_PASTE, fr_clipboard_data_ref (data), (GFreeFunc) fr_clipboard_data_unref); current_dir_relative = data->current_dir + 1; data->tmp_dir = get_temp_work_dir (NULL); created_dirs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (scan = data->files; scan; scan = scan->next) { const char *old_name = (char*) scan->data; char *new_name = g_build_filename (current_dir_relative, old_name + strlen (data->base_dir) - 1, NULL); char *dir = remove_level_from_path (new_name); if ((dir != NULL) && (g_hash_table_lookup (created_dirs, dir) == NULL)) { char *dir_path; dir_path = g_build_filename (data->tmp_dir, dir, NULL); debug (DEBUG_INFO, "mktree %s\n", dir_path); make_directory_tree_from_path (dir_path, 0700, NULL); g_free (dir_path); g_hash_table_replace (created_dirs, g_strdup (dir), "1"); } g_free (dir); g_free (new_name); } g_hash_table_destroy (created_dirs); /**/ if (window->priv->copy_from_archive == NULL) { window->priv->copy_from_archive = fr_archive_new (); g_signal_connect (G_OBJECT (window->priv->copy_from_archive), "start", G_CALLBACK (action_started), window); g_signal_connect (G_OBJECT (window->priv->copy_from_archive), "done", G_CALLBACK (copy_from_archive_action_performed_cb), window); g_signal_connect (G_OBJECT (window->priv->copy_from_archive), "progress", G_CALLBACK (fr_window_progress_cb), window); g_signal_connect (G_OBJECT (window->priv->copy_from_archive), "message", G_CALLBACK (fr_window_message_cb), window); g_signal_connect (G_OBJECT (window->priv->copy_from_archive), "stoppable", G_CALLBACK (fr_window_stoppable_cb), window); fr_archive_set_fake_load_func (window->priv->copy_from_archive, always_fake_load, NULL); } fr_archive_load_local (window->priv->copy_from_archive, data->archive_filename, data->archive_password); } static void fr_window_paste_selection_to (FrWindow *window, const char *current_dir) { GtkClipboard *clipboard; GtkSelectionData *selection_data; FrClipboardData *paste_data; clipboard = gtk_clipboard_get (FR_CLIPBOARD); selection_data = gtk_clipboard_wait_for_contents (clipboard, FR_SPECIAL_URI_LIST); if (selection_data == NULL) return; paste_data = get_clipboard_data_from_selection_data (window, (char*) gtk_selection_data_get_data (selection_data)); paste_data->current_dir = g_strdup (current_dir); fr_window_paste_from_clipboard_data (window, paste_data); gtk_selection_data_free (selection_data); } void fr_window_paste_selection (FrWindow *window, gboolean from_sidebar) { char *utf8_path, *utf8_old_path, *destination; char *current_dir; if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) return; /**/ utf8_old_path = g_filename_to_utf8 (fr_window_get_current_location (window), -1, NULL, NULL, NULL); utf8_path = _gtk_request_dialog_run (GTK_WINDOW (window), (GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL), _("Paste Selection"), _("_Destination folder:"), utf8_old_path, 1024, _("_Cancel"), _("_Paste")); g_free (utf8_old_path); if (utf8_path == NULL) return; destination = g_filename_from_utf8 (utf8_path, -1, NULL, NULL, NULL); g_free (utf8_path); if (destination[0] != '/') current_dir = build_uri (fr_window_get_current_location (window), destination, NULL); else current_dir = g_strdup (destination); g_free (destination); fr_window_paste_selection_to (window, current_dir); g_free (current_dir); } /* -- fr_window_open_files -- */ void fr_window_open_files_with_command (FrWindow *window, GList *file_list, char *command) { GAppInfo *app; GError *error = NULL; app = g_app_info_create_from_commandline (command, NULL, G_APP_INFO_CREATE_NONE, &error); if (error != NULL) { _gtk_error_dialog_run (GTK_WINDOW (window), _("Could not perform the operation"), "%s", error->message); g_clear_error (&error); return; } fr_window_open_files_with_application (window, file_list, app); } void fr_window_open_files_with_application (FrWindow *window, GList *file_list, GAppInfo *app) { GList *uris; GList *scan; GdkAppLaunchContext *context; GError *error = NULL; if (window->priv->activity_ref > 0) return; g_assert (file_list != NULL); uris = NULL; for (scan = file_list; scan; scan = scan->next) uris = g_list_prepend (uris, g_filename_to_uri (scan->data, NULL, NULL)); context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (window))); gdk_app_launch_context_set_screen (context, gtk_widget_get_screen (GTK_WIDGET (window))); gdk_app_launch_context_set_timestamp (context, 0); if (! g_app_info_launch_uris (app, uris, G_APP_LAUNCH_CONTEXT (context), &error)) { _gtk_error_dialog_run (GTK_WINDOW (window), _("Could not perform the operation"), "%s", error->message); g_clear_error (&error); } g_object_unref (context); path_list_free (uris); } typedef struct { FrWindow *window; GList *file_list; gboolean ask_application; CommandData *cdata; } OpenFilesData; static OpenFilesData* open_files_data_new (FrWindow *window, GList *file_list, gboolean ask_application) { OpenFilesData *odata; GList *scan; odata = g_new0 (OpenFilesData, 1); odata->window = window; odata->file_list = path_list_dup (file_list); odata->ask_application = ask_application; odata->cdata = g_new0 (CommandData, 1); odata->cdata->temp_dir = get_temp_work_dir (NULL); odata->cdata->file_list = NULL; for (scan = file_list; scan; scan = scan->next) { char *file = scan->data; char *filename; filename = g_strconcat (odata->cdata->temp_dir, "/", file, NULL); odata->cdata->file_list = g_list_prepend (odata->cdata->file_list, filename); } /* Add to CommandList so the cdata is released on exit. */ CommandList = g_list_prepend (CommandList, odata->cdata); return odata; } static void open_files_data_free (OpenFilesData *odata) { g_return_if_fail (odata != NULL); path_list_free (odata->file_list); g_free (odata); } void fr_window_update_dialog_closed (FrWindow *window) { window->priv->update_dialog = NULL; } gboolean fr_window_update_files (FrWindow *window, GList *file_list) { GList *scan; if (window->priv->activity_ref > 0) return FALSE; if (window->archive->read_only) return FALSE; fr_process_clear (window->archive->process); for (scan = file_list; scan; scan = scan->next) { OpenFile *file = scan->data; GList *local_file_list; local_file_list = g_list_append (NULL, file->path); fr_archive_add (window->archive, local_file_list, file->temp_dir, "/", FALSE, FALSE, window->priv->password, window->priv->encrypt_header, window->priv->compression, window->priv->volume_size); g_list_free (local_file_list); } fr_process_start (window->archive->process); return TRUE; } static void open_file_modified_cb (GFileMonitor *monitor, GFile *monitor_file, GFile *other_file, GFileMonitorEvent event_type, gpointer user_data) { FrWindow *window = user_data; char *monitor_uri; OpenFile *file; GList *scan; if ((event_type != G_FILE_MONITOR_EVENT_CHANGED) && (event_type != G_FILE_MONITOR_EVENT_CREATED)) { return; } monitor_uri = g_file_get_uri (monitor_file); file = NULL; for (scan = window->priv->open_files; scan; scan = scan->next) { OpenFile *test = scan->data; if (uricmp (test->extracted_uri, monitor_uri) == 0) { file = test; break; } } g_free (monitor_uri); g_return_if_fail (file != NULL); if (window->priv->update_dialog == NULL) window->priv->update_dialog = dlg_update (window); dlg_update_add_file (window->priv->update_dialog, file); } static void fr_window_monitor_open_file (FrWindow *window, OpenFile *file) { GFile *f; window->priv->open_files = g_list_prepend (window->priv->open_files, file); f = g_file_new_for_uri (file->extracted_uri); file->monitor = g_file_monitor_file (f, 0, NULL, NULL); g_signal_connect (file->monitor, "changed", G_CALLBACK (open_file_modified_cb), window); g_object_unref (f); } static void monitor_extracted_files (OpenFilesData *odata) { FrWindow *window = odata->window; GList *scan1, *scan2; for (scan1 = odata->file_list, scan2 = odata->cdata->file_list; scan1 && scan2; scan1 = scan1->next, scan2 = scan2->next) { OpenFile *ofile; const char *file = scan1->data; const char *extracted_path = scan2->data; ofile = open_file_new (file, extracted_path, odata->cdata->temp_dir); if (ofile != NULL) fr_window_monitor_open_file (window, ofile); } } static gboolean fr_window_open_extracted_files (OpenFilesData *odata) { GList *file_list = odata->cdata->file_list; const char *first_file; const char *first_mime_type; GAppInfo *app; GList *files_to_open = NULL; GdkAppLaunchContext *context; gboolean result; GError *error = NULL; g_return_val_if_fail (file_list != NULL, FALSE); first_file = (char*) file_list->data; if (first_file == NULL) return FALSE; if (! odata->window->archive->read_only) monitor_extracted_files (odata); if (odata->ask_application) { dlg_open_with (odata->window, file_list); return FALSE; } first_mime_type = get_file_mime_type_for_path (first_file, FALSE); app = g_app_info_get_default_for_type (first_mime_type, FALSE); if (app == NULL) { dlg_open_with (odata->window, file_list); return FALSE; } files_to_open = g_list_append (files_to_open, g_filename_to_uri (first_file, NULL, NULL)); if (g_app_info_supports_files (app)) { GList *scan; for (scan = file_list->next; scan; scan = scan->next) { const char *path = scan->data; const char *mime_type; mime_type = get_file_mime_type_for_path (path, FALSE); if (mime_type == NULL) continue; if (strcmp (mime_type, first_mime_type) == 0) { files_to_open = g_list_append (files_to_open, g_filename_to_uri (path, NULL, NULL)); } else { GAppInfo *app2; app2 = g_app_info_get_default_for_type (mime_type, FALSE); if (g_app_info_equal (app, app2)) files_to_open = g_list_append (files_to_open, g_filename_to_uri (path, NULL, NULL)); g_object_unref (app2); } } } context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (odata->window))); gdk_app_launch_context_set_screen (context, gtk_widget_get_screen (GTK_WIDGET (odata->window))); gdk_app_launch_context_set_timestamp (context, 0); result = g_app_info_launch_uris (app, files_to_open, G_APP_LAUNCH_CONTEXT (context), &error); if (! result) { _gtk_error_dialog_run (GTK_WINDOW (odata->window), _("Could not perform the operation"), "%s", error->message); g_clear_error (&error); } g_object_unref (context); g_object_unref (app); path_list_free (files_to_open); return result; } static void fr_window_open_files__extract_done_cb (FrArchive *archive, FrAction action, FrProcError *error, gpointer callback_data) { OpenFilesData *odata = callback_data; g_signal_handlers_disconnect_matched (G_OBJECT (archive), G_SIGNAL_MATCH_DATA, 0, 0, NULL, 0, odata); if (error->type == FR_PROC_ERROR_NONE) fr_window_open_extracted_files (odata); } void fr_window_open_files (FrWindow *window, GList *file_list, gboolean ask_application) { OpenFilesData *odata; if (window->priv->activity_ref > 0) return; odata = open_files_data_new (window, file_list, ask_application); fr_window_set_current_batch_action (window, FR_BATCH_ACTION_OPEN_FILES, odata, (GFreeFunc) open_files_data_free); g_signal_connect (G_OBJECT (window->archive), "done", G_CALLBACK (fr_window_open_files__extract_done_cb), odata); fr_process_clear (window->archive->process); fr_archive_extract_to_local (window->archive, odata->file_list, odata->cdata->temp_dir, NULL, FALSE, TRUE, FALSE, window->priv->password); fr_process_start (window->archive->process); } /**/ static char* get_default_dir (const char *dir) { if (! is_temp_dir (dir)) return g_strdup (dir); else return NULL; } void fr_window_set_open_default_dir (FrWindow *window, const char *default_dir) { g_return_if_fail (window != NULL); g_return_if_fail (default_dir != NULL); if (window->priv->open_default_dir != NULL) g_free (window->priv->open_default_dir); window->priv->open_default_dir = get_default_dir (default_dir); } const char * fr_window_get_open_default_dir (FrWindow *window) { if (window->priv->open_default_dir == NULL) return get_home_uri (); else return window->priv->open_default_dir; } void fr_window_set_add_default_dir (FrWindow *window, const char *default_dir) { g_return_if_fail (window != NULL); g_return_if_fail (default_dir != NULL); if (window->priv->add_default_dir != NULL) g_free (window->priv->add_default_dir); window->priv->add_default_dir = get_default_dir (default_dir); } const char * fr_window_get_add_default_dir (FrWindow *window) { if (window->priv->add_default_dir == NULL) return get_home_uri (); else return window->priv->add_default_dir; } void fr_window_set_extract_default_dir (FrWindow *window, const char *default_dir, gboolean freeze) { g_return_if_fail (window != NULL); g_return_if_fail (default_dir != NULL); /* do not change this dir while it's used by the non-interactive * extraction operation. */ if (window->priv->extract_interact_use_default_dir) return; window->priv->extract_interact_use_default_dir = freeze; if (window->priv->extract_default_dir != NULL) g_free (window->priv->extract_default_dir); window->priv->extract_default_dir = get_default_dir (default_dir); } const char * fr_window_get_extract_default_dir (FrWindow *window) { if (window->priv->extract_default_dir == NULL) return get_home_uri (); else return window->priv->extract_default_dir; } void fr_window_set_default_dir (FrWindow *window, const char *default_dir, gboolean freeze) { g_return_if_fail (window != NULL); g_return_if_fail (default_dir != NULL); window->priv->freeze_default_dir = freeze; fr_window_set_open_default_dir (window, default_dir); fr_window_set_add_default_dir (window, default_dir); fr_window_set_extract_default_dir (window, default_dir, FALSE); } void fr_window_update_columns_visibility (FrWindow *window) { GtkTreeView *tree_view = GTK_TREE_VIEW (window->priv->list_view); GtkTreeViewColumn *column; column = gtk_tree_view_get_column (tree_view, 1); gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_SIZE)); column = gtk_tree_view_get_column (tree_view, 2); gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_TYPE)); column = gtk_tree_view_get_column (tree_view, 3); gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_TIME)); column = gtk_tree_view_get_column (tree_view, 4); gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_PATH)); } void fr_window_set_toolbar_visibility (FrWindow *window, gboolean visible) { g_return_if_fail (window != NULL); if (visible) gtk_widget_show (window->priv->toolbar); else gtk_widget_hide (window->priv->toolbar); set_active (window, "ViewToolbar", visible); } void fr_window_set_statusbar_visibility (FrWindow *window, gboolean visible) { g_return_if_fail (window != NULL); if (visible) gtk_widget_show (window->priv->statusbar); else gtk_widget_hide (window->priv->statusbar); set_active (window, "ViewStatusbar", visible); } void fr_window_set_folders_visibility (FrWindow *window, gboolean value) { g_return_if_fail (window != NULL); window->priv->view_folders = value; fr_window_update_dir_tree (window); set_active (window, "ViewFolders", window->priv->view_folders); } void fr_window_use_progress_dialog (FrWindow *window, gboolean value) { window->priv->use_progress_dialog = value; } /* -- batch mode procedures -- */ static void fr_window_exec_current_batch_action (FrWindow *window); static void fr_window_exec_batch_action (FrWindow *window, FRBatchAction *action) { ExtractData *edata; RenameData *rdata; OpenFilesData *odata; SaveAsData *sdata; switch (action->type) { case FR_BATCH_ACTION_LOAD: debug (DEBUG_INFO, "[BATCH] LOAD\n"); if (! uri_exists ((char*) action->data)) fr_window_archive_new (window, (char*) action->data); else fr_window_archive_open (window, (char*) action->data, GTK_WINDOW (window)); break; case FR_BATCH_ACTION_ADD: debug (DEBUG_INFO, "[BATCH] ADD\n"); fr_window_archive_add_dropped_items (window, (GList*) action->data, FALSE); break; case FR_BATCH_ACTION_OPEN: debug (DEBUG_INFO, "[BATCH] OPEN\n"); fr_window_push_message (window, _("Add files to an archive")); dlg_batch_add_files (window, (GList*) action->data); break; case FR_BATCH_ACTION_EXTRACT: debug (DEBUG_INFO, "[BATCH] EXTRACT\n"); edata = action->data; fr_window_archive_extract (window, edata->file_list, edata->extract_to_dir, edata->base_dir, edata->skip_older, edata->overwrite, edata->junk_paths, TRUE); break; case FR_BATCH_ACTION_EXTRACT_HERE: debug (DEBUG_INFO, "[BATCH] EXTRACT HERE\n"); fr_window_archive_extract_here (window, FALSE, FR_OVERWRITE_NO, FALSE); break; case FR_BATCH_ACTION_EXTRACT_INTERACT: debug (DEBUG_INFO, "[BATCH] EXTRACT_INTERACT\n"); if (window->priv->extract_interact_use_default_dir && (window->priv->extract_default_dir != NULL)) { fr_window_archive_extract (window, NULL, window->priv->extract_default_dir, NULL, FALSE, FR_OVERWRITE_ASK, FALSE, TRUE); } else { fr_window_push_message (window, _("Extract archive")); dlg_extract (NULL, window); } break; case FR_BATCH_ACTION_RENAME: debug (DEBUG_INFO, "[BATCH] RENAME\n"); rdata = action->data; rename_selection (window, rdata->path_to_rename, rdata->old_name, rdata->new_name, rdata->current_dir, rdata->is_dir, rdata->dir_in_archive, rdata->original_path); break; case FR_BATCH_ACTION_PASTE: debug (DEBUG_INFO, "[BATCH] PASTE\n"); fr_window_paste_from_clipboard_data (window, (FrClipboardData*) action->data); break; case FR_BATCH_ACTION_OPEN_FILES: debug (DEBUG_INFO, "[BATCH] OPEN FILES\n"); odata = action->data; fr_window_open_files (window, odata->file_list, odata->ask_application); break; case FR_BATCH_ACTION_SAVE_AS: debug (DEBUG_INFO, "[BATCH] SAVE_AS\n"); sdata = action->data; fr_window_archive_save_as (window, sdata->uri, sdata->password, sdata->encrypt_header, sdata->volume_size); break; case FR_BATCH_ACTION_TEST: debug (DEBUG_INFO, "[BATCH] TEST\n"); fr_window_archive_test (window); break; case FR_BATCH_ACTION_CLOSE: debug (DEBUG_INFO, "[BATCH] CLOSE\n"); fr_window_archive_close (window); fr_window_exec_next_batch_action (window); break; case FR_BATCH_ACTION_QUIT: debug (DEBUG_INFO, "[BATCH] QUIT\n"); g_signal_emit (window, fr_window_signals[READY], 0, NULL); if ((window->priv->progress_dialog != NULL) && (gtk_widget_get_parent (window->priv->progress_dialog) != GTK_WIDGET (window))) gtk_widget_destroy (window->priv->progress_dialog); gtk_widget_destroy (GTK_WIDGET (window)); break; default: break; } } void fr_window_reset_current_batch_action (FrWindow *window) { FRBatchAction *adata = &window->priv->current_batch_action; if ((adata->data != NULL) && (adata->free_func != NULL)) (*adata->free_func) (adata->data); adata->type = FR_BATCH_ACTION_NONE; adata->data = NULL; adata->free_func = NULL; } void fr_window_set_current_batch_action (FrWindow *window, FrBatchActionType action, void *data, GFreeFunc free_func) { FRBatchAction *adata = &window->priv->current_batch_action; fr_window_reset_current_batch_action (window); adata->type = action; adata->data = data; adata->free_func = free_func; } void fr_window_restart_current_batch_action (FrWindow *window) { fr_window_exec_batch_action (window, &window->priv->current_batch_action); } void fr_window_append_batch_action (FrWindow *window, FrBatchActionType action, void *data, GFreeFunc free_func) { FRBatchAction *a_desc; g_return_if_fail (window != NULL); a_desc = g_new0 (FRBatchAction, 1); a_desc->type = action; a_desc->data = data; a_desc->free_func = free_func; window->priv->batch_action_list = g_list_append (window->priv->batch_action_list, a_desc); } static void fr_window_exec_current_batch_action (FrWindow *window) { FRBatchAction *action; if (window->priv->batch_action == NULL) { window->priv->batch_mode = FALSE; return; } action = (FRBatchAction *) window->priv->batch_action->data; fr_window_exec_batch_action (window, action); } static void fr_window_exec_next_batch_action (FrWindow *window) { if (window->priv->batch_action != NULL) window->priv->batch_action = g_list_next (window->priv->batch_action); else window->priv->batch_action = window->priv->batch_action_list; fr_window_exec_current_batch_action (window); } void fr_window_start_batch (FrWindow *window) { g_return_if_fail (window != NULL); if (window->priv->batch_mode) return; if (window->priv->batch_action_list == NULL) return; if (window->priv->progress_dialog != NULL) gtk_window_set_title (GTK_WINDOW (window->priv->progress_dialog), window->priv->batch_title); window->priv->batch_mode = TRUE; window->priv->batch_action = window->priv->batch_action_list; window->archive->can_create_compressed_file = window->priv->batch_adding_one_file; fr_window_exec_current_batch_action (window); } void fr_window_stop_batch (FrWindow *window) { if (! window->priv->non_interactive) return; window->priv->extract_interact_use_default_dir = FALSE; window->archive->can_create_compressed_file = FALSE; if (window->priv->batch_mode) { if (! window->priv->showing_error_dialog) { gtk_widget_destroy (GTK_WIDGET (window)); return; } } else { gtk_window_present (GTK_WINDOW (window)); fr_window_archive_close (window); } window->priv->batch_mode = FALSE; } void fr_window_resume_batch (FrWindow *window) { fr_window_exec_current_batch_action (window); } gboolean fr_window_is_batch_mode (FrWindow *window) { return window->priv->batch_mode; } void fr_window_new_batch (FrWindow *window, const char *title) { fr_window_free_batch_data (window); window->priv->non_interactive = TRUE; g_free (window->priv->batch_title); window->priv->batch_title = g_strdup (title); } void fr_window_set_batch__extract_here (FrWindow *window, const char *filename) { g_return_if_fail (window != NULL); g_return_if_fail (filename != NULL); fr_window_append_batch_action (window, FR_BATCH_ACTION_LOAD, g_strdup (filename), (GFreeFunc) g_free); fr_window_append_batch_action (window, FR_BATCH_ACTION_EXTRACT_HERE, extract_to_data_new (NULL), (GFreeFunc) extract_data_free); fr_window_append_batch_action (window, FR_BATCH_ACTION_CLOSE, NULL, NULL); } void fr_window_set_batch__extract (FrWindow *window, const char *filename, const char *dest_dir) { g_return_if_fail (window != NULL); g_return_if_fail (filename != NULL); fr_window_append_batch_action (window, FR_BATCH_ACTION_LOAD, g_strdup (filename), (GFreeFunc) g_free); if (dest_dir != NULL) fr_window_append_batch_action (window, FR_BATCH_ACTION_EXTRACT, extract_to_data_new (dest_dir), (GFreeFunc) extract_data_free); else fr_window_append_batch_action (window, FR_BATCH_ACTION_EXTRACT_INTERACT, NULL, NULL); fr_window_append_batch_action (window, FR_BATCH_ACTION_CLOSE, NULL, NULL); } void fr_window_set_batch__add (FrWindow *window, const char *archive, GList *file_list) { window->priv->batch_adding_one_file = (file_list->next == NULL) && (uri_is_file (file_list->data)); if (archive != NULL) fr_window_append_batch_action (window, FR_BATCH_ACTION_LOAD, g_strdup (archive), (GFreeFunc) g_free); else fr_window_append_batch_action (window, FR_BATCH_ACTION_OPEN, file_list, NULL); fr_window_append_batch_action (window, FR_BATCH_ACTION_ADD, file_list, NULL); fr_window_append_batch_action (window, FR_BATCH_ACTION_CLOSE, NULL, NULL); }