1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * File-Roller
5 *
6 * Copyright (C) 2007 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <math.h>
24 #include <string.h>
25 #include <glib/gi18n.h>
26 #include <gio/gio.h>
27 #include <gtk/gtk.h>
28 #include <gdk/gdk.h>
29 #ifdef GDK_WINDOWING_X11
30 # include <gdk/gdkx.h>
31 #endif
32 #include <gdk/gdkkeysyms.h>
33 #include <gdk-pixbuf/gdk-pixbuf.h>
34 #ifdef ENABLE_NOTIFICATION
35 # include <libnotify/notify.h>
36 #endif
37 #include "dlg-batch-add.h"
38 #include "dlg-delete.h"
39 #include "dlg-extract.h"
40 #include "dlg-open-with.h"
41 #include "dlg-ask-password.h"
42 #include "dlg-package-installer.h"
43 #include "dlg-update.h"
44 #include "eggtreemultidnd.h"
45 #include "fr-marshal.h"
46 #include "fr-list-model.h"
47 #include "fr-location-bar.h"
48 #include "fr-archive.h"
49 #include "fr-command.h"
50 #include "fr-error.h"
51 #include "fr-new-archive-dialog.h"
52 #include "fr-window.h"
53 #include "fr-window-actions-entries.h"
54 #include "file-data.h"
55 #include "file-utils.h"
56 #include "glib-utils.h"
57 #include "gth-icon-cache.h"
58 #include "fr-init.h"
59 #include "gtk-utils.h"
60 #include "open-file.h"
61 #include "typedefs.h"
62
63 #define LAST_OUTPUT_SCHEMA_NAME "LastOutput"
64 #define MAX_HISTORY_LEN 5
65 #define ACTIVITY_DELAY 100
66 #define ACTIVITY_PULSE_STEP (0.033)
67 #define MAX_MESSAGE_LENGTH 50
68
69 #define PROGRESS_DIALOG_DEFAULT_WIDTH 500
70 #define PROGRESS_TIMEOUT_MSECS 1000
71 #define PROGRESS_BAR_HEIGHT 10
72 #undef LOG_PROGRESS
73
74 #define HIDE_PROGRESS_TIMEOUT_MSECS 500
75 #define DEFAULT_NAME_COLUMN_WIDTH 250
76 #define OTHER_COLUMNS_WIDTH 100
77 #define RECENT_ITEM_MAX_WIDTH 25
78
79 #define DEF_WIN_WIDTH 600
80 #define DEF_WIN_HEIGHT 480
81 #define DEF_SIDEBAR_WIDTH 200
82
83 #define FILE_LIST_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
84 #define DIR_TREE_ICON_SIZE GTK_ICON_SIZE_MENU
85
86 #define BAD_CHARS "/\\*"
87
88 #define XDS_FILENAME "xds.txt"
89 #define MAX_XDS_ATOM_VAL_LEN 4096
90 #define XDS_ATOM gdk_atom_intern ("XdndDirectSave0", FALSE)
91 #define TEXT_ATOM gdk_atom_intern ("text/plain", FALSE)
92 #define OCTET_ATOM gdk_atom_intern ("application/octet-stream", FALSE)
93 #define XFR_ATOM gdk_atom_intern ("XdndFileRoller0", FALSE)
94
95 #define FR_CLIPBOARD (gdk_atom_intern_static_string ("_FILE_ROLLER_SPECIAL_CLIPBOARD"))
96 #define FR_SPECIAL_URI_LIST (gdk_atom_intern_static_string ("application/file-roller-uri-list"))
97
98 static GtkTargetEntry clipboard_targets[] = {
99 { "application/file-roller-uri-list", 0, 1 }
100 };
101
102 static GtkTargetEntry target_table[] = {
103 { "XdndFileRoller0", 0, 0 },
104 { "text/uri-list", 0, 1 },
105 };
106
107 static GtkTargetEntry folder_tree_targets[] = {
108 { "XdndFileRoller0", 0, 0 },
109 { "XdndDirectSave0", 0, 2 }
110 };
111
112
113 typedef struct {
114 FrBatchActionType type;
115 void * data;
116 GFreeFunc free_func;
117 } FrBatchAction;
118
119
120 typedef struct {
121 FrWindow *window;
122 GList *file_list;
123 GFile *destination;
124 char *base_dir;
125 gboolean skip_older;
126 FrOverwrite overwrite;
127 gboolean junk_paths;
128 char *password;
129 gboolean ask_to_open_destination;
130 gboolean avoid_tarbombs;
131 } ExtractData;
132
133
134 typedef enum {
135 FR_WINDOW_AREA_MENUBAR,
136 FR_WINDOW_AREA_TOOLBAR,
137 FR_WINDOW_AREA_LOCATIONBAR,
138 FR_WINDOW_AREA_CONTENTS,
139 FR_WINDOW_AREA_FILTERBAR,
140 FR_WINDOW_AREA_STATUSBAR,
141 } FrWindowArea;
142
143
144 typedef enum {
145 DIALOG_RESPONSE_NONE = 1,
146 DIALOG_RESPONSE_OPEN_ARCHIVE,
147 DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER,
148 } DialogResponse;
149
150
151 /* -- FrClipboardData -- */
152
153
154 typedef struct {
155 int refs;
156 GFile *file;
157 char *password;
158 FrClipboardOp op;
159 char *base_dir;
160 GList *files;
161 GFile *tmp_dir;
162 char *current_dir;
163 } FrClipboardData;
164
165
166 static FrClipboardData*
fr_clipboard_data_new(void)167 fr_clipboard_data_new (void)
168 {
169 FrClipboardData *data;
170
171 data = g_new0 (FrClipboardData, 1);
172 data->refs = 1;
173
174 return data;
175 }
176
177
178 static FrClipboardData *
fr_clipboard_data_ref(FrClipboardData * clipboard_data)179 fr_clipboard_data_ref (FrClipboardData *clipboard_data)
180 {
181 clipboard_data->refs++;
182 return clipboard_data;
183 }
184
185
186 static void
fr_clipboard_data_unref(FrClipboardData * clipboard_data)187 fr_clipboard_data_unref (FrClipboardData *clipboard_data)
188 {
189 if (clipboard_data == NULL)
190 return;
191 if (--clipboard_data->refs > 0)
192 return;
193
194 _g_object_unref (clipboard_data->file);
195 g_free (clipboard_data->password);
196 g_free (clipboard_data->base_dir);
197 _g_object_unref (clipboard_data->tmp_dir);
198 g_free (clipboard_data->current_dir);
199 g_list_foreach (clipboard_data->files, (GFunc) g_free, NULL);
200 g_list_free (clipboard_data->files);
201 g_free (clipboard_data);
202 }
203
204
205 static void
fr_clipboard_data_set_password(FrClipboardData * clipboard_data,const char * password)206 fr_clipboard_data_set_password (FrClipboardData *clipboard_data,
207 const char *password)
208 {
209 if (clipboard_data->password != password)
210 g_free (clipboard_data->password);
211 if (password != NULL)
212 clipboard_data->password = g_strdup (password);
213 }
214
215
216 /**/
217
218
219 G_DEFINE_TYPE (FrWindow, fr_window, GTK_TYPE_APPLICATION_WINDOW)
220
221
222 enum {
223 ARCHIVE_LOADED,
224 PROGRESS,
225 READY,
226 LAST_SIGNAL
227 };
228
229 static guint fr_window_signals[LAST_SIGNAL] = { 0 };
230
231 struct _FrWindowPrivate {
232 GtkWidget *layout;
233 GtkWidget *contents;
234 GtkWidget *list_view;
235 GtkListStore *list_store;
236 GtkWidget *tree_view;
237 GtkTreeStore *tree_store;
238 GtkWidget *headerbar;
239 GtkWidget *location_bar;
240 GtkWidget *location_entry;
241 GtkWidget *location_label;
242 GtkWidget *filter_bar;
243 GtkWidget *filter_entry;
244 GtkWidget *paned;
245 GtkWidget *sidepane;
246 GtkTreePath *tree_hover_path;
247 GtkTreePath *list_hover_path;
248 GtkTreeViewColumn *filename_column;
249 GtkWindowGroup *window_group;
250 GtkAccelGroup *accel_group;
251 GHashTable *named_dialogs;
252
253 gboolean filter_mode;
254 gint current_view_length;
255
256 GtkWidget * up_arrows[5];
257 GtkWidget * down_arrows[5];
258
259 FrAction action;
260 gboolean archive_present;
261 gboolean archive_new; /* A new archive has been created
262 * but it doesn't contain any
263 * file yet. The real file will
264 * be created only when the user
265 * adds some file to the
266 * archive.*/
267 gboolean reload_archive;
268
269 GFile * archive_file;
270 GFile * open_default_dir; /* default directory to be used
271 * in the Open dialog. */
272 GFile * add_default_dir; /* default directory to be used
273 * in the Add dialog. */
274 GFile * extract_default_dir; /* default directory to be used
275 * in the Extract dialog. */
276 gboolean freeze_default_dir;
277 gboolean destroy_with_error_dialog;
278 gboolean destroy_with_confirmation_dialog;
279
280 FrBatchAction current_action;
281
282 gboolean give_focus_to_the_list;
283 gboolean single_click;
284 GtkTreePath *path_clicked;
285
286 FrWindowSortMethod sort_method;
287 GtkSortType sort_type;
288
289 char * last_location;
290
291 gboolean view_sidebar;
292 FrWindowListMode list_mode;
293 FrWindowListMode last_list_mode;
294 GList * history;
295 GList * history_current;
296 char * password;
297 char * second_password;
298 gboolean encrypt_header;
299 FrCompression compression;
300 guint volume_size;
301
302 guint activity_timeout_handle; /* activity timeout
303 * handle. */
304 gint activity_ref; /* when > 0 some activity
305 * is present. */
306
307 gboolean stoppable;
308 gboolean closing;
309 gboolean notify;
310 gboolean populating_file_list;
311
312 FrClipboardData *clipboard_data;
313 FrClipboardData *copy_data;
314
315 FrArchive *copy_from_archive;
316 GFile *saving_file;
317
318 GtkWidget *file_popup_menu;
319 GtkWidget *folder_popup_menu;
320 GtkWidget *sidebar_folder_popup_menu;
321 GtkWidget *mitem_recents_menu;
322
323 /* dragged files data */
324
325 GFile *drag_destination_folder;
326 char *drag_base_dir;
327 GError *drag_error;
328 GList *drag_file_list; /* the list of files we are
329 * dragging*/
330 gboolean dnd_extract_is_running;
331 gboolean dnd_extract_finished_with_error;
332
333 /* progress dialog data */
334
335 GtkWidget *progress_dialog;
336 GtkWidget *pd_action;
337 GtkWidget *pd_message;
338 GtkWidget *pd_progress_bar;
339 GtkWidget *pd_progress_box;
340 gboolean progress_pulse;
341 guint progress_timeout; /* Timeout to display the progress dialog. */
342 guint hide_progress_timeout; /* Timeout to hide the progress dialog. */
343 GFile *pd_last_archive;
344 GFile *working_archive;
345 double pd_last_fraction;
346 char *pd_last_message;
347 gboolean use_progress_dialog;
348 char *custom_action_message;
349
350 /* update dialog data */
351
352 gpointer update_dialog;
353 GList *open_files;
354
355 /* batch mode data */
356
357 gboolean batch_mode; /* whether we are in a non interactive
358 * mode. */
359 GList *batch_action_list; /* FrBatchAction * elements */
360 GList *batch_action; /* current action. */
361 char *batch_title;
362
363 /* misc */
364
365 GCancellable *cancellable;
366
367 GSettings *settings_listing;
368 GSettings *settings_ui;
369 GSettings *settings_general;
370 GSettings *settings_dialogs;
371 GSettings *settings_nautilus;
372
373 gulong theme_changed_handler_id;
374 gboolean update_dropped_files;
375 gboolean batch_adding_one_file;
376
377 GtkWindow *load_error_parent_window;
378 gboolean showing_error_dialog;
379
380 GthIconCache *list_icon_cache;
381 GthIconCache *tree_icon_cache;
382
383 GFile *last_extraction_destination;
384 GList *last_extraction_files_first_level; /* GFile list */
385 };
386
387
388 /* -- fr_window_free_private_data -- */
389
390
391 static void
fr_batch_action_free(FrBatchAction * action)392 fr_batch_action_free (FrBatchAction *action) {
393 if ((action->data != NULL) && (action->free_func != NULL))
394 (*action->free_func) (action->data);
395 g_free (action);
396 }
397
398
399 static void
fr_window_free_batch_data(FrWindow * window)400 fr_window_free_batch_data (FrWindow *window)
401 {
402 GList *scan;
403
404 for (scan = window->priv->batch_action_list; scan; scan = scan->next)
405 fr_batch_action_free ((FrBatchAction *) scan->data);
406 g_list_free (window->priv->batch_action_list);
407 window->priv->batch_action_list = NULL;
408 window->priv->batch_action = NULL;
409
410 fr_window_reset_current_action (window);
411 }
412
413
414 static GdkAtom
_fr_window_get_clipboard_name(FrWindow * window)415 _fr_window_get_clipboard_name (FrWindow *window)
416 {
417 #ifdef GDK_WINDOWING_X11
418 if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
419 return FR_CLIPBOARD;
420 #endif
421 return GDK_SELECTION_CLIPBOARD;
422 }
423
424
425 static void
fr_window_clipboard_remove_file_list(FrWindow * window,GList * file_list)426 fr_window_clipboard_remove_file_list (FrWindow *window,
427 GList *file_list)
428 {
429 GList *scan1;
430
431 if (window->priv->copy_data == NULL)
432 return;
433
434 if (file_list == NULL) {
435 fr_clipboard_data_unref (window->priv->copy_data);
436 window->priv->copy_data = NULL;
437 return;
438 }
439
440 for (scan1 = file_list; scan1; scan1 = scan1->next) {
441 const char *name1 = scan1->data;
442 GList *scan2;
443
444 for (scan2 = window->priv->copy_data->files; scan2;) {
445 const char *name2 = scan2->data;
446
447 if (strcmp (name1, name2) == 0) {
448 GList *tmp = scan2->next;
449 window->priv->copy_data->files = g_list_remove_link (window->priv->copy_data->files, scan2);
450 g_free (scan2->data);
451 g_list_free (scan2);
452 scan2 = tmp;
453 }
454 else
455 scan2 = scan2->next;
456 }
457 }
458
459 if (window->priv->copy_data->files == NULL) {
460 fr_clipboard_data_unref (window->priv->copy_data);
461 window->priv->copy_data = NULL;
462 gtk_clipboard_clear (gtk_widget_get_clipboard (GTK_WIDGET (window), _fr_window_get_clipboard_name (window)));
463 }
464 }
465
466
467 static void
fr_window_history_clear(FrWindow * window)468 fr_window_history_clear (FrWindow *window)
469 {
470 if (window->priv->history != NULL)
471 _g_string_list_free (window->priv->history);
472 window->priv->history = NULL;
473 window->priv->history_current = NULL;
474 g_free (window->priv->last_location);
475 window->priv->last_location = NULL;
476 }
477
478
479 static void
fr_window_free_open_files(FrWindow * window)480 fr_window_free_open_files (FrWindow *window)
481 {
482 GList *scan;
483
484 for (scan = window->priv->open_files; scan; scan = scan->next) {
485 OpenFile *file = scan->data;
486
487 if (file->monitor != NULL)
488 g_file_monitor_cancel (file->monitor);
489 open_file_free (file);
490 }
491 g_list_free (window->priv->open_files);
492 window->priv->open_files = NULL;
493 }
494
495
496 static void
fr_window_free_private_data(FrWindow * window)497 fr_window_free_private_data (FrWindow *window)
498 {
499 if (window->priv->activity_timeout_handle != 0) {
500 g_source_remove (window->priv->activity_timeout_handle);
501 window->priv->activity_timeout_handle = 0;
502 }
503
504 if (window->priv->progress_timeout != 0) {
505 g_source_remove (window->priv->progress_timeout);
506 window->priv->progress_timeout = 0;
507 }
508
509 if (window->priv->hide_progress_timeout != 0) {
510 g_source_remove (window->priv->hide_progress_timeout);
511 window->priv->hide_progress_timeout = 0;
512 }
513
514 if (window->priv->theme_changed_handler_id != 0)
515 g_signal_handler_disconnect (gtk_icon_theme_get_default (), window->priv->theme_changed_handler_id);
516
517 fr_window_history_clear (window);
518
519 _g_object_unref (window->priv->open_default_dir);
520 _g_object_unref (window->priv->add_default_dir);
521 _g_object_unref (window->priv->extract_default_dir);
522 _g_object_unref (window->priv->archive_file);
523 _g_object_unref (window->priv->last_extraction_destination);
524
525 _g_object_list_unref (window->priv->last_extraction_files_first_level);
526 window->priv->last_extraction_files_first_level = NULL;
527
528 g_free (window->priv->password);
529 g_free (window->priv->second_password);
530 g_free (window->priv->custom_action_message);
531
532 g_object_unref (window->priv->list_store);
533
534 if (window->priv->clipboard_data != NULL) {
535 fr_clipboard_data_unref (window->priv->clipboard_data);
536 window->priv->clipboard_data = NULL;
537 }
538 if (window->priv->copy_data != NULL) {
539 fr_clipboard_data_unref (window->priv->copy_data);
540 window->priv->copy_data = NULL;
541 }
542 if (window->priv->copy_from_archive != NULL) {
543 g_object_unref (window->priv->copy_from_archive);
544 window->priv->copy_from_archive = NULL;
545 }
546
547 _g_object_unref (window->priv->saving_file);
548
549 fr_window_free_open_files (window);
550
551 g_clear_error (&window->priv->drag_error);
552 _g_string_list_free (window->priv->drag_file_list);
553 window->priv->drag_file_list = NULL;
554
555 g_free (window->priv->last_location);
556
557 fr_window_free_batch_data (window);
558 g_free (window->priv->batch_title);
559
560 _g_object_unref (window->priv->pd_last_archive);
561 g_free (window->priv->pd_last_message);
562
563 g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_LIST_MODE, window->priv->last_list_mode);
564
565 _g_object_unref (window->priv->settings_listing);
566 _g_object_unref (window->priv->settings_ui);
567 _g_object_unref (window->priv->settings_general);
568 _g_object_unref (window->priv->settings_dialogs);
569 _g_object_unref (window->priv->settings_nautilus);
570
571 _g_object_unref (window->priv->cancellable);
572 g_hash_table_unref (window->priv->named_dialogs);
573 g_object_unref (window->priv->window_group);
574 g_object_unref (window->priv->accel_group);
575 }
576
577
578 void
fr_window_close(FrWindow * window)579 fr_window_close (FrWindow *window)
580 {
581 if (window->priv->activity_ref > 0)
582 return;
583
584 if (window->priv->closing)
585 return;
586
587 window->priv->closing = TRUE;
588
589 if (gtk_widget_get_realized (GTK_WIDGET (window))) {
590 int width, height;
591
592 gtk_window_get_size (GTK_WINDOW (window), &width, &height);
593 g_settings_set_int (window->priv->settings_ui, PREF_UI_WINDOW_WIDTH, width);
594 g_settings_set_int (window->priv->settings_ui, PREF_UI_WINDOW_HEIGHT, height);
595
596 width = gtk_paned_get_position (GTK_PANED (window->priv->paned));
597 if (width > 0)
598 g_settings_set_int (window->priv->settings_ui, PREF_UI_SIDEBAR_WIDTH, width);
599
600 width = gtk_tree_view_column_get_width (window->priv->filename_column);
601 if (width > 0)
602 g_settings_set_int (window->priv->settings_listing, PREF_LISTING_NAME_COLUMN_WIDTH, width);
603 }
604
605 gtk_widget_destroy (GTK_WIDGET (window));
606 }
607
608
609 #define DIALOG_NAME_KEY "fr_dialog_name"
610
611
612 static void
unset_dialog(GtkWidget * object,gpointer user_data)613 unset_dialog (GtkWidget *object,
614 gpointer user_data)
615 {
616 FrWindow *window = user_data;
617 const char *dialog_name;
618
619 dialog_name = g_object_get_data (G_OBJECT (object), DIALOG_NAME_KEY);
620 if (dialog_name != NULL)
621 g_hash_table_remove (window->priv->named_dialogs, dialog_name);
622 }
623
624
625 void
fr_window_set_dialog(FrWindow * window,const char * dialog_name,GtkWidget * dialog)626 fr_window_set_dialog (FrWindow *window,
627 const char *dialog_name,
628 GtkWidget *dialog)
629 {
630 g_object_set_data (G_OBJECT (dialog), DIALOG_NAME_KEY, (gpointer) _g_str_get_static (dialog_name));
631 g_hash_table_insert (window->priv->named_dialogs, (gpointer) dialog_name, dialog);
632 g_signal_connect (dialog,
633 "destroy",
634 G_CALLBACK (unset_dialog),
635 window);
636 }
637
638
639 gboolean
fr_window_present_dialog_if_created(FrWindow * window,const char * dialog_name)640 fr_window_present_dialog_if_created (FrWindow *window,
641 const char *dialog_name)
642 {
643 GtkWidget *dialog;
644
645 dialog = g_hash_table_lookup (window->priv->named_dialogs, dialog_name);
646 if (dialog != NULL) {
647 gtk_window_present (GTK_WINDOW (dialog));
648 return TRUE;
649 }
650
651 return FALSE;
652 }
653
654
655 static void
fr_window_finalize(GObject * object)656 fr_window_finalize (GObject *object)
657 {
658 FrWindow *window = FR_WINDOW (object);
659
660 fr_window_free_open_files (window);
661
662 if (window->archive != NULL) {
663 g_object_unref (window->archive);
664 window->archive = NULL;
665 }
666
667 if (window->priv != NULL) {
668 fr_window_free_private_data (window);
669 g_free (window->priv);
670 window->priv = NULL;
671 }
672
673 G_OBJECT_CLASS (fr_window_parent_class)->finalize (object);
674 }
675
676
677
678 static void fr_window_update_file_list (FrWindow *window,
679 gboolean update_view);
680 static void fr_window_update_dir_tree (FrWindow *window);
681
682
683 static void
fr_window_enable_action(FrWindow * window,const char * action_name,gboolean enabled)684 fr_window_enable_action (FrWindow *window,
685 const char *action_name,
686 gboolean enabled)
687 {
688 GAction *action;
689
690 action = g_action_map_lookup_action (G_ACTION_MAP (window), action_name);
691 if (action != NULL)
692 g_object_set (action, "enabled", enabled, NULL);
693 }
694
695
696 static void
fr_window_set_action_state(FrWindow * window,const char * action_name,gboolean active)697 fr_window_set_action_state (FrWindow *window,
698 const char *action_name,
699 gboolean active)
700 {
701 GAction *action;
702
703 action = g_action_map_lookup_action (G_ACTION_MAP (window), action_name);
704 if (action != NULL)
705 g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (active));
706 }
707
708
709 static void
fr_window_change_action_state(FrWindow * window,const char * action_name,gboolean value)710 fr_window_change_action_state (FrWindow *window,
711 const char *action_name,
712 gboolean value)
713 {
714 GAction *action;
715 GVariant *old_state;
716 GVariant *new_state;
717
718 action = g_action_map_lookup_action (G_ACTION_MAP (window), action_name);
719 g_return_if_fail (action != NULL);
720
721 old_state = g_action_get_state (action);
722 new_state = g_variant_new_boolean (value);
723 if ((old_state == NULL) || ! g_variant_equal (old_state, new_state))
724 g_action_change_state (action, new_state);
725 else
726 g_variant_unref (new_state);
727
728 if (old_state != NULL)
729 g_variant_unref (old_state);
730 }
731
732
733 static void
fr_window_update_paste_command_sensitivity(FrWindow * window,GtkClipboard * clipboard)734 fr_window_update_paste_command_sensitivity (FrWindow *window,
735 GtkClipboard *clipboard)
736 {
737 gboolean running;
738 gboolean no_archive;
739 gboolean ro;
740
741 if (window->priv->closing)
742 return;
743
744 if (clipboard == NULL)
745 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), _fr_window_get_clipboard_name (window));
746 if (clipboard == NULL)
747 return;
748
749 running = window->priv->activity_ref > 0;
750 no_archive = (window->archive == NULL) || ! window->priv->archive_present;
751 ro = ! no_archive && window->archive->read_only;
752
753 #if 0
754 set_sensitive (window, "Paste",
755 ! no_archive
756 && ! ro
757 && ! running
758 && fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_STORE_MANY_FILES)
759 && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT)
760 && gtk_clipboard_wait_is_target_available (clipboard, FR_SPECIAL_URI_LIST));
761 #endif
762
763 fr_window_enable_action (window, "edit-paste",
764 ! no_archive
765 && ! ro
766 && ! running
767 && fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_STORE_MANY_FILES)
768 && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT)
769 && gtk_clipboard_wait_is_target_available (clipboard, FR_SPECIAL_URI_LIST));
770 }
771
772
773 static void
clipboard_owner_change_cb(GtkClipboard * clipboard,GdkEvent * event,gpointer user_data)774 clipboard_owner_change_cb (GtkClipboard *clipboard,
775 GdkEvent *event,
776 gpointer user_data)
777 {
778 fr_window_update_paste_command_sensitivity ((FrWindow *) user_data, clipboard);
779 }
780
781
782 static void
fr_window_realize(GtkWidget * widget)783 fr_window_realize (GtkWidget *widget)
784 {
785 FrWindow *window = FR_WINDOW (widget);
786 GIcon *icon;
787 GtkClipboard *clipboard;
788
789 GTK_WIDGET_CLASS (fr_window_parent_class)->realize (widget);
790
791 window->priv->list_icon_cache = gth_icon_cache_new_for_widget (GTK_WIDGET (window), GTK_ICON_SIZE_LARGE_TOOLBAR);
792 window->priv->tree_icon_cache = gth_icon_cache_new_for_widget (GTK_WIDGET (window), GTK_ICON_SIZE_MENU);
793
794 icon = g_content_type_get_icon ("text/plain");
795 gth_icon_cache_set_fallback (window->priv->list_icon_cache, icon);
796 gth_icon_cache_set_fallback (window->priv->tree_icon_cache, icon);
797 g_object_unref (icon);
798
799 clipboard = gtk_widget_get_clipboard (widget, _fr_window_get_clipboard_name (window));
800 g_signal_connect (clipboard,
801 "owner_change",
802 G_CALLBACK (clipboard_owner_change_cb),
803 window);
804
805 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store),
806 g_settings_get_enum (window->priv->settings_listing, PREF_LISTING_SORT_METHOD),
807 g_settings_get_enum (window->priv->settings_listing, PREF_LISTING_SORT_TYPE));
808
809 fr_window_update_dir_tree (window);
810 fr_window_update_file_list (window, TRUE);
811 }
812
813
814 static void
fr_window_unrealize(GtkWidget * widget)815 fr_window_unrealize (GtkWidget *widget)
816 {
817 FrWindow *window = FR_WINDOW (widget);
818 GtkClipboard *clipboard;
819
820 gth_icon_cache_free (window->priv->list_icon_cache);
821 window->priv->list_icon_cache = NULL;
822
823 gth_icon_cache_free (window->priv->tree_icon_cache);
824 window->priv->tree_icon_cache = NULL;
825
826 clipboard = gtk_widget_get_clipboard (widget, _fr_window_get_clipboard_name (window));
827 g_signal_handlers_disconnect_by_func (clipboard,
828 G_CALLBACK (clipboard_owner_change_cb),
829 window);
830
831 GTK_WIDGET_CLASS (fr_window_parent_class)->unrealize (widget);
832 }
833
834
835 static void
fr_window_unmap(GtkWidget * widget)836 fr_window_unmap (GtkWidget *widget)
837 {
838 FrWindow *window = FR_WINDOW (widget);
839 GtkSortType order;
840 int column_id;
841
842 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store),
843 &column_id,
844 &order))
845 {
846 g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_SORT_METHOD, column_id);
847 g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_SORT_TYPE, order);
848 }
849
850 GTK_WIDGET_CLASS (fr_window_parent_class)->unmap (widget);
851 }
852
853
854 static void
fr_window_class_init(FrWindowClass * klass)855 fr_window_class_init (FrWindowClass *klass)
856 {
857 GObjectClass *gobject_class;
858 GtkWidgetClass *widget_class;
859
860 fr_window_parent_class = g_type_class_peek_parent (klass);
861
862 fr_window_signals[ARCHIVE_LOADED] =
863 g_signal_new ("archive-loaded",
864 G_TYPE_FROM_CLASS (klass),
865 G_SIGNAL_RUN_LAST,
866 G_STRUCT_OFFSET (FrWindowClass, archive_loaded),
867 NULL, NULL,
868 fr_marshal_VOID__BOOLEAN,
869 G_TYPE_NONE, 1,
870 G_TYPE_BOOLEAN);
871 fr_window_signals[PROGRESS] =
872 g_signal_new ("progress",
873 G_TYPE_FROM_CLASS (klass),
874 G_SIGNAL_RUN_LAST,
875 G_STRUCT_OFFSET (FrWindowClass, progress),
876 NULL, NULL,
877 fr_marshal_VOID__DOUBLE_STRING,
878 G_TYPE_NONE, 2,
879 G_TYPE_DOUBLE,
880 G_TYPE_STRING);
881 fr_window_signals[READY] =
882 g_signal_new ("ready",
883 G_TYPE_FROM_CLASS (klass),
884 G_SIGNAL_RUN_LAST,
885 G_STRUCT_OFFSET (FrWindowClass, ready),
886 NULL, NULL,
887 fr_marshal_VOID__POINTER,
888 G_TYPE_NONE, 1,
889 G_TYPE_POINTER);
890
891 gobject_class = G_OBJECT_CLASS (klass);
892 gobject_class->finalize = fr_window_finalize;
893
894 widget_class = GTK_WIDGET_CLASS (klass);
895 widget_class->realize = fr_window_realize;
896 widget_class->unrealize = fr_window_unrealize;
897 widget_class->unmap = fr_window_unmap;
898 }
899
900
901 static void
fr_window_init(FrWindow * window)902 fr_window_init (FrWindow *window)
903 {
904 window->priv = g_new0 (FrWindowPrivate, 1);
905 window->priv->update_dropped_files = FALSE;
906 window->priv->dnd_extract_is_running = FALSE;
907 window->priv->dnd_extract_finished_with_error = FALSE;
908 window->priv->filter_mode = FALSE;
909 window->priv->use_progress_dialog = TRUE;
910 window->priv->batch_title = NULL;
911 window->priv->cancellable = g_cancellable_new ();
912 window->priv->compression = FR_COMPRESSION_NORMAL;
913 window->priv->window_group = gtk_window_group_new ();
914 window->priv->accel_group = gtk_accel_group_new ();
915 window->priv->populating_file_list = FALSE;
916 window->priv->named_dialogs = g_hash_table_new (g_str_hash, g_str_equal);
917
918 gtk_window_group_add_window (window->priv->window_group, GTK_WINDOW (window));
919 gtk_window_add_accel_group (GTK_WINDOW (window), window->priv->accel_group);
920
921 window->archive = NULL;
922 }
923
924
925
926 /* -- window history -- */
927
928
929 #if 0
930 static void
931 fr_window_history_print (FrWindow *window)
932 {
933 GList *list;
934
935 debug (DEBUG_INFO, "history:\n");
936 for (list = window->priv->history; list; list = list->next)
937 g_print ("\t%s %s\n",
938 (char*) list->data,
939 (list == window->priv->history_current)? "<-": "");
940 g_print ("\n");
941 }
942 #endif
943
944
945 static gboolean
fr_window_dir_exists_in_archive(FrWindow * window,const char * dir_name)946 fr_window_dir_exists_in_archive (FrWindow *window,
947 const char *dir_name)
948 {
949 int dir_name_len;
950 int i;
951
952 if (dir_name == NULL)
953 return FALSE;
954
955 dir_name_len = strlen (dir_name);
956 if (dir_name_len == 0)
957 return TRUE;
958
959 if (strcmp (dir_name, "/") == 0)
960 return TRUE;
961
962 for (i = 0; i < window->archive->files->len; i++) {
963 FileData *fdata = g_ptr_array_index (window->archive->files, i);
964
965 if (strncmp (dir_name, fdata->full_path, dir_name_len) == 0) {
966 return TRUE;
967 }
968 else if (fdata->dir
969 && (fdata->full_path[strlen (fdata->full_path) - 1] != '/')
970 && (strncmp (dir_name, fdata->full_path, dir_name_len - 1) == 0))
971 {
972 return TRUE;
973 }
974 }
975
976 return FALSE;
977 }
978
979
980 static void
fr_window_update_history(FrWindow * window)981 fr_window_update_history (FrWindow *window)
982 {
983 GList *scan;
984
985 /* remove the paths not present in the archive */
986
987 for (scan = window->priv->history; scan; /* void */) {
988 GList *next = scan->next;
989 char *path = scan->data;
990
991 if (! fr_window_dir_exists_in_archive (window, path)) {
992 if (scan == window->priv->history_current)
993 window->priv->history_current = NULL;
994 window->priv->history = g_list_remove_link (window->priv->history, scan);
995 _g_string_list_free (scan);
996 }
997
998 scan = next;
999 }
1000
1001 if (window->priv->history_current == NULL)
1002 window->priv->history_current = window->priv->history;
1003 }
1004
1005
1006 static void
fr_window_history_add(FrWindow * window,const char * path)1007 fr_window_history_add (FrWindow *window,
1008 const char *path)
1009 {
1010 if ((window->priv->history_current == NULL) || (g_strcmp0 (path, window->priv->history_current->data) != 0)) {
1011 GList *scan;
1012 GList *new_current = NULL;
1013
1014 /* search the path in the history */
1015 for (scan = window->priv->history_current; scan; scan = scan->next) {
1016 char *path_in_history = scan->data;
1017
1018 if (g_strcmp0 (path, path_in_history) == 0) {
1019 new_current = scan;
1020 break;
1021 }
1022 }
1023
1024 if (new_current != NULL) {
1025 window->priv->history_current = new_current;
1026 }
1027 else {
1028 /* remove all the paths after the current position */
1029 for (scan = window->priv->history; scan && (scan != window->priv->history_current); /* void */) {
1030 GList *next = scan->next;
1031
1032 window->priv->history = g_list_remove_link (window->priv->history, scan);
1033 _g_string_list_free (scan);
1034
1035 scan = next;
1036 }
1037
1038 window->priv->history = g_list_prepend (window->priv->history, g_strdup (path));
1039 window->priv->history_current = window->priv->history;
1040 }
1041 }
1042 }
1043
1044
1045 static void
fr_window_history_pop(FrWindow * window)1046 fr_window_history_pop (FrWindow *window)
1047 {
1048 GList *first;
1049
1050 if (window->priv->history == NULL)
1051 return;
1052
1053 first = window->priv->history;
1054 window->priv->history = g_list_remove_link (window->priv->history, first);
1055 if (window->priv->history_current == first)
1056 window->priv->history_current = window->priv->history;
1057 g_free (first->data);
1058 g_list_free (first);
1059 }
1060
1061
1062 /* -- activity mode -- */
1063
1064
1065
1066 static void
check_whether_has_a_dir(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1067 check_whether_has_a_dir (GtkTreeModel *model,
1068 GtkTreePath *path,
1069 GtkTreeIter *iter,
1070 gpointer data)
1071 {
1072 gboolean *has_a_dir = data;
1073 FileData *fdata;
1074
1075 gtk_tree_model_get (model, iter,
1076 COLUMN_FILE_DATA, &fdata,
1077 -1);
1078 if (file_data_is_dir (fdata))
1079 *has_a_dir = TRUE;
1080 }
1081
1082
1083 static gboolean
selection_has_a_dir(FrWindow * window)1084 selection_has_a_dir (FrWindow *window)
1085 {
1086 GtkTreeSelection *selection;
1087 gboolean has_a_dir = FALSE;
1088
1089 if (! gtk_widget_get_realized (window->priv->list_view))
1090 return FALSE;
1091
1092 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
1093 if (selection == NULL)
1094 return FALSE;
1095
1096 gtk_tree_selection_selected_foreach (selection,
1097 check_whether_has_a_dir,
1098 &has_a_dir);
1099
1100 return has_a_dir;
1101 }
1102
1103
1104 static void
fr_window_update_sensitivity(FrWindow * window)1105 fr_window_update_sensitivity (FrWindow *window)
1106 {
1107 gboolean no_archive;
1108 gboolean ro;
1109 gboolean file_op;
1110 gboolean running;
1111 gboolean can_store_many_files;
1112 gboolean sel_not_null;
1113 gboolean one_file_selected;
1114 gboolean dir_selected;
1115 int n_selected;
1116
1117 if (window->priv->batch_mode)
1118 return;
1119
1120 running = window->priv->activity_ref > 0;
1121 no_archive = (window->archive == NULL) || ! window->priv->archive_present;
1122 ro = ! no_archive && window->archive->read_only;
1123 file_op = ! no_archive && ! window->priv->archive_new && ! running;
1124 can_store_many_files = (window->archive != NULL) && fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_STORE_MANY_FILES);
1125 n_selected = fr_window_get_n_selected_files (window);
1126 sel_not_null = n_selected > 0;
1127 one_file_selected = n_selected == 1;
1128 dir_selected = selection_has_a_dir (window);
1129
1130 #if 0
1131 set_sensitive (window, "Add", ! no_archive && ! ro && ! running && can_store_many_files);
1132 set_sensitive (window, "Add_Toolbar", ! no_archive && ! ro && ! running && can_store_many_files);
1133 set_sensitive (window, "Copy", ! no_archive && ! ro && ! running && can_store_many_files && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
1134 set_sensitive (window, "Cut", ! no_archive && ! ro && ! running && can_store_many_files && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
1135 set_sensitive (window, "Delete", ! no_archive && ! ro && ! window->priv->archive_new && ! running && can_store_many_files);
1136 set_sensitive (window, "DeselectAll", ! no_archive && sel_not_null);
1137 set_sensitive (window, "Extract", file_op);
1138 set_sensitive (window, "Extract_Toolbar", file_op);
1139 set_sensitive (window, "Find", ! no_archive);
1140 set_sensitive (window, "New", ! running);
1141 set_sensitive (window, "Open", ! running);
1142 set_sensitive (window, "Open_Toolbar", ! running);
1143 set_sensitive (window, "OpenSelection", file_op && sel_not_null && ! dir_selected);
1144 set_sensitive (window, "OpenFolder", file_op && one_file_selected && dir_selected);
1145 set_sensitive (window, "Password", ! running && (! no_archive && window->archive->propPassword));
1146 set_sensitive (window, "Properties", file_op);
1147 set_sensitive (window, "Close", !running || window->priv->stoppable);
1148 set_sensitive (window, "Reload", ! (no_archive || running));
1149 set_sensitive (window, "Rename", ! no_archive && ! ro && ! running && can_store_many_files && one_file_selected);
1150 set_sensitive (window, "SaveAs", ! no_archive && can_store_many_files && ! running);
1151 set_sensitive (window, "SelectAll", ! no_archive);
1152 set_sensitive (window, "TestArchive", ! no_archive && ! running && window->archive->propTest);
1153 set_sensitive (window, "ViewSelection", file_op && one_file_selected && ! dir_selected);
1154 set_sensitive (window, "ViewSelection_Toolbar", file_op && one_file_selected && ! dir_selected);
1155 #endif
1156
1157 if (window->priv->progress_dialog != NULL)
1158 gtk_dialog_set_response_sensitive (GTK_DIALOG (window->priv->progress_dialog),
1159 GTK_RESPONSE_OK,
1160 running && window->priv->stoppable);
1161
1162 fr_window_update_paste_command_sensitivity (window, NULL);
1163
1164 #if 0
1165 set_sensitive (window, "SelectAll", (window->priv->current_view_length > 0) && (window->priv->current_view_length != n_selected));
1166 set_sensitive (window, "DeselectAll", n_selected > 0);
1167
1168 set_sensitive (window, "ViewSidebar", (window->priv->list_mode == FR_WINDOW_LIST_MODE_AS_DIR));
1169
1170 set_sensitive (window, "ViewAllFiles", ! window->priv->filter_mode);
1171 set_sensitive (window, "ViewAsFolder", ! window->priv->filter_mode);
1172 #endif
1173
1174 fr_window_enable_action (window, "add-files", ! no_archive && ! ro && ! running && can_store_many_files);
1175 fr_window_enable_action (window, "close", ! running || window->priv->stoppable);
1176 fr_window_enable_action (window, "delete", ! no_archive && ! ro && ! window->priv->archive_new && ! running && can_store_many_files);
1177 fr_window_enable_action (window, "edit-copy", ! no_archive && ! ro && ! running && can_store_many_files && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
1178 fr_window_enable_action (window, "edit-cut", ! no_archive && ! ro && ! running && can_store_many_files && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
1179 fr_window_enable_action (window, "edit-password", ! running && (! no_archive && window->archive->propPassword));
1180 fr_window_enable_action (window, "extract-files", file_op);
1181 fr_window_enable_action (window, "find", ! no_archive);
1182 fr_window_enable_action (window, "open-folder", file_op && one_file_selected && dir_selected);
1183 fr_window_enable_action (window, "open-with", file_op && sel_not_null && ! dir_selected);
1184 fr_window_enable_action (window, "rename", ! no_archive && ! ro && ! running && can_store_many_files && one_file_selected);
1185 fr_window_enable_action (window, "save-as", ! no_archive && can_store_many_files && ! running);
1186 fr_window_enable_action (window, "test-archive", ! no_archive && ! running && window->archive->propTest);
1187 fr_window_enable_action (window, "view-properties", file_op);
1188 fr_window_enable_action (window, "view-selection", file_op && one_file_selected && ! dir_selected);
1189 }
1190
1191
1192 static int
activity_cb(gpointer data)1193 activity_cb (gpointer data)
1194 {
1195 FrWindow *window = data;
1196
1197 if ((window->priv->pd_progress_bar != NULL) && window->priv->progress_pulse)
1198 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (window->priv->pd_progress_bar));
1199
1200 return TRUE;
1201 }
1202
1203
1204 static void
_fr_window_start_activity_mode(FrWindow * window)1205 _fr_window_start_activity_mode (FrWindow *window)
1206 {
1207 g_return_if_fail (window != NULL);
1208
1209 if (window->priv->activity_ref++ > 0)
1210 return;
1211
1212 window->priv->activity_timeout_handle = g_timeout_add (ACTIVITY_DELAY,
1213 activity_cb,
1214 window);
1215 fr_window_update_sensitivity (window);
1216 }
1217
1218
1219 static void
fr_window_pop_message(FrWindow * window)1220 fr_window_pop_message (FrWindow *window)
1221 {
1222 if (! gtk_widget_get_mapped (GTK_WIDGET (window)))
1223 return;
1224
1225 if (window->priv->progress_dialog != NULL)
1226 gtk_label_set_text (GTK_LABEL (window->priv->pd_message), _("Operation completed"));
1227 }
1228
1229
1230 static GPtrArray *
fr_window_get_current_dir_list(FrWindow * window)1231 fr_window_get_current_dir_list (FrWindow *window)
1232 {
1233 GPtrArray *files;
1234 int i;
1235
1236 files = g_ptr_array_sized_new (128);
1237
1238 for (i = 0; i < window->archive->files->len; i++) {
1239 FileData *fdata = g_ptr_array_index (window->archive->files, i);
1240
1241 if (fdata->list_name == NULL)
1242 continue;
1243 g_ptr_array_add (files, fdata);
1244 }
1245
1246 return files;
1247 }
1248
1249
1250 static void
_fr_window_stop_activity_mode(FrWindow * window)1251 _fr_window_stop_activity_mode (FrWindow *window)
1252 {
1253 g_return_if_fail (window != NULL);
1254
1255 if (window->priv->activity_ref == 0)
1256 return;
1257
1258 fr_window_pop_message (window);
1259
1260 if (--window->priv->activity_ref > 0)
1261 return;
1262
1263 if (window->priv->activity_timeout_handle != 0) {
1264 g_source_remove (window->priv->activity_timeout_handle);
1265 window->priv->activity_timeout_handle = 0;
1266 }
1267
1268 if (window->priv->progress_dialog != NULL)
1269 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->pd_progress_bar), 0.0);
1270
1271 fr_window_update_sensitivity (window);
1272 }
1273
1274
1275 /* -- window_update_file_list -- */
1276
1277
1278 static guint64
get_dir_size(FrWindow * window,const char * current_dir,const char * name)1279 get_dir_size (FrWindow *window,
1280 const char *current_dir,
1281 const char *name)
1282 {
1283 guint64 size;
1284 char *dirname;
1285 int dirname_l;
1286 int i;
1287
1288 dirname = g_strconcat (current_dir, name, "/", NULL);
1289 dirname_l = strlen (dirname);
1290
1291 size = 0;
1292 for (i = 0; i < window->archive->files->len; i++) {
1293 FileData *fd = g_ptr_array_index (window->archive->files, i);
1294
1295 if (strncmp (dirname, fd->full_path, dirname_l) == 0)
1296 size += fd->size;
1297 }
1298
1299 g_free (dirname);
1300
1301 return size;
1302 }
1303
1304
1305 static gboolean
file_data_respects_filter(FrWindow * window,GRegex * filter,FileData * fdata)1306 file_data_respects_filter (FrWindow *window,
1307 GRegex *filter,
1308 FileData *fdata)
1309 {
1310 if ((fdata == NULL) || (filter == NULL))
1311 return TRUE;
1312
1313 if (fdata->dir || (fdata->name == NULL))
1314 return FALSE;
1315
1316 return g_regex_match (filter, fdata->name, 0, NULL);
1317 }
1318
1319
1320 static gboolean
compute_file_list_name(FrWindow * window,GRegex * filter,FileData * fdata,const char * current_dir,int current_dir_len,GHashTable * names_hash,gboolean * different_name)1321 compute_file_list_name (FrWindow *window,
1322 GRegex *filter,
1323 FileData *fdata,
1324 const char *current_dir,
1325 int current_dir_len,
1326 GHashTable *names_hash,
1327 gboolean *different_name)
1328 {
1329 register char *scan, *end;
1330
1331 *different_name = FALSE;
1332
1333 if (! file_data_respects_filter (window, filter, fdata))
1334 return FALSE;
1335
1336 if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) {
1337 file_data_set_list_name (fdata, fdata->name);
1338 if (fdata->dir)
1339 fdata->dir_size = 0;
1340 return FALSE;
1341 }
1342
1343 if (strncmp (fdata->full_path, current_dir, current_dir_len) != 0) {
1344 *different_name = TRUE;
1345 return FALSE;
1346 }
1347
1348 if (strlen (fdata->full_path) == current_dir_len)
1349 return FALSE;
1350
1351 scan = fdata->full_path + current_dir_len;
1352 end = strchr (scan, '/');
1353 if ((end == NULL) && ! fdata->dir) { /* file */
1354 file_data_set_list_name (fdata, scan);
1355 }
1356 else { /* folder */
1357 char *dir_name;
1358
1359 if (end != NULL)
1360 dir_name = g_strndup (scan, end - scan);
1361 else
1362 dir_name = g_strdup (scan);
1363
1364 /* avoid to insert duplicated folders */
1365 if (g_hash_table_lookup (names_hash, dir_name) != NULL) {
1366 g_free (dir_name);
1367 return FALSE;
1368 }
1369 g_hash_table_insert (names_hash, dir_name, GINT_TO_POINTER (1));
1370
1371 if ((end != NULL) && (*(end + 1) != '\0'))
1372 fdata->list_dir = TRUE;
1373 file_data_set_list_name (fdata, dir_name);
1374 fdata->dir_size = get_dir_size (window, current_dir, dir_name);
1375 }
1376
1377 return TRUE;
1378 }
1379
1380
1381 static GRegex *
_fr_window_create_filter(FrWindow * window)1382 _fr_window_create_filter (FrWindow *window)
1383 {
1384 GRegex *filter;
1385 const char *filter_str;
1386
1387 filter = NULL;
1388 filter_str = gtk_entry_get_text (GTK_ENTRY (window->priv->filter_entry));
1389 if ((filter_str != NULL) && (*filter_str != '\0')) {
1390 char *escaped;
1391 char *pattern;
1392
1393 escaped = g_regex_escape_string (filter_str, -1);
1394 pattern = g_strdup_printf (".*%s.*", escaped);
1395 filter = g_regex_new (pattern, G_REGEX_CASELESS | G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY, NULL);
1396
1397 g_free (pattern);
1398 g_free (escaped);
1399 }
1400
1401 return filter;
1402 }
1403
1404
1405 static void
fr_window_compute_list_names(FrWindow * window,GPtrArray * files)1406 fr_window_compute_list_names (FrWindow *window,
1407 GPtrArray *files)
1408 {
1409 const char *current_dir;
1410 int current_dir_len;
1411 GHashTable *names_hash;
1412 GRegex *filter;
1413 int i;
1414 gboolean visible_list_started = FALSE;
1415 gboolean visible_list_completed = FALSE;
1416 gboolean different_name;
1417
1418 current_dir = fr_window_get_current_location (window);
1419 current_dir_len = strlen (current_dir);
1420 names_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1421
1422 filter = _fr_window_create_filter (window);
1423 for (i = 0; i < files->len; i++) {
1424 FileData *fdata = g_ptr_array_index (files, i);
1425
1426 file_data_set_list_name (fdata, NULL);
1427 fdata->list_dir = FALSE;
1428
1429 /* the files array is sorted by path, when the visible list
1430 * is started and we find a path that doesn't match the
1431 * current_dir path, the following files can't match
1432 * the current_dir path. */
1433
1434 if (visible_list_completed)
1435 continue;
1436
1437 if (compute_file_list_name (window, filter, fdata, current_dir, current_dir_len, names_hash, &different_name)) {
1438 visible_list_started = TRUE;
1439 }
1440 else if (visible_list_started && different_name)
1441 visible_list_completed = TRUE;
1442 }
1443
1444 if (filter != NULL)
1445 g_regex_unref (filter);
1446 g_hash_table_destroy (names_hash);
1447 }
1448
1449
1450 static char *
get_parent_dir(const char * current_dir)1451 get_parent_dir (const char *current_dir)
1452 {
1453 char *dir;
1454 char *new_dir;
1455 char *retval;
1456
1457 if (current_dir == NULL)
1458 return NULL;
1459 if (strcmp (current_dir, "/") == 0)
1460 return g_strdup ("/");
1461
1462 dir = g_strdup (current_dir);
1463 dir[strlen (dir) - 1] = 0;
1464 new_dir = _g_path_remove_level (dir);
1465 g_free (dir);
1466
1467 if (new_dir[strlen (new_dir) - 1] == '/')
1468 retval = new_dir;
1469 else {
1470 retval = g_strconcat (new_dir, "/", NULL);
1471 g_free (new_dir);
1472 }
1473
1474 return retval;
1475 }
1476
1477
1478 static GdkPixbuf *
get_mime_type_icon(FrWindow * window,const char * mime_type)1479 get_mime_type_icon (FrWindow *window,
1480 const char *mime_type)
1481 {
1482 GIcon *icon;
1483 GdkPixbuf *pixbuf;
1484
1485 icon = g_content_type_get_icon (mime_type);
1486 pixbuf = gth_icon_cache_get_pixbuf (window->priv->tree_icon_cache, icon);
1487
1488 g_object_unref (icon);
1489
1490 return pixbuf;
1491 }
1492
1493
1494 static GdkPixbuf *
get_icon(FrWindow * window,FileData * fdata)1495 get_icon (FrWindow *window,
1496 FileData *fdata)
1497 {
1498 GIcon *icon = NULL;
1499 GdkPixbuf *pixbuf = NULL;
1500
1501 if (fdata->link != NULL)
1502 icon = g_themed_icon_new ("emblem-symbolic-link");
1503 else {
1504 const char *content_type;
1505
1506 if (file_data_is_dir (fdata))
1507 content_type = MIME_TYPE_DIRECTORY;
1508 else
1509 content_type = fdata->content_type;
1510 icon = g_content_type_get_icon (content_type);
1511 }
1512
1513 pixbuf = gth_icon_cache_get_pixbuf (window->priv->list_icon_cache, icon);
1514 g_object_unref (icon);
1515
1516 return pixbuf;
1517 }
1518
1519
1520 static GdkPixbuf *
get_emblem(FrWindow * window,FileData * fdata)1521 get_emblem (FrWindow *window,
1522 FileData *fdata)
1523 {
1524 const char *emblem_name;
1525 GIcon *icon;
1526 GdkPixbuf *pixbuf;
1527
1528 emblem_name = NULL;
1529 if (fdata->encrypted)
1530 emblem_name = "emblem-readonly";
1531
1532 if (emblem_name == NULL)
1533 return NULL;
1534
1535 icon = g_themed_icon_new (emblem_name);
1536 pixbuf = gth_icon_cache_get_pixbuf (window->priv->list_icon_cache, icon);
1537 g_object_unref (icon);
1538
1539 return pixbuf;
1540 }
1541
1542
1543 static void
add_selected_from_list_view(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1544 add_selected_from_list_view (GtkTreeModel *model,
1545 GtkTreePath *path,
1546 GtkTreeIter *iter,
1547 gpointer data)
1548 {
1549 GList **list = data;
1550 FileData *fdata;
1551
1552 gtk_tree_model_get (model, iter,
1553 COLUMN_FILE_DATA, &fdata,
1554 -1);
1555 *list = g_list_prepend (*list, fdata);
1556 }
1557
1558
1559 static void
add_selected_from_tree_view(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1560 add_selected_from_tree_view (GtkTreeModel *model,
1561 GtkTreePath *path,
1562 GtkTreeIter *iter,
1563 gpointer data)
1564 {
1565 GList **list = data;
1566 char *dir_path;
1567
1568 gtk_tree_model_get (model, iter,
1569 TREE_COLUMN_PATH, &dir_path,
1570 -1);
1571 *list = g_list_prepend (*list, dir_path);
1572 }
1573
1574
1575 static void
fr_window_populate_file_list(FrWindow * window,GPtrArray * files)1576 fr_window_populate_file_list (FrWindow *window,
1577 GPtrArray *files)
1578 {
1579 int sort_column_id;
1580 GtkSortType order;
1581 int i;
1582
1583 if (! gtk_widget_get_realized (GTK_WIDGET (window))) {
1584 _fr_window_stop_activity_mode (window);
1585 return;
1586 }
1587
1588 window->priv->populating_file_list = TRUE;
1589 gtk_list_store_clear (window->priv->list_store);
1590
1591 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store),
1592 &sort_column_id,
1593 &order);
1594 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store),
1595 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
1596 0);
1597
1598 for (i = 0; i < files->len; i++) {
1599 FileData *fdata = g_ptr_array_index (files, i);
1600 GtkTreeIter iter;
1601 GdkPixbuf *icon, *emblem;
1602 char *utf8_name;
1603
1604 if (fdata->list_name == NULL)
1605 continue;
1606
1607 gtk_list_store_append (window->priv->list_store, &iter);
1608
1609 icon = get_icon (window, fdata);
1610 emblem = get_emblem (window, fdata);
1611 utf8_name = g_filename_display_name (fdata->list_name);
1612
1613 if (file_data_is_dir (fdata)) {
1614 char *utf8_path;
1615 char *tmp;
1616 char *s_size;
1617 char *s_time;
1618
1619 if (fdata->list_dir)
1620 tmp = _g_path_remove_ending_separator (fr_window_get_current_location (window));
1621
1622 else
1623 tmp = _g_path_remove_level (fdata->path);
1624 utf8_path = g_filename_display_name (tmp);
1625 g_free (tmp);
1626
1627 s_size = g_format_size (fdata->dir_size);
1628
1629 if (fdata->list_dir)
1630 s_time = g_strdup ("");
1631 else
1632 s_time = _g_time_to_string (fdata->modified);
1633
1634 gtk_list_store_set (window->priv->list_store, &iter,
1635 COLUMN_FILE_DATA, fdata,
1636 COLUMN_ICON, icon,
1637 COLUMN_NAME, utf8_name,
1638 COLUMN_EMBLEM, emblem,
1639 COLUMN_TYPE, _("Folder"),
1640 COLUMN_SIZE, s_size,
1641 COLUMN_TIME, s_time,
1642 COLUMN_PATH, utf8_path,
1643 -1);
1644 g_free (utf8_path);
1645 g_free (s_size);
1646 g_free (s_time);
1647 }
1648 else {
1649 char *utf8_path;
1650 char *s_size;
1651 char *s_time;
1652 char *desc;
1653
1654 utf8_path = g_filename_display_name (fdata->path);
1655
1656 s_size = g_format_size (fdata->size);
1657 s_time = _g_time_to_string (fdata->modified);
1658 desc = g_content_type_get_description (fdata->content_type);
1659
1660 gtk_list_store_set (window->priv->list_store, &iter,
1661 COLUMN_FILE_DATA, fdata,
1662 COLUMN_ICON, icon,
1663 COLUMN_NAME, utf8_name,
1664 COLUMN_EMBLEM, emblem,
1665 COLUMN_TYPE, desc,
1666 COLUMN_SIZE, s_size,
1667 COLUMN_TIME, s_time,
1668 COLUMN_PATH, utf8_path,
1669 -1);
1670 g_free (utf8_path);
1671 g_free (s_size);
1672 g_free (s_time);
1673 g_free (desc);
1674 }
1675
1676 g_free (utf8_name);
1677 _g_object_unref (icon);
1678 _g_object_unref (emblem);
1679 }
1680
1681 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store),
1682 sort_column_id,
1683 order);
1684
1685 window->priv->populating_file_list = FALSE;
1686
1687 _fr_window_stop_activity_mode (window);
1688 }
1689
1690
1691 static int
path_compare(gconstpointer a,gconstpointer b)1692 path_compare (gconstpointer a,
1693 gconstpointer b)
1694 {
1695 char *path_a = *((char**) a);
1696 char *path_b = *((char**) b);
1697
1698 return strcmp (path_a, path_b);
1699 }
1700
1701
1702 static gboolean
get_tree_iter_from_path(FrWindow * window,const char * path,GtkTreeIter * parent,GtkTreeIter * iter)1703 get_tree_iter_from_path (FrWindow *window,
1704 const char *path,
1705 GtkTreeIter *parent,
1706 GtkTreeIter *iter)
1707 {
1708 gboolean result = FALSE;
1709
1710 if (! gtk_tree_model_iter_children (GTK_TREE_MODEL (window->priv->tree_store), iter, parent))
1711 return FALSE;
1712
1713 do {
1714 GtkTreeIter tmp;
1715 char *iter_path;
1716
1717 if (get_tree_iter_from_path (window, path, iter, &tmp)) {
1718 *iter = tmp;
1719 return TRUE;
1720 }
1721
1722 gtk_tree_model_get (GTK_TREE_MODEL (window->priv->tree_store),
1723 iter,
1724 TREE_COLUMN_PATH, &iter_path,
1725 -1);
1726
1727 if ((iter_path != NULL) && (strcmp (path, iter_path) == 0)) {
1728 result = TRUE;
1729 g_free (iter_path);
1730 break;
1731 }
1732 g_free (iter_path);
1733 }
1734 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (window->priv->tree_store), iter));
1735
1736 return result;
1737 }
1738
1739
1740 static void
fr_window_deactivate_filter(FrWindow * window)1741 fr_window_deactivate_filter (FrWindow *window)
1742 {
1743 fr_window_change_action_state (window, "find", FALSE);
1744 }
1745
1746
1747 static void
fr_window_update_current_location(FrWindow * window)1748 fr_window_update_current_location (FrWindow *window)
1749 {
1750 const char *current_dir = fr_window_get_current_location (window);
1751 char *path;
1752 GtkTreeIter iter;
1753
1754 gtk_widget_set_visible (window->priv->location_bar, window->priv->archive_present && (window->priv->list_mode == FR_WINDOW_LIST_MODE_AS_DIR));
1755
1756 if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT)
1757 return;
1758
1759 gtk_entry_set_text (GTK_ENTRY (window->priv->location_entry), window->priv->archive_present? current_dir: "");
1760
1761 fr_window_enable_action (window, "go-back", window->priv->archive_present && (current_dir != NULL) && (window->priv->history_current != NULL) && (window->priv->history_current->next != NULL));
1762 fr_window_enable_action (window, "go-forward", window->priv->archive_present && (current_dir != NULL) && (window->priv->history_current != NULL) && (window->priv->history_current->prev != NULL));
1763 fr_window_enable_action (window, "go-home", window->priv->archive_present);
1764
1765 gtk_widget_set_sensitive (window->priv->location_entry, window->priv->archive_present);
1766 gtk_widget_set_sensitive (window->priv->location_label, window->priv->archive_present);
1767 gtk_widget_set_sensitive (window->priv->filter_entry, window->priv->archive_present);
1768
1769 fr_window_deactivate_filter (window);
1770
1771 #if 0
1772 fr_window_history_print (window);
1773 #endif
1774
1775 path = _g_path_remove_ending_separator (current_dir);
1776 if (get_tree_iter_from_path (window, path, NULL, &iter)) {
1777 GtkTreeSelection *selection;
1778 GtkTreePath *t_path;
1779
1780 t_path = gtk_tree_model_get_path (GTK_TREE_MODEL (window->priv->tree_store), &iter);
1781 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (window->priv->tree_view), t_path);
1782 gtk_tree_path_free (t_path);
1783
1784 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view));
1785 gtk_tree_selection_select_iter (selection, &iter);
1786 }
1787 g_free (path);
1788 }
1789
1790
1791 static void
fr_window_update_dir_tree(FrWindow * window)1792 fr_window_update_dir_tree (FrWindow *window)
1793 {
1794 GPtrArray *dirs;
1795 GRegex *filter;
1796 GHashTable *dir_cache;
1797 int i;
1798 GdkPixbuf *icon;
1799
1800 if (! gtk_widget_get_realized (GTK_WIDGET (window)))
1801 return;
1802
1803 gtk_tree_store_clear (window->priv->tree_store);
1804
1805 if (! window->priv->view_sidebar
1806 || ! window->priv->archive_present
1807 || (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT))
1808 {
1809 gtk_widget_set_sensitive (window->priv->tree_view, FALSE);
1810 gtk_widget_hide (window->priv->sidepane);
1811 return;
1812 }
1813 else {
1814 gtk_widget_set_sensitive (window->priv->tree_view, TRUE);
1815 if (! gtk_widget_get_visible (window->priv->sidepane))
1816 gtk_widget_show_all (window->priv->sidepane);
1817 }
1818
1819 if (gtk_widget_get_realized (window->priv->tree_view))
1820 gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (window->priv->tree_view), 0, 0);
1821
1822 /**/
1823
1824 dirs = g_ptr_array_sized_new (128);
1825
1826 filter = _fr_window_create_filter (window);
1827 dir_cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
1828 for (i = 0; i < window->archive->files->len; i++) {
1829 FileData *fdata = g_ptr_array_index (window->archive->files, i);
1830 char *dir;
1831
1832 if (! file_data_respects_filter (window, filter, fdata))
1833 continue;
1834
1835 if (fdata->dir)
1836 dir = _g_path_remove_ending_separator (fdata->full_path);
1837 else
1838 dir = _g_path_remove_level (fdata->full_path);
1839
1840 while ((dir != NULL) && (strcmp (dir, "/") != 0)) {
1841 char *new_dir;
1842
1843 if (g_hash_table_lookup (dir_cache, dir) != NULL)
1844 break;
1845
1846 new_dir = dir;
1847 g_ptr_array_add (dirs, new_dir);
1848 g_hash_table_replace (dir_cache, new_dir, "1");
1849
1850 dir = _g_path_remove_level (new_dir);
1851 }
1852
1853 g_free (dir);
1854 }
1855 g_hash_table_destroy (dir_cache);
1856 if (filter != NULL)
1857 g_regex_unref (filter);
1858
1859 g_ptr_array_sort (dirs, path_compare);
1860 dir_cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) gtk_tree_path_free);
1861
1862 /**/
1863
1864 icon = get_mime_type_icon (window, MIME_TYPE_ARCHIVE);
1865 {
1866 GtkTreeIter node;
1867 char *name;
1868
1869 name = _g_file_get_display_basename (fr_archive_get_file (window->archive));
1870
1871 gtk_tree_store_append (window->priv->tree_store, &node, NULL);
1872 gtk_tree_store_set (window->priv->tree_store, &node,
1873 TREE_COLUMN_ICON, icon,
1874 TREE_COLUMN_NAME, name,
1875 TREE_COLUMN_PATH, "/",
1876 TREE_COLUMN_WEIGHT, PANGO_WEIGHT_BOLD,
1877 -1);
1878 g_hash_table_replace (dir_cache, "/", gtk_tree_model_get_path (GTK_TREE_MODEL (window->priv->tree_store), &node));
1879
1880 g_free (name);
1881 }
1882 g_object_unref (icon);
1883
1884 /**/
1885
1886 icon = get_mime_type_icon (window, MIME_TYPE_DIRECTORY);
1887 for (i = 0; i < dirs->len; i++) {
1888 char *dir = g_ptr_array_index (dirs, i);
1889 char *parent_dir;
1890 GtkTreePath *parent_path;
1891 GtkTreeIter parent;
1892 GtkTreeIter node;
1893
1894 parent_dir = _g_path_remove_level (dir);
1895 if (parent_dir == NULL)
1896 continue;
1897
1898 parent_path = g_hash_table_lookup (dir_cache, parent_dir);
1899 gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->tree_store),
1900 &parent,
1901 parent_path);
1902 gtk_tree_store_append (window->priv->tree_store, &node, &parent);
1903 gtk_tree_store_set (window->priv->tree_store, &node,
1904 TREE_COLUMN_ICON, icon,
1905 TREE_COLUMN_NAME, _g_path_get_basename (dir),
1906 TREE_COLUMN_PATH, dir,
1907 TREE_COLUMN_WEIGHT, PANGO_WEIGHT_NORMAL,
1908 -1);
1909 g_hash_table_replace (dir_cache, dir, gtk_tree_model_get_path (GTK_TREE_MODEL (window->priv->tree_store), &node));
1910
1911 g_free (parent_dir);
1912 }
1913 g_hash_table_destroy (dir_cache);
1914 if (icon != NULL)
1915 g_object_unref (icon);
1916
1917 g_ptr_array_free (dirs, TRUE);
1918
1919 fr_window_update_current_location (window);
1920 }
1921
1922
1923 static void
fr_window_update_file_list(FrWindow * window,gboolean update_view)1924 fr_window_update_file_list (FrWindow *window,
1925 gboolean update_view)
1926 {
1927 GPtrArray *files;
1928 gboolean free_files = FALSE;
1929
1930 if (! gtk_widget_get_realized (GTK_WIDGET (window)))
1931 return;
1932
1933 if (gtk_widget_get_realized (window->priv->list_view))
1934 gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (window->priv->list_view), 0, 0);
1935
1936 if (! window->priv->archive_present || window->priv->archive_new) {
1937 if (update_view)
1938 gtk_list_store_clear (window->priv->list_store);
1939
1940 window->priv->current_view_length = 0;
1941
1942 if (window->priv->archive_new) {
1943 gtk_widget_set_sensitive (window->priv->list_view, TRUE);
1944 gtk_widget_show_all (gtk_widget_get_parent (window->priv->list_view));
1945 }
1946 else {
1947 gtk_widget_set_sensitive (window->priv->list_view, FALSE);
1948 gtk_widget_hide (gtk_widget_get_parent (window->priv->list_view));
1949 }
1950
1951 return;
1952 }
1953 else {
1954 gtk_widget_set_sensitive (window->priv->list_view, TRUE);
1955 gtk_widget_show_all (gtk_widget_get_parent (window->priv->list_view));
1956 }
1957
1958 if (window->priv->give_focus_to_the_list) {
1959 gtk_widget_grab_focus (window->priv->list_view);
1960 window->priv->give_focus_to_the_list = FALSE;
1961 }
1962
1963 /**/
1964
1965 _fr_window_start_activity_mode (window);
1966
1967 if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) {
1968 fr_window_compute_list_names (window, window->archive->files);
1969 files = window->archive->files;
1970 free_files = FALSE;
1971 }
1972 else {
1973 char *current_dir = g_strdup (fr_window_get_current_location (window));
1974
1975 while (! fr_window_dir_exists_in_archive (window, current_dir)) {
1976 char *tmp;
1977
1978 fr_window_history_pop (window);
1979
1980 tmp = get_parent_dir (current_dir);
1981 g_free (current_dir);
1982 current_dir = tmp;
1983
1984 fr_window_history_add (window, current_dir);
1985 }
1986 g_free (current_dir);
1987
1988 fr_window_compute_list_names (window, window->archive->files);
1989 files = fr_window_get_current_dir_list (window);
1990 free_files = TRUE;
1991 }
1992
1993 if (files != NULL)
1994 window->priv->current_view_length = files->len;
1995 else
1996 window->priv->current_view_length = 0;
1997
1998 if (update_view)
1999 fr_window_populate_file_list (window, files);
2000
2001 if (free_files)
2002 g_ptr_array_free (files, TRUE);
2003 }
2004
2005
2006 static void
fr_window_set_title(FrWindow * window,const char * title)2007 fr_window_set_title (FrWindow *window,
2008 const char *title)
2009 {
2010 gtk_window_set_title (GTK_WINDOW (window), title);
2011 gtk_header_bar_set_title (GTK_HEADER_BAR (window->priv->headerbar), title);
2012 }
2013
2014
2015 static void
fr_window_update_title(FrWindow * window)2016 fr_window_update_title (FrWindow *window)
2017 {
2018 char *title;
2019 char *name;
2020
2021 if (! window->priv->archive_present) {
2022 fr_window_set_title (window, _("Archive Manager"));
2023 return;
2024 }
2025
2026 name = _g_file_get_display_basename (fr_window_get_archive_file (window));
2027 title = g_strdup_printf ("%s %s",
2028 name,
2029 window->archive->read_only ? _("[read only]") : "");
2030 fr_window_set_title (window, title);
2031
2032 g_free (title);
2033 g_free (name);
2034 }
2035
2036
2037 static gboolean
location_entry_key_press_event_cb(GtkWidget * widget,GdkEventKey * event,FrWindow * window)2038 location_entry_key_press_event_cb (GtkWidget *widget,
2039 GdkEventKey *event,
2040 FrWindow *window)
2041 {
2042 if ((event->keyval == GDK_KEY_Return)
2043 || (event->keyval == GDK_KEY_KP_Enter)
2044 || (event->keyval == GDK_KEY_ISO_Enter))
2045 {
2046 fr_window_go_to_location (window, gtk_entry_get_text (GTK_ENTRY (window->priv->location_entry)), FALSE);
2047 }
2048
2049 return FALSE;
2050 }
2051
2052
2053 static void
_fr_window_close_after_notification(FrWindow * window)2054 _fr_window_close_after_notification (FrWindow *window)
2055 {
2056 fr_window_set_current_action (window, FR_BATCH_ACTION_QUIT, NULL, NULL);
2057 fr_window_restart_current_action (window);
2058 }
2059
2060
2061 static gboolean
real_close_progress_dialog(gpointer data)2062 real_close_progress_dialog (gpointer data)
2063 {
2064 FrWindow *window = data;
2065
2066 if (window->priv->hide_progress_timeout != 0) {
2067 g_source_remove (window->priv->hide_progress_timeout);
2068 window->priv->hide_progress_timeout = 0;
2069 }
2070
2071 if (window->priv->progress_dialog != NULL)
2072 gtk_widget_hide (window->priv->progress_dialog);
2073
2074 return FALSE;
2075 }
2076
2077
2078 static void
close_progress_dialog(FrWindow * window,gboolean close_now)2079 close_progress_dialog (FrWindow *window,
2080 gboolean close_now)
2081 {
2082 if (window->priv->progress_timeout != 0) {
2083 g_source_remove (window->priv->progress_timeout);
2084 window->priv->progress_timeout = 0;
2085 }
2086
2087 if (window->priv->progress_dialog == NULL)
2088 return;
2089
2090 if (close_now) {
2091 if (window->priv->hide_progress_timeout != 0) {
2092 g_source_remove (window->priv->hide_progress_timeout);
2093 window->priv->hide_progress_timeout = 0;
2094 }
2095 real_close_progress_dialog (window);
2096 }
2097 else {
2098 if (window->priv->hide_progress_timeout != 0)
2099 return;
2100 window->priv->hide_progress_timeout = g_timeout_add (HIDE_PROGRESS_TIMEOUT_MSECS,
2101 real_close_progress_dialog,
2102 window);
2103 }
2104 }
2105
2106
2107 static gboolean
progress_dialog_delete_event(GtkWidget * caller,GdkEvent * event,FrWindow * window)2108 progress_dialog_delete_event (GtkWidget *caller,
2109 GdkEvent *event,
2110 FrWindow *window)
2111 {
2112 if (window->priv->stoppable) {
2113 fr_window_stop (window);
2114 close_progress_dialog (window, TRUE);
2115 }
2116
2117 return TRUE;
2118 }
2119
2120
2121 /* -- open_folder -- */
2122
2123
2124 typedef struct {
2125 GtkWindow *window;
2126 GFile *folder;
2127 } OpenFolderData;
2128
2129
2130 static OpenFolderData *
open_folder_data_new(GtkWindow * window,GFile * folder)2131 open_folder_data_new (GtkWindow *window,
2132 GFile *folder)
2133 {
2134 OpenFolderData *data;
2135
2136 data = g_new (OpenFolderData, 1);
2137 data->window = g_object_ref (window);
2138 data->folder = g_object_ref (folder);
2139
2140 return data;
2141 }
2142
2143
2144 static void
open_folder_data_free(OpenFolderData * data)2145 open_folder_data_free (OpenFolderData *data)
2146 {
2147 _g_object_unref (data->window);
2148 _g_object_unref (data->folder);
2149 g_free (data);
2150 }
2151
2152
2153 static void
show_folder(GtkWindow * parent_window,GFile * folder)2154 show_folder (GtkWindow *parent_window,
2155 GFile *folder)
2156 {
2157 GError *error = NULL;
2158 char *uri;
2159
2160 uri = g_file_get_uri (folder);
2161 if (! gtk_show_uri_on_window (parent_window, uri, GDK_CURRENT_TIME, &error))
2162 {
2163 GtkWidget *d;
2164 char *utf8_name;
2165 char *message;
2166
2167 utf8_name = _g_file_get_display_basename (folder);
2168 message = g_strdup_printf (_("Could not display the folder “%s”"), utf8_name);
2169 g_free (utf8_name);
2170
2171 d = _gtk_error_dialog_new (parent_window,
2172 GTK_DIALOG_MODAL,
2173 NULL,
2174 message,
2175 "%s",
2176 error->message);
2177 gtk_dialog_run (GTK_DIALOG (d));
2178 gtk_widget_destroy (d);
2179
2180 g_free (message);
2181 g_clear_error (&error);
2182 }
2183
2184 g_free (uri);
2185 }
2186
2187
2188 static void
file_manager_show_items_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2189 file_manager_show_items_cb (GObject *source_object,
2190 GAsyncResult *res,
2191 gpointer user_data)
2192 {
2193 OpenFolderData *data = user_data;
2194 GDBusProxy *proxy;
2195 GVariant *values;
2196 GError *error = NULL;
2197
2198 proxy = G_DBUS_PROXY (source_object);
2199 values = g_dbus_proxy_call_finish (proxy, res, &error);
2200 if (values == NULL) {
2201 show_folder (data->window, data->folder);
2202 g_clear_error (&error);
2203 }
2204
2205 if (values != NULL)
2206 g_variant_unref (values);
2207 g_object_unref (proxy);
2208 open_folder_data_free (data);
2209 }
2210
2211
2212 static void
open_folder(GtkWindow * parent_window,GFile * folder,GList * files)2213 open_folder (GtkWindow *parent_window,
2214 GFile *folder,
2215 GList *files)
2216 {
2217 GDBusConnection *connection;
2218 GError *error = NULL;
2219
2220 if (folder == NULL)
2221 return;
2222
2223 /* only use ShowItems if its a single file to avoid Nautilus to open
2224 * multiple windows */
2225
2226 if ((files == NULL) || (files->next != NULL)) {
2227 show_folder (parent_window, folder);
2228 return;
2229 }
2230
2231 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
2232 if (connection != NULL) {
2233 GDBusProxy *proxy;
2234
2235 proxy = g_dbus_proxy_new_sync (connection,
2236 G_DBUS_PROXY_FLAGS_NONE,
2237 NULL,
2238 "org.freedesktop.FileManager1",
2239 "/org/freedesktop/FileManager1",
2240 "org.freedesktop.FileManager1",
2241 NULL,
2242 &error);
2243
2244 if (proxy != NULL) {
2245 static int sequence = 0;
2246 char **uris;
2247 char *startup_id;
2248
2249 uris = g_new (char *, 2);
2250 uris[0] = g_file_get_uri ((GFile *) files->data);
2251 uris[1] = NULL;
2252
2253 startup_id = g_strdup_printf ("%s-%lu-%s-%s-%d_TIME%lu",
2254 g_get_prgname (),
2255 (unsigned long) getpid (),
2256 g_get_host_name (),
2257 "org.freedesktop.FileManager1",
2258 sequence++,
2259 (unsigned long) g_get_real_time ());
2260
2261 g_dbus_proxy_call (proxy,
2262 "ShowItems",
2263 g_variant_new ("(^ass)", uris, startup_id),
2264 G_DBUS_CALL_FLAGS_NONE,
2265 G_MAXINT,
2266 NULL,
2267 file_manager_show_items_cb,
2268 open_folder_data_new (parent_window, folder));
2269
2270 g_free (startup_id);
2271 g_strfreev (uris);
2272
2273 return;
2274 }
2275 }
2276
2277 show_folder (parent_window, folder);
2278 }
2279
2280
2281 static void
fr_window_view_extraction_destination_folder(FrWindow * window)2282 fr_window_view_extraction_destination_folder (FrWindow *window)
2283 {
2284 open_folder (GTK_WINDOW (window), window->priv->last_extraction_destination, window->priv->last_extraction_files_first_level);
2285 }
2286
2287
2288 static void
progress_dialog_response(GtkDialog * dialog,int response_id,FrWindow * window)2289 progress_dialog_response (GtkDialog *dialog,
2290 int response_id,
2291 FrWindow *window)
2292 {
2293 GtkWidget *new_window;
2294 GFile *saved_file;
2295
2296 saved_file = window->priv->saving_file;
2297 window->priv->saving_file = NULL;
2298
2299 switch (response_id) {
2300 case GTK_RESPONSE_CANCEL:
2301 if (window->priv->stoppable) {
2302 fr_window_stop (window);
2303 close_progress_dialog (window, TRUE);
2304 }
2305 break;
2306 case GTK_RESPONSE_CLOSE:
2307 close_progress_dialog (window, TRUE);
2308 break;
2309 case DIALOG_RESPONSE_OPEN_ARCHIVE:
2310 new_window = fr_window_new ();
2311 gtk_widget_show (new_window);
2312 fr_window_archive_open (FR_WINDOW (new_window), saved_file, GTK_WINDOW (new_window));
2313 close_progress_dialog (window, TRUE);
2314 break;
2315 case DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER:
2316 fr_window_view_extraction_destination_folder (window);
2317 close_progress_dialog (window, TRUE);
2318 break;
2319 default:
2320 break;
2321 }
2322
2323 _g_object_unref (saved_file);
2324 }
2325
2326
2327 static char *
get_action_description(FrWindow * window,FrAction action,GFile * file)2328 get_action_description (FrWindow *window,
2329 FrAction action,
2330 GFile *file)
2331 {
2332 char *basename;
2333 char *message;
2334
2335 basename = _g_file_get_display_basename (file);
2336
2337 message = NULL;
2338 switch (action) {
2339 case FR_ACTION_CREATING_NEW_ARCHIVE:
2340 /* Translators: %s is a filename */
2341 message = g_strdup_printf (_("Creating “%s”"), basename);
2342 break;
2343 case FR_ACTION_LOADING_ARCHIVE:
2344 /* Translators: %s is a filename */
2345 message = g_strdup_printf (_("Loading “%s”"), basename);
2346 break;
2347 case FR_ACTION_LISTING_CONTENT:
2348 /* Translators: %s is a filename */
2349 message = g_strdup_printf (_("Reading “%s”"), basename);
2350 break;
2351 case FR_ACTION_DELETING_FILES:
2352 /* Translators: %s is a filename */
2353 message = g_strdup_printf (_("Deleting the files from “%s”"), basename);
2354 break;
2355 case FR_ACTION_TESTING_ARCHIVE:
2356 /* Translators: %s is a filename */
2357 message = g_strdup_printf (_("Testing “%s”"), basename);
2358 break;
2359 case FR_ACTION_GETTING_FILE_LIST:
2360 message = g_strdup (_("Getting the file list"));
2361 break;
2362 case FR_ACTION_COPYING_FILES_FROM_REMOTE:
2363 /* Translators: %s is a filename */
2364 message = g_strdup_printf (_("Copying the files to add to “%s”"), basename);
2365 break;
2366 case FR_ACTION_ADDING_FILES:
2367 /* Translators: %s is a filename */
2368 message = g_strdup_printf (_("Adding the files to “%s”"), basename);
2369 break;
2370 case FR_ACTION_EXTRACTING_FILES:
2371 /* Translators: %s is a filename */
2372 message = g_strdup_printf (_("Extracting the files from “%s”"), basename);
2373 break;
2374 case FR_ACTION_COPYING_FILES_TO_REMOTE:
2375 message = g_strdup (_("Copying the extracted files to the destination"));
2376 break;
2377 case FR_ACTION_CREATING_ARCHIVE:
2378 /* Translators: %s is a filename */
2379 message = g_strdup_printf (_("Creating “%s”"), basename);
2380 break;
2381 case FR_ACTION_SAVING_REMOTE_ARCHIVE:
2382 case FR_ACTION_ENCRYPTING_ARCHIVE:
2383 /* Translators: %s is a filename */
2384 message = g_strdup_printf (_("Saving “%s”"), basename);
2385 break;
2386 case FR_ACTION_PASTING_FILES:
2387 message = g_strdup (window->priv->custom_action_message);
2388 break;
2389 case FR_ACTION_RENAMING_FILES:
2390 /* Translators: %s is a filename */
2391 message = g_strdup_printf (_("Renaming the files in “%s”"), basename);
2392 break;
2393 case FR_ACTION_UPDATING_FILES:
2394 /* Translators: %s is a filename */
2395 message = g_strdup_printf (_("Updating the files in “%s”"), basename);
2396 break;
2397 case FR_ACTION_NONE:
2398 break;
2399 }
2400
2401 g_free (basename);
2402
2403 return message;
2404 }
2405
2406
2407 static void
progress_dialog_set_action_description(FrWindow * window,const char * description)2408 progress_dialog_set_action_description (FrWindow *window,
2409 const char *description)
2410 {
2411 char *description_markup;
2412
2413 description_markup = g_markup_printf_escaped ("<span weight=\"bold\" size=\"larger\">%s</span>", description);
2414 gtk_label_set_markup (GTK_LABEL (window->priv->pd_action), description_markup);
2415
2416 g_free (description_markup);
2417 }
2418
2419
2420 static void
progress_dialog_update_action_description(FrWindow * window)2421 progress_dialog_update_action_description (FrWindow *window)
2422 {
2423 GFile *current_archive;
2424 char *description;
2425
2426
2427 if (window->priv->progress_dialog == NULL)
2428 return;
2429
2430 if (window->priv->saving_file != NULL)
2431 current_archive = window->priv->saving_file;
2432 else if (window->priv->working_archive != NULL)
2433 current_archive = window->priv->working_archive;
2434 else
2435 current_archive = window->priv->archive_file;
2436
2437 _g_clear_object (&window->priv->pd_last_archive);
2438 if (current_archive != NULL)
2439 window->priv->pd_last_archive = g_object_ref (current_archive);
2440
2441 description = get_action_description (window, window->priv->action, window->priv->pd_last_archive);
2442 progress_dialog_set_action_description (window, description);
2443
2444 g_free (description);
2445 }
2446
2447
2448 static gboolean
fr_window_working_archive_cb(FrArchive * archive,const char * archive_uri,FrWindow * window)2449 fr_window_working_archive_cb (FrArchive *archive,
2450 const char *archive_uri,
2451 FrWindow *window)
2452 {
2453 _g_clear_object (&window->priv->working_archive);
2454 if (archive_uri != NULL)
2455 window->priv->working_archive = g_file_new_for_uri (archive_uri);
2456 progress_dialog_update_action_description (window);
2457
2458 return TRUE;
2459 }
2460
2461
2462 static gboolean
fr_archive_message_cb(FrArchive * archive,const char * msg,FrWindow * window)2463 fr_archive_message_cb (FrArchive *archive,
2464 const char *msg,
2465 FrWindow *window)
2466 {
2467 if (window->priv->pd_last_message != msg) {
2468 g_free (window->priv->pd_last_message);
2469 window->priv->pd_last_message = g_strdup (msg);
2470 }
2471
2472 if (window->priv->progress_dialog == NULL)
2473 return TRUE;
2474
2475 if (msg != NULL) {
2476 while (*msg == ' ')
2477 msg++;
2478 if (*msg == 0)
2479 msg = NULL;
2480 }
2481
2482 if (msg != NULL) {
2483 char *utf8_msg;
2484
2485 if (! g_utf8_validate (msg, -1, NULL))
2486 utf8_msg = g_locale_to_utf8 (msg, -1 , 0, 0, 0);
2487 else
2488 utf8_msg = g_strdup (msg);
2489 if (utf8_msg == NULL)
2490 return TRUE;
2491
2492 if (g_utf8_validate (utf8_msg, -1, NULL)) {
2493 gtk_label_set_text (GTK_LABEL (window->priv->pd_message), utf8_msg);
2494 gtk_widget_show (window->priv->pd_message);
2495 }
2496
2497 g_free (window->priv->pd_last_message);
2498 window->priv->pd_last_message = g_strdup (utf8_msg);
2499
2500 g_signal_emit (G_OBJECT (window),
2501 fr_window_signals[PROGRESS],
2502 0,
2503 window->priv->pd_last_fraction,
2504 window->priv->pd_last_message);
2505
2506 #ifdef LOG_PROGRESS
2507 g_print ("message > %s\n", utf8_msg);
2508 #endif
2509
2510 g_free (utf8_msg);
2511 }
2512 else
2513 gtk_widget_hide (window->priv->pd_message);
2514
2515 progress_dialog_update_action_description (window);
2516
2517 return TRUE;
2518 }
2519
2520
2521 static void
fr_archive_start_cb(FrArchive * archive,FrAction action,FrWindow * window)2522 fr_archive_start_cb (FrArchive *archive,
2523 FrAction action,
2524 FrWindow *window)
2525 {
2526 char *description;
2527
2528 description = get_action_description (window, action, fr_archive_get_file (archive));
2529 fr_archive_message_cb (archive, description, window);
2530
2531 g_free (description);
2532 }
2533
2534
2535 static void
create_the_progress_dialog(FrWindow * window)2536 create_the_progress_dialog (FrWindow *window)
2537 {
2538 GtkWindow *parent;
2539 GtkDialogFlags flags;
2540 const char *title;
2541 GtkBuilder *builder;
2542 gboolean use_header_bar;
2543 GtkWidget *dialog;
2544
2545 if (window->priv->progress_dialog != NULL)
2546 return;
2547
2548 if (window->priv->batch_mode) {
2549 parent = NULL;
2550 flags = 0;
2551 title = window->priv->batch_title;
2552 }
2553 else {
2554 parent = GTK_WINDOW (window);
2555 flags = GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL;
2556 title = NULL;
2557 }
2558
2559 builder = _gtk_builder_new_from_resource ("progress-dialog.ui");
2560 use_header_bar = _gtk_settings_get_dialogs_use_header ();
2561 dialog = g_object_new (GTK_TYPE_DIALOG, "use-header-bar", use_header_bar, NULL);
2562 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
2563 _gtk_builder_get_widget (builder, "progress_dialog_content"));
2564 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2565 gtk_window_set_title (GTK_WINDOW (dialog), title);
2566 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
2567 gtk_window_set_modal (GTK_WINDOW (dialog), (flags & GTK_DIALOG_MODAL));
2568 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), (flags & GTK_DIALOG_DESTROY_WITH_PARENT));
2569 g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, builder);
2570
2571 _gtk_dialog_add_to_window_group (GTK_DIALOG (dialog));
2572
2573 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
2574 _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
2575 NULL);
2576
2577 if (use_header_bar) {
2578 GtkWidget *header_bar = gtk_dialog_get_header_bar (GTK_DIALOG (dialog));
2579 GtkWidget *cancel_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
2580 gtk_container_child_set (GTK_CONTAINER (header_bar), cancel_button, "pack-type", GTK_PACK_END, NULL);
2581 }
2582
2583 window->priv->progress_dialog = dialog;
2584 window->priv->pd_action = _gtk_builder_get_widget (builder, "action_label");
2585 window->priv->pd_progress_bar = _gtk_builder_get_widget (builder, "progress_progressbar");
2586 window->priv->pd_message = _gtk_builder_get_widget (builder, "message_label");
2587 window->priv->pd_progress_box = _gtk_builder_get_widget (builder, "progress_box");
2588
2589 _g_clear_object (&window->priv->pd_last_archive);
2590 window->priv->pd_last_archive = _g_object_ref (window->priv->archive_file);
2591
2592 progress_dialog_update_action_description (window);
2593
2594 /* signals */
2595
2596 g_signal_connect (G_OBJECT (window->priv->progress_dialog),
2597 "response",
2598 G_CALLBACK (progress_dialog_response),
2599 window);
2600 g_signal_connect (G_OBJECT (window->priv->progress_dialog),
2601 "delete_event",
2602 G_CALLBACK (progress_dialog_delete_event),
2603 window);
2604 }
2605
2606
2607 static gboolean
display_progress_dialog(gpointer data)2608 display_progress_dialog (gpointer data)
2609 {
2610 FrWindow *window = data;
2611
2612 if (window->priv->progress_timeout != 0)
2613 g_source_remove (window->priv->progress_timeout);
2614
2615 if (window->priv->use_progress_dialog && (window->priv->progress_dialog != NULL)) {
2616 gtk_dialog_set_response_sensitive (GTK_DIALOG (window->priv->progress_dialog),
2617 GTK_RESPONSE_OK,
2618 window->priv->stoppable);
2619 if (! window->priv->batch_mode)
2620 gtk_window_present (GTK_WINDOW (window));
2621 gtk_window_present (GTK_WINDOW (window->priv->progress_dialog));
2622 fr_archive_message_cb (NULL, window->priv->pd_last_message, window);
2623 }
2624
2625 window->priv->progress_timeout = 0;
2626
2627 return FALSE;
2628 }
2629
2630
2631 static void
open_progress_dialog(FrWindow * window,gboolean open_now)2632 open_progress_dialog (FrWindow *window,
2633 gboolean open_now)
2634 {
2635 if (window->priv->hide_progress_timeout != 0) {
2636 g_source_remove (window->priv->hide_progress_timeout);
2637 window->priv->hide_progress_timeout = 0;
2638 }
2639
2640 if (open_now) {
2641 if (window->priv->progress_timeout != 0)
2642 g_source_remove (window->priv->progress_timeout);
2643 window->priv->progress_timeout = 0;
2644 }
2645
2646 if ((window->priv->progress_timeout != 0)
2647 || ((window->priv->progress_dialog != NULL) && gtk_widget_get_visible (window->priv->progress_dialog)))
2648 return;
2649
2650 create_the_progress_dialog (window);
2651 if (open_now)
2652 display_progress_dialog (window);
2653 else
2654 window->priv->progress_timeout = g_timeout_add (PROGRESS_TIMEOUT_MSECS,
2655 display_progress_dialog,
2656 window);
2657 }
2658
2659
2660 static gboolean
fr_archive_progress_cb(FrArchive * archive,double fraction,FrWindow * window)2661 fr_archive_progress_cb (FrArchive *archive,
2662 double fraction,
2663 FrWindow *window)
2664 {
2665 window->priv->progress_pulse = (fraction < 0.0);
2666 if (! window->priv->progress_pulse) {
2667 fraction = CLAMP (fraction, 0.0, 1.0);
2668 if (window->priv->progress_dialog != NULL)
2669 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->pd_progress_bar), fraction);
2670
2671 if ((archive != NULL) && (fr_archive_progress_get_total_files (archive) > 0)) {
2672 char *message = NULL;
2673 int remaining_files;
2674
2675 remaining_files = fr_archive_progress_get_total_files (archive) - fr_archive_progress_get_completed_files (archive);
2676
2677 switch (window->priv->action) {
2678 case FR_ACTION_ADDING_FILES:
2679 case FR_ACTION_EXTRACTING_FILES:
2680 case FR_ACTION_DELETING_FILES:
2681 case FR_ACTION_UPDATING_FILES:
2682 if (remaining_files > 0)
2683 message = g_strdup_printf (ngettext ("%d file remaining",
2684 "%'d files remaining",
2685 remaining_files), remaining_files);
2686 else
2687 message = g_strdup (_("Please wait…"));
2688 break;
2689 default:
2690 break;
2691 }
2692
2693 if (message != NULL) {
2694 fr_archive_message (archive, message);
2695 g_free (message);
2696 }
2697 }
2698
2699 if (fraction == 1.0)
2700 gtk_widget_hide (window->priv->pd_progress_box);
2701 else
2702 gtk_widget_show (window->priv->pd_progress_box);
2703
2704 window->priv->pd_last_fraction = fraction;
2705
2706 g_signal_emit (G_OBJECT (window),
2707 fr_window_signals[PROGRESS],
2708 0,
2709 window->priv->pd_last_fraction,
2710 window->priv->pd_last_message);
2711
2712 #ifdef LOG_PROGRESS
2713 g_print ("progress > %2.2f\n", fraction);
2714 #endif
2715 }
2716 return TRUE;
2717 }
2718
2719
2720 /* -- confirmation dialog -- */
2721
2722
2723 static void
fr_window_close_confirmation_dialog(FrWindow * window,GtkWidget * dialog)2724 fr_window_close_confirmation_dialog (FrWindow *window,
2725 GtkWidget *dialog)
2726 {
2727 gtk_widget_destroy (dialog);
2728 if (window->priv->batch_mode && window->priv->destroy_with_confirmation_dialog)
2729 _fr_window_close_after_notification (window);
2730 }
2731
2732
2733 static void
confirmation_dialog_response(GtkWidget * dialog,int response_id,FrWindow * window)2734 confirmation_dialog_response (GtkWidget *dialog,
2735 int response_id,
2736 FrWindow *window)
2737 {
2738 GtkWidget *new_window;
2739 GFile *saved_file;
2740
2741 saved_file = window->priv->saving_file;
2742 window->priv->saving_file = NULL;
2743
2744 switch (response_id) {
2745 case GTK_RESPONSE_CLOSE:
2746 fr_window_close_confirmation_dialog (window, dialog);
2747 break;
2748
2749 case DIALOG_RESPONSE_OPEN_ARCHIVE:
2750 new_window = fr_window_new ();
2751 gtk_widget_show (new_window);
2752 fr_window_archive_open (FR_WINDOW (new_window), saved_file, GTK_WINDOW (new_window));
2753 fr_window_close_confirmation_dialog (window, dialog);
2754 break;
2755
2756 case DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER:
2757 fr_window_view_extraction_destination_folder (window);
2758 fr_window_close_confirmation_dialog (window, dialog);
2759 break;
2760
2761 default:
2762 break;
2763 }
2764
2765 _g_object_unref (saved_file);
2766 }
2767
2768
2769 static gboolean
confirmation_dialog_delete_event(GtkWidget * dialog,GdkEvent * event,FrWindow * window)2770 confirmation_dialog_delete_event (GtkWidget *dialog,
2771 GdkEvent *event,
2772 FrWindow *window)
2773 {
2774 fr_window_close_confirmation_dialog (window, dialog);
2775 return TRUE;
2776 }
2777
2778
2779 static void
fr_window_show_confirmation_dialog(FrWindow * window,GtkWidget * dialog)2780 fr_window_show_confirmation_dialog (FrWindow *window,
2781 GtkWidget *dialog)
2782 {
2783 close_progress_dialog (window, TRUE);
2784
2785 g_signal_connect (G_OBJECT (dialog),
2786 "response",
2787 G_CALLBACK (confirmation_dialog_response),
2788 window);
2789 g_signal_connect (G_OBJECT (dialog),
2790 "delete_event",
2791 G_CALLBACK (confirmation_dialog_delete_event),
2792 window);
2793
2794 gtk_widget_show (dialog);
2795 }
2796
2797
2798 static void
fr_window_show_confirmation_dialog_with_open_destination(FrWindow * window)2799 fr_window_show_confirmation_dialog_with_open_destination (FrWindow *window)
2800 {
2801 GtkWidget *dialog;
2802
2803 dialog = _gtk_message_dialog_new (GTK_WINDOW (window),
2804 GTK_DIALOG_MODAL,
2805 _("Extraction completed successfully"),
2806 NULL,
2807 _GTK_LABEL_CLOSE, GTK_RESPONSE_CLOSE,
2808 _("_Show the Files"), DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER,
2809 NULL);
2810
2811 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
2812 fr_window_show_confirmation_dialog (window, dialog);
2813 }
2814
2815
2816 static void
fr_window_show_confirmation_dialog_with_open_archive(FrWindow * window)2817 fr_window_show_confirmation_dialog_with_open_archive (FrWindow *window)
2818 {
2819 GtkWidget *dialog;
2820 char *basename;
2821 char *message;
2822
2823 basename = _g_file_get_display_basename (window->priv->saving_file);
2824 /* Translators: %s is a filename */
2825 message = g_strdup_printf (_("“%s” created successfully"), basename);
2826
2827 dialog = _gtk_message_dialog_new (GTK_WINDOW (window),
2828 GTK_DIALOG_MODAL,
2829 message,
2830 NULL,
2831 _GTK_LABEL_CLOSE, GTK_RESPONSE_CLOSE,
2832 _("_Open the Archive"), DIALOG_RESPONSE_OPEN_ARCHIVE,
2833 NULL);
2834
2835 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
2836 fr_window_show_confirmation_dialog (window, dialog);
2837
2838 g_free (message);
2839 g_free (basename);
2840 }
2841
2842
2843 static void
fr_window_add_to_recent_list(FrWindow * window,GFile * file)2844 fr_window_add_to_recent_list (FrWindow *window,
2845 GFile *file)
2846 {
2847 char *uri;
2848
2849 if (_g_file_is_temp_dir (file))
2850 return;
2851
2852 uri = g_file_get_uri (file);
2853
2854 if (window->archive->mime_type != NULL) {
2855 GtkRecentData *recent_data;
2856
2857 recent_data = g_new0 (GtkRecentData, 1);
2858 recent_data->mime_type = g_content_type_get_mime_type (window->archive->mime_type);
2859 recent_data->app_name = "File Roller";
2860 recent_data->app_exec = "file-roller";
2861 gtk_recent_manager_add_full (gtk_recent_manager_get_default (), uri, recent_data);
2862
2863 g_free (recent_data->mime_type);
2864 g_free (recent_data);
2865 }
2866 else
2867 gtk_recent_manager_add_item (gtk_recent_manager_get_default (), uri);
2868
2869 g_free (uri);
2870 }
2871
2872
2873 static void
fr_window_remove_from_recent_list(FrWindow * window,GFile * file)2874 fr_window_remove_from_recent_list (FrWindow *window,
2875 GFile *file)
2876 {
2877 char *uri;
2878
2879 if (file == NULL)
2880 return;
2881
2882 uri = g_file_get_uri (file);
2883 gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), uri, NULL);
2884
2885 g_free (uri);
2886 }
2887
2888
2889 static void
error_dialog_response_cb(GtkDialog * dialog,gint arg1,gpointer user_data)2890 error_dialog_response_cb (GtkDialog *dialog,
2891 gint arg1,
2892 gpointer user_data)
2893 {
2894 FrWindow *window = user_data;
2895
2896 window->priv->showing_error_dialog = FALSE;
2897 gtk_widget_destroy (GTK_WIDGET (dialog));
2898
2899 if (window->priv->destroy_with_error_dialog) {
2900 if (window->priv->batch_mode) {
2901 g_signal_emit (window,
2902 fr_window_signals[READY],
2903 0,
2904 NULL);
2905 }
2906 gtk_widget_destroy (GTK_WIDGET (window));
2907 }
2908 }
2909
2910
2911 static void
fr_window_show_error_dialog(FrWindow * window,GtkWidget * dialog,GtkWindow * dialog_parent,const char * details)2912 fr_window_show_error_dialog (FrWindow *window,
2913 GtkWidget *dialog,
2914 GtkWindow *dialog_parent,
2915 const char *details)
2916 {
2917 if (window->priv->batch_mode && ! window->priv->use_progress_dialog) {
2918 GError *error;
2919
2920 error = g_error_new_literal (FR_ERROR, FR_ERROR_GENERIC, details ? details : _("Command exited abnormally."));
2921 g_signal_emit (window,
2922 fr_window_signals[READY],
2923 0,
2924 error);
2925
2926 gtk_widget_destroy (GTK_WIDGET (window));
2927
2928 return;
2929 }
2930
2931 close_progress_dialog (window, TRUE);
2932
2933 if (window->priv->batch_mode)
2934 fr_window_destroy_with_error_dialog (window);
2935
2936 g_signal_connect (dialog,
2937 "response",
2938 G_CALLBACK (error_dialog_response_cb),
2939 window);
2940 if (dialog_parent != NULL)
2941 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
2942 gtk_widget_show (dialog);
2943
2944 window->priv->showing_error_dialog = TRUE;
2945 }
2946
2947
2948 void
fr_window_destroy_with_error_dialog(FrWindow * window)2949 fr_window_destroy_with_error_dialog (FrWindow *window)
2950 {
2951 window->priv->destroy_with_error_dialog = TRUE;
2952 }
2953
2954
2955 void
fr_window_set_notify(FrWindow * window,gboolean notify)2956 fr_window_set_notify (FrWindow *window,
2957 gboolean notify)
2958 {
2959 window->priv->notify = notify;
2960 }
2961
2962
2963 static void
_handle_archive_operation_error(FrWindow * window,FrArchive * archive,FrAction action,GError * error,gboolean * continue_batch,gboolean * opens_dialog)2964 _handle_archive_operation_error (FrWindow *window,
2965 FrArchive *archive,
2966 FrAction action,
2967 GError *error,
2968 gboolean *continue_batch,
2969 gboolean *opens_dialog)
2970 {
2971 GtkWindow *dialog_parent;
2972 char *msg;
2973 char *utf8_name;
2974 char *details;
2975 GList *output;
2976 GtkWidget *dialog;
2977
2978 if (continue_batch) *continue_batch = (error == NULL);
2979 if (opens_dialog) *opens_dialog = FALSE;
2980
2981 if (error == NULL)
2982 return;
2983
2984 if ((error != NULL) && (error->code == FR_ERROR_STOPPED))
2985 g_cancellable_reset (window->priv->cancellable);
2986
2987 switch (error->code) {
2988 case FR_ERROR_ASK_PASSWORD:
2989 close_progress_dialog (window, TRUE);
2990 dlg_ask_password (window);
2991 if (opens_dialog) *opens_dialog = TRUE;
2992 break;
2993
2994 case FR_ERROR_UNSUPPORTED_FORMAT:
2995 close_progress_dialog (window, TRUE);
2996 dlg_package_installer (window,
2997 window->priv->archive_file,
2998 action,
2999 window->priv->cancellable);
3000 if (opens_dialog) *opens_dialog = TRUE;
3001 break;
3002
3003 #if 0
3004 case FR_PROC_ERROR_BAD_CHARSET:
3005 close_progress_dialog (window, TRUE);
3006 /* dlg_ask_archive_charset (window); FIXME: implement after feature freeze */
3007 break;
3008 #endif
3009
3010 case FR_ERROR_STOPPED:
3011 /* nothing */
3012 break;
3013
3014 default:
3015 /* generic error => show an error dialog */
3016
3017 msg = NULL;
3018 details = NULL;
3019 output = NULL;
3020
3021 if (window->priv->batch_mode) {
3022 dialog_parent = NULL;
3023 window->priv->load_error_parent_window = NULL;
3024 }
3025 else {
3026 dialog_parent = (GtkWindow *) window;
3027 if (window->priv->load_error_parent_window == NULL)
3028 window->priv->load_error_parent_window = (GtkWindow *) window;
3029 }
3030
3031 switch (action) {
3032 case FR_ACTION_CREATING_NEW_ARCHIVE:
3033 dialog_parent = window->priv->load_error_parent_window;
3034 msg = _("Could not create the archive");
3035 break;
3036
3037 case FR_ACTION_EXTRACTING_FILES:
3038 case FR_ACTION_COPYING_FILES_TO_REMOTE:
3039 msg = _("An error occurred while extracting files.");
3040 break;
3041
3042 case FR_ACTION_LOADING_ARCHIVE:
3043 dialog_parent = window->priv->load_error_parent_window;
3044 utf8_name = _g_file_get_display_basename (window->priv->archive_file);
3045 msg = g_strdup_printf (_("Could not open “%s”"), utf8_name);
3046 g_free (utf8_name);
3047 break;
3048
3049 case FR_ACTION_LISTING_CONTENT:
3050 msg = _("An error occurred while loading the archive.");
3051 break;
3052
3053 case FR_ACTION_DELETING_FILES:
3054 msg = _("An error occurred while deleting files from the archive.");
3055 break;
3056
3057 case FR_ACTION_ADDING_FILES:
3058 case FR_ACTION_GETTING_FILE_LIST:
3059 case FR_ACTION_COPYING_FILES_FROM_REMOTE:
3060 msg = _("An error occurred while adding files to the archive.");
3061 break;
3062
3063 case FR_ACTION_TESTING_ARCHIVE:
3064 msg = _("An error occurred while testing archive.");
3065 break;
3066
3067 case FR_ACTION_SAVING_REMOTE_ARCHIVE:
3068 case FR_ACTION_ENCRYPTING_ARCHIVE:
3069 msg = _("An error occurred while saving the archive.");
3070 break;
3071
3072 case FR_ACTION_RENAMING_FILES:
3073 msg = _("An error occurred while renaming the files.");
3074 break;
3075
3076 case FR_ACTION_UPDATING_FILES:
3077 msg = _("An error occurred while updating the files.");
3078 break;
3079
3080 default:
3081 msg = _("An error occurred.");
3082 break;
3083 }
3084
3085 switch (error->code) {
3086 case FR_ERROR_COMMAND_NOT_FOUND:
3087 details = _("Command not found.");
3088 break;
3089 case FR_ERROR_EXITED_ABNORMALLY:
3090 details = _("Command exited abnormally.");
3091 break;
3092 case FR_ERROR_SPAWN:
3093 details = error->message;
3094 break;
3095 default:
3096 details = error->message;
3097 break;
3098 }
3099
3100 if ((error->code != FR_ERROR_GENERIC) && FR_IS_COMMAND (archive))
3101 output = fr_command_get_last_output (FR_COMMAND (archive));
3102
3103 dialog = _gtk_error_dialog_new (dialog_parent,
3104 0,
3105 output,
3106 msg,
3107 ((details != NULL) ? "%s" : NULL),
3108 details);
3109 fr_window_show_error_dialog (window, dialog, dialog_parent, details);
3110 break;
3111 }
3112 }
3113
3114
3115 static void fr_window_batch_exec_next_action (FrWindow *window);
3116 static void fr_window_archive_list (FrWindow *window);
3117
3118
3119 static void
_archive_operation_completed(FrWindow * window,FrAction action,GError * error)3120 _archive_operation_completed (FrWindow *window,
3121 FrAction action,
3122 GError *error)
3123 {
3124 gboolean continue_batch = FALSE;
3125 gboolean opens_dialog;
3126 gboolean operation_canceled;
3127 GFile *archive_dir;
3128 gboolean is_temp_dir;
3129
3130 #ifdef DEBUG
3131 debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", action_names[action]);
3132 #endif
3133
3134 _fr_window_stop_activity_mode (window);
3135 _handle_archive_operation_error (window, window->archive, action, error, &continue_batch, &opens_dialog);
3136 if (opens_dialog)
3137 return;
3138
3139 operation_canceled = g_error_matches (error, FR_ERROR, FR_ERROR_STOPPED);
3140
3141 switch (action) {
3142 case FR_ACTION_CREATING_NEW_ARCHIVE:
3143 case FR_ACTION_CREATING_ARCHIVE:
3144 close_progress_dialog (window, FALSE);
3145 if (! operation_canceled) {
3146 fr_window_history_clear (window);
3147 fr_window_go_to_location (window, "/", TRUE);
3148 fr_window_update_dir_tree (window);
3149 fr_window_update_title (window);
3150 fr_window_update_sensitivity (window);
3151 }
3152 break;
3153
3154 case FR_ACTION_LOADING_ARCHIVE:
3155 close_progress_dialog (window, FALSE);
3156 if (error != NULL) {
3157 fr_window_remove_from_recent_list (window, window->priv->archive_file);
3158 fr_window_archive_close (window);
3159 }
3160 else {
3161 fr_window_archive_list (window);
3162 return;
3163 }
3164 break;
3165
3166 case FR_ACTION_LISTING_CONTENT:
3167 /* update the file because multi-volume archives can have
3168 * a different name after loading. */
3169 _g_object_unref (window->priv->archive_file);
3170 window->priv->archive_file = _g_object_ref (fr_archive_get_file (window->archive));
3171
3172 window->priv->reload_archive = FALSE;
3173
3174 close_progress_dialog (window, FALSE);
3175 if (error != NULL) {
3176 fr_window_remove_from_recent_list (window, window->priv->archive_file);
3177 fr_window_archive_close (window);
3178 fr_window_set_password (window, NULL);
3179 break;
3180 }
3181
3182 /* error == NULL */
3183
3184 archive_dir = g_file_get_parent (window->priv->archive_file);
3185 is_temp_dir = _g_file_is_temp_dir (archive_dir);
3186 if (! window->priv->archive_present) {
3187 window->priv->archive_present = TRUE;
3188
3189 fr_window_history_clear (window);
3190 fr_window_history_add (window, "/");
3191
3192 if (! is_temp_dir) {
3193 fr_window_set_open_default_dir (window, archive_dir);
3194 fr_window_set_add_default_dir (window, archive_dir);
3195 if (! window->priv->freeze_default_dir)
3196 fr_window_set_extract_default_dir (window, archive_dir);
3197 }
3198
3199 window->priv->archive_new = FALSE;
3200 }
3201 g_object_unref (archive_dir);
3202
3203 if (! is_temp_dir)
3204 fr_window_add_to_recent_list (window, window->priv->archive_file);
3205
3206 fr_window_update_history (window);
3207 fr_window_update_title (window);
3208 fr_window_go_to_location (window, fr_window_get_current_location (window), TRUE);
3209 fr_window_update_dir_tree (window);
3210
3211 if (! window->priv->batch_mode)
3212 gtk_window_present (GTK_WINDOW (window));
3213 break;
3214
3215 case FR_ACTION_DELETING_FILES:
3216 case FR_ACTION_ADDING_FILES:
3217 close_progress_dialog (window, FALSE);
3218
3219 /* update the file because multi-volume archives can have
3220 * a different name after creation. */
3221 _g_object_unref (window->priv->archive_file);
3222 window->priv->archive_file = _g_object_ref (fr_archive_get_file (window->archive));
3223
3224 if (window->priv->notify) {
3225 _g_object_unref (window->priv->saving_file);
3226 window->priv->saving_file = g_object_ref (window->priv->archive_file);
3227 }
3228
3229 if (error == NULL) {
3230 if (window->priv->archive_new)
3231 window->priv->archive_new = FALSE;
3232 fr_window_add_to_recent_list (window, window->priv->archive_file);
3233 }
3234
3235 if (! window->priv->batch_mode && ! operation_canceled)
3236 window->priv->reload_archive = TRUE;
3237
3238 break;
3239
3240 case FR_ACTION_TESTING_ARCHIVE:
3241 close_progress_dialog (window, FALSE);
3242 if (error == NULL)
3243 fr_window_view_last_output (window, _("Test Result"));
3244 return;
3245
3246 case FR_ACTION_EXTRACTING_FILES:
3247 close_progress_dialog (window, FALSE);
3248 break;
3249
3250 case FR_ACTION_RENAMING_FILES:
3251 case FR_ACTION_UPDATING_FILES:
3252 close_progress_dialog (window, FALSE);
3253 if (! window->priv->batch_mode && ! operation_canceled)
3254 window->priv->reload_archive = TRUE;
3255 break;
3256
3257 default:
3258 close_progress_dialog (window, FALSE);
3259 continue_batch = FALSE;
3260 break;
3261 }
3262
3263 if (continue_batch)
3264 fr_window_batch_exec_next_action (window);
3265 else
3266 fr_window_batch_stop (window);
3267 }
3268
3269
3270 static void
_archive_operation_cancelled(FrWindow * window,FrAction action)3271 _archive_operation_cancelled (FrWindow *window,
3272 FrAction action)
3273 {
3274 GError *error;
3275
3276 error = g_error_new_literal (FR_ERROR, FR_ERROR_STOPPED, "");
3277 _archive_operation_completed (window, action, error);
3278
3279 g_error_free (error);
3280 }
3281
3282
3283 static void
_archive_operation_started(FrWindow * window,FrAction action)3284 _archive_operation_started (FrWindow *window,
3285 FrAction action)
3286 {
3287 GFile *archive;
3288
3289 window->priv->action = action;
3290 _fr_window_start_activity_mode (window);
3291
3292 #ifdef DEBUG
3293 debug (DEBUG_INFO, "%s [START] (FR::Window)\n", action_names[action]);
3294 #endif
3295
3296 archive = window->priv->pd_last_archive;
3297 if (archive == NULL)
3298 archive = window->priv->archive_file;
3299
3300 switch (action) {
3301 case FR_ACTION_EXTRACTING_FILES:
3302 open_progress_dialog (window, ((window->priv->saving_file != NULL)
3303 || window->priv->batch_mode));
3304 break;
3305 default:
3306 open_progress_dialog (window, window->priv->batch_mode);
3307 break;
3308 }
3309
3310 fr_archive_progress_cb (NULL, -1.0, window);
3311 fr_archive_message_cb (NULL, _("Please wait…"), window);
3312 }
3313
3314
3315 /* -- selections -- */
3316
3317
3318 #undef DEBUG_GET_DIR_LIST_FROM_PATH
3319
3320
3321 static GList *
get_dir_list_from_path(FrWindow * window,char * path)3322 get_dir_list_from_path (FrWindow *window,
3323 char *path)
3324 {
3325 char *dirname;
3326 int dirname_l;
3327 GList *list = NULL;
3328 int i;
3329
3330 if (path[strlen (path) - 1] != '/')
3331 dirname = g_strconcat (path, "/", NULL);
3332 else
3333 dirname = g_strdup (path);
3334 dirname_l = strlen (dirname);
3335 for (i = 0; i < window->archive->files->len; i++) {
3336 FileData *fd = g_ptr_array_index (window->archive->files, i);
3337 gboolean matches = FALSE;
3338
3339 #ifdef DEBUG_GET_DIR_LIST_FROM_PATH
3340 g_print ("%s <=> %s (%d)\n", dirname, fd->full_path, dirname_l);
3341 #endif
3342
3343 if (fd->dir) {
3344 int full_path_l = strlen (fd->full_path);
3345 if ((full_path_l == dirname_l - 1) && (strncmp (dirname, fd->full_path, full_path_l) == 0))
3346 /* example: dirname is '/path/to/dir/' and fd->full_path is '/path/to/dir' */
3347 matches = TRUE;
3348 else if (strcmp (dirname, fd->full_path) == 0)
3349 matches = TRUE;
3350 }
3351
3352 if (! matches && strncmp (dirname, fd->full_path, dirname_l) == 0) {
3353 matches = TRUE;
3354 }
3355
3356 if (matches) {
3357 #ifdef DEBUG_GET_DIR_LIST_FROM_PATH
3358 g_print ("`-> OK\n");
3359 #endif
3360 list = g_list_prepend (list, g_strdup (fd->original_path));
3361 }
3362 }
3363 g_free (dirname);
3364
3365 return g_list_reverse (list);
3366 }
3367
3368
3369 static GList *
get_dir_list_from_file_data(FrWindow * window,FileData * fdata)3370 get_dir_list_from_file_data (FrWindow *window,
3371 FileData *fdata)
3372 {
3373 char *dirname;
3374 GList *list;
3375
3376 dirname = g_strconcat (fr_window_get_current_location (window),
3377 fdata->list_name,
3378 NULL);
3379 list = get_dir_list_from_path (window, dirname);
3380 g_free (dirname);
3381
3382 return list;
3383 }
3384
3385
3386 GList *
fr_window_get_file_list_selection(FrWindow * window,gboolean recursive,gboolean * has_dirs)3387 fr_window_get_file_list_selection (FrWindow *window,
3388 gboolean recursive,
3389 gboolean *has_dirs)
3390 {
3391 GtkTreeSelection *selection;
3392 GList *selections = NULL, *list, *scan;
3393
3394 g_return_val_if_fail (window != NULL, NULL);
3395
3396 if (has_dirs != NULL)
3397 *has_dirs = FALSE;
3398
3399 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
3400 if (selection == NULL)
3401 return NULL;
3402 gtk_tree_selection_selected_foreach (selection, add_selected_from_list_view, &selections);
3403
3404 list = NULL;
3405 for (scan = selections; scan; scan = scan->next) {
3406 FileData *fd = scan->data;
3407
3408 if (!fd)
3409 continue;
3410
3411 if (file_data_is_dir (fd)) {
3412 if (has_dirs != NULL)
3413 *has_dirs = TRUE;
3414
3415 if (recursive)
3416 list = g_list_concat (list, get_dir_list_from_file_data (window, fd));
3417 }
3418 else
3419 list = g_list_prepend (list, g_strdup (fd->original_path));
3420 }
3421 if (selections)
3422 g_list_free (selections);
3423
3424 return g_list_reverse (list);
3425 }
3426
3427
3428 GList *
fr_window_get_folder_tree_selection(FrWindow * window,gboolean recursive,gboolean * has_dirs)3429 fr_window_get_folder_tree_selection (FrWindow *window,
3430 gboolean recursive,
3431 gboolean *has_dirs)
3432 {
3433 GtkTreeSelection *tree_selection;
3434 GList *selections, *list, *scan;
3435
3436 g_return_val_if_fail (window != NULL, NULL);
3437
3438 if (has_dirs != NULL)
3439 *has_dirs = FALSE;
3440
3441 tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view));
3442 if (tree_selection == NULL)
3443 return NULL;
3444
3445 selections = NULL;
3446 gtk_tree_selection_selected_foreach (tree_selection, add_selected_from_tree_view, &selections);
3447 if (selections == NULL)
3448 return NULL;
3449
3450 if (has_dirs != NULL)
3451 *has_dirs = TRUE;
3452
3453 list = NULL;
3454 for (scan = selections; scan; scan = scan->next) {
3455 char *path = scan->data;
3456
3457 if (recursive)
3458 list = g_list_concat (list, get_dir_list_from_path (window, path));
3459 }
3460 _g_string_list_free (selections);
3461
3462 return g_list_reverse (list);
3463 }
3464
3465
3466 GList *
fr_window_get_file_list_from_path_list(FrWindow * window,GList * path_list,gboolean * has_dirs)3467 fr_window_get_file_list_from_path_list (FrWindow *window,
3468 GList *path_list,
3469 gboolean *has_dirs)
3470 {
3471 GtkTreeModel *model;
3472 GList *selections, *list, *scan;
3473
3474 g_return_val_if_fail (window != NULL, NULL);
3475
3476 model = GTK_TREE_MODEL (window->priv->list_store);
3477 selections = NULL;
3478
3479 if (has_dirs != NULL)
3480 *has_dirs = FALSE;
3481
3482 for (scan = path_list; scan; scan = scan->next) {
3483 GtkTreeRowReference *reference = scan->data;
3484 GtkTreePath *path;
3485 GtkTreeIter iter;
3486 FileData *fdata;
3487
3488 path = gtk_tree_row_reference_get_path (reference);
3489 if (path == NULL)
3490 continue;
3491
3492 if (! gtk_tree_model_get_iter (model, &iter, path))
3493 continue;
3494
3495 gtk_tree_model_get (model, &iter,
3496 COLUMN_FILE_DATA, &fdata,
3497 -1);
3498
3499 selections = g_list_prepend (selections, fdata);
3500 }
3501
3502 list = NULL;
3503 for (scan = selections; scan; scan = scan->next) {
3504 FileData *fd = scan->data;
3505
3506 if (!fd)
3507 continue;
3508
3509 if (file_data_is_dir (fd)) {
3510 if (has_dirs != NULL)
3511 *has_dirs = TRUE;
3512 list = g_list_concat (list, get_dir_list_from_file_data (window, fd));
3513 }
3514 else
3515 list = g_list_prepend (list, g_strdup (fd->original_path));
3516 }
3517
3518 if (selections != NULL)
3519 g_list_free (selections);
3520
3521 return g_list_reverse (list);
3522 }
3523
3524
3525 GList *
fr_window_get_file_list_pattern(FrWindow * window,const char * pattern)3526 fr_window_get_file_list_pattern (FrWindow *window,
3527 const char *pattern)
3528 {
3529 GRegex **regexps;
3530 GList *list;
3531 int i;
3532
3533 g_return_val_if_fail (window != NULL, NULL);
3534
3535 regexps = _g_regexp_split_from_patterns (pattern, G_REGEX_CASELESS);
3536 list = NULL;
3537 for (i = 0; i < window->archive->files->len; i++) {
3538 FileData *fd = g_ptr_array_index (window->archive->files, i);
3539 char *utf8_name;
3540
3541 if (fd == NULL)
3542 continue;
3543
3544 utf8_name = g_filename_to_utf8 (fd->name, -1, NULL, NULL, NULL);
3545 if (_g_regexp_matchv (regexps, utf8_name, 0))
3546 list = g_list_prepend (list, g_strdup (fd->original_path));
3547 g_free (utf8_name);
3548 }
3549 _g_regexp_freev (regexps);
3550
3551 return g_list_reverse (list);
3552 }
3553
3554
3555 static GList *
fr_window_get_file_list(FrWindow * window)3556 fr_window_get_file_list (FrWindow *window)
3557 {
3558 GList *list;
3559 int i;
3560
3561 g_return_val_if_fail (window != NULL, NULL);
3562
3563 list = NULL;
3564 for (i = 0; i < window->archive->files->len; i++) {
3565 FileData *fd = g_ptr_array_index (window->archive->files, i);
3566 list = g_list_prepend (list, g_strdup (fd->original_path));
3567 }
3568
3569 return g_list_reverse (list);
3570 }
3571
3572
3573 int
fr_window_get_n_selected_files(FrWindow * window)3574 fr_window_get_n_selected_files (FrWindow *window)
3575 {
3576 return _gtk_tree_selection_count_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)));
3577 }
3578
3579
3580 /**/
3581
3582
3583 static int
dir_tree_button_press_cb(GtkWidget * widget,GdkEventButton * event,gpointer data)3584 dir_tree_button_press_cb (GtkWidget *widget,
3585 GdkEventButton *event,
3586 gpointer data)
3587 {
3588 FrWindow *window = data;
3589 GtkTreeSelection *selection;
3590
3591 if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->tree_view)))
3592 return FALSE;
3593
3594 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view));
3595 if (selection == NULL)
3596 return FALSE;
3597
3598 if ((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) {
3599 GtkTreePath *path;
3600 GtkTreeIter iter;
3601
3602 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->tree_view),
3603 event->x, event->y,
3604 &path, NULL, NULL, NULL)) {
3605
3606 if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->tree_store), &iter, path)) {
3607 gtk_tree_path_free (path);
3608 return FALSE;
3609 }
3610 gtk_tree_path_free (path);
3611
3612 if (! gtk_tree_selection_iter_is_selected (selection, &iter)) {
3613 gtk_tree_selection_unselect_all (selection);
3614 gtk_tree_selection_select_iter (selection, &iter);
3615 }
3616
3617 gtk_menu_popup_at_pointer (GTK_MENU (window->priv->sidebar_folder_popup_menu), (GdkEvent *) event);
3618 }
3619 else
3620 gtk_tree_selection_unselect_all (selection);
3621
3622 return TRUE;
3623 }
3624 else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 8)) {
3625 fr_window_go_back (window);
3626 return TRUE;
3627 }
3628 else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 9)) {
3629 fr_window_go_forward (window);
3630 return TRUE;
3631 }
3632
3633 return FALSE;
3634 }
3635
3636
3637 static FileData *
fr_window_get_selected_item_from_file_list(FrWindow * window)3638 fr_window_get_selected_item_from_file_list (FrWindow *window)
3639 {
3640 GtkTreeSelection *tree_selection;
3641 GList *selection;
3642 FileData *fdata = NULL;
3643
3644 g_return_val_if_fail (window != NULL, NULL);
3645
3646 tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
3647 if (tree_selection == NULL)
3648 return NULL;
3649
3650 selection = NULL;
3651 gtk_tree_selection_selected_foreach (tree_selection, add_selected_from_list_view, &selection);
3652 if ((selection == NULL) || (selection->next != NULL)) {
3653 /* return NULL if the selection contains more than one entry. */
3654 g_list_free (selection);
3655 return NULL;
3656 }
3657
3658 fdata = file_data_copy (selection->data);
3659 g_list_free (selection);
3660
3661 return fdata;
3662 }
3663
3664
3665 static char *
fr_window_get_selected_folder_in_tree_view(FrWindow * window)3666 fr_window_get_selected_folder_in_tree_view (FrWindow *window)
3667 {
3668 GtkTreeSelection *tree_selection;
3669 GList *selections;
3670 char *path = NULL;
3671
3672 g_return_val_if_fail (window != NULL, NULL);
3673
3674 tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view));
3675 if (tree_selection == NULL)
3676 return NULL;
3677
3678 selections = NULL;
3679 gtk_tree_selection_selected_foreach (tree_selection, add_selected_from_tree_view, &selections);
3680
3681 if (selections != NULL) {
3682 path = selections->data;
3683 g_list_free (selections);
3684 }
3685
3686 return path;
3687 }
3688
3689
3690 void
fr_window_current_folder_activated(FrWindow * window,gboolean from_sidebar)3691 fr_window_current_folder_activated (FrWindow *window,
3692 gboolean from_sidebar)
3693 {
3694 char *dir_path;
3695
3696 if (! from_sidebar) {
3697 FileData *fdata;
3698 char *dir_name;
3699
3700 fdata = fr_window_get_selected_item_from_file_list (window);
3701 if ((fdata == NULL) || ! file_data_is_dir (fdata)) {
3702 file_data_free (fdata);
3703 return;
3704 }
3705 dir_name = g_strdup (fdata->list_name);
3706 dir_path = g_strconcat (fr_window_get_current_location (window),
3707 dir_name,
3708 "/",
3709 NULL);
3710 g_free (dir_name);
3711 file_data_free (fdata);
3712 }
3713 else
3714 dir_path = fr_window_get_selected_folder_in_tree_view (window);
3715
3716 fr_window_go_to_location (window, dir_path, FALSE);
3717
3718 g_free (dir_path);
3719 }
3720
3721
3722 static gboolean
row_activated_cb(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer data)3723 row_activated_cb (GtkTreeView *tree_view,
3724 GtkTreePath *path,
3725 GtkTreeViewColumn *column,
3726 gpointer data)
3727 {
3728 FrWindow *window = data;
3729 FileData *fdata;
3730 GtkTreeIter iter;
3731
3732 if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store),
3733 &iter,
3734 path))
3735 return FALSE;
3736
3737 gtk_tree_model_get (GTK_TREE_MODEL (window->priv->list_store), &iter,
3738 COLUMN_FILE_DATA, &fdata,
3739 -1);
3740
3741 if (! file_data_is_dir (fdata)) {
3742 GList *list = g_list_prepend (NULL, fdata->original_path);
3743 fr_window_open_files (window, list, FALSE);
3744 g_list_free (list);
3745 }
3746 else if (window->priv->list_mode == FR_WINDOW_LIST_MODE_AS_DIR) {
3747 char *new_dir;
3748 new_dir = g_strconcat (fr_window_get_current_location (window),
3749 fdata->list_name,
3750 "/",
3751 NULL);
3752 fr_window_go_to_location (window, new_dir, FALSE);
3753 g_free (new_dir);
3754 }
3755
3756 return FALSE;
3757 }
3758
3759
3760 static int
file_button_press_cb(GtkWidget * widget,GdkEventButton * event,gpointer data)3761 file_button_press_cb (GtkWidget *widget,
3762 GdkEventButton *event,
3763 gpointer data)
3764 {
3765 FrWindow *window = data;
3766 GtkTreeSelection *selection;
3767
3768 if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view)))
3769 return FALSE;
3770
3771 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
3772 if (selection == NULL)
3773 return FALSE;
3774
3775 if (window->priv->path_clicked != NULL) {
3776 gtk_tree_path_free (window->priv->path_clicked);
3777 window->priv->path_clicked = NULL;
3778 }
3779
3780 if ((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) {
3781 GtkTreePath *path;
3782 GtkTreeIter iter;
3783 int n_selected;
3784
3785 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->list_view),
3786 event->x, event->y,
3787 &path, NULL, NULL, NULL)) {
3788
3789 if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store), &iter, path)) {
3790 gtk_tree_path_free (path);
3791 return FALSE;
3792 }
3793 gtk_tree_path_free (path);
3794
3795 if (! gtk_tree_selection_iter_is_selected (selection, &iter)) {
3796 gtk_tree_selection_unselect_all (selection);
3797 gtk_tree_selection_select_iter (selection, &iter);
3798 }
3799 }
3800 else
3801 gtk_tree_selection_unselect_all (selection);
3802
3803 n_selected = fr_window_get_n_selected_files (window);
3804 if ((n_selected == 1) && selection_has_a_dir (window))
3805 gtk_menu_popup_at_pointer (GTK_MENU (window->priv->folder_popup_menu), (GdkEvent *) event);
3806 else
3807 gtk_menu_popup_at_pointer (GTK_MENU (window->priv->file_popup_menu), (GdkEvent *) event);
3808 return TRUE;
3809 }
3810 else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 1)) {
3811 GtkTreePath *path = NULL;
3812
3813 if (! gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->list_view),
3814 event->x, event->y,
3815 &path, NULL, NULL, NULL)) {
3816 gtk_tree_selection_unselect_all (selection);
3817 }
3818
3819 if (window->priv->path_clicked != NULL) {
3820 gtk_tree_path_free (window->priv->path_clicked);
3821 window->priv->path_clicked = NULL;
3822 }
3823
3824 if (path != NULL) {
3825 window->priv->path_clicked = gtk_tree_path_copy (path);
3826 gtk_tree_path_free (path);
3827 }
3828
3829 return FALSE;
3830 }
3831 else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 8)) {
3832 // go back
3833 fr_window_go_back (window);
3834 return TRUE;
3835 }
3836 else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 9)) {
3837 // go forward
3838 fr_window_go_forward (window);
3839 return TRUE;
3840 }
3841
3842 return FALSE;
3843 }
3844
3845
3846 static int
file_button_release_cb(GtkWidget * widget,GdkEventButton * event,gpointer data)3847 file_button_release_cb (GtkWidget *widget,
3848 GdkEventButton *event,
3849 gpointer data)
3850 {
3851 FrWindow *window = data;
3852 GtkTreeSelection *selection;
3853
3854 if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view)))
3855 return FALSE;
3856
3857 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
3858 if (selection == NULL)
3859 return FALSE;
3860
3861 if (window->priv->path_clicked == NULL)
3862 return FALSE;
3863
3864 if ((event->type == GDK_BUTTON_RELEASE)
3865 && (event->button == 1)
3866 && (window->priv->path_clicked != NULL)) {
3867 GtkTreePath *path = NULL;
3868
3869 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->list_view),
3870 event->x, event->y,
3871 &path, NULL, NULL, NULL)) {
3872
3873 if ((gtk_tree_path_compare (window->priv->path_clicked, path) == 0)
3874 && window->priv->single_click
3875 && ! ((event->state & GDK_CONTROL_MASK) || (event->state & GDK_SHIFT_MASK))) {
3876 gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget),
3877 path,
3878 NULL,
3879 FALSE);
3880 gtk_tree_view_row_activated (GTK_TREE_VIEW (widget),
3881 path,
3882 NULL);
3883 }
3884 }
3885
3886 if (path != NULL)
3887 gtk_tree_path_free (path);
3888 }
3889
3890 if (window->priv->path_clicked != NULL) {
3891 gtk_tree_path_free (window->priv->path_clicked);
3892 window->priv->path_clicked = NULL;
3893 }
3894
3895 return FALSE;
3896 }
3897
3898
3899 static gboolean
file_motion_notify_callback(GtkWidget * widget,GdkEventMotion * event,gpointer user_data)3900 file_motion_notify_callback (GtkWidget *widget,
3901 GdkEventMotion *event,
3902 gpointer user_data)
3903 {
3904 FrWindow *window = user_data;
3905 GdkCursor *cursor;
3906 GtkTreePath *last_hover_path;
3907 GtkTreeIter iter;
3908
3909 if (! window->priv->single_click)
3910 return FALSE;
3911
3912 if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view)))
3913 return FALSE;
3914
3915 last_hover_path = window->priv->list_hover_path;
3916
3917 gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
3918 event->x, event->y,
3919 &window->priv->list_hover_path,
3920 NULL, NULL, NULL);
3921
3922 if (window->priv->list_hover_path != NULL)
3923 cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (window)),
3924 GDK_HAND2);
3925 else
3926 cursor = NULL;
3927
3928 gdk_window_set_cursor (event->window, cursor);
3929
3930 if (cursor != NULL)
3931 g_object_unref (cursor);
3932
3933 /* only redraw if the hover row has changed */
3934 if (!(last_hover_path == NULL && window->priv->list_hover_path == NULL) &&
3935 (!(last_hover_path != NULL && window->priv->list_hover_path != NULL) ||
3936 gtk_tree_path_compare (last_hover_path, window->priv->list_hover_path)))
3937 {
3938 if (last_hover_path) {
3939 gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store),
3940 &iter, last_hover_path);
3941 gtk_tree_model_row_changed (GTK_TREE_MODEL (window->priv->list_store),
3942 last_hover_path, &iter);
3943 }
3944
3945 if (window->priv->list_hover_path) {
3946 gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store),
3947 &iter, window->priv->list_hover_path);
3948 gtk_tree_model_row_changed (GTK_TREE_MODEL (window->priv->list_store),
3949 window->priv->list_hover_path, &iter);
3950 }
3951 }
3952
3953 gtk_tree_path_free (last_hover_path);
3954
3955 return FALSE;
3956 }
3957
3958
3959 static gboolean
file_leave_notify_callback(GtkWidget * widget,GdkEventCrossing * event,gpointer user_data)3960 file_leave_notify_callback (GtkWidget *widget,
3961 GdkEventCrossing *event,
3962 gpointer user_data)
3963 {
3964 FrWindow *window = user_data;
3965 GtkTreeIter iter;
3966
3967 if (window->priv->single_click && (window->priv->list_hover_path != NULL)) {
3968 gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store),
3969 &iter,
3970 window->priv->list_hover_path);
3971 gtk_tree_model_row_changed (GTK_TREE_MODEL (window->priv->list_store),
3972 window->priv->list_hover_path,
3973 &iter);
3974
3975 gtk_tree_path_free (window->priv->list_hover_path);
3976 window->priv->list_hover_path = NULL;
3977 }
3978
3979 return FALSE;
3980 }
3981
3982
3983 /* -- drag and drop -- */
3984
3985
3986 static GList *
get_file_list_from_selection_data(char * uri_list)3987 get_file_list_from_selection_data (char *uri_list)
3988 {
3989 GList *list = NULL;
3990 char **uris;
3991 int i;
3992
3993 if (uri_list == NULL)
3994 return NULL;
3995
3996 uris = g_uri_list_extract_uris (uri_list);
3997 for (i = 0; uris[i] != NULL; i++)
3998 list = g_list_prepend (list, g_file_new_for_uri (uris[i]));
3999 g_strfreev (uris);
4000
4001 return g_list_reverse (list);
4002 }
4003
4004
4005 static gboolean
fr_window_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time,gpointer user_data)4006 fr_window_drag_motion (GtkWidget *widget,
4007 GdkDragContext *context,
4008 gint x,
4009 gint y,
4010 guint time,
4011 gpointer user_data)
4012 {
4013 FrWindow *window = user_data;
4014
4015 if ((gtk_drag_get_source_widget (context) == window->priv->list_view)
4016 || (gtk_drag_get_source_widget (context) == window->priv->tree_view))
4017 {
4018 gdk_drag_status (context, 0, time);
4019 return FALSE;
4020 }
4021
4022 return TRUE;
4023 }
4024
4025
4026 static void fr_window_paste_from_clipboard_data (FrWindow *window, FrClipboardData *data);
4027
4028
4029 static FrClipboardData*
get_clipboard_data_from_selection_data(FrWindow * window,const char * data)4030 get_clipboard_data_from_selection_data (FrWindow *window,
4031 const char *data)
4032 {
4033 FrClipboardData *clipboard_data;
4034 char **uris;
4035 int i;
4036
4037 clipboard_data = fr_clipboard_data_new ();
4038
4039 uris = g_strsplit (data, "\r\n", -1);
4040
4041 clipboard_data->file = g_file_new_for_uri (uris[0]);
4042 if (window->priv->second_password != NULL)
4043 clipboard_data->password = g_strdup (window->priv->second_password);
4044 else if (strcmp (uris[1], "") != 0)
4045 clipboard_data->password = g_strdup (uris[1]);
4046 clipboard_data->op = (strcmp (uris[2], "copy") == 0) ? FR_CLIPBOARD_OP_COPY : FR_CLIPBOARD_OP_CUT;
4047 clipboard_data->base_dir = g_strdup (uris[3]);
4048 for (i = 4; uris[i] != NULL; i++)
4049 if (uris[i][0] != '\0')
4050 clipboard_data->files = g_list_prepend (clipboard_data->files, g_strdup (uris[i]));
4051 clipboard_data->files = g_list_reverse (clipboard_data->files);
4052
4053 g_strfreev (uris);
4054
4055 return clipboard_data;
4056 }
4057
4058
4059 gboolean
fr_window_create_archive_and_continue(FrWindow * window,GFile * file,const char * mime_type,GtkWindow * error_dialog_parent)4060 fr_window_create_archive_and_continue (FrWindow *window,
4061 GFile *file,
4062 const char *mime_type,
4063 GtkWindow *error_dialog_parent)
4064 {
4065 gboolean result = FALSE;
4066
4067 if (fr_window_archive_new (FR_WINDOW (window), file, mime_type)) {
4068 if (! fr_window_is_batch_mode (FR_WINDOW (window)))
4069 gtk_window_present (GTK_WINDOW (window));
4070 _archive_operation_completed (window, FR_ACTION_CREATING_NEW_ARCHIVE, NULL);
4071
4072 result = TRUE;
4073 }
4074 else {
4075 GError *error;
4076
4077 error = g_error_new_literal (FR_ERROR, FR_ERROR_GENERIC, _("Archive type not supported."));
4078 window->priv->load_error_parent_window = error_dialog_parent;
4079 _archive_operation_completed (window, FR_ACTION_CREATING_NEW_ARCHIVE, error);
4080
4081 g_error_free (error);
4082
4083 result = FALSE;
4084 }
4085
4086 return result;
4087 }
4088
4089
4090 static gboolean
_fr_window_get_ask_to_open_destination(FrWindow * window)4091 _fr_window_get_ask_to_open_destination (FrWindow *window)
4092 {
4093 return ! window->priv->batch_mode || window->priv->notify;
4094 }
4095
4096
4097 static void
new_archive_dialog_response_cb(GtkDialog * dialog,int response,gpointer user_data)4098 new_archive_dialog_response_cb (GtkDialog *dialog,
4099 int response,
4100 gpointer user_data)
4101 {
4102 FrWindow *window = user_data;
4103 GFile *file;
4104 const char *mime_type;
4105 GtkWidget *archive_window;
4106 gboolean new_window;
4107 const char *password;
4108 gboolean encrypt_header;
4109 int volume_size;
4110
4111 if ((response == GTK_RESPONSE_CANCEL) || (response == GTK_RESPONSE_DELETE_EVENT)) {
4112 gtk_widget_destroy (GTK_WIDGET (dialog));
4113 _archive_operation_cancelled (window, FR_ACTION_CREATING_NEW_ARCHIVE);
4114 return;
4115 }
4116
4117 file = fr_new_archive_dialog_get_file (FR_NEW_ARCHIVE_DIALOG (dialog), &mime_type);
4118 if (file == NULL)
4119 return;
4120
4121 new_window = fr_window_archive_is_present (window) && ! fr_window_is_batch_mode (window);
4122 if (new_window)
4123 archive_window = fr_window_new ();
4124 else
4125 archive_window = (GtkWidget *) window;
4126
4127 password = fr_new_archive_dialog_get_password (FR_NEW_ARCHIVE_DIALOG (dialog));
4128 encrypt_header = fr_new_archive_dialog_get_encrypt_header (FR_NEW_ARCHIVE_DIALOG (dialog));
4129 volume_size = fr_new_archive_dialog_get_volume_size (FR_NEW_ARCHIVE_DIALOG (dialog));
4130
4131 fr_window_set_password (FR_WINDOW (archive_window), password);
4132 fr_window_set_encrypt_header (FR_WINDOW (archive_window), encrypt_header);
4133 fr_window_set_volume_size (FR_WINDOW (archive_window), volume_size);
4134
4135 if (fr_window_create_archive_and_continue (FR_WINDOW (archive_window),
4136 file,
4137 mime_type,
4138 GTK_WINDOW (dialog)))
4139 {
4140 gtk_widget_destroy (GTK_WIDGET (dialog));
4141 }
4142 else if (new_window)
4143 gtk_widget_destroy (archive_window);
4144
4145 g_object_unref (file);
4146 }
4147
4148
4149 static void
fr_window_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * data,guint info,guint time,gpointer extra_data)4150 fr_window_drag_data_received (GtkWidget *widget,
4151 GdkDragContext *context,
4152 gint x,
4153 gint y,
4154 GtkSelectionData *data,
4155 guint info,
4156 guint time,
4157 gpointer extra_data)
4158 {
4159 FrWindow *window = extra_data;
4160 GList *list;
4161 gboolean one_file;
4162 gboolean is_an_archive;
4163
4164 debug (DEBUG_INFO, "::DragDataReceived -->\n");
4165
4166 if ((gtk_drag_get_source_widget (context) == window->priv->list_view)
4167 || (gtk_drag_get_source_widget (context) == window->priv->tree_view))
4168 {
4169 gtk_drag_finish (context, FALSE, FALSE, time);
4170 return;
4171 }
4172
4173 if (! ((gtk_selection_data_get_length (data) >= 0) && (gtk_selection_data_get_format (data) == 8))) {
4174 gtk_drag_finish (context, FALSE, FALSE, time);
4175 return;
4176 }
4177
4178 if (window->priv->activity_ref > 0) {
4179 gtk_drag_finish (context, FALSE, FALSE, time);
4180 return;
4181 }
4182
4183 gtk_drag_finish (context, TRUE, FALSE, time);
4184
4185 if (gtk_selection_data_get_target (data) == XFR_ATOM) {
4186 FrClipboardData *dnd_data;
4187
4188 dnd_data = get_clipboard_data_from_selection_data (window, (char*) gtk_selection_data_get_data (data));
4189 dnd_data->current_dir = g_strdup (fr_window_get_current_location (window));
4190 fr_window_paste_from_clipboard_data (window, dnd_data);
4191
4192 return;
4193 }
4194
4195 list = get_file_list_from_selection_data ((char*) gtk_selection_data_get_data (data));
4196 if (list == NULL) {
4197 GtkWidget *d;
4198
4199 d = _gtk_error_dialog_new (GTK_WINDOW (window),
4200 GTK_DIALOG_MODAL,
4201 NULL,
4202 _("Could not perform the operation"),
4203 NULL);
4204 gtk_dialog_run (GTK_DIALOG (d));
4205 gtk_widget_destroy(d);
4206
4207 return;
4208 }
4209
4210 one_file = (list->next == NULL);
4211 if (one_file)
4212 is_an_archive = _g_file_is_archive (G_FILE (list->data));
4213 else
4214 is_an_archive = FALSE;
4215
4216 if (window->priv->archive_present
4217 && (window->archive != NULL)
4218 && ! window->archive->read_only
4219 && fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_STORE_MANY_FILES))
4220 {
4221 if (one_file && is_an_archive) {
4222 GtkWidget *d;
4223 gint r;
4224
4225 d = _gtk_message_dialog_new (GTK_WINDOW (window),
4226 GTK_DIALOG_MODAL,
4227 _("Do you want to add this file to the current archive or open it as a new archive?"),
4228 NULL,
4229 _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
4230 _GTK_LABEL_ADD, 0,
4231 _GTK_LABEL_OPEN, 1,
4232 NULL);
4233
4234 gtk_dialog_set_default_response (GTK_DIALOG (d), 2);
4235
4236 r = gtk_dialog_run (GTK_DIALOG (d));
4237 gtk_widget_destroy (GTK_WIDGET (d));
4238
4239 if (r == 0) /* Add */
4240 fr_window_archive_add_dropped_items (window, list);
4241 else if (r == 1) /* Open */
4242 fr_window_archive_open (window, G_FILE (list->data), GTK_WINDOW (window));
4243 }
4244 else
4245 fr_window_archive_add_dropped_items (window, list);
4246 }
4247 else {
4248 if (one_file && is_an_archive)
4249 fr_window_archive_open (window, G_FILE (list->data), GTK_WINDOW (window));
4250 else {
4251 GtkWidget *d;
4252 int r;
4253
4254 d = _gtk_message_dialog_new (GTK_WINDOW (window),
4255 GTK_DIALOG_MODAL,
4256 _("Do you want to create a new archive with these files?"),
4257 NULL,
4258 _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
4259 _("Create _Archive"), GTK_RESPONSE_YES,
4260 NULL);
4261
4262 gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_YES);
4263 r = gtk_dialog_run (GTK_DIALOG (d));
4264 gtk_widget_destroy (GTK_WIDGET (d));
4265
4266 if (r == GTK_RESPONSE_YES) {
4267 GFile *first_file;
4268 GFile *folder;
4269 char *archive_name;
4270 GtkWidget *dialog;
4271
4272 fr_window_free_batch_data (window);
4273 fr_window_batch_append_action (window,
4274 FR_BATCH_ACTION_ADD,
4275 _g_object_list_ref (list),
4276 (GFreeFunc) _g_object_list_unref);
4277
4278 first_file = G_FILE (list->data);
4279 folder = g_file_get_parent (first_file);
4280 if (folder != NULL)
4281 fr_window_set_open_default_dir (window, folder);
4282
4283 if ((list->next != NULL) && (folder != NULL))
4284 archive_name = g_file_get_basename (folder);
4285 else
4286 archive_name = g_file_get_basename (first_file);
4287
4288 dialog = fr_new_archive_dialog_new (_("New Archive"),
4289 GTK_WINDOW (window),
4290 FR_NEW_ARCHIVE_ACTION_SAVE_AS,
4291 fr_window_get_open_default_dir (window),
4292 archive_name,
4293 NULL);
4294 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
4295 g_signal_connect (G_OBJECT (dialog),
4296 "response",
4297 G_CALLBACK (new_archive_dialog_response_cb),
4298 window);
4299 gtk_window_present (GTK_WINDOW (dialog));
4300
4301 g_free (archive_name);
4302 _g_object_unref (folder);
4303 }
4304 }
4305 }
4306
4307 _g_object_list_unref (list);
4308
4309 debug (DEBUG_INFO, "::DragDataReceived <--\n");
4310 }
4311
4312
4313 static gboolean
tree_view_drag_begin(GtkWidget * widget,GdkDragContext * context,GtkTreeModel * tree_model,int filename_column,gpointer data)4314 tree_view_drag_begin (GtkWidget *widget,
4315 GdkDragContext *context,
4316 GtkTreeModel *tree_model,
4317 int filename_column,
4318 gpointer data)
4319 {
4320 FrWindow *window = data;
4321 GtkTreeSelection *selection;
4322 GtkTreeIter iter;
4323 GList *selected_tree_paths;
4324 char *xds_filename;
4325
4326 debug (DEBUG_INFO, "::DragBegin -->\n");
4327
4328 if (window->priv->activity_ref > 0)
4329 return FALSE;
4330
4331 if (window->priv->path_clicked != NULL) {
4332 gtk_tree_path_free (window->priv->path_clicked);
4333 window->priv->path_clicked = NULL;
4334 }
4335
4336 _g_clear_object (&window->priv->drag_destination_folder);
4337
4338 g_free (window->priv->drag_base_dir);
4339 window->priv->drag_base_dir = NULL;
4340
4341 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
4342 selected_tree_paths = gtk_tree_selection_get_selected_rows (selection, NULL);
4343
4344 if (gtk_tree_model_get_iter (tree_model,
4345 &iter,
4346 (GtkTreePath *) selected_tree_paths->data))
4347 {
4348 gtk_tree_model_get (tree_model,
4349 &iter,
4350 filename_column, &xds_filename,
4351 -1);
4352 }
4353 else
4354 xds_filename = g_strdup (XDS_FILENAME);
4355
4356 gdk_property_change (gdk_drag_context_get_source_window (context),
4357 XDS_ATOM, TEXT_ATOM,
4358 8, GDK_PROP_MODE_REPLACE,
4359 (guchar *) xds_filename,
4360 strlen (xds_filename));
4361
4362 g_free (xds_filename);
4363 g_list_free_full (selected_tree_paths, (GDestroyNotify) gtk_tree_path_free);
4364
4365 return TRUE;
4366 }
4367
4368
4369 static gboolean
file_list_drag_begin(GtkWidget * widget,GdkDragContext * context,gpointer data)4370 file_list_drag_begin (GtkWidget *widget,
4371 GdkDragContext *context,
4372 gpointer data)
4373 {
4374 FrWindow *window = data;
4375 return tree_view_drag_begin (widget,
4376 context,
4377 GTK_TREE_MODEL (window->priv->list_store),
4378 COLUMN_NAME,
4379 data);
4380 }
4381
4382
4383 static gboolean
folde_tree_drag_begin(GtkWidget * widget,GdkDragContext * context,gpointer data)4384 folde_tree_drag_begin (GtkWidget *widget,
4385 GdkDragContext *context,
4386 gpointer data)
4387 {
4388 FrWindow *window = data;
4389 return tree_view_drag_begin (widget,
4390 context,
4391 GTK_TREE_MODEL (window->priv->tree_store),
4392 TREE_COLUMN_NAME,
4393 data);
4394 }
4395
4396
4397 static void
file_list_drag_end(GtkWidget * widget,GdkDragContext * context,gpointer data)4398 file_list_drag_end (GtkWidget *widget,
4399 GdkDragContext *context,
4400 gpointer data)
4401 {
4402 FrWindow *window = data;
4403
4404 debug (DEBUG_INFO, "::DragEnd -->\n");
4405
4406 gdk_property_delete (gdk_drag_context_get_source_window (context), XDS_ATOM);
4407
4408 if (window->priv->drag_error != NULL) {
4409 _gtk_error_dialog_run (GTK_WINDOW (window),
4410 _("Extraction not performed"),
4411 "%s",
4412 window->priv->drag_error->message);
4413 g_clear_error (&window->priv->drag_error);
4414 }
4415 else if (window->priv->drag_destination_folder != NULL) {
4416 _g_string_list_free (window->priv->drag_file_list);
4417 window->priv->drag_file_list = NULL;
4418 }
4419
4420 debug (DEBUG_INFO, "::DragEnd <--\n");
4421 }
4422
4423
4424 /* The following three functions taken from bugzilla
4425 * (http://bugzilla.gnome.org/attachment.cgi?id=49362&action=view)
4426 * Author: Christian Neumair
4427 * Copyright: 2005 Free Software Foundation, Inc
4428 * License: GPL */
4429 static char *
get_xds_atom_value(GdkDragContext * context)4430 get_xds_atom_value (GdkDragContext *context)
4431 {
4432 char *data = NULL;
4433 char *ret;
4434 int len;
4435
4436 g_return_val_if_fail (context != NULL, NULL);
4437 g_return_val_if_fail (gdk_drag_context_get_source_window (context) != NULL, NULL);
4438
4439 if (gdk_property_get (gdk_drag_context_get_source_window (context),
4440 XDS_ATOM, TEXT_ATOM,
4441 0, MAX_XDS_ATOM_VAL_LEN,
4442 FALSE, NULL, NULL, &len,
4443 (unsigned char **) &ret))
4444 {
4445 data = g_strndup (ret, len);
4446 g_free (ret);
4447 }
4448
4449 return data;
4450 }
4451
4452
4453 static gboolean
context_offers_target(GdkDragContext * context,GdkAtom target)4454 context_offers_target (GdkDragContext *context,
4455 GdkAtom target)
4456 {
4457 return (g_list_find (gdk_drag_context_list_targets (context), target) != NULL);
4458 }
4459
4460
4461 static gboolean
nautilus_xds_dnd_is_valid_xds_context(GdkDragContext * context)4462 nautilus_xds_dnd_is_valid_xds_context (GdkDragContext *context)
4463 {
4464 gboolean ret = FALSE;
4465
4466 g_return_val_if_fail (context != NULL, FALSE);
4467
4468 if (context_offers_target (context, XDS_ATOM)) {
4469 char *tmp = get_xds_atom_value (context);
4470 ret = (tmp != NULL);
4471 g_free (tmp);
4472 }
4473
4474 return ret;
4475 }
4476
4477
4478 static char *
get_selection_data_from_clipboard_data(FrWindow * window,FrClipboardData * data)4479 get_selection_data_from_clipboard_data (FrWindow *window,
4480 FrClipboardData *data)
4481 {
4482 GString *list;
4483 char *uri;
4484 GList *scan;
4485
4486 if (data == NULL)
4487 return NULL;
4488
4489 list = g_string_new (NULL);
4490
4491 uri = g_file_get_uri (fr_archive_get_file (window->archive));
4492 g_string_append (list, uri);
4493 g_free (uri);
4494
4495 g_string_append (list, "\r\n");
4496 if (window->priv->password != NULL)
4497 g_string_append (list, window->priv->password);
4498 g_string_append (list, "\r\n");
4499 g_string_append (list, (data->op == FR_CLIPBOARD_OP_COPY) ? "copy" : "cut");
4500 g_string_append (list, "\r\n");
4501 g_string_append (list, data->base_dir);
4502 g_string_append (list, "\r\n");
4503 for (scan = data->files; scan; scan = scan->next) {
4504 g_string_append (list, scan->data);
4505 g_string_append (list, "\r\n");
4506 }
4507
4508 return g_string_free (list, FALSE);
4509 }
4510
4511
4512 /* -- wait_dnd_extraction -- */
4513
4514
4515 typedef struct {
4516 FrWindow *window;
4517 GMainLoop *loop;
4518 } DndWaitInfo;
4519
4520
4521 static gboolean
extraction_is_finished(gpointer * data)4522 extraction_is_finished (gpointer *data)
4523 {
4524 DndWaitInfo *wait_info;
4525 wait_info = (DndWaitInfo *) data;
4526
4527 return wait_info->window->priv->dnd_extract_is_running;
4528 }
4529
4530
4531 static void
notify_extraction_finished(gpointer * data)4532 notify_extraction_finished (gpointer *data)
4533 {
4534 DndWaitInfo *wait_info;
4535 wait_info = (DndWaitInfo *) data;
4536
4537 if (g_main_loop_is_running (wait_info->loop))
4538 g_main_loop_quit (wait_info->loop);
4539 }
4540
4541
4542 static void
wait_dnd_extraction(FrWindow * window)4543 wait_dnd_extraction (FrWindow *window)
4544 {
4545 window->priv->dnd_extract_is_running = TRUE;
4546 window->priv->dnd_extract_finished_with_error = FALSE;
4547 fr_window_archive_extract (window,
4548 window->priv->drag_file_list,
4549 window->priv->drag_destination_folder,
4550 window->priv->drag_base_dir,
4551 FALSE,
4552 FR_OVERWRITE_ASK,
4553 FALSE,
4554 FALSE);
4555
4556 DndWaitInfo wait_info = { NULL, NULL };
4557 wait_info.loop = g_main_loop_new (NULL, FALSE);
4558 wait_info.window = window;
4559 g_timeout_add_full (G_PRIORITY_DEFAULT,
4560 500,
4561 (GSourceFunc) extraction_is_finished,
4562 &wait_info,
4563 (GDestroyNotify) notify_extraction_finished);
4564
4565 g_main_loop_run (wait_info.loop);
4566
4567 g_main_loop_unref (wait_info.loop);
4568 wait_info.loop = NULL;
4569 wait_info.window = NULL;
4570 window->priv->dnd_extract_is_running = FALSE;
4571 }
4572
4573
4574 static gboolean
fr_window_folder_tree_drag_data_get(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * selection_data,guint info,guint time,gpointer user_data)4575 fr_window_folder_tree_drag_data_get (GtkWidget *widget,
4576 GdkDragContext *context,
4577 GtkSelectionData *selection_data,
4578 guint info,
4579 guint time,
4580 gpointer user_data)
4581 {
4582 FrWindow *window = user_data;
4583 GList *file_list;
4584 char *uri;
4585 GFile *destination;
4586 GFile *destination_folder;
4587 char *xds_response;
4588
4589 debug (DEBUG_INFO, "::DragDataGet -->\n");
4590
4591 if (window->priv->activity_ref > 0)
4592 return FALSE;
4593
4594 file_list = fr_window_get_folder_tree_selection (window, TRUE, NULL);
4595 if (file_list == NULL)
4596 return FALSE;
4597
4598 if (gtk_selection_data_get_target (selection_data) == XFR_ATOM) {
4599 FrClipboardData *tmp;
4600 char *data;
4601
4602 tmp = fr_clipboard_data_new ();
4603 tmp->files = file_list;
4604 tmp->op = FR_CLIPBOARD_OP_COPY;
4605 tmp->base_dir = g_strdup (fr_window_get_current_location (window));
4606
4607 data = get_selection_data_from_clipboard_data (window, tmp);
4608 gtk_selection_data_set (selection_data, XFR_ATOM, 8, (guchar *) data, strlen (data));
4609
4610 fr_clipboard_data_unref (tmp);
4611 g_free (data);
4612
4613 return TRUE;
4614 }
4615
4616 if (! nautilus_xds_dnd_is_valid_xds_context (context))
4617 return FALSE;
4618
4619 uri = get_xds_atom_value (context);
4620 g_return_val_if_fail (uri != NULL, FALSE);
4621
4622 destination = g_file_new_for_uri (uri);
4623 destination_folder = g_file_get_parent (destination);
4624
4625 g_object_unref (destination);
4626 g_free (uri);
4627
4628 /* check whether the extraction can be performed in the destination
4629 * folder */
4630
4631 g_clear_error (&window->priv->drag_error);
4632
4633 if (! _g_file_check_permissions (destination_folder, R_OK | W_OK)) {
4634 char *display_name;
4635
4636 display_name = _g_file_get_display_basename (destination_folder);
4637 window->priv->drag_error = g_error_new (FR_ERROR, 0, _("You don’t have the right permissions to extract archives in the folder “%s”"), display_name);
4638
4639 g_free (display_name);
4640 }
4641
4642 if (window->priv->drag_error == NULL) {
4643 char *selected_folder;
4644
4645 _g_object_unref (window->priv->drag_destination_folder);
4646 g_free (window->priv->drag_base_dir);
4647 _g_string_list_free (window->priv->drag_file_list);
4648 window->priv->drag_destination_folder = g_object_ref (destination_folder);
4649 selected_folder = fr_window_get_selected_folder_in_tree_view (window);
4650 window->priv->drag_base_dir = _g_path_remove_level (selected_folder);
4651 window->priv->drag_file_list = file_list;
4652
4653 wait_dnd_extraction (window);
4654
4655 g_free (selected_folder);
4656 }
4657
4658 g_object_unref (destination_folder);
4659
4660 /* sends back the response */
4661
4662 xds_response = ((window->priv->drag_error == NULL && !window->priv->dnd_extract_finished_with_error) ? "S" : "E");
4663 gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (guchar *) xds_response, 1);
4664
4665 window->priv->dnd_extract_finished_with_error = FALSE;
4666
4667 debug (DEBUG_INFO, "::DragDataGet <--\n");
4668
4669 return TRUE;
4670 }
4671
4672
4673 gboolean
fr_window_file_list_drag_data_get(FrWindow * window,GdkDragContext * context,GtkSelectionData * selection_data,GList * path_list)4674 fr_window_file_list_drag_data_get (FrWindow *window,
4675 GdkDragContext *context,
4676 GtkSelectionData *selection_data,
4677 GList *path_list)
4678 {
4679 char *uri;
4680 char *xds_response;
4681 GFile *destination;
4682 GFile *destination_folder;
4683
4684 debug (DEBUG_INFO, "::DragDataGet -->\n");
4685
4686 if (window->priv->path_clicked != NULL) {
4687 gtk_tree_path_free (window->priv->path_clicked);
4688 window->priv->path_clicked = NULL;
4689 }
4690
4691 if (window->priv->activity_ref > 0)
4692 return FALSE;
4693
4694 if (gtk_selection_data_get_target (selection_data) == XFR_ATOM) {
4695 FrClipboardData *tmp;
4696 char *data;
4697
4698 tmp = fr_clipboard_data_new ();
4699 tmp->files = fr_window_get_file_list_selection (window, TRUE, NULL);
4700 tmp->op = FR_CLIPBOARD_OP_COPY;
4701 tmp->base_dir = g_strdup (fr_window_get_current_location (window));
4702
4703 data = get_selection_data_from_clipboard_data (window, tmp);
4704 gtk_selection_data_set (selection_data, XFR_ATOM, 8, (guchar *) data, strlen (data));
4705
4706 fr_clipboard_data_unref (tmp);
4707 g_free (data);
4708
4709 return TRUE;
4710 }
4711
4712 if (! nautilus_xds_dnd_is_valid_xds_context (context))
4713 return FALSE;
4714
4715 uri = get_xds_atom_value (context);
4716 g_return_val_if_fail (uri != NULL, FALSE);
4717
4718 destination = g_file_new_for_uri (uri);
4719 g_free (uri);
4720
4721 if (destination == NULL)
4722 return FALSE;
4723
4724 destination_folder = g_file_get_parent (destination);
4725 g_object_unref (destination);
4726
4727 if (destination_folder == NULL)
4728 return FALSE;
4729
4730 /* check whether the extraction can be performed in the destination
4731 * folder */
4732
4733 g_clear_error (&window->priv->drag_error);
4734
4735 if (! _g_file_check_permissions (destination_folder, R_OK | W_OK)) {
4736 char *display_name;
4737
4738 display_name = _g_file_get_display_basename (destination_folder);
4739 window->priv->drag_error = g_error_new (FR_ERROR, 0, _("You don’t have the right permissions to extract archives in the folder “%s”"), display_name);
4740
4741 g_free (display_name);
4742 }
4743
4744 if (window->priv->drag_error == NULL) {
4745 _g_object_unref (window->priv->drag_destination_folder);
4746 g_free (window->priv->drag_base_dir);
4747 _g_string_list_free (window->priv->drag_file_list);
4748 window->priv->drag_destination_folder = g_object_ref (destination_folder);
4749 window->priv->drag_base_dir = g_strdup (fr_window_get_current_location (window));
4750 window->priv->drag_file_list = fr_window_get_file_list_from_path_list (window, path_list, NULL);
4751
4752 wait_dnd_extraction (window);
4753 }
4754
4755 g_object_unref (destination_folder);
4756
4757 /* sends back the response */
4758
4759 xds_response = ((window->priv->drag_error == NULL && !window->priv->dnd_extract_finished_with_error) ? "S" : "E");
4760 gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (guchar *) xds_response, 1);
4761
4762 window->priv->dnd_extract_finished_with_error = FALSE;
4763
4764 debug (DEBUG_INFO, "::DragDataGet <--\n");
4765
4766 return TRUE;
4767 }
4768
4769
4770 /* -- window_new -- */
4771
4772
4773 static void
fr_window_update_columns_visibility(FrWindow * window)4774 fr_window_update_columns_visibility (FrWindow *window)
4775 {
4776 GtkTreeView *tree_view = GTK_TREE_VIEW (window->priv->list_view);
4777 GtkTreeViewColumn *column;
4778
4779 column = gtk_tree_view_get_column (tree_view, 1);
4780 gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_SIZE));
4781
4782 column = gtk_tree_view_get_column (tree_view, 2);
4783 gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_TYPE));
4784
4785 column = gtk_tree_view_get_column (tree_view, 3);
4786 gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_TIME));
4787
4788 column = gtk_tree_view_get_column (tree_view, 4);
4789 gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_PATH));
4790 }
4791
4792
4793 static gboolean
key_press_cb(GtkWidget * widget,GdkEventKey * event,gpointer data)4794 key_press_cb (GtkWidget *widget,
4795 GdkEventKey *event,
4796 gpointer data)
4797 {
4798 FrWindow *window = data;
4799 gboolean retval = FALSE;
4800 gboolean alt;
4801
4802 if (gtk_widget_has_focus (window->priv->location_entry))
4803 return FALSE;
4804
4805 if (gtk_widget_has_focus (window->priv->filter_entry)) {
4806 switch (event->keyval) {
4807 case GDK_KEY_Escape:
4808 fr_window_deactivate_filter (window);
4809 retval = TRUE;
4810 break;
4811 default:
4812 break;
4813 }
4814 return retval;
4815 }
4816
4817 alt = (event->state & GDK_MOD1_MASK) == GDK_MOD1_MASK;
4818
4819 switch (event->keyval) {
4820 case GDK_KEY_Escape:
4821 fr_window_stop (window);
4822 if (window->priv->filter_mode)
4823 fr_window_deactivate_filter (window);
4824 retval = TRUE;
4825 break;
4826
4827 case GDK_KEY_F10:
4828 if (event->state & GDK_SHIFT_MASK) {
4829 GtkTreeSelection *selection;
4830
4831 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
4832 if (selection == NULL)
4833 return FALSE;
4834
4835 gtk_menu_popup_at_pointer (GTK_MENU (window->priv->file_popup_menu), (GdkEvent *) event);
4836 retval = TRUE;
4837 }
4838 break;
4839
4840 case GDK_KEY_Up:
4841 case GDK_KEY_KP_Up:
4842 if (alt) {
4843 fr_window_go_up_one_level (window);
4844 retval = TRUE;
4845 }
4846 break;
4847
4848 case GDK_KEY_BackSpace:
4849 fr_window_go_up_one_level (window);
4850 retval = TRUE;
4851 break;
4852
4853 case GDK_KEY_Right:
4854 case GDK_KEY_KP_Right:
4855 if (alt) {
4856 fr_window_go_forward (window);
4857 retval = TRUE;
4858 }
4859 break;
4860
4861 case GDK_KEY_Left:
4862 case GDK_KEY_KP_Left:
4863 if (alt) {
4864 fr_window_go_back (window);
4865 retval = TRUE;
4866 }
4867 break;
4868
4869 case GDK_KEY_Home:
4870 case GDK_KEY_KP_Home:
4871 if (alt) {
4872 fr_window_go_to_location (window, "/", FALSE);
4873 retval = TRUE;
4874 }
4875 break;
4876
4877 case GDK_KEY_Delete:
4878 if (! gtk_widget_has_focus (window->priv->filter_entry)) {
4879 fr_window_activate_delete (NULL, NULL, window);
4880 retval = TRUE;
4881 }
4882 break;
4883
4884 default:
4885 break;
4886 }
4887
4888 return retval;
4889 }
4890
4891
4892 static gboolean
dir_tree_selection_changed_cb(GtkTreeSelection * selection,gpointer user_data)4893 dir_tree_selection_changed_cb (GtkTreeSelection *selection,
4894 gpointer user_data)
4895 {
4896 FrWindow *window = user_data;
4897 GtkTreeIter iter;
4898
4899 if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
4900 char *path;
4901
4902 gtk_tree_model_get (GTK_TREE_MODEL (window->priv->tree_store),
4903 &iter,
4904 TREE_COLUMN_PATH, &path,
4905 -1);
4906 fr_window_go_to_location (window, path, FALSE);
4907 g_free (path);
4908 }
4909
4910 return FALSE;
4911 }
4912
4913
4914 static gboolean
selection_changed_cb(GtkTreeSelection * selection,gpointer user_data)4915 selection_changed_cb (GtkTreeSelection *selection,
4916 gpointer user_data)
4917 {
4918 FrWindow *window = user_data;
4919
4920 fr_window_update_sensitivity (window);
4921
4922 return FALSE;
4923 }
4924
4925
4926 static gboolean
fr_window_delete_event_cb(GtkWidget * caller,GdkEvent * event,FrWindow * window)4927 fr_window_delete_event_cb (GtkWidget *caller,
4928 GdkEvent *event,
4929 FrWindow *window)
4930 {
4931 fr_window_close (window);
4932 return TRUE;
4933 }
4934
4935
4936 static gboolean
is_single_click_policy(FrWindow * window)4937 is_single_click_policy (FrWindow *window)
4938 {
4939 char *value;
4940 gboolean result;
4941
4942 if (window->priv->settings_nautilus == NULL)
4943 return FALSE;
4944
4945 value = g_settings_get_string (window->priv->settings_nautilus, NAUTILUS_CLICK_POLICY);
4946 result = (value != NULL) && (strncmp (value, "single", 6) == 0);
4947 g_free (value);
4948
4949 return result;
4950 }
4951
4952
4953 static void
filename_cell_data_func(GtkTreeViewColumn * column,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,FrWindow * window)4954 filename_cell_data_func (GtkTreeViewColumn *column,
4955 GtkCellRenderer *renderer,
4956 GtkTreeModel *model,
4957 GtkTreeIter *iter,
4958 FrWindow *window)
4959 {
4960 char *text;
4961 GtkTreePath *path;
4962 PangoUnderline underline;
4963
4964 gtk_tree_model_get (model, iter,
4965 COLUMN_NAME, &text,
4966 -1);
4967
4968 if (window->priv->single_click) {
4969 path = gtk_tree_model_get_path (model, iter);
4970
4971 if ((window->priv->list_hover_path == NULL)
4972 || gtk_tree_path_compare (path, window->priv->list_hover_path))
4973 underline = PANGO_UNDERLINE_NONE;
4974 else
4975 underline = PANGO_UNDERLINE_SINGLE;
4976
4977 gtk_tree_path_free (path);
4978 }
4979 else
4980 underline = PANGO_UNDERLINE_NONE;
4981
4982 g_object_set (G_OBJECT (renderer),
4983 "text", text,
4984 "underline", underline,
4985 NULL);
4986
4987 g_free (text);
4988 }
4989
4990
4991 static void
add_dir_tree_columns(FrWindow * window,GtkTreeView * treeview)4992 add_dir_tree_columns (FrWindow *window,
4993 GtkTreeView *treeview)
4994 {
4995 GtkCellRenderer *renderer;
4996 GtkTreeViewColumn *column;
4997 GValue value = { 0, };
4998
4999 /* First column. */
5000
5001 column = gtk_tree_view_column_new ();
5002 gtk_tree_view_column_set_title (column, _("Folders"));
5003
5004 /* icon */
5005
5006 renderer = gtk_cell_renderer_pixbuf_new ();
5007 gtk_tree_view_column_pack_start (column, renderer, FALSE);
5008 gtk_tree_view_column_set_attributes (column, renderer,
5009 "pixbuf", TREE_COLUMN_ICON,
5010 NULL);
5011
5012 /* name */
5013
5014 renderer = gtk_cell_renderer_text_new ();
5015
5016 g_value_init (&value, PANGO_TYPE_ELLIPSIZE_MODE);
5017 g_value_set_enum (&value, PANGO_ELLIPSIZE_END);
5018 g_object_set_property (G_OBJECT (renderer), "ellipsize", &value);
5019 g_value_unset (&value);
5020
5021 gtk_tree_view_column_pack_start (column,
5022 renderer,
5023 TRUE);
5024 gtk_tree_view_column_set_attributes (column, renderer,
5025 "text", TREE_COLUMN_NAME,
5026 "weight", TREE_COLUMN_WEIGHT,
5027 NULL);
5028
5029 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
5030 gtk_tree_view_column_set_sort_column_id (column, TREE_COLUMN_NAME);
5031
5032 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
5033 }
5034
5035
5036 static void
add_file_list_columns(FrWindow * window,GtkTreeView * treeview)5037 add_file_list_columns (FrWindow *window,
5038 GtkTreeView *treeview)
5039 {
5040 static char *titles[] = {NC_("File", "Size"),
5041 NC_("File", "Type"),
5042 NC_("File", "Modified"),
5043 NC_("File", "Location")};
5044 GtkCellRenderer *renderer;
5045 GtkTreeViewColumn *column;
5046 GValue value = { 0, };
5047 int i, j, w;
5048
5049 /* First column. */
5050
5051 window->priv->filename_column = column = gtk_tree_view_column_new ();
5052 gtk_tree_view_column_set_title (column, C_("File", "Name"));
5053
5054 /* emblem */
5055
5056 renderer = gtk_cell_renderer_pixbuf_new ();
5057 gtk_tree_view_column_pack_end (column, renderer, FALSE);
5058 gtk_tree_view_column_set_attributes (column, renderer,
5059 "pixbuf", COLUMN_EMBLEM,
5060 NULL);
5061
5062 /* icon */
5063
5064 renderer = gtk_cell_renderer_pixbuf_new ();
5065 gtk_tree_view_column_pack_start (column, renderer, FALSE);
5066 gtk_tree_view_column_set_attributes (column, renderer,
5067 "pixbuf", COLUMN_ICON,
5068 NULL);
5069
5070 /* name */
5071
5072 window->priv->single_click = is_single_click_policy (window);
5073
5074 renderer = gtk_cell_renderer_text_new ();
5075
5076 g_value_init (&value, PANGO_TYPE_ELLIPSIZE_MODE);
5077 g_value_set_enum (&value, PANGO_ELLIPSIZE_END);
5078 g_object_set_property (G_OBJECT (renderer), "ellipsize", &value);
5079 g_value_unset (&value);
5080
5081 gtk_tree_view_column_pack_start (column,
5082 renderer,
5083 TRUE);
5084 gtk_tree_view_column_set_attributes (column, renderer,
5085 "text", COLUMN_NAME,
5086 NULL);
5087
5088 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
5089 w = g_settings_get_int (window->priv->settings_listing, PREF_LISTING_NAME_COLUMN_WIDTH);
5090 if (w <= 0)
5091 w = DEFAULT_NAME_COLUMN_WIDTH;
5092 gtk_tree_view_column_set_fixed_width (column, w);
5093 gtk_tree_view_column_set_resizable (column, TRUE);
5094 gtk_tree_view_column_set_sort_column_id (column, FR_WINDOW_SORT_BY_NAME);
5095 gtk_tree_view_column_set_cell_data_func (column, renderer,
5096 (GtkTreeCellDataFunc) filename_cell_data_func,
5097 window, NULL);
5098
5099 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
5100
5101 /* Other columns */
5102
5103 for (j = 0, i = COLUMN_SIZE; i < NUMBER_OF_COLUMNS; i++, j++) {
5104 GValue value = { 0, };
5105
5106 renderer = gtk_cell_renderer_text_new ();
5107 column = gtk_tree_view_column_new_with_attributes (g_dpgettext2 (NULL, "File", titles[j]),
5108 renderer,
5109 "text", i,
5110 NULL);
5111
5112 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
5113 gtk_tree_view_column_set_fixed_width (column, OTHER_COLUMNS_WIDTH);
5114 gtk_tree_view_column_set_resizable (column, TRUE);
5115
5116 gtk_tree_view_column_set_sort_column_id (column, FR_WINDOW_SORT_BY_NAME + 1 + j);
5117
5118 g_value_init (&value, PANGO_TYPE_ELLIPSIZE_MODE);
5119 g_value_set_enum (&value, PANGO_ELLIPSIZE_END);
5120 g_object_set_property (G_OBJECT (renderer), "ellipsize", &value);
5121 g_value_unset (&value);
5122
5123 gtk_tree_view_append_column (treeview, column);
5124 }
5125 }
5126
5127
5128 static int
name_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)5129 name_column_sort_func (GtkTreeModel *model,
5130 GtkTreeIter *a,
5131 GtkTreeIter *b,
5132 gpointer user_data)
5133 {
5134 FileData *fdata1;
5135 FileData *fdata2;
5136 GtkSortType sort_order;
5137 int result;
5138
5139 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), NULL, &sort_order);
5140
5141 gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1);
5142 gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1);
5143
5144 if (file_data_is_dir (fdata1) == file_data_is_dir (fdata2)) {
5145 result = strcmp (fdata1->sort_key, fdata2->sort_key);
5146 }
5147 else {
5148 result = file_data_is_dir (fdata1) ? -1 : 1;
5149 if (sort_order == GTK_SORT_DESCENDING)
5150 result = -1 * result;
5151 }
5152
5153 return result;
5154 }
5155
5156
5157 static int
size_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)5158 size_column_sort_func (GtkTreeModel *model,
5159 GtkTreeIter *a,
5160 GtkTreeIter *b,
5161 gpointer user_data)
5162 {
5163 FileData *fdata1;
5164 FileData *fdata2;
5165 GtkSortType sort_order;
5166 int result;
5167 goffset size_difference;
5168
5169 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), NULL, &sort_order);
5170
5171 gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1);
5172 gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1);
5173
5174 if (file_data_is_dir (fdata1) == file_data_is_dir (fdata2)) {
5175 if (file_data_is_dir (fdata1))
5176 size_difference = fdata1->dir_size - fdata2->dir_size;
5177 else
5178 size_difference = fdata1->size - fdata2->size;
5179 result = (size_difference > 0) - (size_difference < 0);
5180 }
5181 else {
5182 result = file_data_is_dir (fdata1) ? -1 : 1;
5183 if (sort_order == GTK_SORT_DESCENDING)
5184 result = -1 * result;
5185 }
5186
5187 return result;
5188 }
5189
5190
5191 static int
type_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)5192 type_column_sort_func (GtkTreeModel *model,
5193 GtkTreeIter *a,
5194 GtkTreeIter *b,
5195 gpointer user_data)
5196 {
5197 FileData *fdata1;
5198 FileData *fdata2;
5199 GtkSortType sort_order;
5200 int result;
5201
5202 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), NULL, &sort_order);
5203
5204 gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1);
5205 gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1);
5206
5207 if (file_data_is_dir (fdata1) == file_data_is_dir (fdata2)) {
5208 if (file_data_is_dir (fdata1)) {
5209 result = strcmp (fdata1->sort_key, fdata2->sort_key);
5210 if (sort_order == GTK_SORT_DESCENDING)
5211 result = -1 * result;
5212 }
5213 else {
5214 const char *desc1, *desc2;
5215
5216 desc1 = g_content_type_get_description (fdata1->content_type);
5217 desc2 = g_content_type_get_description (fdata2->content_type);
5218 result = strcasecmp (desc1, desc2);
5219 if (result == 0)
5220 result = strcmp (fdata1->sort_key, fdata2->sort_key);
5221 }
5222 }
5223 else {
5224 result = file_data_is_dir (fdata1) ? -1 : 1;
5225 if (sort_order == GTK_SORT_DESCENDING)
5226 result = -1 * result;
5227 }
5228
5229 return result;
5230 }
5231
5232
5233 static int
time_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)5234 time_column_sort_func (GtkTreeModel *model,
5235 GtkTreeIter *a,
5236 GtkTreeIter *b,
5237 gpointer user_data)
5238 {
5239 FileData *fdata1;
5240 FileData *fdata2;
5241 GtkSortType sort_order;
5242 int result;
5243
5244 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), NULL, &sort_order);
5245
5246 gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1);
5247 gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1);
5248
5249 if (file_data_is_dir (fdata1) == file_data_is_dir (fdata2)) {
5250 if (file_data_is_dir (fdata1)) {
5251 result = strcmp (fdata1->sort_key, fdata2->sort_key);
5252 if (sort_order == GTK_SORT_DESCENDING)
5253 result = -1 * result;
5254 }
5255 else
5256 result = fdata1->modified - fdata2->modified;
5257 }
5258 else {
5259 result = file_data_is_dir (fdata1) ? -1 : 1;
5260 if (sort_order == GTK_SORT_DESCENDING)
5261 result = -1 * result;
5262 }
5263
5264 return result;
5265 }
5266
5267
5268 static int
path_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)5269 path_column_sort_func (GtkTreeModel *model,
5270 GtkTreeIter *a,
5271 GtkTreeIter *b,
5272 gpointer user_data)
5273 {
5274 FileData *fdata1;
5275 FileData *fdata2;
5276 char *path1;
5277 char *path2;
5278 int result;
5279
5280 gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, COLUMN_PATH, &path1, -1);
5281 gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, COLUMN_PATH, &path2, -1);
5282
5283 result = strcmp (path1, path2);
5284 if (result == 0)
5285 result = strcmp (fdata1->sort_key, fdata2->sort_key);
5286
5287 g_free (path1);
5288 g_free (path2);
5289
5290 return result;
5291 }
5292
5293
5294 static gboolean
fr_window_show_cb(GtkWidget * widget,FrWindow * window)5295 fr_window_show_cb (GtkWidget *widget,
5296 FrWindow *window)
5297 {
5298 fr_window_update_current_location (window);
5299
5300 window->priv->view_sidebar = g_settings_get_boolean (window->priv->settings_ui, PREF_UI_VIEW_SIDEBAR);
5301 fr_window_set_action_state (window, "view-sidebar", window->priv->view_sidebar);
5302
5303 gtk_widget_hide (window->priv->filter_bar);
5304
5305 return TRUE;
5306 }
5307
5308
5309 /* preferences changes notification callbacks */
5310
5311
5312 static void
pref_view_folders_changed(GSettings * settings,const char * key,gpointer user_data)5313 pref_view_folders_changed (GSettings *settings,
5314 const char *key,
5315 gpointer user_data)
5316 {
5317 FrWindow *window = user_data;
5318
5319 fr_window_set_folders_visibility (window, g_settings_get_boolean (settings, key));
5320 }
5321
5322
5323 static void
pref_show_field_changed(GSettings * settings,const char * key,gpointer user_data)5324 pref_show_field_changed (GSettings *settings,
5325 const char *key,
5326 gpointer user_data)
5327 {
5328 FrWindow *window = user_data;
5329
5330 fr_window_update_columns_visibility (window);
5331 }
5332
5333
5334 static void
pref_list_mode_changed(GSettings * settings,const char * key,gpointer user_data)5335 pref_list_mode_changed (GSettings *settings,
5336 const char *key,
5337 gpointer user_data)
5338 {
5339 FrWindow *window = user_data;
5340
5341 fr_window_set_list_mode (window, g_settings_get_enum (settings, key));
5342 }
5343
5344
5345 static void
pref_click_policy_changed(GSettings * settings,const char * key,gpointer user_data)5346 pref_click_policy_changed (GSettings *settings,
5347 const char *key,
5348 gpointer user_data)
5349 {
5350 FrWindow *window = user_data;
5351 GdkWindow *win = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view));
5352 GdkDisplay *display;
5353
5354 window->priv->single_click = is_single_click_policy (window);
5355
5356 gdk_window_set_cursor (win, NULL);
5357 display = gtk_widget_get_display (GTK_WIDGET (window->priv->list_view));
5358 if (display != NULL)
5359 gdk_display_flush (display);
5360 }
5361
5362
5363 static void
theme_changed_cb(GtkIconTheme * theme,FrWindow * window)5364 theme_changed_cb (GtkIconTheme *theme,
5365 FrWindow *window)
5366 {
5367 if (window->priv->populating_file_list)
5368 return;
5369
5370 gth_icon_cache_clear (window->priv->list_icon_cache);
5371 gth_icon_cache_clear (window->priv->tree_icon_cache);
5372
5373 fr_window_update_file_list (window, TRUE);
5374 fr_window_update_dir_tree (window);
5375 }
5376
5377
5378 static gboolean
fr_archive_stoppable_cb(FrArchive * archive,gboolean stoppable,FrWindow * window)5379 fr_archive_stoppable_cb (FrArchive *archive,
5380 gboolean stoppable,
5381 FrWindow *window)
5382 {
5383 window->priv->stoppable = stoppable;
5384 if (window->priv->progress_dialog != NULL)
5385 gtk_dialog_set_response_sensitive (GTK_DIALOG (window->priv->progress_dialog),
5386 GTK_RESPONSE_OK,
5387 stoppable);
5388 return TRUE;
5389 }
5390
5391
5392 static void
fr_window_activate_filter(FrWindow * window)5393 fr_window_activate_filter (FrWindow *window)
5394 {
5395 GtkTreeView *tree_view = GTK_TREE_VIEW (window->priv->list_view);
5396 GtkTreeViewColumn *column;
5397
5398 gtk_widget_show (window->priv->filter_bar);
5399 window->priv->list_mode = FR_WINDOW_LIST_MODE_FLAT;
5400
5401 gtk_list_store_clear (window->priv->list_store);
5402
5403 column = gtk_tree_view_get_column (tree_view, 4);
5404 gtk_tree_view_column_set_visible (column, TRUE);
5405
5406 fr_window_update_file_list (window, TRUE);
5407 fr_window_update_dir_tree (window);
5408 fr_window_update_current_location (window);
5409 }
5410
5411
5412 static void
filter_entry_search_changed_cb(GtkEntry * entry,FrWindow * window)5413 filter_entry_search_changed_cb (GtkEntry *entry,
5414 FrWindow *window)
5415 {
5416 fr_window_activate_filter (window);
5417 }
5418
5419
5420 static void
fr_window_attach(FrWindow * window,GtkWidget * child,FrWindowArea area)5421 fr_window_attach (FrWindow *window,
5422 GtkWidget *child,
5423 FrWindowArea area)
5424 {
5425 int position;
5426
5427 g_return_if_fail (window != NULL);
5428 g_return_if_fail (FR_IS_WINDOW (window));
5429 g_return_if_fail (child != NULL);
5430 g_return_if_fail (GTK_IS_WIDGET (child));
5431
5432 switch (area) {
5433 case FR_WINDOW_AREA_MENUBAR:
5434 position = 0;
5435 break;
5436 case FR_WINDOW_AREA_TOOLBAR:
5437 position = 1;
5438 break;
5439 case FR_WINDOW_AREA_LOCATIONBAR:
5440 position = 2;
5441 break;
5442 case FR_WINDOW_AREA_FILTERBAR:
5443 position = 3;
5444 break;
5445 case FR_WINDOW_AREA_CONTENTS:
5446 position = 4;
5447 if (window->priv->contents != NULL)
5448 gtk_widget_destroy (window->priv->contents);
5449 window->priv->contents = child;
5450 gtk_widget_set_vexpand (child, TRUE);
5451 break;
5452 case FR_WINDOW_AREA_STATUSBAR:
5453 position = 5;
5454 break;
5455 default:
5456 g_critical ("%s: area not recognized!", G_STRFUNC);
5457 return;
5458 break;
5459 }
5460
5461 gtk_widget_set_hexpand (child, TRUE);
5462 gtk_grid_attach (GTK_GRID (window->priv->layout),
5463 child,
5464 0, position,
5465 1, 1);
5466 }
5467
5468
5469 /* -- fr_window_add_accelerators -- */
5470
5471
5472 static GtkAccelGroup *
gth_window_get_accel_group(FrWindow * window)5473 gth_window_get_accel_group (FrWindow *window)
5474 {
5475 if (window->priv->accel_group == NULL) {
5476 window->priv->accel_group = gtk_accel_group_new ();
5477 gtk_window_add_accel_group (GTK_WINDOW (window), window->priv->accel_group);
5478 }
5479
5480 return window->priv->accel_group;
5481 }
5482
5483
5484 static void
fr_window_add_accelerators(FrWindow * window,const FrAccelerator * accelerators,int n_accelerators)5485 fr_window_add_accelerators (FrWindow *window,
5486 const FrAccelerator *accelerators,
5487 int n_accelerators)
5488 {
5489 GtkAccelGroup *accel_group;
5490 int i;
5491
5492 accel_group = gth_window_get_accel_group (window);
5493 for (i = 0; i < n_accelerators; i++) {
5494 const FrAccelerator *acc = accelerators + i;
5495
5496 _gtk_window_add_accelerator_for_action (GTK_WINDOW (window),
5497 accel_group,
5498 acc->action_name,
5499 acc->accelerator,
5500 NULL);
5501 }
5502 }
5503
5504
5505 static void
fr_window_construct(FrWindow * window)5506 fr_window_construct (FrWindow *window)
5507 {
5508 GtkWidget *list_scrolled_window;
5509 GtkWidget *navigation_commands;
5510 GtkWidget *location_bar_content;
5511 GtkWidget *location_box;
5512 GtkWidget *filter_box;
5513 GtkWidget *tree_scrolled_window;
5514 GtkWidget *button;
5515 GtkTreeSelection *selection;
5516 GtkSizeGroup *header_bar_size_group;
5517
5518 /* Create the settings objects */
5519
5520 window->priv->settings_listing = g_settings_new (FILE_ROLLER_SCHEMA_LISTING);
5521 window->priv->settings_ui = g_settings_new (FILE_ROLLER_SCHEMA_UI);
5522 window->priv->settings_general = g_settings_new (FILE_ROLLER_SCHEMA_GENERAL);
5523 window->priv->settings_dialogs = g_settings_new (FILE_ROLLER_SCHEMA_DIALOGS);
5524 window->priv->settings_nautilus = _g_settings_new_if_schema_installed (NAUTILUS_SCHEMA);
5525
5526 /* Create the application. */
5527
5528 window->priv->layout = gtk_grid_new ();
5529 gtk_container_add (GTK_CONTAINER (window), window->priv->layout);
5530 gtk_widget_show (window->priv->layout);
5531
5532 gtk_window_set_title (GTK_WINDOW (window), _("Archive Manager"));
5533
5534 g_signal_connect (G_OBJECT (window),
5535 "delete_event",
5536 G_CALLBACK (fr_window_delete_event_cb),
5537 window);
5538
5539 g_signal_connect (G_OBJECT (window),
5540 "show",
5541 G_CALLBACK (fr_window_show_cb),
5542 window);
5543
5544 window->priv->theme_changed_handler_id =
5545 g_signal_connect (gtk_icon_theme_get_default (),
5546 "changed",
5547 G_CALLBACK (theme_changed_cb),
5548 window);
5549
5550 gtk_window_set_default_size (GTK_WINDOW (window),
5551 g_settings_get_int (window->priv->settings_ui, PREF_UI_WINDOW_WIDTH),
5552 g_settings_get_int (window->priv->settings_ui, PREF_UI_WINDOW_HEIGHT));
5553
5554 g_signal_connect (G_OBJECT (window),
5555 "key_press_event",
5556 G_CALLBACK (key_press_cb),
5557 window);
5558
5559 /* Initialize Data. */
5560
5561 window->priv->list_mode = window->priv->last_list_mode = g_settings_get_enum (window->priv->settings_listing, PREF_LISTING_LIST_MODE);
5562 g_settings_set_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_PATH, (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT));
5563
5564 window->priv->history = NULL;
5565 window->priv->history_current = NULL;
5566
5567 window->priv->action = FR_ACTION_NONE;
5568
5569 window->priv->open_default_dir = g_object_ref (_g_file_get_home ());
5570 window->priv->add_default_dir = NULL;
5571 window->priv->extract_default_dir = g_object_ref (_g_file_get_home ());
5572
5573 window->priv->give_focus_to_the_list = FALSE;
5574
5575 window->priv->activity_ref = 0;
5576 window->priv->activity_timeout_handle = 0;
5577
5578 window->priv->archive_present = FALSE;
5579 window->priv->archive_new = FALSE;
5580 window->priv->reload_archive = FALSE;
5581 window->priv->archive_file = NULL;
5582
5583 window->priv->drag_destination_folder = NULL;
5584 window->priv->drag_base_dir = NULL;
5585 window->priv->drag_error = NULL;
5586 window->priv->drag_file_list = NULL;
5587
5588 window->priv->batch_mode = FALSE;
5589 window->priv->batch_action_list = NULL;
5590 window->priv->batch_action = NULL;
5591
5592 window->priv->password = NULL;
5593 window->priv->compression = g_settings_get_enum (window->priv->settings_general, PREF_GENERAL_COMPRESSION_LEVEL);
5594 window->priv->encrypt_header = g_settings_get_boolean (window->priv->settings_general, PREF_GENERAL_ENCRYPT_HEADER);
5595 window->priv->volume_size = 0;
5596
5597 window->priv->stoppable = TRUE;
5598
5599 window->priv->batch_adding_one_file = FALSE;
5600
5601 window->priv->path_clicked = NULL;
5602
5603 window->priv->current_view_length = 0;
5604
5605 window->priv->current_action.type = FR_BATCH_ACTION_NONE;
5606 window->priv->current_action.data = NULL;
5607 window->priv->current_action.free_func = NULL;
5608
5609 window->priv->pd_last_archive = NULL;
5610 window->priv->pd_last_message = NULL;
5611 window->priv->pd_last_fraction = 0.0;
5612
5613 /* Create the widgets. */
5614
5615 /* * File list. */
5616
5617 window->priv->list_store = fr_list_model_new (NUMBER_OF_COLUMNS,
5618 G_TYPE_POINTER,
5619 GDK_TYPE_PIXBUF,
5620 G_TYPE_STRING,
5621 GDK_TYPE_PIXBUF,
5622 G_TYPE_STRING,
5623 G_TYPE_STRING,
5624 G_TYPE_STRING,
5625 G_TYPE_STRING);
5626 g_object_set_data (G_OBJECT (window->priv->list_store), "FrWindow", window);
5627 window->priv->list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window->priv->list_store));
5628
5629 add_file_list_columns (window, GTK_TREE_VIEW (window->priv->list_view));
5630 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (window->priv->list_view),
5631 TRUE);
5632 gtk_tree_view_set_search_column (GTK_TREE_VIEW (window->priv->list_view),
5633 COLUMN_NAME);
5634
5635 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
5636 FR_WINDOW_SORT_BY_NAME, name_column_sort_func,
5637 NULL, NULL);
5638 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
5639 FR_WINDOW_SORT_BY_SIZE, size_column_sort_func,
5640 NULL, NULL);
5641 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
5642 FR_WINDOW_SORT_BY_TYPE, type_column_sort_func,
5643 NULL, NULL);
5644 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
5645 FR_WINDOW_SORT_BY_TIME, time_column_sort_func,
5646 NULL, NULL);
5647 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
5648 FR_WINDOW_SORT_BY_PATH, path_column_sort_func,
5649 NULL, NULL);
5650
5651 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
5652 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
5653
5654 g_signal_connect (selection,
5655 "changed",
5656 G_CALLBACK (selection_changed_cb),
5657 window);
5658 g_signal_connect (G_OBJECT (window->priv->list_view),
5659 "row_activated",
5660 G_CALLBACK (row_activated_cb),
5661 window);
5662 g_signal_connect (G_OBJECT (window->priv->list_view),
5663 "button_press_event",
5664 G_CALLBACK (file_button_press_cb),
5665 window);
5666 g_signal_connect (G_OBJECT (window->priv->list_view),
5667 "button_release_event",
5668 G_CALLBACK (file_button_release_cb),
5669 window);
5670 g_signal_connect (G_OBJECT (window->priv->list_view),
5671 "motion_notify_event",
5672 G_CALLBACK (file_motion_notify_callback),
5673 window);
5674 g_signal_connect (G_OBJECT (window->priv->list_view),
5675 "leave_notify_event",
5676 G_CALLBACK (file_leave_notify_callback),
5677 window);
5678 g_signal_connect (G_OBJECT (window->priv->list_view),
5679 "drag_begin",
5680 G_CALLBACK (file_list_drag_begin),
5681 window);
5682 g_signal_connect (G_OBJECT (window->priv->list_view),
5683 "drag_end",
5684 G_CALLBACK (file_list_drag_end),
5685 window);
5686 egg_tree_multi_drag_add_drag_support (GTK_TREE_VIEW (window->priv->list_view));
5687
5688 list_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
5689 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (list_scrolled_window),
5690 GTK_POLICY_AUTOMATIC,
5691 GTK_POLICY_AUTOMATIC);
5692 gtk_container_add (GTK_CONTAINER (list_scrolled_window), window->priv->list_view);
5693
5694 /* filter bar */
5695
5696 window->priv->filter_bar = gtk_search_bar_new ();
5697 filter_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
5698 window->priv->filter_entry = gtk_search_entry_new ();
5699 gtk_entry_set_width_chars (GTK_ENTRY (window->priv->filter_entry), 40);
5700 g_signal_connect (G_OBJECT (window->priv->filter_entry),
5701 "search-changed",
5702 G_CALLBACK (filter_entry_search_changed_cb),
5703 window);
5704 gtk_search_bar_connect_entry (GTK_SEARCH_BAR (window->priv->filter_bar), GTK_ENTRY (window->priv->filter_entry));
5705 gtk_container_add (GTK_CONTAINER (window->priv->filter_bar), filter_box);
5706 gtk_box_pack_start (GTK_BOX (filter_box), window->priv->filter_entry, TRUE, TRUE, 0);
5707 gtk_widget_show_all (window->priv->filter_bar);
5708 fr_window_attach (FR_WINDOW (window), window->priv->filter_bar, FR_WINDOW_AREA_FILTERBAR);
5709
5710 /* tree view */
5711
5712 window->priv->tree_store = gtk_tree_store_new (TREE_NUMBER_OF_COLUMNS,
5713 G_TYPE_STRING,
5714 GDK_TYPE_PIXBUF,
5715 G_TYPE_STRING,
5716 PANGO_TYPE_WEIGHT);
5717 window->priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window->priv->tree_store));
5718 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (window->priv->tree_view), FALSE);
5719 add_dir_tree_columns (window, GTK_TREE_VIEW (window->priv->tree_view));
5720
5721 g_signal_connect (G_OBJECT (window->priv->tree_view),
5722 "button_press_event",
5723 G_CALLBACK (dir_tree_button_press_cb),
5724 window);
5725
5726 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view));
5727 g_signal_connect (selection,
5728 "changed",
5729 G_CALLBACK (dir_tree_selection_changed_cb),
5730 window);
5731
5732 g_signal_connect (G_OBJECT (window->priv->tree_view),
5733 "drag_begin",
5734 G_CALLBACK (folde_tree_drag_begin),
5735 window);
5736 g_signal_connect (G_OBJECT (window->priv->tree_view),
5737 "drag_end",
5738 G_CALLBACK (file_list_drag_end),
5739 window);
5740 g_signal_connect (G_OBJECT (window->priv->tree_view),
5741 "drag_data_get",
5742 G_CALLBACK (fr_window_folder_tree_drag_data_get),
5743 window);
5744 gtk_drag_source_set (window->priv->tree_view,
5745 GDK_BUTTON1_MASK,
5746 folder_tree_targets, G_N_ELEMENTS (folder_tree_targets),
5747 GDK_ACTION_COPY);
5748
5749 tree_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
5750 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (tree_scrolled_window),
5751 GTK_POLICY_AUTOMATIC,
5752 GTK_POLICY_AUTOMATIC);
5753 gtk_container_add (GTK_CONTAINER (tree_scrolled_window), window->priv->tree_view);
5754
5755 /* side pane */
5756
5757 window->priv->sidepane = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
5758 gtk_box_pack_start (GTK_BOX (window->priv->sidepane), tree_scrolled_window, TRUE, TRUE, 0);
5759
5760 /* main content */
5761
5762 window->priv->paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
5763 gtk_paned_pack1 (GTK_PANED (window->priv->paned), window->priv->sidepane, FALSE, TRUE);
5764 gtk_paned_pack2 (GTK_PANED (window->priv->paned), list_scrolled_window, TRUE, TRUE);
5765 gtk_paned_set_position (GTK_PANED (window->priv->paned), g_settings_get_int (window->priv->settings_ui, PREF_UI_SIDEBAR_WIDTH));
5766 gtk_drag_dest_set (GTK_WIDGET (window->priv->paned),
5767 GTK_DEST_DEFAULT_ALL,
5768 target_table, G_N_ELEMENTS (target_table),
5769 GDK_ACTION_COPY);
5770
5771 g_signal_connect (G_OBJECT (window->priv->paned),
5772 "drag_data_received",
5773 G_CALLBACK (fr_window_drag_data_received),
5774 window);
5775 g_signal_connect (G_OBJECT (window->priv->paned),
5776 "drag_motion",
5777 G_CALLBACK (fr_window_drag_motion),
5778 window);
5779
5780 fr_window_attach (FR_WINDOW (window), window->priv->paned, FR_WINDOW_AREA_CONTENTS);
5781 gtk_widget_show_all (window->priv->paned);
5782
5783 /* ui actions */
5784
5785 g_action_map_add_action_entries (G_ACTION_MAP (window),
5786 fr_window_actions,
5787 G_N_ELEMENTS (fr_window_actions),
5788 window);
5789 fr_window_add_accelerators (window,
5790 fr_window_accelerators,
5791 G_N_ELEMENTS (fr_window_accelerators));
5792
5793 /* header bar */
5794
5795 window->priv->headerbar = gtk_header_bar_new ();
5796 gtk_widget_show (window->priv->headerbar);
5797 gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (window->priv->headerbar), TRUE);
5798 gtk_window_set_titlebar (GTK_WINDOW (window), window->priv->headerbar);
5799
5800 /* header bar buttons */
5801
5802 header_bar_size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
5803
5804 button = _gtk_header_bar_create_text_button (C_("Action", "Extract"), NULL, "win.extract-files");
5805 gtk_size_group_add_widget (header_bar_size_group, button);
5806 gtk_header_bar_pack_start (GTK_HEADER_BAR (window->priv->headerbar), button);
5807
5808 button = _gtk_header_bar_create_image_button ("list-add-symbolic", C_("Action", "Add Files"), "win.add-files");
5809 gtk_size_group_add_widget (header_bar_size_group, button);
5810 gtk_header_bar_pack_start (GTK_HEADER_BAR (window->priv->headerbar), button);
5811
5812 #if ! GTK_CHECK_VERSION(3,11,4)
5813 button = _gtk_header_bar_create_image_toggle_button ("edit-find-symbolic", _("Find files by name"), "win.find");
5814 gtk_size_group_add_widget (header_bar_size_group, button);
5815 gtk_header_bar_pack_end (GTK_HEADER_BAR (window->priv->headerbar), button);
5816 #endif
5817
5818 /* gears menu button */
5819
5820 {
5821 GtkBuilder *builder;
5822 GMenuModel *menu;
5823
5824 builder = _gtk_builder_new_from_resource ("gears-menu.ui");
5825 menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
5826 button = _gtk_menu_button_new_for_header_bar ();
5827 gtk_size_group_add_widget (header_bar_size_group, button);
5828 #if ! GTK_CHECK_VERSION(3,13,0)
5829 gtk_container_add (GTK_CONTAINER (button), gtk_image_new_from_icon_name ("emblem-system-symbolic", GTK_ICON_SIZE_MENU));
5830 #else
5831 gtk_menu_button_set_direction (GTK_MENU_BUTTON (button), GTK_ARROW_NONE);
5832 #endif
5833 gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button), menu);
5834 gtk_widget_show_all (button);
5835 gtk_header_bar_pack_end (GTK_HEADER_BAR (window->priv->headerbar), button);
5836
5837 _gtk_window_add_accelerators_from_menu ((GTK_WINDOW (window)), menu);
5838
5839 g_object_unref (builder);
5840 }
5841
5842 #if GTK_CHECK_VERSION(3,11,4)
5843 button = _gtk_header_bar_create_image_toggle_button ("edit-find-symbolic", _("Find files by name"), "win.find");
5844 gtk_size_group_add_widget (header_bar_size_group, button);
5845 gtk_header_bar_pack_end (GTK_HEADER_BAR (window->priv->headerbar), button);
5846 #endif
5847
5848 g_object_unref (header_bar_size_group);
5849
5850 /* location bar */
5851
5852 window->priv->location_bar = fr_location_bar_new ();
5853
5854 location_bar_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
5855 gtk_container_set_border_width (GTK_CONTAINER (location_bar_content), 4);
5856 gtk_box_pack_start (GTK_BOX (window->priv->location_bar), location_bar_content, TRUE, TRUE, 0);
5857
5858 navigation_commands = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
5859 gtk_box_pack_start (GTK_BOX (navigation_commands),
5860 _gtk_header_bar_create_image_button ("go-previous-symbolic", _("Go to the previous visited location"), "win.go-back"),
5861 FALSE,
5862 FALSE,
5863 0);
5864 gtk_box_pack_start (GTK_BOX (navigation_commands),
5865 _gtk_header_bar_create_image_button ("go-next-symbolic", _("Go to the next visited location"), "win.go-forward"),
5866 FALSE,
5867 FALSE,
5868 0);
5869 gtk_widget_show_all (navigation_commands);
5870 gtk_style_context_add_class (gtk_widget_get_style_context (navigation_commands), GTK_STYLE_CLASS_RAISED);
5871 gtk_style_context_add_class (gtk_widget_get_style_context (navigation_commands), GTK_STYLE_CLASS_LINKED);
5872 gtk_box_pack_start (GTK_BOX (location_bar_content), navigation_commands, FALSE, FALSE, 0);
5873
5874 gtk_box_pack_start (GTK_BOX (location_bar_content),
5875 _gtk_header_bar_create_image_button ("user-home-symbolic", _("Go to the home location"), "win.go-home"),
5876 FALSE,
5877 FALSE,
5878 0);
5879
5880 /* current location */
5881
5882 location_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
5883 /* Translators: after the colon there is a folder name. */
5884 window->priv->location_label = gtk_label_new_with_mnemonic (_("_Location:"));
5885 gtk_box_pack_start (GTK_BOX (location_box), window->priv->location_label, FALSE, FALSE, 5);
5886
5887 window->priv->location_entry = gtk_entry_new ();
5888 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (window->priv->location_entry),
5889 GTK_ENTRY_ICON_PRIMARY,
5890 "folder-symbolic");
5891 g_signal_connect (G_OBJECT (window->priv->location_entry),
5892 "key_press_event",
5893 G_CALLBACK (location_entry_key_press_event_cb),
5894 window);
5895 gtk_box_pack_start (GTK_BOX (location_box), window->priv->location_entry, TRUE, TRUE, 5);
5896 gtk_box_pack_start (GTK_BOX (location_bar_content), location_box, TRUE, TRUE, 0);
5897
5898 gtk_widget_show_all (window->priv->location_bar);
5899 fr_window_attach (FR_WINDOW (window), window->priv->location_bar, FR_WINDOW_AREA_LOCATIONBAR);
5900 if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT)
5901 gtk_widget_hide (window->priv->location_bar);
5902 else
5903 gtk_widget_show (window->priv->location_bar);
5904
5905 /* popup menus */
5906 {
5907 GtkBuilder *builder;
5908
5909 builder = _gtk_builder_new_from_resource ("menus.ui");
5910
5911 window->priv->file_popup_menu = gtk_menu_new_from_model (G_MENU_MODEL (gtk_builder_get_object (builder, "file-popup")));
5912 gtk_menu_attach_to_widget (GTK_MENU (window->priv->file_popup_menu), GTK_WIDGET (window), NULL);
5913
5914 window->priv->folder_popup_menu = gtk_menu_new_from_model (G_MENU_MODEL (gtk_builder_get_object (builder, "folder-popup")));
5915 gtk_menu_attach_to_widget (GTK_MENU (window->priv->folder_popup_menu), GTK_WIDGET (window), NULL);
5916
5917 window->priv->sidebar_folder_popup_menu = gtk_menu_new_from_model (G_MENU_MODEL (gtk_builder_get_object (builder, "sidebar-popup")));
5918 gtk_menu_attach_to_widget (GTK_MENU (window->priv->sidebar_folder_popup_menu), GTK_WIDGET (window), NULL);
5919
5920 g_object_unref (builder);
5921 }
5922
5923 /**/
5924
5925 fr_window_update_title (window);
5926 fr_window_update_sensitivity (window);
5927 fr_window_update_current_location (window);
5928 fr_window_update_columns_visibility (window);
5929
5930 /* Add notification callbacks. */
5931
5932 g_signal_connect (window->priv->settings_ui,
5933 "changed::" PREF_UI_VIEW_SIDEBAR,
5934 G_CALLBACK (pref_view_folders_changed),
5935 window);
5936 g_signal_connect (window->priv->settings_listing,
5937 "changed::" PREF_LISTING_SHOW_TYPE,
5938 G_CALLBACK (pref_show_field_changed),
5939 window);
5940 g_signal_connect (window->priv->settings_listing,
5941 "changed::" PREF_LISTING_SHOW_SIZE,
5942 G_CALLBACK (pref_show_field_changed),
5943 window);
5944 g_signal_connect (window->priv->settings_listing,
5945 "changed::" PREF_LISTING_SHOW_TIME,
5946 G_CALLBACK (pref_show_field_changed),
5947 window);
5948 g_signal_connect (window->priv->settings_listing,
5949 "changed::" PREF_LISTING_SHOW_PATH,
5950 G_CALLBACK (pref_show_field_changed),
5951 window);
5952 g_signal_connect (window->priv->settings_listing,
5953 "changed::" PREF_LISTING_LIST_MODE,
5954 G_CALLBACK (pref_list_mode_changed),
5955 window);
5956
5957 if (window->priv->settings_nautilus)
5958 g_signal_connect (window->priv->settings_nautilus,
5959 "changed::" NAUTILUS_CLICK_POLICY,
5960 G_CALLBACK (pref_click_policy_changed),
5961 window);
5962
5963 /* Give focus to the list. */
5964
5965 gtk_widget_grab_focus (window->priv->list_view);
5966 }
5967
5968
5969 GtkWidget *
fr_window_new(void)5970 fr_window_new (void)
5971 {
5972 GtkWidget *window;
5973
5974 window = g_object_new (FR_TYPE_WINDOW, "application", g_application_get_default (), NULL);
5975 fr_window_construct ((FrWindow*) window);
5976
5977 return window;
5978 }
5979
5980
5981 static void
_fr_window_set_archive(FrWindow * window,FrArchive * archive)5982 _fr_window_set_archive (FrWindow *window,
5983 FrArchive *archive)
5984 {
5985 if (window->archive != NULL) {
5986 g_signal_handlers_disconnect_by_data (window->archive, window);
5987 g_object_unref (window->archive);
5988 }
5989
5990 window->archive = _g_object_ref (archive);
5991
5992 if (window->archive == NULL)
5993 return;
5994
5995 g_signal_connect (G_OBJECT (window->archive),
5996 "progress",
5997 G_CALLBACK (fr_archive_progress_cb),
5998 window);
5999 g_signal_connect (G_OBJECT (window->archive),
6000 "message",
6001 G_CALLBACK (fr_archive_message_cb),
6002 window);
6003 g_signal_connect (G_OBJECT (window->archive),
6004 "start",
6005 G_CALLBACK (fr_archive_start_cb),
6006 window);
6007 g_signal_connect (G_OBJECT (window->archive),
6008 "stoppable",
6009 G_CALLBACK (fr_archive_stoppable_cb),
6010 window);
6011 g_signal_connect (G_OBJECT (window->archive),
6012 "working-archive",
6013 G_CALLBACK (fr_window_working_archive_cb),
6014 window);
6015 }
6016
6017
6018 static void
_fr_window_set_archive_file(FrWindow * window,GFile * file)6019 _fr_window_set_archive_file (FrWindow *window,
6020 GFile *file)
6021 {
6022 _g_object_unref (window->priv->archive_file);
6023 window->priv->archive_file = _g_object_ref (file);
6024 }
6025
6026
6027 gboolean
fr_window_archive_new(FrWindow * window,GFile * file,const char * mime_type)6028 fr_window_archive_new (FrWindow *window,
6029 GFile *file,
6030 const char *mime_type)
6031 {
6032 FrArchive *archive;
6033
6034 g_return_val_if_fail (window != NULL, FALSE);
6035
6036 archive = fr_archive_create (file, mime_type);
6037 if (archive != NULL) {
6038 fr_window_archive_close (window);
6039 _fr_window_set_archive (window, archive);
6040 _fr_window_set_archive_file (window, file);
6041 window->priv->archive_present = TRUE;
6042 window->priv->archive_new = TRUE;
6043
6044 g_object_unref (archive);
6045 }
6046
6047 return archive != NULL;
6048 }
6049
6050
6051 static void
archive_list_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6052 archive_list_ready_cb (GObject *source_object,
6053 GAsyncResult *result,
6054 gpointer user_data)
6055 {
6056 FrWindow *window = user_data;
6057 GError *error = NULL;
6058
6059 fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
6060 _archive_operation_completed (window, FR_ACTION_LISTING_CONTENT, error);
6061
6062 _g_error_free (error);
6063 }
6064
6065
6066 static void
fr_window_archive_list(FrWindow * window)6067 fr_window_archive_list (FrWindow *window)
6068 {
6069 if (! fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_READ)) {
6070 fr_window_archive_close (window);
6071 fr_window_archive_open (window, window->priv->archive_file, NULL);
6072 return;
6073 }
6074
6075 _archive_operation_started (window, FR_ACTION_LISTING_CONTENT);
6076 fr_archive_list (window->archive,
6077 window->priv->password,
6078 window->priv->cancellable,
6079 archive_list_ready_cb,
6080 window);
6081 }
6082
6083
6084 static void
archive_open_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6085 archive_open_ready_cb (GObject *source_object,
6086 GAsyncResult *result,
6087 gpointer user_data)
6088 {
6089 FrWindow *window = user_data;
6090 FrArchive *archive;
6091 GError *error = NULL;
6092
6093 archive = fr_archive_open_finish (G_FILE (source_object), result, &error);
6094 _fr_window_set_archive (window, archive);
6095
6096 g_signal_emit (window,
6097 fr_window_signals[ARCHIVE_LOADED],
6098 0,
6099 error == NULL);
6100
6101 _archive_operation_completed (window, FR_ACTION_LOADING_ARCHIVE, error);
6102 _g_error_free (error);
6103 _g_object_unref (archive);
6104 }
6105
6106
6107 FrWindow *
fr_window_archive_open(FrWindow * current_window,GFile * file,GtkWindow * parent)6108 fr_window_archive_open (FrWindow *current_window,
6109 GFile *file,
6110 GtkWindow *parent)
6111 {
6112 FrWindow *window = current_window;
6113
6114 g_return_val_if_fail (file != NULL, FALSE);
6115
6116 if (current_window->priv->archive_present)
6117 window = (FrWindow *) fr_window_new ();
6118
6119 g_return_val_if_fail (window != NULL, FALSE);
6120
6121 fr_window_archive_close (window);
6122 _fr_window_set_archive_file (window, file);
6123 window->priv->give_focus_to_the_list = TRUE;
6124 window->priv->load_error_parent_window = parent;
6125
6126 _archive_operation_started (window, FR_ACTION_LOADING_ARCHIVE);
6127
6128 /* this is used to reload the archive after asking a password */
6129 fr_window_set_current_action (window,
6130 FR_BATCH_ACTION_LOAD,
6131 g_object_ref (file),
6132 (GFreeFunc) g_object_unref);
6133
6134 fr_archive_open (file,
6135 window->priv->cancellable,
6136 archive_open_ready_cb,
6137 window);
6138
6139 return window;
6140 }
6141
6142
6143 void
fr_window_archive_close(FrWindow * window)6144 fr_window_archive_close (FrWindow *window)
6145 {
6146 g_return_if_fail (window != NULL);
6147
6148 if (! window->priv->archive_new && ! window->priv->archive_present)
6149 return;
6150
6151 fr_window_free_open_files (window);
6152 fr_clipboard_data_unref (window->priv->copy_data);
6153 window->priv->copy_data = NULL;
6154
6155 fr_window_set_password (window, NULL);
6156 fr_window_set_volume_size (window, 0);
6157 fr_window_history_clear (window);
6158
6159 _fr_window_set_archive (window, NULL);
6160 window->priv->archive_new = FALSE;
6161 window->priv->archive_present = FALSE;
6162
6163 fr_window_update_title (window);
6164 fr_window_update_sensitivity (window);
6165 fr_window_update_file_list (window, FALSE);
6166 fr_window_update_dir_tree (window);
6167 fr_window_update_current_location (window);
6168 }
6169
6170
6171 GFile *
fr_window_get_archive_file(FrWindow * window)6172 fr_window_get_archive_file (FrWindow *window)
6173 {
6174 g_return_val_if_fail (window != NULL, NULL);
6175
6176 return window->priv->archive_file;
6177 }
6178
6179
6180 GFile *
fr_window_get_archive_file_for_paste(FrWindow * window)6181 fr_window_get_archive_file_for_paste (FrWindow *window)
6182 {
6183 g_return_val_if_fail (window != NULL, NULL);
6184
6185 if (window->priv->clipboard_data != NULL)
6186 return window->priv->clipboard_data->file;
6187 else
6188 return NULL;
6189 }
6190
6191
6192 gboolean
fr_window_archive_is_present(FrWindow * window)6193 fr_window_archive_is_present (FrWindow *window)
6194 {
6195 g_return_val_if_fail (window != NULL, FALSE);
6196
6197 return window->priv->archive_present;
6198 }
6199
6200
6201 void
fr_window_archive_reload(FrWindow * window)6202 fr_window_archive_reload (FrWindow *window)
6203 {
6204 g_return_if_fail (window != NULL);
6205
6206 if (window->priv->activity_ref > 0)
6207 return;
6208 if (window->priv->archive_new)
6209 return;
6210 if (window->archive == NULL)
6211 return;
6212
6213 fr_window_archive_list (window);
6214 }
6215
6216
6217 /**/
6218
6219
6220 #ifdef ENABLE_NOTIFICATION
6221
6222
6223 static void
notify_action_open_archive_cb(NotifyNotification * notification,char * action,gpointer user_data)6224 notify_action_open_archive_cb (NotifyNotification *notification,
6225 char *action,
6226 gpointer user_data)
6227 {
6228 GFile *saved_file = user_data;
6229 GtkWidget *new_window;
6230
6231 new_window = fr_window_new ();
6232 gtk_widget_show (new_window);
6233 fr_window_archive_open (FR_WINDOW (new_window),
6234 saved_file,
6235 GTK_WINDOW (new_window));
6236 }
6237
6238
6239 static void
_fr_window_notify_creation_complete(FrWindow * window)6240 _fr_window_notify_creation_complete (FrWindow *window)
6241 {
6242 char *basename;
6243 char *message;
6244 NotifyNotification *notification;
6245 gboolean notification_supports_actions;
6246 GList *caps;
6247
6248 basename = _g_file_get_display_basename (window->priv->saving_file);
6249 /* Translators: %s is a filename */
6250 message = g_strdup_printf (_("“%s” created successfully"), basename);
6251 notification = notify_notification_new (window->priv->batch_title, message, "file-roller");
6252 notify_notification_set_hint_string (notification, "desktop-entry", "file-roller");
6253
6254 notification_supports_actions = FALSE;
6255 caps = notify_get_server_caps ();
6256 if (caps != NULL) {
6257 notification_supports_actions = g_list_find_custom (caps, "actions", (GCompareFunc) strcmp) != NULL;
6258 _g_string_list_free (caps);
6259 }
6260
6261 if (notification_supports_actions) {
6262 notify_notification_add_action (notification,
6263 "document-open-symbolic",
6264 C_("Action", "Open"),
6265 notify_action_open_archive_cb,
6266 g_object_ref (window->priv->saving_file),
6267 g_object_unref);
6268 /*notify_notification_set_hint (notification,
6269 "action-icons",
6270 g_variant_new_boolean (TRUE));*/
6271 }
6272
6273 notify_notification_show (notification, NULL);
6274 g_free (message);
6275 g_free (basename);
6276 }
6277
6278
6279 #else
6280
6281
6282 static void
_fr_window_notify_creation_complete(FrWindow * window)6283 _fr_window_notify_creation_complete (FrWindow *window)
6284 {
6285 gtk_window_present (GTK_WINDOW (window->priv->progress_dialog));
6286 }
6287
6288
6289 #endif
6290
6291
6292 static void
archive_add_files_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6293 archive_add_files_ready_cb (GObject *source_object,
6294 GAsyncResult *result,
6295 gpointer user_data)
6296 {
6297 FrWindow *window = user_data;
6298 gboolean notify;
6299 GError *error = NULL;
6300
6301 notify = window->priv->notify;
6302
6303 g_object_ref (window);
6304 fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
6305 _archive_operation_completed (window, FR_ACTION_ADDING_FILES, error);
6306
6307 if ((error == NULL) && notify) {
6308 window->priv->destroy_with_confirmation_dialog = TRUE;
6309 fr_window_show_confirmation_dialog_with_open_archive (window);
6310
6311 if (! gtk_window_has_toplevel_focus (GTK_WINDOW (window->priv->progress_dialog)))
6312 _fr_window_notify_creation_complete (window);
6313 }
6314
6315 _g_error_free (error);
6316 g_object_unref (window);
6317 }
6318
6319
6320 void
fr_window_archive_add_files(FrWindow * window,GList * file_list,GFile * base_dir,gboolean update)6321 fr_window_archive_add_files (FrWindow *window,
6322 GList *file_list, /* GFile list */
6323 GFile *base_dir,
6324 gboolean update)
6325 {
6326 _archive_operation_started (window, FR_ACTION_ADDING_FILES);
6327
6328 fr_archive_add_files (window->archive,
6329 file_list,
6330 base_dir,
6331 fr_window_get_current_location (window),
6332 update,
6333 FALSE,
6334 window->priv->password,
6335 window->priv->encrypt_header,
6336 window->priv->compression,
6337 window->priv->volume_size,
6338 window->priv->cancellable,
6339 archive_add_files_ready_cb,
6340 window);
6341 }
6342
6343
6344 void
fr_window_archive_add_with_filter(FrWindow * window,GList * file_list,GFile * base_dir,const char * include_files,const char * exclude_files,const char * exclude_folders,const char * dest_dir,gboolean update,gboolean follow_links)6345 fr_window_archive_add_with_filter (FrWindow *window,
6346 GList *file_list, /* GFile list */
6347 GFile *base_dir,
6348 const char *include_files,
6349 const char *exclude_files,
6350 const char *exclude_folders,
6351 const char *dest_dir,
6352 gboolean update,
6353 gboolean follow_links)
6354 {
6355 _archive_operation_started (window, FR_ACTION_ADDING_FILES);
6356
6357 fr_archive_add_files_with_filter (window->archive,
6358 file_list,
6359 base_dir,
6360 include_files,
6361 exclude_files,
6362 exclude_folders,
6363 (dest_dir == NULL)? fr_window_get_current_location (window): dest_dir,
6364 update,
6365 follow_links,
6366 window->priv->password,
6367 window->priv->encrypt_header,
6368 window->priv->compression,
6369 window->priv->volume_size,
6370 window->priv->cancellable,
6371 archive_add_files_ready_cb,
6372 window);
6373 }
6374
6375
6376 void
fr_window_archive_add_dropped_items(FrWindow * window,GList * file_list)6377 fr_window_archive_add_dropped_items (FrWindow *window,
6378 GList *file_list)
6379 {
6380 _archive_operation_started (window, FR_ACTION_ADDING_FILES);
6381
6382 fr_archive_add_dropped_items (window->archive,
6383 file_list,
6384 fr_window_get_current_location (window),
6385 window->priv->password,
6386 window->priv->encrypt_header,
6387 window->priv->compression,
6388 window->priv->volume_size,
6389 window->priv->cancellable,
6390 archive_add_files_ready_cb,
6391 window);
6392 }
6393
6394
6395 /* -- fr_window_archive_remove -- */
6396
6397
6398 static void
archive_remove_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6399 archive_remove_ready_cb (GObject *source_object,
6400 GAsyncResult *result,
6401 gpointer user_data)
6402 {
6403 FrWindow *window = user_data;
6404 GError *error = NULL;
6405
6406 fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
6407 _archive_operation_completed (window, FR_ACTION_DELETING_FILES, error);
6408
6409 _g_error_free (error);
6410 }
6411
6412
6413 void
fr_window_archive_remove(FrWindow * window,GList * file_list)6414 fr_window_archive_remove (FrWindow *window,
6415 GList *file_list)
6416 {
6417 GList *new_file_list;
6418
6419 new_file_list = _g_string_list_dup (file_list);
6420 fr_window_set_current_action (window,
6421 FR_BATCH_ACTION_REMOVE,
6422 new_file_list,
6423 (GFreeFunc) _g_string_list_free);
6424
6425 _archive_operation_started (window, FR_ACTION_DELETING_FILES);
6426
6427 g_object_set (window->archive,
6428 "compression", window->priv->compression,
6429 "encrypt-header", window->priv->encrypt_header,
6430 "password", window->priv->password,
6431 "volume-size", window->priv->volume_size,
6432 NULL);
6433
6434 fr_window_clipboard_remove_file_list (window, file_list);
6435 fr_archive_remove (window->archive,
6436 new_file_list,
6437 window->priv->compression,
6438 window->priv->cancellable,
6439 archive_remove_ready_cb,
6440 window);
6441 }
6442
6443
6444 /* -- fr_window_archive_extract -- */
6445
6446
6447 static ExtractData *
extract_data_new(FrWindow * window,GList * file_list,GFile * destination,const char * base_dir,gboolean skip_older,FrOverwrite overwrite,gboolean junk_paths,gboolean ask_to_open_destination,gboolean avoid_tarbombs)6448 extract_data_new (FrWindow *window,
6449 GList *file_list,
6450 GFile *destination,
6451 const char *base_dir,
6452 gboolean skip_older,
6453 FrOverwrite overwrite,
6454 gboolean junk_paths,
6455 gboolean ask_to_open_destination,
6456 gboolean avoid_tarbombs)
6457 {
6458 ExtractData *edata;
6459
6460 edata = g_new0 (ExtractData, 1);
6461 edata->window = _g_object_ref (window);
6462 edata->file_list = _g_string_list_dup (file_list);
6463 edata->destination = _g_object_ref (destination);
6464 edata->skip_older = skip_older;
6465 edata->overwrite = overwrite;
6466 edata->junk_paths = junk_paths;
6467 if (base_dir != NULL)
6468 edata->base_dir = g_strdup (base_dir);
6469 edata->ask_to_open_destination = ask_to_open_destination;
6470 edata->avoid_tarbombs = avoid_tarbombs;
6471
6472 return edata;
6473 }
6474
6475
6476 static void
extract_data_free(ExtractData * edata)6477 extract_data_free (ExtractData *edata)
6478 {
6479 g_return_if_fail (edata != NULL);
6480
6481 _g_string_list_free (edata->file_list);
6482 _g_object_unref (edata->destination);
6483 _g_object_unref (edata->window);
6484 g_free (edata->base_dir);
6485
6486 g_free (edata);
6487 }
6488
6489
6490 typedef struct {
6491 FrWindow *window;
6492 ExtractData *edata;
6493 GList *current_file;
6494 gboolean extract_all;
6495 } OverwriteData;
6496
6497
6498 #define _FR_RESPONSE_OVERWRITE_YES_ALL 100
6499 #define _FR_RESPONSE_OVERWRITE_YES 101
6500 #define _FR_RESPONSE_OVERWRITE_NO 102
6501 #define _FR_RESPONSE_OVERWRITE_NO_ALL 103
6502
6503
6504 static void
archive_extraction_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6505 archive_extraction_ready_cb (GObject *source_object,
6506 GAsyncResult *result,
6507 gpointer user_data)
6508 {
6509 ExtractData *edata = user_data;
6510 FrWindow *window = edata->window;
6511 gboolean ask_to_open_destination;
6512 gboolean batch_mode;
6513 GError *error = NULL;
6514
6515 batch_mode = window->priv->batch_mode;
6516 ask_to_open_destination = edata->ask_to_open_destination;
6517 g_object_ref (window);
6518
6519 _g_clear_object (&window->priv->last_extraction_destination);
6520 window->priv->last_extraction_destination = _g_object_ref (fr_archive_get_last_extraction_destination (window->archive));
6521
6522 _g_object_list_unref (window->priv->last_extraction_files_first_level);
6523 window->priv->last_extraction_files_first_level = NULL;
6524
6525 if (ask_to_open_destination && ! edata->junk_paths) {
6526 /* collect the files to show in the file manager */
6527
6528 GHashTable *names_hash;
6529 gboolean stop = FALSE;
6530 int i;
6531
6532 names_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
6533 for (i = 0; ! stop && (i < window->archive->files->len); i++) {
6534 FileData *fdata = g_ptr_array_index (window->archive->files, i);
6535 char *first_level;
6536 char *second_slash;
6537
6538 if ((fdata->full_path == NULL) || (fdata->full_path[0] == 0))
6539 continue;
6540
6541 second_slash = strchr (fdata->full_path + 1, '/');
6542 if (second_slash != NULL)
6543 first_level = g_strndup (fdata->full_path, second_slash - fdata->full_path);
6544 else
6545 first_level = g_strdup (fdata->full_path);
6546
6547 /* avoid to insert duplicated entries */
6548
6549 if (g_hash_table_lookup (names_hash, first_level) == NULL) {
6550
6551 /* only use this list if there is a single entry,
6552 * because Nautilus opens a window for each file
6553 * even when the files are all in the same folder. */
6554
6555 if (window->priv->last_extraction_files_first_level != NULL) {
6556 _g_object_list_unref (window->priv->last_extraction_files_first_level);
6557 window->priv->last_extraction_files_first_level = NULL;
6558 stop = TRUE;
6559 }
6560 else {
6561 g_hash_table_insert (names_hash, g_strdup (first_level), GINT_TO_POINTER (1));
6562 window->priv->last_extraction_files_first_level = g_list_prepend (window->priv->last_extraction_files_first_level, _g_file_append_path (window->priv->last_extraction_destination, first_level, NULL));
6563 }
6564 }
6565
6566 g_free (first_level);
6567 }
6568
6569 g_hash_table_destroy (names_hash);
6570 }
6571
6572 fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
6573 _archive_operation_completed (window, FR_ACTION_EXTRACTING_FILES, error);
6574 if ((error == NULL) || (error->code != FR_ERROR_ASK_PASSWORD))
6575 fr_window_dnd_extraction_finished (window, error != NULL);
6576
6577 if ((error == NULL) && ask_to_open_destination) {
6578 window->priv->destroy_with_confirmation_dialog = window->priv->batch_mode;
6579 fr_window_show_confirmation_dialog_with_open_destination (window);
6580 }
6581 else if ((error == NULL) && ! batch_mode && ! gtk_window_has_toplevel_focus (GTK_WINDOW (window->priv->progress_dialog)))
6582 gtk_window_present (GTK_WINDOW (window));
6583
6584 _g_error_free (error);
6585 g_object_unref (window);
6586 }
6587
6588
6589 static void
_fr_window_archive_extract_from_edata(FrWindow * window,ExtractData * edata)6590 _fr_window_archive_extract_from_edata (FrWindow *window,
6591 ExtractData *edata)
6592 {
6593 GList *scan;
6594 gsize total_size;
6595
6596 total_size = 0;
6597 for (scan = edata->file_list; scan; scan = scan->next) {
6598 char *filename = scan->data;
6599 FileData *file_data;
6600
6601 file_data = g_hash_table_lookup (window->archive->files_hash, filename);
6602 if (file_data == NULL)
6603 continue;
6604
6605 total_size += file_data->size;
6606 }
6607 fr_archive_progress_set_total_bytes (window->archive, total_size);
6608
6609 _archive_operation_started (window, FR_ACTION_EXTRACTING_FILES);
6610
6611 fr_archive_extract (window->archive,
6612 edata->file_list,
6613 edata->destination,
6614 edata->base_dir,
6615 edata->skip_older,
6616 edata->overwrite == FR_OVERWRITE_YES,
6617 edata->junk_paths,
6618 window->priv->password,
6619 window->priv->cancellable,
6620 archive_extraction_ready_cb,
6621 edata);
6622 }
6623
6624
6625 static void _fr_window_ask_overwrite_dialog (OverwriteData *odata);
6626
6627
6628 static OverwriteData *
overwrite_data_new(FrWindow * window)6629 overwrite_data_new (FrWindow *window)
6630 {
6631 OverwriteData *odata;
6632
6633 odata = g_new0 (OverwriteData, 1);
6634 odata->window = _g_object_ref (window);
6635 odata->edata = NULL;
6636 odata->current_file = NULL;
6637 odata->extract_all = FALSE;
6638
6639 return odata;
6640 }
6641
6642
6643 static void
overwrite_data_free(OverwriteData * odata)6644 overwrite_data_free (OverwriteData *odata)
6645 {
6646 _g_object_unref (odata->window);
6647 g_free (odata);
6648 }
6649
6650
6651 /* remove the file from the list to extract */
6652 static void
overwrite_data_skip_current(OverwriteData * odata)6653 overwrite_data_skip_current (OverwriteData *odata)
6654 {
6655 GList *next = odata->current_file->next;
6656
6657 odata->edata->file_list = g_list_remove_link (odata->edata->file_list, odata->current_file);
6658 _g_string_list_free (odata->current_file);
6659 odata->current_file = next;
6660 odata->extract_all = FALSE;
6661 }
6662
6663
6664 static void
overwrite_dialog_response_cb(GtkDialog * dialog,int response_id,gpointer user_data)6665 overwrite_dialog_response_cb (GtkDialog *dialog,
6666 int response_id,
6667 gpointer user_data)
6668 {
6669 OverwriteData *odata = user_data;
6670 gboolean do_not_extract = FALSE;
6671
6672 switch (response_id) {
6673 case _FR_RESPONSE_OVERWRITE_YES_ALL:
6674 odata->edata->overwrite = FR_OVERWRITE_YES;
6675 break;
6676
6677 case _FR_RESPONSE_OVERWRITE_YES:
6678 odata->current_file = odata->current_file->next;
6679 break;
6680
6681 case _FR_RESPONSE_OVERWRITE_NO_ALL:
6682 overwrite_data_skip_current (odata);
6683 odata->edata->overwrite = FR_OVERWRITE_NO;
6684 break;
6685
6686 case _FR_RESPONSE_OVERWRITE_NO:
6687 overwrite_data_skip_current (odata);
6688 break;
6689
6690 case GTK_RESPONSE_DELETE_EVENT:
6691 case GTK_RESPONSE_CANCEL:
6692 do_not_extract = TRUE;
6693 break;
6694
6695 default:
6696 break;
6697 }
6698
6699 gtk_widget_destroy (GTK_WIDGET (dialog));
6700
6701 if (do_not_extract) {
6702 fr_window_batch_stop (odata->window);
6703 fr_window_dnd_extraction_finished (odata->window, FALSE);
6704 overwrite_data_free (odata);
6705 return;
6706 }
6707
6708 _fr_window_ask_overwrite_dialog (odata);
6709 }
6710
6711
6712 static void
query_info_ready_for_overwrite_dialog_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6713 query_info_ready_for_overwrite_dialog_cb (GObject *source_object,
6714 GAsyncResult *result,
6715 gpointer user_data)
6716 {
6717 OverwriteData *odata = user_data;
6718 GFile *destination = G_FILE (source_object);
6719 GFileInfo *info;
6720 GFileType file_type;
6721
6722 info = g_file_query_info_finish (destination, result, NULL);
6723
6724 /* file does not exist -> keep in the files to extract. */
6725
6726 if (info == NULL) {
6727 odata->current_file = odata->current_file->next;
6728 _fr_window_ask_overwrite_dialog (odata);
6729 g_object_unref (destination);
6730 return;
6731 }
6732
6733 /* file exists and user selected "Overwrite Nothing" -> automatically
6734 * skip the file. */
6735
6736 if (odata->edata->overwrite == FR_OVERWRITE_NO) {
6737 overwrite_data_skip_current (odata);
6738 _fr_window_ask_overwrite_dialog (odata);
6739 g_object_unref (destination);
6740 return;
6741 }
6742
6743 /* file exists and odata->edata->overwrite == FR_OVERWRITE_ASK */
6744
6745 file_type = g_file_info_get_file_type (info);
6746 if ((file_type != G_FILE_TYPE_UNKNOWN) && (file_type != G_FILE_TYPE_DIRECTORY)) {
6747 char *msg;
6748 GFile *parent;
6749 char *parent_name;
6750 char *details;
6751 GtkWidget *d;
6752
6753 msg = g_strdup_printf (_("Replace file “%s”?"), g_file_info_get_display_name (info));
6754 parent = g_file_get_parent (destination);
6755 parent_name = g_file_get_parse_name (parent);
6756 details = g_strdup_printf (_("Another file with the same name already exists in “%s”."), parent_name);
6757 d = _gtk_message_dialog_new (GTK_WINDOW (odata->window),
6758 GTK_DIALOG_MODAL,
6759 msg,
6760 details,
6761 _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
6762 _("Replace _All"), _FR_RESPONSE_OVERWRITE_YES_ALL,
6763 _("Replace _Nothing"), _FR_RESPONSE_OVERWRITE_NO_ALL,
6764 _("_Skip"), _FR_RESPONSE_OVERWRITE_NO,
6765 _("_Replace"), _FR_RESPONSE_OVERWRITE_YES,
6766 NULL);
6767 gtk_dialog_set_default_response (GTK_DIALOG (d), _FR_RESPONSE_OVERWRITE_YES);
6768 g_signal_connect (d,
6769 "response",
6770 G_CALLBACK (overwrite_dialog_response_cb),
6771 odata);
6772 gtk_widget_show (d);
6773
6774 g_free (msg);
6775 g_free (parent_name);
6776 g_free (details);
6777 g_object_unref (parent);
6778 g_object_unref (info);
6779 g_object_unref (destination);
6780
6781 return;
6782 }
6783
6784 g_object_unref (info);
6785 g_object_unref (destination);
6786
6787 /* file exists and it's a directory or unknown -> skip */
6788
6789 overwrite_data_skip_current (odata);
6790 _fr_window_ask_overwrite_dialog (odata);
6791 }
6792
6793
6794 static void
_fr_window_ask_overwrite_dialog(OverwriteData * odata)6795 _fr_window_ask_overwrite_dialog (OverwriteData *odata)
6796 {
6797 gboolean perform_extraction = TRUE;
6798 gboolean check_file_existence;
6799
6800 check_file_existence = (odata->edata->overwrite == FR_OVERWRITE_ASK) || (odata->edata->overwrite == FR_OVERWRITE_NO);
6801 if (check_file_existence && (odata->current_file != NULL)) {
6802 const char *base_name;
6803 GFile *destination;
6804
6805 base_name = _g_path_get_relative_basename_safe ((char *) odata->current_file->data, odata->edata->base_dir, odata->edata->junk_paths);
6806 if (base_name != NULL) {
6807 destination = g_file_get_child (odata->edata->destination, base_name);
6808 g_file_query_info_async (destination,
6809 G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
6810 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
6811 G_PRIORITY_DEFAULT,
6812 odata->window->priv->cancellable,
6813 query_info_ready_for_overwrite_dialog_cb,
6814 odata);
6815
6816 return;
6817 }
6818 else {
6819 overwrite_data_skip_current (odata);
6820 _fr_window_ask_overwrite_dialog (odata);
6821 return;
6822 }
6823 }
6824
6825 if (odata->edata->file_list == NULL)
6826 perform_extraction = FALSE;
6827
6828 if (perform_extraction) {
6829 /* speed optimization: passing NULL when extracting all the
6830 * files is faster if the command supports the
6831 * propCanExtractAll property. */
6832 if (odata->extract_all) {
6833 _g_string_list_free (odata->edata->file_list);
6834 odata->edata->file_list = NULL;
6835 }
6836 odata->edata->overwrite = FR_OVERWRITE_YES;
6837
6838 _fr_window_archive_extract_from_edata (odata->window, odata->edata);
6839 }
6840 else {
6841 GtkWidget *d;
6842
6843 d = _gtk_message_dialog_new (GTK_WINDOW (odata->window),
6844 0,
6845 _("Extraction not performed"),
6846 NULL,
6847 _GTK_LABEL_CLOSE, GTK_RESPONSE_OK,
6848 NULL);
6849 gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_OK);
6850 fr_window_show_error_dialog (odata->window, d, GTK_WINDOW (odata->window), _("Extraction not performed"));
6851
6852 fr_window_batch_stop (odata->window);
6853 fr_window_dnd_extraction_finished (odata->window, TRUE);
6854 }
6855
6856 overwrite_data_free (odata);
6857 }
6858
6859
6860 static gboolean
archive_is_encrypted(FrWindow * window,GList * file_list)6861 archive_is_encrypted (FrWindow *window,
6862 GList *file_list)
6863 {
6864 gboolean encrypted = FALSE;
6865
6866 if (file_list == NULL) {
6867 int i;
6868
6869 for (i = 0; ! encrypted && i < window->archive->files->len; i++) {
6870 FileData *fdata = g_ptr_array_index (window->archive->files, i);
6871
6872 if (fdata->encrypted)
6873 encrypted = TRUE;
6874 }
6875 }
6876 else {
6877 GList *scan;
6878
6879 for (scan = file_list; ! encrypted && scan; scan = scan->next) {
6880 char *filename = scan->data;
6881 FileData *fdata;
6882
6883 fdata = g_hash_table_lookup (window->archive->files_hash, filename);
6884 g_return_val_if_fail (fdata != NULL, FALSE);
6885
6886 if (fdata->encrypted)
6887 encrypted = TRUE;
6888 }
6889 }
6890
6891 return encrypted;
6892 }
6893
6894
6895 /* ask some questions to the user before calling _fr_window_archive_extract_from_edata */
6896 static void
_fr_window_archive_extract_from_edata_maybe(FrWindow * window,ExtractData * edata)6897 _fr_window_archive_extract_from_edata_maybe (FrWindow *window,
6898 ExtractData *edata)
6899 {
6900 gboolean do_not_extract = FALSE;
6901 GError *error = NULL;
6902
6903 if (archive_is_encrypted (window, edata->file_list) && (window->priv->password == NULL)) {
6904 dlg_ask_password (window);
6905 return;
6906 }
6907
6908 if (! _g_file_query_is_dir (edata->destination)) {
6909
6910 /* There is nothing to ask if the destination doesn't exist. */
6911 if (edata->overwrite == FR_OVERWRITE_ASK)
6912 edata->overwrite = FR_OVERWRITE_YES;
6913
6914 if (! ForceDirectoryCreation && ! edata->avoid_tarbombs) {
6915 GtkWidget *d;
6916 int r;
6917 char *folder_name;
6918 char *msg;
6919
6920 folder_name = _g_file_get_display_basename (edata->destination);
6921 msg = g_strdup_printf (_("Destination folder “%s” does not exist.\n\nDo you want to create it?"), folder_name);
6922 g_free (folder_name);
6923
6924 d = _gtk_message_dialog_new (GTK_WINDOW (window),
6925 GTK_DIALOG_MODAL,
6926 msg,
6927 NULL,
6928 _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
6929 _("Create _Folder"), GTK_RESPONSE_YES,
6930 NULL);
6931
6932 gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_YES);
6933 r = gtk_dialog_run (GTK_DIALOG (d));
6934 gtk_widget_destroy (GTK_WIDGET (d));
6935
6936 g_free (msg);
6937
6938 if (r != GTK_RESPONSE_YES)
6939 do_not_extract = TRUE;
6940 }
6941
6942 if (! do_not_extract && ! _g_file_make_directory_tree (edata->destination, 0755, &error)) {
6943 GtkWidget *d;
6944 char *details;
6945
6946 details = g_strdup_printf (_("Could not create the destination folder: %s."), error->message);
6947 d = _gtk_error_dialog_new (GTK_WINDOW (window),
6948 0,
6949 NULL,
6950 _("Extraction not performed"),
6951 "%s",
6952 details);
6953 g_clear_error (&error);
6954 fr_window_show_error_dialog (window, d, GTK_WINDOW (window), details);
6955 fr_window_batch_stop (window);
6956 fr_window_dnd_extraction_finished (window, TRUE);
6957
6958 g_free (details);
6959
6960 return;
6961 }
6962 }
6963
6964 if (do_not_extract) {
6965 GtkWidget *d;
6966
6967 d = _gtk_message_dialog_new (GTK_WINDOW (window),
6968 0,
6969 _("Extraction not performed"),
6970 NULL,
6971 _GTK_LABEL_CLOSE, GTK_RESPONSE_OK,
6972 NULL);
6973 gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_OK);
6974 fr_window_show_error_dialog (window, d, GTK_WINDOW (window), _("Extraction not performed"));
6975 fr_window_batch_stop (window);
6976 fr_window_dnd_extraction_finished (window, TRUE);
6977
6978 return;
6979 }
6980
6981 if (edata->overwrite == FR_OVERWRITE_ASK) {
6982 OverwriteData *odata;
6983
6984 odata = overwrite_data_new (window);
6985 odata->edata = edata;
6986 odata->extract_all = (edata->file_list == NULL) || (g_list_length (edata->file_list) == window->archive->files->len);
6987 if (edata->file_list == NULL)
6988 edata->file_list = fr_window_get_file_list (window);
6989 odata->current_file = odata->edata->file_list;
6990
6991 _fr_window_ask_overwrite_dialog (odata);
6992 }
6993 else
6994 _fr_window_archive_extract_from_edata (window, edata);
6995 }
6996
6997
6998 void
fr_window_archive_extract(FrWindow * window,GList * file_list,GFile * destination,const char * base_dir,gboolean skip_older,FrOverwrite overwrite,gboolean junk_paths,gboolean ask_to_open_destination)6999 fr_window_archive_extract (FrWindow *window,
7000 GList *file_list,
7001 GFile *destination,
7002 const char *base_dir,
7003 gboolean skip_older,
7004 FrOverwrite overwrite,
7005 gboolean junk_paths,
7006 gboolean ask_to_open_destination)
7007 {
7008 ExtractData *edata;
7009
7010 edata = extract_data_new (window,
7011 file_list,
7012 destination,
7013 base_dir,
7014 skip_older,
7015 overwrite,
7016 junk_paths,
7017 ask_to_open_destination,
7018 FALSE);
7019
7020 fr_window_set_current_action (window,
7021 FR_BATCH_ACTION_EXTRACT,
7022 edata,
7023 (GFreeFunc) extract_data_free);
7024
7025 _fr_window_archive_extract_from_edata_maybe (window, edata);
7026 }
7027
7028
7029 /* -- fr_window_archive_extract_here -- */
7030
7031
7032 #define MIN_TOPLEVEL_ITEMS_FOR_A_TARBOMB 2
7033
7034
7035 static gboolean
_archive_extraction_generates_a_tarbomb(FrArchive * archive)7036 _archive_extraction_generates_a_tarbomb (FrArchive *archive)
7037 {
7038 gboolean tarbomb = FALSE;
7039 GHashTable *names_hash;
7040 int n_toplevel_items, i;
7041
7042 names_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
7043 n_toplevel_items = 0;
7044 for (i = 0; ! tarbomb && (i < archive->files->len); i++) {
7045 FileData *fdata = g_ptr_array_index (archive->files, i);
7046 char *second_separator;
7047 char *name = NULL;
7048 gboolean name_created;
7049
7050 if ((fdata->full_path == NULL) || (fdata->full_path[0] == '\0'))
7051 continue;
7052
7053 second_separator = strchr (fdata->full_path + 1 /* skip the first separator */, '/');
7054 if (second_separator != NULL) {
7055 name = g_strndup (fdata->full_path, second_separator - fdata->full_path);
7056 name_created = TRUE;
7057 }
7058 else {
7059 name = fdata->full_path;
7060 name_created = FALSE;
7061 }
7062
7063 if (g_hash_table_lookup (names_hash, name) == NULL) {
7064 g_hash_table_insert (names_hash, name_created ? name : g_strdup (name), GINT_TO_POINTER (1));
7065 n_toplevel_items++;
7066 if (n_toplevel_items >= MIN_TOPLEVEL_ITEMS_FOR_A_TARBOMB)
7067 tarbomb = TRUE;
7068 }
7069 else if (name_created)
7070 g_free (name);
7071 }
7072 g_hash_table_destroy (names_hash);
7073
7074 return tarbomb;
7075 }
7076
7077
7078 static GFile *
_get_destination_to_avoid_tarbomb(GFile * file)7079 _get_destination_to_avoid_tarbomb (GFile *file)
7080 {
7081 GFile *directory;
7082 char *name;
7083 const char *ext;
7084 char *new_name;
7085 GFile *destination;
7086
7087 directory = g_file_get_parent (file);
7088 name = g_file_get_basename (file);
7089 ext = get_archive_filename_extension (name);
7090 if (ext == NULL)
7091 /* if no extension is present add a suffix to the name... */
7092 new_name = g_strconcat (name, "_FILES", NULL);
7093 else
7094 /* ...else use the name without the extension */
7095 new_name = g_strndup (name, strlen (name) - strlen (ext));
7096 destination = g_file_get_child (directory, new_name);
7097
7098 g_free (new_name);
7099 g_free (name);
7100 g_object_unref (directory);
7101
7102 return destination;
7103 }
7104
7105
7106 void
fr_window_archive_extract_here(FrWindow * window,gboolean skip_older,gboolean overwrite,gboolean junk_paths)7107 fr_window_archive_extract_here (FrWindow *window,
7108 gboolean skip_older,
7109 gboolean overwrite,
7110 gboolean junk_paths)
7111 {
7112 GFile *destination;
7113 ExtractData *edata;
7114
7115 if (_archive_extraction_generates_a_tarbomb (window->archive))
7116 destination = _get_destination_to_avoid_tarbomb (fr_archive_get_file (window->archive));
7117 else
7118 destination = g_file_get_parent (fr_archive_get_file (window->archive));
7119
7120 edata = extract_data_new (window,
7121 NULL,
7122 destination,
7123 NULL,
7124 skip_older,
7125 overwrite,
7126 junk_paths,
7127 _fr_window_get_ask_to_open_destination (window),
7128 TRUE);
7129
7130 fr_window_set_current_action (window,
7131 FR_BATCH_ACTION_EXTRACT,
7132 edata,
7133 (GFreeFunc) extract_data_free);
7134
7135 _fr_window_archive_extract_from_edata_maybe (window, edata);
7136
7137 g_object_unref (destination);
7138 }
7139
7140
7141 /* -- fr_window_archive_test -- */
7142
7143
7144 static void
archive_test_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7145 archive_test_ready_cb (GObject *source_object,
7146 GAsyncResult *result,
7147 gpointer user_data)
7148 {
7149 FrWindow *window = user_data;
7150 GError *error = NULL;
7151
7152 fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
7153 _archive_operation_completed (window, FR_ACTION_TESTING_ARCHIVE, error);
7154
7155 _g_error_free (error);
7156 }
7157
7158
7159 void
fr_window_archive_test(FrWindow * window)7160 fr_window_archive_test (FrWindow *window)
7161 {
7162 _archive_operation_started (window, FR_ACTION_TESTING_ARCHIVE);
7163 fr_window_set_current_action (window,
7164 FR_BATCH_ACTION_TEST,
7165 NULL,
7166 NULL);
7167 fr_archive_test (window->archive,
7168 window->priv->password,
7169 window->priv->cancellable,
7170 archive_test_ready_cb,
7171 window);
7172 }
7173
7174
7175 void
fr_window_set_password(FrWindow * window,const char * password)7176 fr_window_set_password (FrWindow *window,
7177 const char *password)
7178 {
7179 g_return_if_fail (window != NULL);
7180
7181 if (window->priv->password == password)
7182 return;
7183
7184 if (window->priv->password != NULL) {
7185 g_free (window->priv->password);
7186 window->priv->password = NULL;
7187 }
7188
7189 if ((password != NULL) && (password[0] != '\0'))
7190 window->priv->password = g_strdup (password);
7191 }
7192
7193
7194 void
fr_window_set_password_for_second_archive(FrWindow * window,const char * password)7195 fr_window_set_password_for_second_archive (FrWindow *window,
7196 const char *password)
7197 {
7198 g_return_if_fail (window != NULL);
7199
7200 if (window->priv->second_password != NULL) {
7201 g_free (window->priv->second_password);
7202 window->priv->second_password = NULL;
7203 }
7204
7205 if ((password != NULL) && (password[0] != '\0'))
7206 window->priv->second_password = g_strdup (password);
7207 }
7208
7209
7210 const char *
fr_window_get_password(FrWindow * window)7211 fr_window_get_password (FrWindow *window)
7212 {
7213 g_return_val_if_fail (window != NULL, NULL);
7214
7215 return window->priv->password;
7216 }
7217
7218
7219 const char *
fr_window_get_password_for_second_archive(FrWindow * window)7220 fr_window_get_password_for_second_archive (FrWindow *window)
7221 {
7222 g_return_val_if_fail (window != NULL, NULL);
7223
7224 return window->priv->second_password;
7225 }
7226
7227
7228 void
fr_window_set_encrypt_header(FrWindow * window,gboolean encrypt_header)7229 fr_window_set_encrypt_header (FrWindow *window,
7230 gboolean encrypt_header)
7231 {
7232 g_return_if_fail (window != NULL);
7233
7234 window->priv->encrypt_header = encrypt_header;
7235 }
7236
7237
7238 gboolean
fr_window_get_encrypt_header(FrWindow * window)7239 fr_window_get_encrypt_header (FrWindow *window)
7240 {
7241 return window->priv->encrypt_header;
7242 }
7243
7244
7245 void
fr_window_set_compression(FrWindow * window,FrCompression compression)7246 fr_window_set_compression (FrWindow *window,
7247 FrCompression compression)
7248 {
7249 g_return_if_fail (window != NULL);
7250
7251 window->priv->compression = compression;
7252 }
7253
7254
7255 FrCompression
fr_window_get_compression(FrWindow * window)7256 fr_window_get_compression (FrWindow *window)
7257 {
7258 return window->priv->compression;
7259 }
7260
7261
7262 void
fr_window_set_volume_size(FrWindow * window,guint volume_size)7263 fr_window_set_volume_size (FrWindow *window,
7264 guint volume_size)
7265 {
7266 g_return_if_fail (window != NULL);
7267
7268 window->priv->volume_size = volume_size;
7269 }
7270
7271
7272 guint
fr_window_get_volume_size(FrWindow * window)7273 fr_window_get_volume_size (FrWindow *window)
7274 {
7275 return window->priv->volume_size;
7276 }
7277
7278
7279 void
fr_window_go_to_location(FrWindow * window,const char * path,gboolean force_update)7280 fr_window_go_to_location (FrWindow *window,
7281 const char *path,
7282 gboolean force_update)
7283 {
7284 char *dir;
7285
7286 g_return_if_fail (window != NULL);
7287 g_return_if_fail (path != NULL);
7288
7289 if (force_update) {
7290 g_free (window->priv->last_location);
7291 window->priv->last_location = NULL;
7292 }
7293
7294 if (path[strlen (path) - 1] != '/')
7295 dir = g_strconcat (path, "/", NULL);
7296 else
7297 dir = g_strdup (path);
7298
7299 if ((window->priv->last_location == NULL) || (strcmp (window->priv->last_location, dir) != 0)) {
7300 g_free (window->priv->last_location);
7301 window->priv->last_location = dir;
7302
7303 fr_window_history_add (window, dir);
7304 fr_window_update_file_list (window, TRUE);
7305 fr_window_update_current_location (window);
7306 }
7307 else
7308 g_free (dir);
7309 }
7310
7311
7312 const char *
fr_window_get_current_location(FrWindow * window)7313 fr_window_get_current_location (FrWindow *window)
7314 {
7315 if (window->priv->history_current == NULL) {
7316 fr_window_history_add (window, "/");
7317 return window->priv->history_current->data;
7318 }
7319 else
7320 return (const char*) window->priv->history_current->data;
7321 }
7322
7323
7324 void
fr_window_go_up_one_level(FrWindow * window)7325 fr_window_go_up_one_level (FrWindow *window)
7326 {
7327 char *parent_dir;
7328
7329 g_return_if_fail (window != NULL);
7330
7331 parent_dir = get_parent_dir (fr_window_get_current_location (window));
7332 fr_window_go_to_location (window, parent_dir, FALSE);
7333 g_free (parent_dir);
7334 }
7335
7336
7337 void
fr_window_go_back(FrWindow * window)7338 fr_window_go_back (FrWindow *window)
7339 {
7340 g_return_if_fail (window != NULL);
7341
7342 if (window->priv->history == NULL)
7343 return;
7344 if (window->priv->history_current == NULL)
7345 return;
7346 if (window->priv->history_current->next == NULL)
7347 return;
7348 window->priv->history_current = window->priv->history_current->next;
7349
7350 fr_window_go_to_location (window, window->priv->history_current->data, FALSE);
7351 }
7352
7353
7354 void
fr_window_go_forward(FrWindow * window)7355 fr_window_go_forward (FrWindow *window)
7356 {
7357 g_return_if_fail (window != NULL);
7358
7359 if (window->priv->history == NULL)
7360 return;
7361 if (window->priv->history_current == NULL)
7362 return;
7363 if (window->priv->history_current->prev == NULL)
7364 return;
7365 window->priv->history_current = window->priv->history_current->prev;
7366
7367 fr_window_go_to_location (window, window->priv->history_current->data, FALSE);
7368 }
7369
7370
7371 void
fr_window_set_list_mode(FrWindow * window,FrWindowListMode list_mode)7372 fr_window_set_list_mode (FrWindow *window,
7373 FrWindowListMode list_mode)
7374 {
7375 g_return_if_fail (window != NULL);
7376
7377 if (list_mode == window->priv->list_mode)
7378 return;
7379
7380 window->priv->list_mode = window->priv->last_list_mode = list_mode;
7381 if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) {
7382 fr_window_history_clear (window);
7383 fr_window_history_add (window, "/");
7384 }
7385
7386 g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_LIST_MODE, window->priv->last_list_mode);
7387 g_settings_set_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_PATH, (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT));
7388
7389 fr_window_update_file_list (window, TRUE);
7390 fr_window_update_dir_tree (window);
7391 fr_window_update_current_location (window);
7392 }
7393
7394
7395 GtkTreeModel *
fr_window_get_list_store(FrWindow * window)7396 fr_window_get_list_store (FrWindow *window)
7397 {
7398 return GTK_TREE_MODEL (window->priv->list_store);
7399 }
7400
7401
7402 void
fr_window_find(FrWindow * window,gboolean active)7403 fr_window_find (FrWindow *window,
7404 gboolean active)
7405 {
7406 gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (window->priv->filter_bar), active);
7407 if (active) {
7408 window->priv->filter_mode = TRUE;
7409 gtk_widget_show (window->priv->filter_bar);
7410 gtk_widget_hide (window->priv->location_bar);
7411 }
7412 else {
7413 window->priv->filter_mode = FALSE;
7414 window->priv->list_mode = window->priv->last_list_mode;
7415
7416 gtk_entry_set_text (GTK_ENTRY (window->priv->filter_entry), "");
7417 gtk_widget_hide (window->priv->filter_bar);
7418
7419 gtk_list_store_clear (window->priv->list_store);
7420
7421 fr_window_update_columns_visibility (window);
7422 fr_window_update_file_list (window, TRUE);
7423 fr_window_update_dir_tree (window);
7424 fr_window_update_current_location (window);
7425 fr_window_go_to_location (window, gtk_entry_get_text (GTK_ENTRY (window->priv->location_entry)), FALSE);
7426 }
7427 }
7428
7429
7430 void
fr_window_select_all(FrWindow * window)7431 fr_window_select_all (FrWindow *window)
7432 {
7433 gtk_tree_selection_select_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)));
7434 }
7435
7436
7437 void
fr_window_unselect_all(FrWindow * window)7438 fr_window_unselect_all (FrWindow *window)
7439 {
7440 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)));
7441 }
7442
7443
7444 void
fr_window_stop(FrWindow * window)7445 fr_window_stop (FrWindow *window)
7446 {
7447 if (window->priv->stoppable && (window->priv->activity_ref > 0))
7448 g_cancellable_cancel (window->priv->cancellable);
7449 }
7450
7451
7452 void
fr_window_action_new_archive(FrWindow * window)7453 fr_window_action_new_archive (FrWindow *window)
7454 {
7455 GtkWidget *dialog;
7456
7457 if (fr_window_present_dialog_if_created (window, "new_archive"))
7458 return;
7459
7460 dialog = fr_new_archive_dialog_new (_("New Archive"),
7461 GTK_WINDOW (window),
7462 FR_NEW_ARCHIVE_ACTION_NEW_MANY_FILES,
7463 fr_window_get_open_default_dir (window),
7464 NULL,
7465 NULL);
7466 if ((fr_window_archive_is_present (window) && ! fr_window_is_batch_mode (window) ? NULL : GTK_WINDOW (window)))
7467 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
7468 g_signal_connect (G_OBJECT (dialog),
7469 "response",
7470 G_CALLBACK (new_archive_dialog_response_cb),
7471 window);
7472 fr_window_set_dialog (window, "new_archive", dialog);
7473 gtk_window_present (GTK_WINDOW (dialog));
7474 }
7475
7476
7477 /* -- fr_window_action_save_as -- */
7478
7479
7480 typedef struct {
7481 FrWindow *window;
7482 FrArchive *new_archive;
7483 GFile *file;
7484 char *mime_type;
7485 char *password;
7486 gboolean encrypt_header;
7487 guint volume_size;
7488 GFile *temp_extraction_dir;
7489 } ConvertData;
7490
7491
7492 static ConvertData *
convert_data_new(GFile * file,const char * mime_type,const char * password,gboolean encrypt_header,guint volume_size)7493 convert_data_new (GFile *file,
7494 const char *mime_type,
7495 const char *password,
7496 gboolean encrypt_header,
7497 guint volume_size)
7498 {
7499 ConvertData *cdata;
7500
7501 cdata = g_new0 (ConvertData, 1);
7502 cdata->file = _g_object_ref (file);
7503 if (mime_type != NULL)
7504 cdata->mime_type = g_strdup (mime_type);
7505 if (password != NULL)
7506 cdata->password = g_strdup (password);
7507 cdata->encrypt_header = encrypt_header;
7508 cdata->volume_size = volume_size;
7509 cdata->temp_extraction_dir = _g_file_get_temp_work_dir (NULL);
7510
7511 return cdata;
7512 }
7513
7514
7515 static void
convert_data_free(ConvertData * cdata)7516 convert_data_free (ConvertData *cdata)
7517 {
7518 if (cdata == NULL)
7519 return;
7520 _g_file_remove_directory (cdata->temp_extraction_dir, NULL, NULL);
7521 _g_object_unref (cdata->temp_extraction_dir);
7522 _g_object_unref (cdata->file);
7523 _g_object_unref (cdata->new_archive);
7524 g_free (cdata->mime_type);
7525 g_free (cdata->password);
7526 g_free (cdata);
7527 }
7528
7529
7530 static void
archive_add_ready_for_conversion_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7531 archive_add_ready_for_conversion_cb (GObject *source_object,
7532 GAsyncResult *result,
7533 gpointer user_data)
7534 {
7535 ConvertData *cdata = user_data;
7536 FrWindow *window = cdata->window;
7537 GError *error = NULL;
7538
7539 fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
7540
7541 _fr_window_stop_activity_mode (window);
7542 close_progress_dialog (window, FALSE);
7543
7544 if (error != NULL) {
7545 _handle_archive_operation_error (window,
7546 cdata->new_archive,
7547 FR_ACTION_ADDING_FILES,
7548 error,
7549 NULL,
7550 NULL);
7551 fr_window_batch_stop (window);
7552 g_error_free (error);
7553 return;
7554 }
7555
7556 fr_window_show_confirmation_dialog_with_open_archive (window);
7557 fr_window_batch_exec_next_action (window);
7558 }
7559
7560
7561 static void
_convertion_completed_with_error(FrWindow * window,FrAction action,GError * error)7562 _convertion_completed_with_error (FrWindow *window,
7563 FrAction action,
7564 GError *error)
7565 {
7566 gboolean opens_dialog;
7567
7568 g_return_if_fail (error != NULL);
7569
7570 #ifdef DEBUG
7571 debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", action_names[action]);
7572 #endif
7573
7574 _fr_window_stop_activity_mode (window);
7575 close_progress_dialog (window, FALSE);
7576
7577 _handle_archive_operation_error (window, window->archive, action, error, NULL, &opens_dialog);
7578 if (opens_dialog)
7579 return;
7580
7581 _g_clear_object (&window->priv->saving_file);
7582 fr_window_batch_stop (window);
7583 }
7584
7585
7586 static void
archive_extraction_ready_for_convertion_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7587 archive_extraction_ready_for_convertion_cb (GObject *source_object,
7588 GAsyncResult *result,
7589 gpointer user_data)
7590 {
7591 ConvertData *cdata = user_data;
7592 FrWindow *window = cdata->window;
7593 GList *list;
7594 GError *error = NULL;
7595
7596 if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
7597 _convertion_completed_with_error (window, FR_ACTION_EXTRACTING_FILES, error);
7598 return;
7599 }
7600
7601 list = g_list_prepend (NULL, cdata->temp_extraction_dir);
7602 fr_archive_add_files (cdata->new_archive,
7603 list,
7604 cdata->temp_extraction_dir,
7605 NULL,
7606 FALSE,
7607 FALSE,
7608 cdata->password,
7609 cdata->encrypt_header,
7610 window->priv->compression,
7611 cdata->volume_size,
7612 window->priv->cancellable,
7613 archive_add_ready_for_conversion_cb,
7614 cdata);
7615
7616 g_list_free (list);
7617 }
7618
7619
7620 static void
fr_window_archive_save_as(FrWindow * window,GFile * file,const char * mime_type,const char * password,gboolean encrypt_header,guint volume_size)7621 fr_window_archive_save_as (FrWindow *window,
7622 GFile *file,
7623 const char *mime_type,
7624 const char *password,
7625 gboolean encrypt_header,
7626 guint volume_size)
7627 {
7628 FrArchive *new_archive;
7629 ConvertData *cdata;
7630
7631 g_return_if_fail (window != NULL);
7632 g_return_if_fail (file != NULL);
7633 g_return_if_fail (window->archive != NULL);
7634
7635 /* create the new archive */
7636
7637 new_archive = fr_archive_create (file, mime_type);
7638 if (new_archive == NULL) {
7639 GtkWidget *d;
7640 char *utf8_name;
7641 char *message;
7642
7643 utf8_name = _g_file_get_display_basename (file);
7644 message = g_strdup_printf (_("Could not save the archive “%s”"), utf8_name);
7645 g_free (utf8_name);
7646
7647 d = _gtk_error_dialog_new (GTK_WINDOW (window),
7648 GTK_DIALOG_DESTROY_WITH_PARENT,
7649 NULL,
7650 message,
7651 "%s",
7652 _("Archive type not supported."));
7653 gtk_dialog_run (GTK_DIALOG (d));
7654 gtk_widget_destroy (d);
7655
7656 g_free (message);
7657
7658 return;
7659 }
7660
7661 cdata = convert_data_new (file, mime_type, password, encrypt_header, volume_size);
7662 cdata->window = window;
7663 cdata->new_archive = new_archive;
7664
7665 _archive_operation_started (window, FR_ACTION_CREATING_ARCHIVE);
7666 fr_window_set_current_action (window,
7667 FR_BATCH_ACTION_SAVE_AS,
7668 cdata,
7669 (GFreeFunc) convert_data_free);
7670
7671 g_signal_connect (cdata->new_archive,
7672 "progress",
7673 G_CALLBACK (fr_archive_progress_cb),
7674 window);
7675 g_signal_connect (cdata->new_archive,
7676 "message",
7677 G_CALLBACK (fr_archive_message_cb),
7678 window);
7679 g_signal_connect (cdata->new_archive,
7680 "start",
7681 G_CALLBACK (fr_archive_start_cb),
7682 window);
7683 g_signal_connect (cdata->new_archive,
7684 "stoppable",
7685 G_CALLBACK (fr_archive_stoppable_cb),
7686 window);
7687 g_signal_connect (cdata->new_archive,
7688 "working-archive",
7689 G_CALLBACK (fr_window_working_archive_cb),
7690 window);
7691
7692 _g_object_unref (window->priv->saving_file);
7693 window->priv->saving_file = g_object_ref (cdata->file);
7694
7695 fr_archive_action_started (window->archive, FR_ACTION_EXTRACTING_FILES);
7696 fr_archive_extract (window->archive,
7697 NULL,
7698 cdata->temp_extraction_dir,
7699 NULL,
7700 FALSE,
7701 TRUE,
7702 FALSE,
7703 window->priv->password,
7704 window->priv->cancellable,
7705 archive_extraction_ready_for_convertion_cb,
7706 cdata);
7707 }
7708
7709
7710 static void
save_as_archive_dialog_response_cb(GtkDialog * dialog,int response,gpointer user_data)7711 save_as_archive_dialog_response_cb (GtkDialog *dialog,
7712 int response,
7713 gpointer user_data)
7714 {
7715 FrWindow *window = user_data;
7716 GFile *file;
7717 const char *mime_type;
7718 const char *password;
7719 gboolean encrypt_header;
7720 int volume_size;
7721 GSettings *settings;
7722
7723 if ((response == GTK_RESPONSE_CANCEL) || (response == GTK_RESPONSE_DELETE_EVENT)) {
7724 gtk_widget_destroy (GTK_WIDGET (dialog));
7725 _archive_operation_cancelled (window, FR_ACTION_CREATING_ARCHIVE);
7726 return;
7727 }
7728
7729 if (response != GTK_RESPONSE_OK)
7730 return;
7731
7732 file = fr_new_archive_dialog_get_file (FR_NEW_ARCHIVE_DIALOG (dialog), &mime_type);
7733 if (file == NULL)
7734 return;
7735
7736 password = fr_new_archive_dialog_get_password (FR_NEW_ARCHIVE_DIALOG (dialog));
7737 encrypt_header = fr_new_archive_dialog_get_encrypt_header (FR_NEW_ARCHIVE_DIALOG (dialog));
7738 volume_size = fr_new_archive_dialog_get_volume_size (FR_NEW_ARCHIVE_DIALOG (dialog));
7739
7740 settings = g_settings_new (FILE_ROLLER_SCHEMA_NEW);
7741 g_settings_set_int (settings, PREF_NEW_VOLUME_SIZE, volume_size);
7742 g_object_unref (settings);
7743
7744 fr_window_archive_save_as (window, file, mime_type, password, encrypt_header, volume_size);
7745
7746 gtk_widget_destroy (GTK_WIDGET (dialog));
7747 g_object_unref (file);
7748 }
7749
7750
7751 void
fr_window_action_save_as(FrWindow * window)7752 fr_window_action_save_as (FrWindow *window)
7753 {
7754 char *archive_name;
7755 GtkWidget *dialog;
7756
7757 archive_name = NULL;
7758 if (window->priv->archive_file != NULL) {
7759 GFileInfo *info;
7760
7761 info = g_file_query_info (window->priv->archive_file,
7762 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
7763 0, NULL, NULL);
7764
7765 if (info != NULL) {
7766 archive_name = g_strdup (g_file_info_get_display_name (info));
7767 g_object_unref (info);
7768 }
7769 }
7770
7771 dialog = fr_new_archive_dialog_new (_("Save"),
7772 GTK_WINDOW (window),
7773 FR_NEW_ARCHIVE_ACTION_SAVE_AS,
7774 fr_window_get_open_default_dir (window),
7775 archive_name,
7776 window->priv->archive_file);
7777 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
7778 g_signal_connect (G_OBJECT (dialog),
7779 "response",
7780 G_CALLBACK (save_as_archive_dialog_response_cb),
7781 window);
7782 gtk_window_present (GTK_WINDOW (dialog));
7783
7784 g_free (archive_name);
7785 }
7786
7787
7788 /* -- fr_window_archive_encrypt -- */
7789
7790
7791 typedef struct {
7792 FrWindow *window;
7793 char *password;
7794 gboolean encrypt_header;
7795 GFile *temp_extraction_dir;
7796 GFile *temp_new_file;
7797 FrArchive *new_archive;
7798 } EncryptData;
7799
7800
7801 static EncryptData *
encrypt_data_new(FrWindow * window,const char * password,gboolean encrypt_header)7802 encrypt_data_new (FrWindow *window,
7803 const char *password,
7804 gboolean encrypt_header)
7805 {
7806 EncryptData *edata;
7807
7808 edata = g_new0 (EncryptData, 1);
7809 edata->window = window;
7810 if (password != NULL)
7811 edata->password = g_strdup (password);
7812 edata->encrypt_header = encrypt_header;
7813 edata->temp_extraction_dir = _g_file_get_temp_work_dir (NULL);
7814
7815 return edata;
7816 }
7817
7818
7819 static void
encrypt_data_free(EncryptData * edata)7820 encrypt_data_free (EncryptData *edata)
7821 {
7822 if (edata == NULL)
7823 return;
7824
7825 if (edata->temp_new_file != NULL) {
7826 GFile *parent = g_file_get_parent (edata->temp_new_file);
7827 if (parent != NULL)
7828 _g_file_remove_directory (parent, NULL, NULL);
7829 _g_object_unref (parent);
7830 }
7831 _g_object_unref (edata->temp_new_file);
7832 _g_object_unref (edata->new_archive);
7833 _g_file_remove_directory (edata->temp_extraction_dir, NULL, NULL);
7834 _g_object_unref (edata->temp_extraction_dir);
7835 g_free (edata->password);
7836 g_free (edata);
7837 }
7838
7839
7840 static void
_encrypt_operation_completed_with_error(FrWindow * window,FrAction action,GError * error)7841 _encrypt_operation_completed_with_error (FrWindow *window,
7842 FrAction action,
7843 GError *error)
7844 {
7845 gboolean opens_dialog;
7846
7847 g_return_if_fail (error != NULL);
7848
7849 #ifdef DEBUG
7850 debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", action_names[action]);
7851 #endif
7852
7853 _fr_window_stop_activity_mode (window);
7854 _handle_archive_operation_error (window, window->archive, action, error, NULL, &opens_dialog);
7855 if (opens_dialog)
7856 return;
7857
7858 close_progress_dialog (window, FALSE);
7859 fr_window_batch_stop (window);
7860 }
7861
7862
7863 static void
ecryption_copy_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7864 ecryption_copy_ready_cb (GObject *source_object,
7865 GAsyncResult *result,
7866 gpointer user_data)
7867 {
7868 EncryptData *edata = user_data;
7869 FrWindow *window = edata->window;
7870 GError *error = NULL;
7871
7872 _fr_window_stop_activity_mode (window);
7873 close_progress_dialog (window, FALSE);
7874
7875 if (! g_file_copy_finish (G_FILE (source_object), result, &error)) {
7876 _handle_archive_operation_error (window,
7877 edata->new_archive,
7878 FR_ACTION_CREATING_NEW_ARCHIVE,
7879 error,
7880 NULL,
7881 NULL);
7882 fr_window_batch_stop (window);
7883
7884 g_error_free (error);
7885 return;
7886 }
7887
7888 fr_window_set_password (window, edata->password);
7889 fr_window_set_encrypt_header (window, edata->encrypt_header);
7890 window->priv->reload_archive = TRUE;
7891 fr_window_batch_exec_next_action (window);
7892 }
7893
7894
7895 static void
encryption_copy_progress_cb(goffset current_num_bytes,goffset total_num_bytes,gpointer user_data)7896 encryption_copy_progress_cb (goffset current_num_bytes,
7897 goffset total_num_bytes,
7898 gpointer user_data)
7899 {
7900 EncryptData *edata = user_data;
7901
7902 fr_archive_progress (edata->new_archive, (double) current_num_bytes / total_num_bytes);
7903 }
7904
7905
7906 static void
archive_add_ready_for_encryption_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7907 archive_add_ready_for_encryption_cb (GObject *source_object,
7908 GAsyncResult *result,
7909 gpointer user_data)
7910 {
7911 EncryptData *edata = user_data;
7912 FrWindow *window = edata->window;
7913 GError *error = NULL;
7914
7915 if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
7916 _encrypt_operation_completed_with_error (window, FR_ACTION_ENCRYPTING_ARCHIVE, error);
7917 return;
7918 }
7919
7920 fr_archive_action_started (window->archive, FR_ACTION_SAVING_REMOTE_ARCHIVE);
7921 g_file_copy_async (edata->temp_new_file,
7922 fr_archive_get_file (window->archive),
7923 G_FILE_COPY_OVERWRITE,
7924 G_PRIORITY_DEFAULT,
7925 window->priv->cancellable,
7926 encryption_copy_progress_cb,
7927 edata,
7928 ecryption_copy_ready_cb,
7929 edata);
7930 }
7931
7932
7933 static void
archive_extraction_ready_for_encryption_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7934 archive_extraction_ready_for_encryption_cb (GObject *source_object,
7935 GAsyncResult *result,
7936 gpointer user_data)
7937 {
7938 EncryptData *edata = user_data;
7939 FrWindow *window = edata->window;
7940 GList *list;
7941 GError *error = NULL;
7942
7943 if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
7944 _encrypt_operation_completed_with_error (window, FR_ACTION_ENCRYPTING_ARCHIVE, error);
7945 return;
7946 }
7947
7948 fr_archive_action_started (window->archive, FR_ACTION_ENCRYPTING_ARCHIVE);
7949
7950 list = g_list_prepend (NULL, edata->temp_extraction_dir);
7951 fr_archive_add_files (edata->new_archive,
7952 list,
7953 edata->temp_extraction_dir,
7954 NULL,
7955 FALSE,
7956 FALSE,
7957 edata->password,
7958 edata->encrypt_header,
7959 window->priv->compression,
7960 0,
7961 window->priv->cancellable,
7962 archive_add_ready_for_encryption_cb,
7963 edata);
7964
7965 g_list_free (list);
7966 }
7967
7968
7969 void
fr_window_archive_encrypt(FrWindow * window,const char * password,gboolean encrypt_header)7970 fr_window_archive_encrypt (FrWindow *window,
7971 const char *password,
7972 gboolean encrypt_header)
7973 {
7974 EncryptData *edata;
7975 GFile *temp_destination_parent;
7976 GFile *temp_destination;
7977 char *basename;
7978 GFile *temp_new_file;
7979 FrArchive *new_archive;
7980
7981 /* create the new archive */
7982
7983 if (g_file_is_native (fr_archive_get_file (window->archive)))
7984 temp_destination_parent = g_file_get_parent (fr_archive_get_file (window->archive));
7985 else
7986 temp_destination_parent = NULL;
7987 temp_destination = _g_file_get_temp_work_dir (temp_destination_parent);
7988 basename = g_file_get_basename (fr_archive_get_file (window->archive));
7989 temp_new_file = g_file_get_child (temp_destination, basename);
7990
7991 g_free (basename);
7992 _g_object_unref (temp_destination_parent);
7993
7994 new_archive = fr_archive_create (temp_new_file, fr_archive_get_mime_type (window->archive));
7995 if (new_archive == NULL) {
7996 GtkWidget *d;
7997 char *utf8_name;
7998 char *message;
7999
8000 utf8_name = _g_file_get_display_basename (temp_new_file);
8001 message = g_strdup_printf (_("Could not save the archive “%s”"), utf8_name);
8002 g_free (utf8_name);
8003
8004 d = _gtk_error_dialog_new (GTK_WINDOW (window),
8005 GTK_DIALOG_DESTROY_WITH_PARENT,
8006 NULL,
8007 message,
8008 "%s",
8009 _("Archive type not supported."));
8010 gtk_dialog_run (GTK_DIALOG (d));
8011 gtk_widget_destroy (d);
8012
8013 g_free (message);
8014 g_object_unref (temp_new_file);
8015
8016 _g_file_remove_directory (temp_destination, NULL, NULL);
8017 g_object_unref (temp_destination);
8018
8019 return;
8020 }
8021
8022 g_object_unref (temp_destination);
8023
8024 edata = encrypt_data_new (window, password, encrypt_header);
8025 edata->temp_new_file = temp_new_file;
8026 edata->new_archive = new_archive;
8027
8028 g_signal_connect (edata->new_archive,
8029 "progress",
8030 G_CALLBACK (fr_archive_progress_cb),
8031 window);
8032 g_signal_connect (edata->new_archive,
8033 "message",
8034 G_CALLBACK (fr_archive_message_cb),
8035 window);
8036 g_signal_connect (edata->new_archive,
8037 "start",
8038 G_CALLBACK (fr_archive_start_cb),
8039 window);
8040 g_signal_connect (edata->new_archive,
8041 "stoppable",
8042 G_CALLBACK (fr_archive_stoppable_cb),
8043 window);
8044 g_signal_connect (edata->new_archive,
8045 "working-archive",
8046 G_CALLBACK (fr_window_working_archive_cb),
8047 window);
8048
8049 _archive_operation_started (window, FR_ACTION_ENCRYPTING_ARCHIVE);
8050 fr_window_set_current_action (window,
8051 FR_BATCH_ACTION_ENCRYPT,
8052 edata,
8053 (GFreeFunc) encrypt_data_free);
8054
8055 fr_archive_action_started (window->archive, FR_ACTION_EXTRACTING_FILES);
8056 fr_archive_extract (window->archive,
8057 NULL,
8058 edata->temp_extraction_dir,
8059 NULL,
8060 FALSE,
8061 TRUE,
8062 FALSE,
8063 window->priv->password,
8064 window->priv->cancellable,
8065 archive_extraction_ready_for_encryption_cb,
8066 edata);
8067 }
8068
8069
8070 /* -- fr_window_view_last_output -- */
8071
8072
8073 static gboolean
last_output_window__unrealize_cb(GtkWidget * widget,gpointer data)8074 last_output_window__unrealize_cb (GtkWidget *widget,
8075 gpointer data)
8076 {
8077 pref_util_save_window_geometry (GTK_WINDOW (widget), LAST_OUTPUT_SCHEMA_NAME);
8078 return FALSE;
8079 }
8080
8081
8082 void
fr_window_view_last_output(FrWindow * window,const char * title)8083 fr_window_view_last_output (FrWindow *window,
8084 const char *title)
8085 {
8086 GtkWidget *dialog;
8087 GtkWidget *vbox;
8088 GtkWidget *text_view;
8089 GtkWidget *scrolled;
8090 GtkTextBuffer *text_buffer;
8091 GtkTextIter iter;
8092 GList *scan;
8093
8094 if (title == NULL)
8095 title = _("Last Output");
8096
8097 dialog = g_object_new (GTK_TYPE_DIALOG,
8098 "title", title,
8099 "transient-for", window,
8100 "destroy-with-parent", TRUE,
8101 "use-header-bar", TRUE,
8102 NULL);
8103 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
8104 gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
8105 gtk_widget_set_size_request (dialog, 500, 300);
8106
8107 /* Add text */
8108
8109 scrolled = gtk_scrolled_window_new (NULL, NULL);
8110 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
8111 GTK_POLICY_AUTOMATIC,
8112 GTK_POLICY_AUTOMATIC);
8113 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
8114 GTK_SHADOW_ETCHED_IN);
8115
8116 text_buffer = gtk_text_buffer_new (NULL);
8117 gtk_text_buffer_create_tag (text_buffer, "monospace",
8118 "family", "monospace", NULL);
8119
8120 text_view = gtk_text_view_new_with_buffer (text_buffer);
8121 g_object_unref (text_buffer);
8122 gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
8123 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
8124
8125 /**/
8126
8127 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
8128 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
8129
8130 gtk_container_add (GTK_CONTAINER (scrolled), text_view);
8131 gtk_box_pack_start (GTK_BOX (vbox), scrolled,
8132 TRUE, TRUE, 0);
8133
8134 gtk_widget_show_all (vbox);
8135 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
8136 vbox,
8137 TRUE, TRUE, 0);
8138
8139 /* signals */
8140
8141 g_signal_connect (G_OBJECT (dialog),
8142 "response",
8143 G_CALLBACK (gtk_widget_destroy),
8144 NULL);
8145
8146 g_signal_connect (G_OBJECT (dialog),
8147 "unrealize",
8148 G_CALLBACK (last_output_window__unrealize_cb),
8149 NULL);
8150
8151 /**/
8152
8153 gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 0);
8154 if (FR_IS_COMMAND (window->archive))
8155 scan = fr_command_get_last_output (FR_COMMAND (window->archive));
8156 else
8157 scan = NULL;
8158 for (; scan; scan = scan->next) {
8159 char *line = scan->data;
8160 char *utf8_line;
8161 gsize bytes_written;
8162
8163 utf8_line = g_locale_to_utf8 (line, -1, NULL, &bytes_written, NULL);
8164 gtk_text_buffer_insert_with_tags_by_name (text_buffer,
8165 &iter,
8166 utf8_line,
8167 bytes_written,
8168 "monospace", NULL);
8169 g_free (utf8_line);
8170 gtk_text_buffer_insert (text_buffer, &iter, "\n", 1);
8171 }
8172
8173 /**/
8174
8175 pref_util_restore_window_geometry (GTK_WINDOW (dialog), LAST_OUTPUT_SCHEMA_NAME);
8176 }
8177
8178
8179 /* -- fr_window_rename_selection -- */
8180
8181
8182 typedef struct {
8183 char *path_to_rename;
8184 char *old_name;
8185 char *new_name;
8186 char *current_dir;
8187 gboolean is_dir;
8188 gboolean dir_in_archive;
8189 char *original_path;
8190 } RenameData;
8191
8192
8193 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)8194 rename_data_new (const char *path_to_rename,
8195 const char *old_name,
8196 const char *new_name,
8197 const char *current_dir,
8198 gboolean is_dir,
8199 gboolean dir_in_archive,
8200 const char *original_path)
8201 {
8202 RenameData *rdata;
8203
8204 rdata = g_new0 (RenameData, 1);
8205 rdata->path_to_rename = g_strdup (path_to_rename);
8206 if (old_name != NULL)
8207 rdata->old_name = g_strdup (old_name);
8208 if (new_name != NULL)
8209 rdata->new_name = g_strdup (new_name);
8210 if (current_dir != NULL)
8211 rdata->current_dir = g_strdup (current_dir);
8212 rdata->is_dir = is_dir;
8213 rdata->dir_in_archive = dir_in_archive;
8214 if (original_path != NULL)
8215 rdata->original_path = g_strdup (original_path);
8216
8217 return rdata;
8218 }
8219
8220
8221 static void
rename_data_free(RenameData * rdata)8222 rename_data_free (RenameData *rdata)
8223 {
8224 g_return_if_fail (rdata != NULL);
8225
8226 g_free (rdata->path_to_rename);
8227 g_free (rdata->old_name);
8228 g_free (rdata->new_name);
8229 g_free (rdata->current_dir);
8230 g_free (rdata->original_path);
8231 g_free (rdata);
8232 }
8233
8234
8235 static void
archive_rename_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8236 archive_rename_ready_cb (GObject *source_object,
8237 GAsyncResult *result,
8238 gpointer user_data)
8239 {
8240 FrWindow *window = user_data;
8241 GError *error = NULL;
8242
8243 fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
8244 _archive_operation_completed (window, FR_ACTION_RENAMING_FILES, error);
8245
8246 _g_error_free (error);
8247 }
8248
8249
8250 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)8251 rename_selection (FrWindow *window,
8252 const char *path_to_rename,
8253 const char *old_name,
8254 const char *new_name,
8255 const char *current_dir,
8256 gboolean is_dir,
8257 gboolean dir_in_archive,
8258 const char *original_path)
8259 {
8260 RenameData *rdata;
8261 GList *file_list;
8262
8263 rdata = rename_data_new (path_to_rename,
8264 old_name,
8265 new_name,
8266 current_dir,
8267 is_dir,
8268 dir_in_archive,
8269 original_path);
8270 fr_window_set_current_action (window,
8271 FR_BATCH_ACTION_RENAME,
8272 rdata,
8273 (GFreeFunc) rename_data_free);
8274
8275 _archive_operation_started (window, FR_ACTION_RENAMING_FILES);
8276
8277 g_object_set (window->archive,
8278 "compression", window->priv->compression,
8279 "encrypt-header", window->priv->encrypt_header,
8280 "password", window->priv->password,
8281 "volume-size", window->priv->volume_size,
8282 NULL);
8283
8284 if (is_dir)
8285 file_list = get_dir_list_from_path (window, rdata->path_to_rename);
8286 else
8287 file_list = g_list_append (NULL, g_strdup (rdata->path_to_rename));
8288 fr_window_clipboard_remove_file_list (window, file_list);
8289 fr_archive_rename (window->archive,
8290 file_list,
8291 rdata->old_name,
8292 rdata->new_name,
8293 rdata->current_dir,
8294 rdata->is_dir,
8295 rdata->dir_in_archive,
8296 rdata->original_path,
8297 window->priv->cancellable,
8298 archive_rename_ready_cb,
8299 window);
8300
8301 _g_string_list_free (file_list);
8302 }
8303
8304
8305 static gboolean
valid_name(const char * new_name,const char * old_name,char ** reason)8306 valid_name (const char *new_name,
8307 const char *old_name,
8308 char **reason)
8309 {
8310 char *utf8_new_name;
8311 gboolean retval = TRUE;
8312
8313 new_name = _g_str_eat_spaces (new_name);
8314 utf8_new_name = g_filename_display_name (new_name);
8315
8316 if (*new_name == '\0') {
8317 /* Translators: the name references to a filename. This message can appear when renaming a file. */
8318 *reason = g_strdup (_("New name is void, please type a name."));
8319 retval = FALSE;
8320 }
8321 else if (strcmp (new_name, old_name) == 0) {
8322 /* Translators: the name references to a filename. This message can appear when renaming a file. */
8323 *reason = g_strdup (_("New name is the same as old one, please type other name."));
8324 retval = FALSE;
8325 }
8326 else if (_g_strchrs (new_name, BAD_CHARS)) {
8327 /* Translators: the %s references to a filename. This message can appear when renaming a file. */
8328 *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);
8329 retval = FALSE;
8330 }
8331
8332 g_free (utf8_new_name);
8333
8334 return retval;
8335 }
8336
8337
8338 static gboolean
name_is_present(FrWindow * window,const char * current_dir,const char * new_name,char ** reason)8339 name_is_present (FrWindow *window,
8340 const char *current_dir,
8341 const char *new_name,
8342 char **reason)
8343 {
8344 gboolean retval = FALSE;
8345 int i;
8346 char *new_filename;
8347 int new_filename_l;
8348
8349 *reason = NULL;
8350
8351 new_filename = g_build_filename (current_dir, new_name, NULL);
8352 new_filename_l = strlen (new_filename);
8353
8354 for (i = 0; i < window->archive->files->len; i++) {
8355 FileData *fdata = g_ptr_array_index (window->archive->files, i);
8356 const char *filename = fdata->full_path;
8357
8358 if ((strncmp (filename, new_filename, new_filename_l) == 0)
8359 && ((filename[new_filename_l] == '\0')
8360 || (filename[new_filename_l] == G_DIR_SEPARATOR))) {
8361 char *utf8_name = g_filename_display_name (new_name);
8362
8363 if (filename[new_filename_l] == G_DIR_SEPARATOR)
8364 *reason = g_strdup_printf (_("A folder named “%s” already exists.\n\n%s"), utf8_name, _("Please use a different name."));
8365 else
8366 *reason = g_strdup_printf (_("A file named “%s” already exists.\n\n%s"), utf8_name, _("Please use a different name."));
8367
8368 retval = TRUE;
8369 break;
8370 }
8371 }
8372
8373 g_free (new_filename);
8374
8375 return retval;
8376 }
8377
8378
8379 void
fr_window_rename_selection(FrWindow * window,gboolean from_sidebar)8380 fr_window_rename_selection (FrWindow *window,
8381 gboolean from_sidebar)
8382 {
8383 char *path_to_rename;
8384 char *parent_dir;
8385 char *old_name;
8386 gboolean renaming_dir = FALSE;
8387 gboolean dir_in_archive = FALSE;
8388 char *original_path = NULL;
8389 char *utf8_old_name;
8390 char *utf8_new_name;
8391
8392 if (from_sidebar) {
8393 path_to_rename = fr_window_get_selected_folder_in_tree_view (window);
8394 if (path_to_rename == NULL)
8395 return;
8396 parent_dir = _g_path_remove_level (path_to_rename);
8397 old_name = g_strdup (_g_path_get_basename (path_to_rename));
8398 renaming_dir = TRUE;
8399 }
8400 else {
8401 FileData *selected_item;
8402
8403 selected_item = fr_window_get_selected_item_from_file_list (window);
8404 if (selected_item == NULL)
8405 return;
8406
8407 renaming_dir = file_data_is_dir (selected_item);
8408 dir_in_archive = selected_item->dir && ! selected_item->list_dir;
8409 original_path = g_strdup (selected_item->original_path);
8410
8411 if (renaming_dir && ! dir_in_archive) {
8412 parent_dir = g_strdup (fr_window_get_current_location (window));
8413 old_name = g_strdup (selected_item->list_name);
8414 path_to_rename = g_build_filename (parent_dir, old_name, NULL);
8415 }
8416 else {
8417 if (renaming_dir) {
8418 path_to_rename = _g_path_remove_ending_separator (selected_item->full_path);
8419 parent_dir = _g_path_remove_level (path_to_rename);
8420 }
8421 else {
8422 path_to_rename = g_strdup (selected_item->original_path);
8423 parent_dir = _g_path_remove_level (selected_item->full_path);
8424 }
8425 old_name = g_strdup (selected_item->name);
8426 }
8427
8428 file_data_free (selected_item);
8429 }
8430
8431 retry__rename_selection:
8432 utf8_old_name = g_locale_to_utf8 (old_name, -1 ,0 ,0 ,0);
8433 utf8_new_name = _gtk_request_dialog_run (GTK_WINDOW (window),
8434 (GTK_DIALOG_DESTROY_WITH_PARENT
8435 | GTK_DIALOG_MODAL),
8436 _("Rename"),
8437 (renaming_dir ? _("_New folder name:") : _("_New file name:")),
8438 utf8_old_name,
8439 1024,
8440 _GTK_LABEL_CANCEL,
8441 _("_Rename"));
8442 g_free (utf8_old_name);
8443
8444 if (utf8_new_name != NULL) {
8445 char *new_name;
8446 char *reason = NULL;
8447
8448 new_name = g_filename_from_utf8 (utf8_new_name, -1, 0, 0, 0);
8449 g_free (utf8_new_name);
8450
8451 if (! valid_name (new_name, old_name, &reason)) {
8452 char *utf8_name = g_filename_display_name (new_name);
8453 GtkWidget *dlg;
8454
8455 dlg = _gtk_error_dialog_new (GTK_WINDOW (window),
8456 GTK_DIALOG_DESTROY_WITH_PARENT,
8457 NULL,
8458 (renaming_dir ? _("Could not rename the folder") : _("Could not rename the file")),
8459 "%s",
8460 reason);
8461 gtk_dialog_run (GTK_DIALOG (dlg));
8462 gtk_widget_destroy (dlg);
8463
8464 g_free (reason);
8465 g_free (utf8_name);
8466 g_free (new_name);
8467
8468 goto retry__rename_selection;
8469 }
8470
8471 if (name_is_present (window, parent_dir, new_name, &reason)) {
8472 GtkWidget *dlg;
8473
8474 dlg = _gtk_message_dialog_new (GTK_WINDOW (window),
8475 GTK_DIALOG_MODAL,
8476 (renaming_dir ? _("Could not rename the folder") : _("Could not rename the file")),
8477 reason,
8478 _GTK_LABEL_CLOSE, GTK_RESPONSE_OK,
8479 NULL);
8480 gtk_dialog_run (GTK_DIALOG (dlg));
8481 gtk_widget_destroy (dlg);
8482 g_free (reason);
8483 g_free (new_name);
8484 goto retry__rename_selection;
8485 }
8486
8487 rename_selection (window,
8488 path_to_rename,
8489 old_name,
8490 new_name,
8491 parent_dir,
8492 renaming_dir,
8493 dir_in_archive,
8494 original_path);
8495
8496 g_free (new_name);
8497 }
8498
8499 g_free (old_name);
8500 g_free (parent_dir);
8501 g_free (path_to_rename);
8502 g_free (original_path);
8503 }
8504
8505
8506 /* -- fr_window_paste_selection -- */
8507
8508
8509 static void
fr_clipboard_get(GtkClipboard * clipboard,GtkSelectionData * selection_data,guint info,gpointer user_data_or_owner)8510 fr_clipboard_get (GtkClipboard *clipboard,
8511 GtkSelectionData *selection_data,
8512 guint info,
8513 gpointer user_data_or_owner)
8514 {
8515 FrWindow *window = user_data_or_owner;
8516 char *data;
8517
8518 if (gtk_selection_data_get_target (selection_data) != FR_SPECIAL_URI_LIST)
8519 return;
8520
8521 data = get_selection_data_from_clipboard_data (window, window->priv->copy_data);
8522 if (data != NULL) {
8523 gtk_selection_data_set (selection_data,
8524 gtk_selection_data_get_target (selection_data),
8525 8,
8526 (guchar *) data,
8527 strlen (data));
8528 g_free (data);
8529 }
8530 }
8531
8532
8533 static void
fr_clipboard_clear(GtkClipboard * clipboard,gpointer user_data_or_owner)8534 fr_clipboard_clear (GtkClipboard *clipboard,
8535 gpointer user_data_or_owner)
8536 {
8537 FrWindow *window = user_data_or_owner;
8538
8539 if (window->priv->copy_data != NULL) {
8540 fr_clipboard_data_unref (window->priv->copy_data);
8541 window->priv->copy_data = NULL;
8542 }
8543 }
8544
8545
8546 GList *
fr_window_get_selection(FrWindow * window,gboolean from_sidebar,char ** return_base_dir)8547 fr_window_get_selection (FrWindow *window,
8548 gboolean from_sidebar,
8549 char **return_base_dir)
8550 {
8551 GList *files;
8552 char *base_dir;
8553
8554 if (from_sidebar) {
8555 char *selected_folder;
8556 char *parent_folder;
8557
8558 files = fr_window_get_folder_tree_selection (window, TRUE, NULL);
8559 selected_folder = fr_window_get_selected_folder_in_tree_view (window);
8560 parent_folder = _g_path_remove_level (selected_folder);
8561 if (parent_folder == NULL)
8562 base_dir = g_strdup ("/");
8563 else if (parent_folder[strlen (parent_folder) - 1] == '/')
8564 base_dir = g_strdup (parent_folder);
8565 else
8566 base_dir = g_strconcat (parent_folder, "/", NULL);
8567 g_free (selected_folder);
8568 g_free (parent_folder);
8569 }
8570 else {
8571 files = fr_window_get_file_list_selection (window, TRUE, NULL);
8572 base_dir = g_strdup (fr_window_get_current_location (window));
8573 }
8574
8575 if (return_base_dir)
8576 *return_base_dir = base_dir;
8577 else
8578 g_free (base_dir);
8579
8580 return files;
8581 }
8582
8583
8584 static void
fr_window_copy_or_cut_selection(FrWindow * window,FrClipboardOp op,gboolean from_sidebar)8585 fr_window_copy_or_cut_selection (FrWindow *window,
8586 FrClipboardOp op,
8587 gboolean from_sidebar)
8588 {
8589 GList *files;
8590 char *base_dir;
8591 GtkClipboard *clipboard;
8592
8593 files = fr_window_get_selection (window, from_sidebar, &base_dir);
8594
8595 if (window->priv->copy_data != NULL)
8596 fr_clipboard_data_unref (window->priv->copy_data);
8597 window->priv->copy_data = fr_clipboard_data_new ();
8598 window->priv->copy_data->files = files;
8599 window->priv->copy_data->op = op;
8600 window->priv->copy_data->base_dir = base_dir;
8601
8602 clipboard = gtk_clipboard_get (_fr_window_get_clipboard_name (window));
8603 gtk_clipboard_set_with_owner (clipboard,
8604 clipboard_targets,
8605 G_N_ELEMENTS (clipboard_targets),
8606 fr_clipboard_get,
8607 fr_clipboard_clear,
8608 G_OBJECT (window));
8609
8610 fr_window_update_sensitivity (window);
8611 }
8612
8613
8614 void
fr_window_copy_selection(FrWindow * window,gboolean from_sidebar)8615 fr_window_copy_selection (FrWindow *window,
8616 gboolean from_sidebar)
8617 {
8618 fr_window_copy_or_cut_selection (window, FR_CLIPBOARD_OP_COPY, from_sidebar);
8619 }
8620
8621
8622 void
fr_window_cut_selection(FrWindow * window,gboolean from_sidebar)8623 fr_window_cut_selection (FrWindow *window,
8624 gboolean from_sidebar)
8625 {
8626 fr_window_copy_or_cut_selection (window, FR_CLIPBOARD_OP_CUT, from_sidebar);
8627 }
8628
8629
8630 /* -- fr_window_paste_from_clipboard_data -- */
8631
8632
8633 static void
_paste_from_archive_operation_completed(FrWindow * window,FrAction action,GError * error)8634 _paste_from_archive_operation_completed (FrWindow *window,
8635 FrAction action,
8636 GError *error)
8637 {
8638 FrArchive *archive;
8639
8640 #ifdef DEBUG
8641 debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", action_names[action]);
8642 #endif
8643
8644 _fr_window_stop_activity_mode (window);
8645 close_progress_dialog (window, FALSE);
8646
8647 if ((error != NULL) && (error->code == FR_ERROR_ASK_PASSWORD)) {
8648 dlg_ask_password_for_second_archive (window);
8649 return;
8650 }
8651
8652 if (action == FR_ACTION_ADDING_FILES)
8653 archive = window->archive;
8654 else
8655 archive = window->priv->copy_from_archive;
8656 _handle_archive_operation_error (window, archive, action, error, NULL, NULL);
8657
8658 if (error != NULL) {
8659 if (window->priv->second_password != NULL) {
8660 g_free (window->priv->second_password);
8661 window->priv->second_password = NULL;
8662 }
8663
8664 fr_clipboard_data_unref (window->priv->clipboard_data);
8665 window->priv->clipboard_data = NULL;
8666 }
8667 }
8668
8669
8670 static void
paste_from_archive_completed_successfully(FrWindow * window)8671 paste_from_archive_completed_successfully (FrWindow *window)
8672 {
8673 _paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, NULL);
8674
8675 fr_clipboard_data_unref (window->priv->clipboard_data);
8676 window->priv->clipboard_data = NULL;
8677
8678 if (window->priv->second_password != NULL) {
8679 g_free (window->priv->second_password);
8680 window->priv->second_password = NULL;
8681 }
8682
8683 window->priv->archive_new = FALSE;
8684 fr_window_archive_reload (window);
8685 }
8686
8687
8688 static void
paste_from_archive_remove_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8689 paste_from_archive_remove_ready_cb (GObject *source_object,
8690 GAsyncResult *result,
8691 gpointer user_data)
8692 {
8693 FrWindow *window = user_data;
8694 GError *error = NULL;
8695
8696 if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
8697 _paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, error);
8698 g_error_free (error);
8699 return;
8700 }
8701
8702 paste_from_archive_completed_successfully (window);
8703 }
8704
8705
8706 static void
paste_from_archive_paste_clipboard_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8707 paste_from_archive_paste_clipboard_ready_cb (GObject *source_object,
8708 GAsyncResult *result,
8709 gpointer user_data)
8710 {
8711 FrWindow *window = user_data;
8712 GError *error = NULL;
8713
8714 if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
8715 _paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, error);
8716 g_error_free (error);
8717 return;
8718 }
8719
8720 if (window->priv->clipboard_data->op == FR_CLIPBOARD_OP_CUT) {
8721 fr_archive_action_started (window->priv->copy_from_archive, FR_ACTION_DELETING_FILES);
8722 fr_archive_remove (window->priv->copy_from_archive,
8723 window->priv->clipboard_data->files,
8724 window->priv->compression,
8725 window->priv->cancellable,
8726 paste_from_archive_remove_ready_cb,
8727 window);
8728 }
8729 else
8730 paste_from_archive_completed_successfully (window);
8731 }
8732
8733
8734 static void
paste_from_archive_extract_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8735 paste_from_archive_extract_ready_cb (GObject *source_object,
8736 GAsyncResult *result,
8737 gpointer user_data)
8738 {
8739 FrWindow *window = user_data;
8740 GError *error = NULL;
8741
8742 if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
8743 _paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, error);
8744 g_error_free (error);
8745 return;
8746 }
8747
8748 fr_archive_paste_clipboard (window->archive,
8749 window->priv->clipboard_data->file,
8750 window->priv->password,
8751 window->priv->encrypt_header,
8752 window->priv->compression,
8753 window->priv->volume_size,
8754 window->priv->clipboard_data->op,
8755 window->priv->clipboard_data->base_dir,
8756 window->priv->clipboard_data->files,
8757 window->priv->clipboard_data->tmp_dir,
8758 window->priv->clipboard_data->current_dir,
8759 window->priv->cancellable,
8760 paste_from_archive_paste_clipboard_ready_cb,
8761 window);
8762 }
8763
8764
8765 static void
paste_from_archive_list_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8766 paste_from_archive_list_ready_cb (GObject *source_object,
8767 GAsyncResult *result,
8768 gpointer user_data)
8769 {
8770 FrWindow *window = user_data;
8771 GError *error = NULL;
8772
8773 if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
8774 _paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, error);
8775 g_error_free (error);
8776 return;
8777 }
8778
8779 fr_archive_action_started (window->priv->copy_from_archive, FR_ACTION_EXTRACTING_FILES);
8780 fr_archive_extract (window->priv->copy_from_archive,
8781 window->priv->clipboard_data->files,
8782 window->priv->clipboard_data->tmp_dir,
8783 NULL,
8784 FALSE,
8785 TRUE,
8786 FALSE,
8787 window->priv->clipboard_data->password,
8788 window->priv->cancellable,
8789 paste_from_archive_extract_ready_cb,
8790 window);
8791 }
8792
8793
8794 static void
paste_from_archive_open_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8795 paste_from_archive_open_cb (GObject *source_object,
8796 GAsyncResult *result,
8797 gpointer user_data)
8798 {
8799 FrWindow *window = user_data;
8800 GError *error;
8801
8802 _g_object_unref (window->priv->copy_from_archive);
8803 window->priv->copy_from_archive = fr_archive_open_finish (G_FILE (source_object), result, &error);
8804 if (window->priv->copy_from_archive == NULL) {
8805 _paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, error);
8806 g_error_free (error);
8807 return;
8808 }
8809
8810 g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
8811 "progress",
8812 G_CALLBACK (fr_archive_progress_cb),
8813 window);
8814 g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
8815 "message",
8816 G_CALLBACK (fr_archive_message_cb),
8817 window);
8818 g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
8819 "start",
8820 G_CALLBACK (fr_archive_start_cb),
8821 window);
8822 g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
8823 "stoppable",
8824 G_CALLBACK (fr_archive_stoppable_cb),
8825 window);
8826 g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
8827 "working-archive",
8828 G_CALLBACK (fr_window_working_archive_cb),
8829 window);
8830
8831 fr_archive_action_started (window->priv->copy_from_archive, FR_ACTION_LISTING_CONTENT);
8832 fr_archive_list (window->priv->copy_from_archive,
8833 window->priv->clipboard_data->password,
8834 window->priv->cancellable,
8835 paste_from_archive_list_ready_cb,
8836 window);
8837 }
8838
8839
8840 static void
_window_started_loading_file(FrWindow * window,GFile * file)8841 _window_started_loading_file (FrWindow *window,
8842 GFile *file)
8843 {
8844 char *description;
8845
8846 description = get_action_description (window, FR_ACTION_LOADING_ARCHIVE, file);
8847 fr_archive_message_cb (NULL, description, window);
8848
8849 g_free (description);
8850 }
8851
8852
8853 static void
fr_window_paste_from_clipboard_data(FrWindow * window,FrClipboardData * data)8854 fr_window_paste_from_clipboard_data (FrWindow *window,
8855 FrClipboardData *data)
8856 {
8857 const char *current_dir_relative;
8858 GHashTable *created_dirs;
8859 GList *scan;
8860 char *from_archive;
8861 char *to_archive;
8862
8863 if (window->priv->second_password != NULL)
8864 fr_clipboard_data_set_password (data, window->priv->second_password);
8865
8866 if (window->priv->clipboard_data != data) {
8867 fr_clipboard_data_unref (window->priv->clipboard_data);
8868 window->priv->clipboard_data = data;
8869 }
8870
8871 fr_window_set_current_action (window,
8872 FR_BATCH_ACTION_PASTE,
8873 fr_clipboard_data_ref (data),
8874 (GFreeFunc) fr_clipboard_data_unref);
8875
8876 current_dir_relative = data->current_dir + 1;
8877
8878 data->tmp_dir = _g_file_get_temp_work_dir (NULL);
8879 created_dirs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
8880 for (scan = data->files; scan; scan = scan->next) {
8881 const char *old_name = (char*) scan->data;
8882 char *new_name;
8883 char *dir;
8884
8885 new_name = g_build_filename (current_dir_relative, old_name + strlen (data->base_dir) - 1, NULL);
8886 dir = _g_path_remove_level (new_name);
8887 if ((dir != NULL) && (g_hash_table_lookup (created_dirs, dir) == NULL)) {
8888 GFile *directory;
8889 char *uri;
8890
8891 directory = _g_file_append_path (data->tmp_dir, dir, NULL);
8892 uri = g_file_get_uri (directory);
8893 debug (DEBUG_INFO, "mktree %s\n", uri);
8894 _g_file_make_directory_tree (directory, 0700, NULL);
8895
8896 g_hash_table_replace (created_dirs, g_strdup (dir), GINT_TO_POINTER (1));
8897
8898 g_object_unref (directory);
8899 g_free (uri);
8900 }
8901
8902 g_free (dir);
8903 g_free (new_name);
8904 }
8905 g_hash_table_destroy (created_dirs);
8906
8907 /**/
8908
8909 g_free (window->priv->custom_action_message);
8910 from_archive = _g_file_get_display_basename (data->file);
8911 to_archive = _g_file_get_display_basename (window->priv->archive_file);
8912 if (data->op == FR_CLIPBOARD_OP_CUT)
8913 /* Translators: %s are archive filenames */
8914 window->priv->custom_action_message = g_strdup_printf (_("Moving the files from “%s” to “%s”"), from_archive, to_archive);
8915 else
8916 /* Translators: %s are archive filenames */
8917 window->priv->custom_action_message = g_strdup_printf (_("Copying the files from “%s” to “%s”"), from_archive, to_archive);
8918 _archive_operation_started (window, FR_ACTION_PASTING_FILES);
8919
8920 _window_started_loading_file (window, data->file);
8921 fr_archive_open (data->file,
8922 window->priv->cancellable,
8923 paste_from_archive_open_cb,
8924 window);
8925
8926 g_free (to_archive);
8927 g_free (from_archive);
8928 }
8929
8930
8931 static void
fr_window_paste_selection_to(FrWindow * window,const char * current_dir)8932 fr_window_paste_selection_to (FrWindow *window,
8933 const char *current_dir)
8934 {
8935 GtkClipboard *clipboard;
8936 GtkSelectionData *selection_data;
8937 FrClipboardData *paste_data;
8938
8939 clipboard = gtk_clipboard_get (_fr_window_get_clipboard_name (window));
8940 selection_data = gtk_clipboard_wait_for_contents (clipboard, FR_SPECIAL_URI_LIST);
8941 if (selection_data == NULL)
8942 return;
8943
8944 paste_data = get_clipboard_data_from_selection_data (window, (char*) gtk_selection_data_get_data (selection_data));
8945 paste_data->current_dir = g_strdup (current_dir);
8946 fr_window_paste_from_clipboard_data (window, paste_data);
8947
8948 gtk_selection_data_free (selection_data);
8949 }
8950
8951
8952 void
fr_window_paste_selection(FrWindow * window,gboolean from_sidebar)8953 fr_window_paste_selection (FrWindow *window,
8954 gboolean from_sidebar)
8955 {
8956 char *utf8_path, *utf8_old_path, *destination;
8957 char *current_dir;
8958
8959 if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT)
8960 return;
8961
8962 /**/
8963
8964 utf8_old_path = g_filename_to_utf8 (fr_window_get_current_location (window), -1, NULL, NULL, NULL);
8965 utf8_path = _gtk_request_dialog_run (GTK_WINDOW (window),
8966 (GTK_DIALOG_DESTROY_WITH_PARENT
8967 | GTK_DIALOG_MODAL),
8968 _("Paste Selection"),
8969 _("_Destination folder:"),
8970 utf8_old_path,
8971 1024,
8972 _GTK_LABEL_CANCEL,
8973 _("_Paste"));
8974 g_free (utf8_old_path);
8975 if (utf8_path == NULL)
8976 return;
8977
8978 destination = g_filename_from_utf8 (utf8_path, -1, NULL, NULL, NULL);
8979 g_free (utf8_path);
8980
8981 if (destination[0] != '/')
8982 current_dir = g_build_filename (fr_window_get_current_location (window), destination, NULL);
8983 else
8984 current_dir = g_strdup (destination);
8985 g_free (destination);
8986
8987 fr_window_paste_selection_to (window, current_dir);
8988
8989 g_free (current_dir);
8990 }
8991
8992
8993 /* -- fr_window_open_files -- */
8994
8995
8996 void
fr_window_open_files_with_command(FrWindow * window,GList * file_list,char * command)8997 fr_window_open_files_with_command (FrWindow *window,
8998 GList *file_list,
8999 char *command)
9000 {
9001 GAppInfo *app;
9002 GError *error = NULL;
9003
9004 app = g_app_info_create_from_commandline (command, NULL, G_APP_INFO_CREATE_NONE, &error);
9005 if (error != NULL) {
9006 _gtk_error_dialog_run (GTK_WINDOW (window),
9007 _("Could not perform the operation"),
9008 "%s",
9009 error->message);
9010 g_clear_error (&error);
9011 return;
9012 }
9013
9014 fr_window_open_files_with_application (window, file_list, app);
9015 }
9016
9017
9018 void
fr_window_open_files_with_application(FrWindow * window,GList * file_list,GAppInfo * app)9019 fr_window_open_files_with_application (FrWindow *window,
9020 GList *file_list,
9021 GAppInfo *app)
9022 {
9023 GList *uris;
9024 GList *scan;
9025 GdkAppLaunchContext *context;
9026 GError *error = NULL;
9027
9028 if (window->priv->activity_ref > 0)
9029 return;
9030
9031 uris = NULL;
9032 for (scan = file_list; scan; scan = scan->next)
9033 uris = g_list_prepend (uris, g_file_get_uri (G_FILE (scan->data)));
9034
9035 context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (window)));
9036 gdk_app_launch_context_set_screen (context, gtk_widget_get_screen (GTK_WIDGET (window)));
9037 gdk_app_launch_context_set_timestamp (context, 0);
9038
9039 if (! g_app_info_launch_uris (app, uris, G_APP_LAUNCH_CONTEXT (context), &error)) {
9040 _gtk_error_dialog_run (GTK_WINDOW (window),
9041 _("Could not perform the operation"),
9042 "%s",
9043 error->message);
9044 g_clear_error (&error);
9045 }
9046
9047 g_object_unref (context);
9048 _g_string_list_free (uris);
9049 }
9050
9051
9052 typedef struct {
9053 int ref_count;
9054 FrWindow *window;
9055 GList *file_list;
9056 gboolean ask_application;
9057 CommandData *cdata;
9058 } OpenFilesData;
9059
9060
9061 static OpenFilesData*
open_files_data_new(FrWindow * window,GList * file_list,gboolean ask_application)9062 open_files_data_new (FrWindow *window,
9063 GList *file_list,
9064 gboolean ask_application)
9065
9066 {
9067 OpenFilesData *odata;
9068 GList *scan;
9069
9070 odata = g_new0 (OpenFilesData, 1);
9071 odata->ref_count = 1;
9072 odata->window = g_object_ref (window);
9073 odata->file_list = _g_string_list_dup (file_list);
9074 odata->ask_application = ask_application;
9075 odata->cdata = g_new0 (CommandData, 1);
9076 odata->cdata->temp_dir = _g_file_get_temp_work_dir (NULL);
9077 odata->cdata->file_list = NULL;
9078 for (scan = file_list; scan; scan = scan->next) {
9079 char *filename = scan->data;
9080 GFile *file;
9081
9082 file = _g_file_append_path (odata->cdata->temp_dir, filename, NULL);
9083 odata->cdata->file_list = g_list_prepend (odata->cdata->file_list, file);
9084 }
9085
9086 /* Add to CommandList so the cdata is released on exit. */
9087 CommandList = g_list_prepend (CommandList, odata->cdata);
9088
9089 return odata;
9090 }
9091
9092
9093 static void
open_files_data_ref(OpenFilesData * odata)9094 open_files_data_ref (OpenFilesData *odata)
9095 {
9096 g_return_if_fail (odata != NULL);
9097 odata->ref_count++;
9098 }
9099
9100
9101 static void
open_files_data_unref(OpenFilesData * odata)9102 open_files_data_unref (OpenFilesData *odata)
9103 {
9104 g_return_if_fail (odata != NULL);
9105
9106 if (--odata->ref_count > 0)
9107 return;
9108
9109 _g_string_list_free (odata->file_list);
9110 g_object_unref (odata->window);
9111 g_free (odata);
9112 }
9113
9114
9115 /* -- -- */
9116
9117
9118 void
fr_window_update_dialog_closed(FrWindow * window)9119 fr_window_update_dialog_closed (FrWindow *window)
9120 {
9121 window->priv->update_dialog = NULL;
9122 }
9123
9124
9125 static void
update_files_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)9126 update_files_ready_cb (GObject *source_object,
9127 GAsyncResult *result,
9128 gpointer user_data)
9129 {
9130 FrWindow *window = user_data;
9131 GError *error = NULL;
9132
9133 fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
9134 _archive_operation_completed (window, FR_ACTION_UPDATING_FILES, error);
9135
9136 _g_error_free (error);
9137 }
9138
9139
9140 gboolean
fr_window_update_files(FrWindow * window,GList * open_file_list)9141 fr_window_update_files (FrWindow *window,
9142 GList *open_file_list)
9143 {
9144 GList *file_list;
9145 GList *dir_list;
9146 GList *scan;
9147
9148 if (window->priv->activity_ref > 0)
9149 return FALSE;
9150
9151 if (window->archive->read_only)
9152 return FALSE;
9153
9154 /* the size will be computed by the archive object */
9155 window->archive->files_to_add_size = 0;
9156
9157 file_list = NULL;
9158 dir_list = NULL;
9159 for (scan = open_file_list; scan; scan = scan->next) {
9160 OpenFile *open_file = scan->data;
9161
9162 file_list = g_list_prepend (file_list, g_object_ref (open_file->extracted_file));
9163 dir_list = g_list_prepend (dir_list, g_object_ref (open_file->temp_dir));
9164 }
9165
9166 _archive_operation_started (window, FR_ACTION_UPDATING_FILES);
9167
9168 fr_archive_update_open_files (window->archive,
9169 file_list,
9170 dir_list,
9171 window->priv->password,
9172 window->priv->encrypt_header,
9173 window->priv->compression,
9174 window->priv->volume_size,
9175 window->priv->cancellable,
9176 update_files_ready_cb,
9177 window);
9178
9179 _g_object_list_unref (dir_list);
9180 _g_object_list_unref (file_list);
9181
9182 return TRUE;
9183 }
9184
9185
9186 static void
open_file_modified_cb(GFileMonitor * monitor,GFile * monitor_file,GFile * other_file,GFileMonitorEvent event_type,gpointer user_data)9187 open_file_modified_cb (GFileMonitor *monitor,
9188 GFile *monitor_file,
9189 GFile *other_file,
9190 GFileMonitorEvent event_type,
9191 gpointer user_data)
9192 {
9193 FrWindow *window = user_data;
9194 OpenFile *file;
9195 GList *scan;
9196
9197 if ((event_type != G_FILE_MONITOR_EVENT_CHANGED)
9198 && (event_type != G_FILE_MONITOR_EVENT_CREATED))
9199 {
9200 return;
9201 }
9202
9203 file = NULL;
9204 for (scan = window->priv->open_files; scan; scan = scan->next) {
9205 OpenFile *test = scan->data;
9206 if (_g_file_cmp_uris (test->extracted_file, monitor_file) == 0) {
9207 file = test;
9208 break;
9209 }
9210 }
9211
9212 g_return_if_fail (file != NULL);
9213
9214 if (window->priv->update_dialog == NULL)
9215 window->priv->update_dialog = dlg_update (window);
9216 dlg_update_add_file (window->priv->update_dialog, file);
9217 }
9218
9219
9220 static void
fr_window_monitor_open_file(FrWindow * window,OpenFile * file)9221 fr_window_monitor_open_file (FrWindow *window,
9222 OpenFile *file)
9223 {
9224 window->priv->open_files = g_list_prepend (window->priv->open_files, file);
9225 file->monitor = g_file_monitor_file (file->extracted_file, 0, NULL, NULL);
9226 g_signal_connect (file->monitor,
9227 "changed",
9228 G_CALLBACK (open_file_modified_cb),
9229 window);
9230 }
9231
9232
9233 static void
monitor_extracted_files(OpenFilesData * odata)9234 monitor_extracted_files (OpenFilesData *odata)
9235 {
9236 FrWindow *window = odata->window;
9237 GList *scan1, *scan2;
9238
9239 for (scan1 = odata->file_list, scan2 = odata->cdata->file_list;
9240 scan1 && scan2;
9241 scan1 = scan1->next, scan2 = scan2->next)
9242 {
9243 char *original_path = (char *) scan1->data;
9244 GFile *extracted_file = G_FILE (scan2->data);
9245 OpenFile *ofile;
9246
9247 ofile = open_file_new (original_path, extracted_file, odata->cdata->temp_dir);
9248 if (ofile != NULL)
9249 fr_window_monitor_open_file (window, ofile);
9250 }
9251 }
9252
9253
9254 static gboolean
fr_window_open_extracted_files(OpenFilesData * odata)9255 fr_window_open_extracted_files (OpenFilesData *odata)
9256 {
9257 GList *file_list = odata->cdata->file_list;
9258 GFile *first_file;
9259 const char *first_mime_type;
9260 GAppInfo *app;
9261 GList *files_to_open = NULL;
9262 GdkAppLaunchContext *context;
9263 gboolean result;
9264 GError *error = NULL;
9265
9266 g_return_val_if_fail (file_list != NULL, FALSE);
9267
9268 first_file = G_FILE (file_list->data);
9269 if (first_file == NULL)
9270 return FALSE;
9271
9272 if (! odata->window->archive->read_only)
9273 monitor_extracted_files (odata);
9274
9275 if (odata->ask_application) {
9276 dlg_open_with (odata->window, file_list);
9277 return FALSE;
9278 }
9279
9280 first_mime_type = _g_file_get_mime_type (first_file, FALSE);
9281 app = g_app_info_get_default_for_type (first_mime_type, FALSE);
9282
9283 if (app == NULL) {
9284 dlg_open_with (odata->window, file_list);
9285 return FALSE;
9286 }
9287
9288 files_to_open = g_list_append (files_to_open, g_file_get_uri (first_file));
9289
9290 if (g_app_info_supports_files (app)) {
9291 GList *scan;
9292
9293 for (scan = file_list->next; scan; scan = scan->next) {
9294 GFile *file = G_FILE (scan->data);
9295 const char *mime_type;
9296
9297 mime_type = _g_file_get_mime_type (file, FALSE);
9298 if (mime_type == NULL)
9299 continue;
9300
9301 if (strcmp (mime_type, first_mime_type) == 0) {
9302 files_to_open = g_list_append (files_to_open, g_file_get_uri (file));
9303 }
9304 else {
9305 GAppInfo *app2;
9306
9307 app2 = g_app_info_get_default_for_type (mime_type, FALSE);
9308 if (g_app_info_equal (app, app2))
9309 files_to_open = g_list_append (files_to_open, g_file_get_uri (file));
9310 g_object_unref (app2);
9311 }
9312 }
9313 }
9314
9315 context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (odata->window)));
9316 gdk_app_launch_context_set_screen (context, gtk_widget_get_screen (GTK_WIDGET (odata->window)));
9317 gdk_app_launch_context_set_timestamp (context, 0);
9318 result = g_app_info_launch_uris (app, files_to_open, G_APP_LAUNCH_CONTEXT (context), &error);
9319 if (! result) {
9320 _gtk_error_dialog_run (GTK_WINDOW (odata->window),
9321 _("Could not perform the operation"),
9322 "%s",
9323 error->message);
9324 g_clear_error (&error);
9325 }
9326
9327 g_object_unref (context);
9328 g_object_unref (app);
9329 _g_string_list_free (files_to_open);
9330
9331 return result;
9332 }
9333
9334
9335 static void
open_files_extract_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)9336 open_files_extract_ready_cb (GObject *source_object,
9337 GAsyncResult *result,
9338 gpointer user_data)
9339 {
9340 OpenFilesData *odata = user_data;
9341 GError *error = NULL;
9342
9343 open_files_data_ref (odata);
9344 fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
9345 _archive_operation_completed (odata->window, FR_ACTION_EXTRACTING_FILES, error);
9346
9347 if (error == NULL)
9348 fr_window_open_extracted_files (odata);
9349
9350 open_files_data_unref (odata);
9351 _g_error_free (error);
9352 }
9353
9354
9355 void
fr_window_open_files(FrWindow * window,GList * file_list,gboolean ask_application)9356 fr_window_open_files (FrWindow *window,
9357 GList *file_list,
9358 gboolean ask_application)
9359 {
9360 OpenFilesData *odata;
9361
9362 if (window->priv->activity_ref > 0)
9363 return;
9364
9365 odata = open_files_data_new (window, file_list, ask_application);
9366 fr_window_set_current_action (window,
9367 FR_BATCH_ACTION_OPEN_FILES,
9368 odata,
9369 (GFreeFunc) open_files_data_unref);
9370
9371 _archive_operation_started (odata->window, FR_ACTION_EXTRACTING_FILES);
9372
9373 fr_archive_extract (window->archive,
9374 odata->file_list,
9375 odata->cdata->temp_dir,
9376 NULL,
9377 FALSE,
9378 TRUE,
9379 FALSE,
9380 window->priv->password,
9381 window->priv->cancellable,
9382 open_files_extract_ready_cb,
9383 odata);
9384 }
9385
9386
9387 /**/
9388
9389
9390 static GFile *
_get_default_dir(GFile * directory)9391 _get_default_dir (GFile *directory)
9392 {
9393 if (! _g_file_is_temp_dir (directory))
9394 return g_object_ref (directory);
9395 else
9396 return NULL;
9397 }
9398
9399
9400 void
fr_window_set_open_default_dir(FrWindow * window,GFile * default_dir)9401 fr_window_set_open_default_dir (FrWindow *window,
9402 GFile *default_dir)
9403 {
9404 g_return_if_fail (window != NULL);
9405 g_return_if_fail (default_dir != NULL);
9406
9407 _g_object_unref (window->priv->open_default_dir);
9408 window->priv->open_default_dir = _get_default_dir (default_dir);
9409 }
9410
9411
9412 GFile *
fr_window_get_open_default_dir(FrWindow * window)9413 fr_window_get_open_default_dir (FrWindow *window)
9414 {
9415 if (window->priv->open_default_dir == NULL)
9416 return _g_file_get_home ();
9417 else
9418 return window->priv->open_default_dir;
9419 }
9420
9421
9422 void
fr_window_set_add_default_dir(FrWindow * window,GFile * default_dir)9423 fr_window_set_add_default_dir (FrWindow *window,
9424 GFile *default_dir)
9425 {
9426 g_return_if_fail (window != NULL);
9427 g_return_if_fail (default_dir != NULL);
9428
9429 _g_object_unref (window->priv->add_default_dir);
9430 window->priv->add_default_dir = _get_default_dir (default_dir);
9431 }
9432
9433
9434 GFile *
fr_window_get_add_default_dir(FrWindow * window)9435 fr_window_get_add_default_dir (FrWindow *window)
9436 {
9437 return window->priv->add_default_dir;
9438 }
9439
9440
9441 void
fr_window_set_extract_default_dir(FrWindow * window,GFile * default_dir)9442 fr_window_set_extract_default_dir (FrWindow *window,
9443 GFile *default_dir)
9444 {
9445 g_return_if_fail (window != NULL);
9446 g_return_if_fail (default_dir != NULL);
9447
9448 _g_object_unref (window->priv->extract_default_dir);
9449 window->priv->extract_default_dir = _get_default_dir (default_dir);
9450 }
9451
9452
9453 GFile *
fr_window_get_extract_default_dir(FrWindow * window)9454 fr_window_get_extract_default_dir (FrWindow *window)
9455 {
9456 if (window->priv->extract_default_dir == NULL)
9457 return _g_file_get_home ();
9458 else
9459 return window->priv->extract_default_dir;
9460 }
9461
9462
9463 void
fr_window_set_default_dir(FrWindow * window,GFile * default_dir,gboolean freeze)9464 fr_window_set_default_dir (FrWindow *window,
9465 GFile *default_dir,
9466 gboolean freeze)
9467 {
9468 g_return_if_fail (window != NULL);
9469 g_return_if_fail (default_dir != NULL);
9470
9471 window->priv->freeze_default_dir = freeze;
9472
9473 fr_window_set_open_default_dir (window, default_dir);
9474 fr_window_set_add_default_dir (window, default_dir);
9475 fr_window_set_extract_default_dir (window, default_dir);
9476 }
9477
9478
9479 void
fr_window_set_folders_visibility(FrWindow * window,gboolean value)9480 fr_window_set_folders_visibility (FrWindow *window,
9481 gboolean value)
9482 {
9483 g_return_if_fail (window != NULL);
9484
9485 window->priv->view_sidebar = value;
9486 fr_window_update_dir_tree (window);
9487
9488 fr_window_set_action_state (window, "view-sidebar", window->priv->view_sidebar);
9489 }
9490
9491
9492 void
fr_window_use_progress_dialog(FrWindow * window,gboolean value)9493 fr_window_use_progress_dialog (FrWindow *window,
9494 gboolean value)
9495 {
9496 window->priv->use_progress_dialog = value;
9497 }
9498
9499
9500 /* -- batch mode procedures -- */
9501
9502
9503 static void fr_window_batch_exec_current_action (FrWindow *window);
9504
9505
9506 static void
fr_window_exec_batch_action(FrWindow * window,FrBatchAction * action)9507 fr_window_exec_batch_action (FrWindow *window,
9508 FrBatchAction *action)
9509 {
9510 ExtractData *edata;
9511 RenameData *rdata;
9512 OpenFilesData *odata;
9513 ConvertData *cdata;
9514 EncryptData *enc_data;
9515
9516 switch (action->type) {
9517 case FR_BATCH_ACTION_LOAD:
9518 debug (DEBUG_INFO, "[BATCH] LOAD\n");
9519
9520 if (! g_file_query_exists (G_FILE (action->data), NULL)) {
9521 GError *error = NULL;
9522
9523 if (! fr_window_archive_new (window, G_FILE (action->data), NULL))
9524 error = g_error_new_literal (FR_ERROR, FR_ERROR_GENERIC, _("Archive type not supported."));
9525 _archive_operation_completed (window, FR_ACTION_CREATING_NEW_ARCHIVE, error);
9526
9527 _g_error_free (error);
9528 }
9529 else
9530 fr_window_archive_open (window, G_FILE (action->data), GTK_WINDOW (window));
9531 break;
9532
9533 case FR_BATCH_ACTION_ADD:
9534 debug (DEBUG_INFO, "[BATCH] ADD\n");
9535
9536 fr_window_archive_add_dropped_items (window, (GList *) action->data);
9537 break;
9538
9539 case FR_BATCH_ACTION_REMOVE:
9540 debug (DEBUG_INFO, "[BATCH] REMOVE\n");
9541 fr_window_archive_remove (window, (GList *) action->data);
9542 break;
9543
9544 case FR_BATCH_ACTION_OPEN:
9545 debug (DEBUG_INFO, "[BATCH] OPEN\n");
9546
9547 dlg_batch_add_files (window, (GList *) action->data);
9548 break;
9549
9550 case FR_BATCH_ACTION_EXTRACT:
9551 debug (DEBUG_INFO, "[BATCH] EXTRACT\n");
9552
9553 edata = action->data;
9554 fr_window_archive_extract (window,
9555 edata->file_list,
9556 edata->destination,
9557 edata->base_dir,
9558 edata->skip_older,
9559 edata->overwrite,
9560 edata->junk_paths,
9561 edata->ask_to_open_destination);
9562 break;
9563
9564 case FR_BATCH_ACTION_EXTRACT_HERE:
9565 debug (DEBUG_INFO, "[BATCH] EXTRACT HERE\n");
9566
9567 edata = action->data;
9568 fr_window_archive_extract_here (window,
9569 edata->skip_older,
9570 edata->overwrite,
9571 edata->junk_paths);
9572 break;
9573
9574 case FR_BATCH_ACTION_EXTRACT_ASK_OPTIONS:
9575 debug (DEBUG_INFO, "[BATCH] EXTRACT ASK OPTIONS\n");
9576
9577 dlg_extract (NULL, window);
9578 break;
9579
9580 case FR_BATCH_ACTION_RENAME:
9581 debug (DEBUG_INFO, "[BATCH] RENAME\n");
9582
9583 rdata = action->data;
9584 rename_selection (window,
9585 rdata->path_to_rename,
9586 rdata->old_name,
9587 rdata->new_name,
9588 rdata->current_dir,
9589 rdata->is_dir,
9590 rdata->dir_in_archive,
9591 rdata->original_path);
9592 break;
9593
9594 case FR_BATCH_ACTION_PASTE:
9595 debug (DEBUG_INFO, "[BATCH] PASTE\n");
9596
9597 fr_window_paste_from_clipboard_data (window, (FrClipboardData*) action->data);
9598 break;
9599
9600 case FR_BATCH_ACTION_OPEN_FILES:
9601 debug (DEBUG_INFO, "[BATCH] OPEN FILES\n");
9602
9603 odata = action->data;
9604 fr_window_open_files (window, odata->file_list, odata->ask_application);
9605 break;
9606
9607 case FR_BATCH_ACTION_SAVE_AS:
9608 debug (DEBUG_INFO, "[BATCH] SAVE_AS\n");
9609
9610 cdata = action->data;
9611 fr_window_archive_save_as (window,
9612 cdata->file,
9613 cdata->mime_type,
9614 cdata->password,
9615 cdata->encrypt_header,
9616 cdata->volume_size);
9617 break;
9618
9619 case FR_BATCH_ACTION_TEST:
9620 debug (DEBUG_INFO, "[BATCH] TEST\n");
9621
9622 fr_window_archive_test (window);
9623 break;
9624
9625 case FR_BATCH_ACTION_ENCRYPT:
9626 debug (DEBUG_INFO, "[BATCH] ENCRYPT\n");
9627
9628 enc_data = action->data;
9629 fr_window_archive_encrypt (window,
9630 enc_data->password,
9631 enc_data->encrypt_header);
9632 break;
9633
9634
9635 case FR_BATCH_ACTION_CLOSE:
9636 debug (DEBUG_INFO, "[BATCH] CLOSE\n");
9637
9638 fr_window_archive_close (window);
9639 fr_window_batch_exec_next_action (window);
9640 break;
9641
9642 case FR_BATCH_ACTION_QUIT:
9643 debug (DEBUG_INFO, "[BATCH] QUIT\n");
9644
9645 g_signal_emit (window,
9646 fr_window_signals[READY],
9647 0,
9648 NULL);
9649
9650 if ((window->priv->progress_dialog != NULL) && (gtk_widget_get_parent (window->priv->progress_dialog) != GTK_WIDGET (window))) {
9651 gtk_widget_destroy (window->priv->progress_dialog);
9652 window->priv->progress_dialog = NULL;
9653 }
9654 gtk_widget_destroy (GTK_WIDGET (window));
9655 break;
9656
9657 default:
9658 break;
9659 }
9660 }
9661
9662
9663 void
fr_window_set_current_action(FrWindow * window,FrBatchActionType action_type,void * data,GFreeFunc free_func)9664 fr_window_set_current_action (FrWindow *window,
9665 FrBatchActionType action_type,
9666 void *data,
9667 GFreeFunc free_func)
9668 {
9669 FrBatchAction *action;
9670
9671 fr_window_reset_current_action (window);
9672
9673 action = &window->priv->current_action;
9674 action->type = action_type;
9675 action->data = data;
9676 action->free_func = free_func;
9677 }
9678
9679
9680 void
fr_window_reset_current_action(FrWindow * window)9681 fr_window_reset_current_action (FrWindow *window)
9682 {
9683 FrBatchAction *action = &window->priv->current_action;
9684
9685 if ((action->data != NULL) && (action->free_func != NULL))
9686 (*action->free_func) (action->data);
9687 action->type = FR_BATCH_ACTION_NONE;
9688 action->data = NULL;
9689 action->free_func = NULL;
9690 }
9691
9692
9693 void
fr_window_restart_current_action(FrWindow * window)9694 fr_window_restart_current_action (FrWindow *window)
9695 {
9696 fr_window_exec_batch_action (window, &window->priv->current_action);
9697 }
9698
9699
9700 void
fr_window_batch_append_action(FrWindow * window,FrBatchActionType action,void * data,GFreeFunc free_func)9701 fr_window_batch_append_action (FrWindow *window,
9702 FrBatchActionType action,
9703 void *data,
9704 GFreeFunc free_func)
9705 {
9706 FrBatchAction *a_desc;
9707
9708 g_return_if_fail (window != NULL);
9709
9710 a_desc = g_new0 (FrBatchAction, 1);
9711 a_desc->type = action;
9712 a_desc->data = data;
9713 a_desc->free_func = free_func;
9714
9715 window->priv->batch_action_list = g_list_append (window->priv->batch_action_list, a_desc);
9716 }
9717
9718
9719 void
fr_window_batch_replace_current_action(FrWindow * window,FrBatchActionType action,void * data,GFreeFunc free_func)9720 fr_window_batch_replace_current_action (FrWindow *window,
9721 FrBatchActionType action,
9722 void *data,
9723 GFreeFunc free_func)
9724 {
9725 FrBatchAction *a_desc;
9726
9727 g_return_if_fail (window != NULL);
9728 g_return_if_fail (window->priv->batch_action != NULL);
9729
9730 a_desc = g_new0 (FrBatchAction, 1);
9731 a_desc->type = action;
9732 a_desc->data = data;
9733 a_desc->free_func = free_func;
9734
9735 fr_batch_action_free ((FrBatchAction *) window->priv->batch_action->data);
9736 window->priv->batch_action->data = a_desc;
9737 }
9738
9739
9740 static void
fr_window_batch_exec_current_action(FrWindow * window)9741 fr_window_batch_exec_current_action (FrWindow *window)
9742 {
9743 FrBatchAction *action;
9744
9745 if (window->priv->batch_action == NULL) {
9746 fr_window_free_batch_data (window);
9747 if (window->priv->reload_archive) {
9748 window->priv->reload_archive = FALSE;
9749 fr_window_archive_reload (window);
9750 }
9751 return;
9752 }
9753
9754 action = (FrBatchAction *) window->priv->batch_action->data;
9755 fr_window_exec_batch_action (window, action);
9756 }
9757
9758
9759 static void
fr_window_batch_exec_next_action(FrWindow * window)9760 fr_window_batch_exec_next_action (FrWindow *window)
9761 {
9762 if (window->priv->batch_action != NULL)
9763 window->priv->batch_action = g_list_next (window->priv->batch_action);
9764 else
9765 window->priv->batch_action = window->priv->batch_action_list;
9766 fr_window_batch_exec_current_action (window);
9767 }
9768
9769
9770 void
fr_window_batch_start(FrWindow * window)9771 fr_window_batch_start (FrWindow *window)
9772 {
9773 g_return_if_fail (window != NULL);
9774
9775 if (window->priv->batch_mode)
9776 return;
9777
9778 if (window->priv->batch_action_list == NULL)
9779 return;
9780
9781 if (window->priv->progress_dialog != NULL)
9782 gtk_window_set_title (GTK_WINDOW (window->priv->progress_dialog),
9783 window->priv->batch_title);
9784
9785 window->priv->batch_mode = TRUE;
9786 window->priv->batch_action = window->priv->batch_action_list;
9787 gtk_widget_hide (GTK_WIDGET (window));
9788
9789 fr_window_batch_exec_current_action (window);
9790 }
9791
9792
9793 void
fr_window_batch_stop(FrWindow * window)9794 fr_window_batch_stop (FrWindow *window)
9795 {
9796 if (! window->priv->batch_mode) {
9797 fr_window_free_batch_data (window);
9798 window->priv->reload_archive = FALSE;
9799 return;
9800 }
9801
9802 if (! window->priv->showing_error_dialog) {
9803 g_signal_emit (window,
9804 fr_window_signals[READY],
9805 0,
9806 NULL);
9807 gtk_widget_destroy (GTK_WIDGET (window));
9808 }
9809 }
9810
9811
9812 void
fr_window_batch_stop_with_error(FrWindow * window,FrAction action,FrErrorType error_type,const char * error_message)9813 fr_window_batch_stop_with_error (FrWindow *window,
9814 FrAction action,
9815 FrErrorType error_type,
9816 const char *error_message)
9817 {
9818 GError *error;
9819
9820 error = g_error_new_literal (FR_ERROR, error_type, error_message);
9821 _archive_operation_completed (window, action , error);
9822
9823 g_error_free (error);
9824 }
9825
9826
9827 void
fr_window_batch_resume(FrWindow * window)9828 fr_window_batch_resume (FrWindow *window)
9829 {
9830 fr_window_batch_exec_current_action (window);
9831 }
9832
9833
9834 gboolean
fr_window_is_batch_mode(FrWindow * window)9835 fr_window_is_batch_mode (FrWindow *window)
9836 {
9837 return window->priv->batch_mode;
9838 }
9839
9840
9841 FrBatchActionType
fr_window_batch_get_current_action_type(FrWindow * window)9842 fr_window_batch_get_current_action_type (FrWindow *window)
9843 {
9844 FrBatchAction *action;
9845
9846 if (! window->priv->batch_mode || (window->priv->batch_action == NULL))
9847 return FR_BATCH_ACTION_NONE;
9848
9849 action = (FrBatchAction *) window->priv->batch_action->data;
9850 if (action == NULL)
9851 return FR_BATCH_ACTION_NONE;
9852
9853 return action->type;
9854 }
9855
9856
9857 void
fr_window_batch_new(FrWindow * window,const char * title)9858 fr_window_batch_new (FrWindow *window,
9859 const char *title)
9860 {
9861 fr_window_free_batch_data (window);
9862 g_free (window->priv->batch_title);
9863 window->priv->batch_title = g_strdup (title);
9864 }
9865
9866
9867 const char *
fr_window_batch_get_title(FrWindow * window)9868 fr_window_batch_get_title (FrWindow *window)
9869 {
9870 return window->priv->batch_title;
9871 }
9872
9873
9874 void
fr_window_batch__extract_here(FrWindow * window,GFile * archive,gboolean ask_to_open_destination)9875 fr_window_batch__extract_here (FrWindow *window,
9876 GFile *archive,
9877 gboolean ask_to_open_destination)
9878 {
9879 g_return_if_fail (window != NULL);
9880 g_return_if_fail (archive != NULL);
9881
9882 fr_window_batch_append_action (window,
9883 FR_BATCH_ACTION_LOAD,
9884 g_object_ref (archive),
9885 (GFreeFunc) g_object_unref);
9886 fr_window_batch_append_action (window,
9887 FR_BATCH_ACTION_EXTRACT_HERE,
9888 extract_data_new (window,
9889 NULL,
9890 NULL,
9891 NULL,
9892 FALSE,
9893 FR_OVERWRITE_ASK,
9894 FALSE,
9895 ask_to_open_destination,
9896 TRUE),
9897 (GFreeFunc) extract_data_free);
9898 fr_window_batch_append_action (window,
9899 FR_BATCH_ACTION_CLOSE,
9900 NULL,
9901 NULL);
9902 }
9903
9904
9905 void
fr_window_batch__extract(FrWindow * window,GFile * archive,GFile * destination,gboolean ask_to_open_destination)9906 fr_window_batch__extract (FrWindow *window,
9907 GFile *archive,
9908 GFile *destination,
9909 gboolean ask_to_open_destination)
9910 {
9911 g_return_if_fail (window != NULL);
9912 g_return_if_fail (archive != NULL);
9913
9914 fr_window_batch_append_action (window,
9915 FR_BATCH_ACTION_LOAD,
9916 g_object_ref (archive),
9917 (GFreeFunc) g_object_unref);
9918 if (destination != NULL)
9919 fr_window_batch_append_action (window,
9920 FR_BATCH_ACTION_EXTRACT,
9921 extract_data_new (window,
9922 NULL,
9923 destination,
9924 NULL,
9925 FALSE,
9926 FR_OVERWRITE_ASK,
9927 FALSE,
9928 ask_to_open_destination,
9929 FALSE),
9930 (GFreeFunc) extract_data_free);
9931 else
9932 fr_window_batch_append_action (window,
9933 FR_BATCH_ACTION_EXTRACT_ASK_OPTIONS,
9934 NULL,
9935 NULL);
9936 fr_window_batch_append_action (window,
9937 FR_BATCH_ACTION_CLOSE,
9938 NULL,
9939 NULL);
9940 }
9941
9942
9943 void
fr_window_batch__add_files(FrWindow * window,GFile * archive,GList * file_list)9944 fr_window_batch__add_files (FrWindow *window,
9945 GFile *archive,
9946 GList *file_list)
9947 {
9948 window->priv->batch_adding_one_file = (file_list->next == NULL) && (_g_file_query_is_file (file_list->data));
9949
9950 if (archive != NULL)
9951 fr_window_batch_append_action (window,
9952 FR_BATCH_ACTION_LOAD,
9953 g_object_ref (archive),
9954 (GFreeFunc) g_object_unref);
9955 else
9956 fr_window_batch_append_action (window,
9957 FR_BATCH_ACTION_OPEN,
9958 _g_object_list_ref (file_list),
9959 (GFreeFunc) _g_object_list_unref);
9960 fr_window_batch_append_action (window,
9961 FR_BATCH_ACTION_ADD,
9962 _g_object_list_ref (file_list),
9963 (GFreeFunc) _g_object_list_unref);
9964 fr_window_batch_append_action (window,
9965 FR_BATCH_ACTION_CLOSE,
9966 NULL,
9967 NULL);
9968 }
9969
9970
9971 void
fr_window_dnd_extraction_finished(FrWindow * window,gboolean error)9972 fr_window_dnd_extraction_finished (FrWindow *window,
9973 gboolean error)
9974 {
9975 if (window->priv->dnd_extract_is_running == TRUE) {
9976 window->priv->dnd_extract_is_running = FALSE;
9977 window->priv->dnd_extract_finished_with_error = error;
9978 }
9979 }
9980
9981
9982 void
fr_window_extract_archive_and_continue(FrWindow * window,GList * file_list,GFile * destination,const char * base_dir,gboolean skip_older,FrOverwrite overwrite,gboolean junk_paths)9983 fr_window_extract_archive_and_continue (FrWindow *window,
9984 GList *file_list,
9985 GFile *destination,
9986 const char *base_dir,
9987 gboolean skip_older,
9988 FrOverwrite overwrite,
9989 gboolean junk_paths)
9990 {
9991 if (fr_window_batch_get_current_action_type (window) == FR_BATCH_ACTION_EXTRACT_ASK_OPTIONS) {
9992
9993 /* no need to ask the user the extract options again if the
9994 * action is re-executed (for example when asking the password) */
9995
9996 fr_window_batch_replace_current_action (window,
9997 FR_BATCH_ACTION_EXTRACT,
9998 extract_data_new (window,
9999 file_list,
10000 destination,
10001 base_dir,
10002 skip_older,
10003 FR_OVERWRITE_ASK,
10004 junk_paths,
10005 _fr_window_get_ask_to_open_destination (window),
10006 FALSE),
10007 (GFreeFunc) extract_data_free);
10008 fr_window_batch_resume (window);
10009 }
10010 else
10011 fr_window_archive_extract (window,
10012 file_list,
10013 destination,
10014 base_dir,
10015 skip_older,
10016 FR_OVERWRITE_ASK,
10017 junk_paths,
10018 _fr_window_get_ask_to_open_destination (window));
10019 }
10020