1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* nemo-view.c
4 *
5 * Copyright (C) 1999, 2000 Free Software Foundation
6 * Copyright (C) 2000, 2001 Eazel, Inc.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (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 GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street - Suite 500,
21 * Boston, MA 02110-1335, USA.
22 *
23 * Authors: Ettore Perazzoli,
24 * John Sullivan <sullivan@eazel.com>,
25 * Darin Adler <darin@bentspoon.com>,
26 * Pavel Cisler <pavel@eazel.com>,
27 * David Emory Watson <dwatson@cs.ucr.edu>
28 */
29
30 #include <config.h>
31
32 #include "nemo-view.h"
33
34 #include "nemo-actions.h"
35 #include "nemo-desktop-icon-view.h"
36 #include "nemo-error-reporting.h"
37 #include "nemo-list-view.h"
38 #include "nemo-mime-actions.h"
39 #include "nemo-previewer.h"
40 #include "nemo-properties-window.h"
41 #include "nemo-bookmark-list.h"
42 #include "nemo-directory-private.h"
43
44 #include <sys/stat.h>
45 #include <fcntl.h>
46
47 #include <gdk/gdkx.h>
48 #include <gdk/gdkkeysyms.h>
49 #include <gtk/gtk.h>
50 #include <glib.h>
51 #include <glib/gi18n.h>
52 #include <glib/gstdio.h>
53 #include <gio/gio.h>
54 #include <math.h>
55
56 #include <eel/eel-glib-extensions.h>
57 #include <eel/eel-gnome-extensions.h>
58 #include <eel/eel-gtk-extensions.h>
59 #include <eel/eel-stock-dialogs.h>
60 #include <eel/eel-string.h>
61 #include <eel/eel-vfs-extensions.h>
62
63 #include <libnemo-extension/nemo-menu-provider.h>
64 #include <libnemo-private/nemo-bookmark.h>
65 #include <libnemo-private/nemo-clipboard.h>
66 #include <libnemo-private/nemo-clipboard-monitor.h>
67 #include <libnemo-private/nemo-desktop-icon-file.h>
68 #include <libnemo-private/nemo-desktop-directory.h>
69 #include <libnemo-private/nemo-search-directory.h>
70 #include <libnemo-private/nemo-directory.h>
71 #include <libnemo-private/nemo-dnd.h>
72 #include <libnemo-private/nemo-file-attributes.h>
73 #include <libnemo-private/nemo-file-changes-queue.h>
74 #include <libnemo-private/nemo-file-dnd.h>
75 #include <libnemo-private/nemo-file-operations.h>
76 #include <libnemo-private/nemo-file-utilities.h>
77 #include <libnemo-private/nemo-file-private.h>
78 #include <libnemo-private/nemo-global-preferences.h>
79 #include <libnemo-private/nemo-link.h>
80 #include <libnemo-private/nemo-metadata.h>
81 #include <libnemo-private/nemo-recent.h>
82 #include <libnemo-private/nemo-module.h>
83 #include <libnemo-private/nemo-program-choosing.h>
84 #include <libnemo-private/nemo-trash-monitor.h>
85 #include <libnemo-private/nemo-ui-utilities.h>
86 #include <libnemo-private/nemo-signaller.h>
87 #include <libnemo-private/nemo-icon-names.h>
88 #include <libnemo-private/nemo-file-undo-manager.h>
89 #include <libnemo-private/nemo-action.h>
90 #include <libnemo-private/nemo-widget-action.h>
91 #include <libnemo-private/nemo-separator-action.h>
92 #include <libnemo-private/nemo-action-manager.h>
93 #include <libnemo-private/nemo-mime-application-chooser.h>
94
95 #define DEBUG_FLAG NEMO_DEBUG_DIRECTORY_VIEW
96 #include <libnemo-private/nemo-debug.h>
97
98 /* Minimum starting update inverval */
99 #define UPDATE_INTERVAL_MIN 200
100 /* Maximum update interval */
101 #define UPDATE_INTERVAL_MAX 2000
102 /* Amount of miliseconds the update interval is increased */
103 #define UPDATE_INTERVAL_INC 250
104 /* Interval at which the update interval is increased */
105 #define UPDATE_INTERVAL_TIMEOUT_INTERVAL 500
106 /* Milliseconds that have to pass without a change to reset the update interval */
107 #define UPDATE_INTERVAL_RESET 1000
108
109 #define SILENT_WINDOW_OPEN_LIMIT 5
110
111 #define DUPLICATE_HORIZONTAL_ICON_OFFSET 70
112 #define DUPLICATE_VERTICAL_ICON_OFFSET 30
113
114 #define MAX_QUEUED_UPDATES 250
115
116 #define NEMO_VIEW_MENU_PATH_OPEN_PLACEHOLDER "/MenuBar/File/Open Placeholder"
117 #define NEMO_VIEW_MENU_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER "/MenuBar/File/Open Placeholder/Open With/Applications Placeholder"
118 #define NEMO_VIEW_MENU_PATH_APPLICATIONS_PLACEHOLDER "/MenuBar/File/Open Placeholder/Applications Placeholder"
119 #define NEMO_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER "/MenuBar/File/Open Placeholder/Scripts/Scripts Placeholder"
120 #define NEMO_VIEW_MENU_PATH_ACTIONS_PLACEHOLDER "/MenuBar/File/Open Placeholder/ActionsPlaceholder"
121 #define NEMO_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER "/MenuBar/Edit/Extension Actions"
122 #define NEMO_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER "/MenuBar/File/New Items Placeholder/New Documents/New Documents Placeholder"
123 #define NEMO_VIEW_MENU_PATH_OPEN "/MenuBar/File/Open Placeholder/Open"
124
125 #define NEMO_VIEW_POPUP_PATH_SELECTION "/selection"
126 #define NEMO_VIEW_POPUP_PATH_OPEN_PLACEHOLDER "/selection/Open Placeholder"
127 #define NEMO_VIEW_POPUP_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER "/selection/Open Placeholder/Open With/Applications Placeholder"
128 #define NEMO_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER "/selection/Open Placeholder/Applications Placeholder"
129 #define NEMO_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER "/selection/Open Placeholder/Scripts/Scripts Placeholder"
130 #define NEMO_VIEW_POPUP_PATH_ACTIONS_PLACEHOLDER "/selection/Open Placeholder/ActionsPlaceholder"
131 #define NEMO_VIEW_POPUP_PATH_EXTENSION_ACTIONS "/selection/Extension Actions"
132 #define NEMO_VIEW_POPUP_PATH_OPEN "/selection/Open Placeholder/Open"
133
134 #define NEMO_VIEW_POPUP_PATH_BACKGROUND "/background"
135 #define NEMO_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_PLACEHOLDER "/background/Before Zoom Items/New Object Items/Scripts/Scripts Placeholder"
136 #define NEMO_VIEW_POPUP_PATH_BACKGROUND_ACTIONS_PLACEHOLDER "/background/Before Zoom Items/New Object Items/ActionsPlaceholder"
137 #define NEMO_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER "/background/Before Zoom Items/New Object Items/New Documents/New Documents Placeholder"
138
139 #define NEMO_VIEW_POPUP_PATH_LOCATION "/location"
140
141 #define NEMO_VIEW_POPUP_PATH_BOOKMARK_MOVETO_ENTRIES_PLACEHOLDER "/selection/File Actions/MoveToMenu/BookmarkMoveToPlaceHolder"
142 #define NEMO_VIEW_POPUP_PATH_BOOKMARK_COPYTO_ENTRIES_PLACEHOLDER "/selection/File Actions/CopyToMenu/BookmarkCopyToPlaceHolder"
143 #define NEMO_VIEW_MENU_PATH_BOOKMARK_MOVETO_ENTRIES_PLACEHOLDER "/MenuBar/Edit/File Items Placeholder/MoveToMenu/BookmarkMoveToPlaceHolder"
144 #define NEMO_VIEW_MENU_PATH_BOOKMARK_COPYTO_ENTRIES_PLACEHOLDER "/MenuBar/Edit/File Items Placeholder/CopyToMenu/BookmarkCopyToPlaceHolder"
145
146 #define NEMO_VIEW_POPUP_PATH_PLACES_MOVETO_ENTRIES_PLACEHOLDER "/selection/File Actions/MoveToMenu/PlacesMoveToPlaceHolder"
147 #define NEMO_VIEW_POPUP_PATH_PLACES_COPYTO_ENTRIES_PLACEHOLDER "/selection/File Actions/CopyToMenu/PlacesCopyToPlaceHolder"
148 #define NEMO_VIEW_MENU_PATH_PLACES_MOVETO_ENTRIES_PLACEHOLDER "/MenuBar/Edit/File Items Placeholder/MoveToMenu/PlacesMoveToPlaceHolder"
149 #define NEMO_VIEW_MENU_PATH_PLACES_COPYTO_ENTRIES_PLACEHOLDER "/MenuBar/Edit/File Items Placeholder/CopyToMenu/PlacesCopyToPlaceHolder"
150
151 #define MAX_MENU_LEVELS 5
152 #define TEMPLATE_LIMIT 30
153
154 enum {
155 ADD_FILE,
156 BEGIN_FILE_CHANGES,
157 BEGIN_LOADING,
158 CLEAR,
159 END_FILE_CHANGES,
160 END_LOADING,
161 FILE_CHANGED,
162 LOAD_ERROR,
163 MOVE_COPY_ITEMS,
164 REMOVE_FILE,
165 ZOOM_LEVEL_CHANGED,
166 SELECTION_CHANGED,
167 TRASH,
168 DELETE,
169 LAST_SIGNAL
170 };
171
172 enum {
173 PROP_WINDOW_SLOT = 1,
174 PROP_SUPPORTS_ZOOMING,
175 NUM_PROPERTIES
176 };
177
178 static guint signals[LAST_SIGNAL] = { 0 };
179 static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
180
181 static GdkAtom copied_files_atom;
182
183 static char *scripts_directory_uri = NULL;
184 static int scripts_directory_uri_length;
185
186 struct NemoViewDetails
187 {
188 NemoWindow *window;
189 NemoWindowSlot *slot;
190 NemoDirectory *model;
191 NemoFile *directory_as_file;
192 NemoFile *location_popup_directory_as_file;
193 NemoBookmarkList *bookmarks;
194 GdkEventButton *location_popup_event;
195 GtkActionGroup *dir_action_group;
196 guint dir_merge_id;
197
198 gboolean supports_zooming;
199
200 GList *scripts_directory_list;
201 GtkActionGroup *scripts_action_group;
202 guint scripts_merge_id;
203
204 GtkActionGroup *actions_action_group;
205 guint actions_merge_id;
206 guint action_manager_changed_id;
207 NemoActionManager *action_manager;
208
209 GList *templates_directory_list;
210 GtkActionGroup *templates_action_group;
211 guint templates_merge_id;
212
213 GtkActionGroup *extensions_menu_action_group;
214 guint extensions_menu_merge_id;
215
216 guint display_selection_idle_id;
217 guint update_menus_timeout_id;
218 guint update_status_idle_id;
219 guint reveal_selection_idle_id;
220
221 guint display_pending_source_id;
222 guint changes_timeout_id;
223
224 guint update_interval;
225 guint64 last_queued;
226
227 guint files_added_handler_id;
228 guint files_changed_handler_id;
229 guint load_error_handler_id;
230 guint done_loading_handler_id;
231 guint file_changed_handler_id;
232
233 guint delayed_rename_file_id;
234
235 GList *new_added_files;
236 GList *new_changed_files;
237
238 GHashTable *non_ready_files;
239
240 GList *old_added_files;
241 GList *old_changed_files;
242
243 GList *pending_selection;
244
245 /* whether we are in the active slot */
246 gboolean active;
247
248 /* loading indicates whether this view has begun loading a directory.
249 * This flag should need not be set inside subclasses. NemoView automatically
250 * sets 'loading' to TRUE before it begins loading a directory's contents and to FALSE
251 * after it finishes loading the directory and its view.
252 */
253 gboolean loading;
254 gboolean menu_states_untrustworthy;
255 gboolean scripts_invalid;
256 gboolean templates_invalid;
257 gboolean actions_invalid;
258 gboolean reported_load_error;
259
260 /* flag to indicate that no file updates should be dispatched to subclasses.
261 * This is a workaround for bug #87701 that prevents the list view from
262 * losing focus when the underlying GtkTreeView is updated.
263 */
264 gboolean updates_frozen;
265 guint updates_queued;
266 gboolean needs_reload;
267
268 gboolean is_renaming;
269
270 gboolean sort_directories_first;
271
272 gboolean show_foreign_files;
273 gboolean show_hidden_files;
274 gboolean ignore_hidden_file_preferences;
275
276 gboolean batching_selection_level;
277 gboolean selection_changed_while_batched;
278
279 gboolean selection_was_removed;
280
281 gboolean metadata_for_directory_as_file_pending;
282 gboolean metadata_for_files_in_directory_pending;
283
284 gboolean selection_change_is_due_to_shell;
285 gboolean send_selection_change_to_shell;
286
287 GtkActionGroup *open_with_action_group;
288 guint open_with_merge_id;
289
290 GList *subdirectory_list;
291
292 guint copy_move_merge_ids[4];
293 GtkActionGroup *copy_move_action_groups[4];
294 guint bookmarks_changed_id;
295
296 GdkPoint context_menu_position;
297
298 gboolean showing_bookmarks_in_to_menus;
299 gboolean showing_places_in_to_menus;
300
301 GVolumeMonitor *volume_monitor;
302
303 GTimer *load_timer;
304 };
305
306 typedef struct {
307 NemoFile *file;
308 NemoDirectory *directory;
309 } FileAndDirectory;
310
311 /* forward declarations */
312
313 static gboolean display_selection_info_idle_callback (gpointer data);
314 static void nemo_view_duplicate_selection (NemoView *view,
315 GList *files,
316 GArray *item_locations);
317 static void nemo_view_create_links_for_files (NemoView *view,
318 GList *files,
319 GArray *item_locations);
320 static void trash_or_delete_files (GtkWindow *parent_window,
321 const GList *files,
322 gboolean delete_if_all_already_in_trash,
323 NemoView *view);
324 static void load_directory (NemoView *view,
325 NemoDirectory *directory);
326 static void nemo_view_merge_menus (NemoView *view);
327 static void nemo_view_unmerge_menus (NemoView *view);
328 static void nemo_view_init_show_hidden_files (NemoView *view);
329 static void clipboard_changed_callback (NemoClipboardMonitor *monitor,
330 NemoView *view);
331 static void open_one_in_new_window (gpointer data,
332 gpointer callback_data);
333 static void schedule_update_menus (NemoView *view);
334 static void schedule_update_menus_callback (gpointer callback_data);
335 static void remove_update_menus_timeout_callback (NemoView *view);
336 static void schedule_update_status (NemoView *view);
337 static void remove_update_status_idle_callback (NemoView *view);
338 static void reset_update_interval (NemoView *view);
339 static void schedule_idle_display_of_pending_files (NemoView *view);
340 static void unschedule_display_of_pending_files (NemoView *view);
341 static void disconnect_model_handlers (NemoView *view);
342 static void metadata_for_directory_as_file_ready_callback (NemoFile *file,
343 gpointer callback_data);
344 static void metadata_for_files_in_directory_ready_callback (NemoDirectory *directory,
345 GList *files,
346 gpointer callback_data);
347 static void nemo_view_trash_state_changed_callback (NemoTrashMonitor *trash,
348 gboolean state,
349 gpointer callback_data);
350 static void nemo_view_select_file (NemoView *view,
351 NemoFile *file);
352
353 static void update_templates_directory (NemoView *view);
354 static void user_dirs_changed (NemoView *view);
355
356 static gboolean file_list_all_are_folders (GList *file_list);
357
358 static void unschedule_pop_up_location_context_menu (NemoView *view);
359 static void disconnect_bookmark_signals (NemoView *view);
360 static void run_action_callback (NemoAction *action, gpointer callback_data);
361
362 G_DEFINE_TYPE (NemoView, nemo_view, GTK_TYPE_SCROLLED_WINDOW);
363 #define parent_class nemo_view_parent_class
364
365 /* virtual methods (public and non-public) */
366
367 /**
368 * nemo_view_merge_menus:
369 *
370 * Add this view's menus to the window's menu bar.
371 * @view: NemoView in question.
372 */
373 static void
nemo_view_merge_menus(NemoView * view)374 nemo_view_merge_menus (NemoView *view)
375 {
376 g_return_if_fail (NEMO_IS_VIEW (view));
377
378 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->merge_menus (view);
379 }
380
381 static void
nemo_view_unmerge_menus(NemoView * view)382 nemo_view_unmerge_menus (NemoView *view)
383 {
384 g_return_if_fail (NEMO_IS_VIEW (view));
385
386 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->unmerge_menus (view);}
387
388 static char *
real_get_backing_uri(NemoView * view)389 real_get_backing_uri (NemoView *view)
390 {
391 NemoDirectory *directory;
392 char *uri;
393
394 g_return_val_if_fail (NEMO_IS_VIEW (view), NULL);
395
396 if (view->details->model == NULL) {
397 return NULL;
398 }
399
400 directory = view->details->model;
401
402 if (NEMO_IS_DESKTOP_DIRECTORY (directory)) {
403 directory = nemo_desktop_directory_get_real_directory (NEMO_DESKTOP_DIRECTORY (directory));
404 } else {
405 nemo_directory_ref (directory);
406 }
407
408 uri = nemo_directory_get_uri (directory);
409
410 nemo_directory_unref (directory);
411
412 return uri;
413 }
414
415 /**
416 *
417 * nemo_view_get_backing_uri:
418 *
419 * Returns the URI for the target location of new directory, new file, new
420 * link and paste operations.
421 */
422
423 char *
nemo_view_get_backing_uri(NemoView * view)424 nemo_view_get_backing_uri (NemoView *view)
425 {
426 g_return_val_if_fail (NEMO_IS_VIEW (view), NULL);
427
428 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_backing_uri (view);
429 }
430
431 /**
432 * nemo_view_select_all:
433 *
434 * select all the items in the view
435 *
436 **/
437 static void
nemo_view_select_all(NemoView * view)438 nemo_view_select_all (NemoView *view)
439 {
440 g_return_if_fail (NEMO_IS_VIEW (view));
441
442 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->select_all (view);
443 }
444
445 static void
nemo_view_call_set_selection(NemoView * view,GList * selection)446 nemo_view_call_set_selection (NemoView *view, GList *selection)
447 {
448 g_return_if_fail (NEMO_IS_VIEW (view));
449
450 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->set_selection (view, selection);
451 }
452
453 static GList *
nemo_view_get_selection_for_file_transfer(NemoView * view)454 nemo_view_get_selection_for_file_transfer (NemoView *view)
455 {
456 g_return_val_if_fail (NEMO_IS_VIEW (view), NULL);
457
458 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection_for_file_transfer (view);
459 }
460
461 /**
462 * nemo_view_get_selected_icon_locations:
463 *
464 * return an array of locations of selected icons if available
465 * Return value: GArray of GdkPoints
466 *
467 **/
468 static GArray *
nemo_view_get_selected_icon_locations(NemoView * view)469 nemo_view_get_selected_icon_locations (NemoView *view)
470 {
471 g_return_val_if_fail (NEMO_IS_VIEW (view), NULL);
472
473 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selected_icon_locations (view);
474 }
475
476 static void
nemo_view_invert_selection(NemoView * view)477 nemo_view_invert_selection (NemoView *view)
478 {
479 g_return_if_fail (NEMO_IS_VIEW (view));
480
481 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->invert_selection (view);
482 }
483
484 /**
485 * nemo_view_reveal_selection:
486 *
487 * Scroll as necessary to reveal the selected items.
488 **/
489 static void
nemo_view_reveal_selection(NemoView * view)490 nemo_view_reveal_selection (NemoView *view)
491 {
492 g_return_if_fail (NEMO_IS_VIEW (view));
493
494 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->reveal_selection (view);
495 }
496
497 /**
498 * nemo_view_reset_to_defaults:
499 *
500 * set sorting order, zoom level, etc. to match defaults
501 *
502 **/
503 static void
nemo_view_reset_to_defaults(NemoView * view)504 nemo_view_reset_to_defaults (NemoView *view)
505 {
506 NemoFile *file;
507 NemoWindow *window;
508 g_return_if_fail (NEMO_IS_VIEW (view));
509
510 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->reset_to_defaults (view);
511
512 gboolean show_hidden = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES);
513
514 window = view->details->window;
515 if (show_hidden) {
516 nemo_window_set_hidden_files_mode (window, NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE);
517 } else {
518 nemo_window_set_hidden_files_mode (window, NEMO_WINDOW_SHOW_HIDDEN_FILES_DISABLE);
519 }
520
521 file = view->details->slot->viewed_file;
522 nemo_file_set_metadata(file, NEMO_METADATA_KEY_SHOW_THUMBNAILS, NULL, NULL);
523 nemo_file_set_metadata(file, NEMO_METADATA_KEY_DEFAULT_VIEW, NULL, NULL);
524 gtk_action_activate (gtk_action_group_get_action (nemo_window_get_main_action_group (window), NEMO_ACTION_RELOAD));
525 }
526
527 static gboolean
nemo_view_using_manual_layout(NemoView * view)528 nemo_view_using_manual_layout (NemoView *view)
529 {
530 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
531
532 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->using_manual_layout (view);
533 }
534
535 static guint
nemo_view_get_item_count(NemoView * view)536 nemo_view_get_item_count (NemoView *view)
537 {
538 g_return_val_if_fail (NEMO_IS_VIEW (view), 0);
539
540 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_item_count (view);
541 }
542
543 /**
544 * nemo_view_can_rename_file
545 *
546 * Determine whether a file can be renamed.
547 * @file: A NemoFile
548 *
549 * Return value: TRUE if @file can be renamed, FALSE otherwise.
550 *
551 **/
552 static gboolean
nemo_view_can_rename_file(NemoView * view,NemoFile * file)553 nemo_view_can_rename_file (NemoView *view, NemoFile *file)
554 {
555 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_rename_file (view, file);
556 }
557
558 static gboolean
nemo_view_is_read_only(NemoView * view)559 nemo_view_is_read_only (NemoView *view)
560 {
561 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
562
563 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_read_only (view);
564 }
565
566 static gboolean
showing_trash_directory(NemoView * view)567 showing_trash_directory (NemoView *view)
568 {
569 NemoFile *file;
570
571 file = nemo_view_get_directory_as_file (view);
572 if (file != NULL) {
573 return nemo_file_is_in_trash (file);
574 }
575 return FALSE;
576 }
577
578 static gboolean
showing_recent_directory(NemoView * view)579 showing_recent_directory (NemoView *view)
580 {
581 NemoFile *file;
582
583 file = nemo_view_get_directory_as_file (view);
584 if (file != NULL) {
585 return nemo_file_is_in_recent (file);
586 }
587 return FALSE;
588 }
589
590 static gboolean
showing_favorites_directory(NemoView * view)591 showing_favorites_directory (NemoView *view)
592 {
593 NemoFile *file;
594
595 file = nemo_view_get_directory_as_file (view);
596 if (file != NULL) {
597 return nemo_file_is_in_favorites (file);
598 }
599 return FALSE;
600 }
601
602 static gboolean
nemo_view_supports_creating_files(NemoView * view)603 nemo_view_supports_creating_files (NemoView *view)
604 {
605 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
606
607 return !nemo_view_is_read_only (view)
608 && !showing_trash_directory (view)
609 && !showing_recent_directory (view)
610 && !showing_favorites_directory (view);
611 }
612
613 static gboolean
nemo_view_is_empty(NemoView * view)614 nemo_view_is_empty (NemoView *view)
615 {
616 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
617
618 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_empty (view);
619 }
620
621 /**
622 * nemo_view_bump_zoom_level:
623 *
624 * bump the current zoom level by invoking the relevant subclass through the slot
625 *
626 **/
627 void
nemo_view_bump_zoom_level(NemoView * view,int zoom_increment)628 nemo_view_bump_zoom_level (NemoView *view,
629 int zoom_increment)
630 {
631 g_return_if_fail (NEMO_IS_VIEW (view));
632
633 if (!nemo_view_supports_zooming (view)) {
634 return;
635 }
636
637 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->bump_zoom_level (view, zoom_increment);
638 }
639
640 /**
641 * nemo_view_zoom_to_level:
642 *
643 * Set the current zoom level by invoking the relevant subclass through the slot
644 *
645 **/
646 void
nemo_view_zoom_to_level(NemoView * view,NemoZoomLevel zoom_level)647 nemo_view_zoom_to_level (NemoView *view,
648 NemoZoomLevel zoom_level)
649 {
650 g_return_if_fail (NEMO_IS_VIEW (view));
651
652 if (!nemo_view_supports_zooming (view)) {
653 return;
654 }
655
656 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->zoom_to_level (view, zoom_level);
657 }
658
659 NemoZoomLevel
nemo_view_get_zoom_level(NemoView * view)660 nemo_view_get_zoom_level (NemoView *view)
661 {
662 g_return_val_if_fail (NEMO_IS_VIEW (view), NEMO_ZOOM_LEVEL_STANDARD);
663
664 if (!nemo_view_supports_zooming (view)) {
665 return NEMO_ZOOM_LEVEL_STANDARD;
666 }
667
668 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_zoom_level (view);
669 }
670
671 /**
672 * nemo_view_can_zoom_in:
673 *
674 * Determine whether the view can be zoomed any closer.
675 * @view: The zoomable NemoView.
676 *
677 * Return value: TRUE if @view can be zoomed any closer, FALSE otherwise.
678 *
679 **/
680 gboolean
nemo_view_can_zoom_in(NemoView * view)681 nemo_view_can_zoom_in (NemoView *view)
682 {
683 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
684
685 if (!nemo_view_supports_zooming (view)) {
686 return FALSE;
687 }
688
689 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_in (view);
690 }
691
692 /**
693 * nemo_view_can_zoom_out:
694 *
695 * Determine whether the view can be zoomed any further away.
696 * @view: The zoomable NemoView.
697 *
698 * Return value: TRUE if @view can be zoomed any further away, FALSE otherwise.
699 *
700 **/
701 gboolean
nemo_view_can_zoom_out(NemoView * view)702 nemo_view_can_zoom_out (NemoView *view)
703 {
704 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
705
706 if (!nemo_view_supports_zooming (view)) {
707 return FALSE;
708 }
709
710 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_out (view);
711 }
712
713 gboolean
nemo_view_supports_zooming(NemoView * view)714 nemo_view_supports_zooming (NemoView *view)
715 {
716 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
717
718 return view->details->supports_zooming;
719 }
720
721 /**
722 * nemo_view_restore_default_zoom_level:
723 *
724 * restore to the default zoom level by invoking the relevant subclass through the slot
725 *
726 **/
727 void
nemo_view_restore_default_zoom_level(NemoView * view)728 nemo_view_restore_default_zoom_level (NemoView *view)
729 {
730 g_return_if_fail (NEMO_IS_VIEW (view));
731
732 if (!nemo_view_supports_zooming (view)) {
733 return;
734 }
735
736 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->restore_default_zoom_level (view);
737 }
738
739 /*
740 static NemoZoomLevel
741 nemo_view_get_default_zoom_level (NemoView *view)
742 {
743 g_return_if_fail (NEMO_IS_VIEW (view));
744
745 if (!nemo_view_supports_zooming (view)) {
746 return -1;
747 }
748
749 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_default_zoom_level (view);
750 }
751 */
752
753 const char *
nemo_view_get_view_id(NemoView * view)754 nemo_view_get_view_id (NemoView *view)
755 {
756 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_view_id (view);
757 }
758
759 char *
nemo_view_get_first_visible_file(NemoView * view)760 nemo_view_get_first_visible_file (NemoView *view)
761 {
762 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_first_visible_file (view);
763 }
764
765 void
nemo_view_scroll_to_file(NemoView * view,const char * uri)766 nemo_view_scroll_to_file (NemoView *view,
767 const char *uri)
768 {
769 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->scroll_to_file (view, uri);
770 }
771
772 /**
773 * nemo_view_get_selection:
774 *
775 * Get a list of NemoFile pointers that represents the
776 * currently-selected items in this view. Subclasses must override
777 * the signal handler for the 'get_selection' signal. Callers are
778 * responsible for g_free-ing the list (but not its data).
779 * @view: NemoView whose selected items are of interest.
780 *
781 * Return value: GList of NemoFile pointers representing the selection.
782 *
783 **/
784 GList *
nemo_view_get_selection(NemoView * view)785 nemo_view_get_selection (NemoView *view)
786 {
787 g_return_val_if_fail (NEMO_IS_VIEW (view), NULL);
788
789 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection (view);
790 }
791
792 /**
793 * nemo_view_peek_selection:
794 *
795 * Get a list of NemoFile pointers that represents the
796 * currently-selected items in this view. Subclasses must override
797 * the signal handler for the 'peek_selection' signal. The returned list
798 * is owned by the view's icon container and should not be freed.
799 * @view: NemoView whose selected items are of interest.
800 *
801 * Return value: GList of NemoFile pointers representing the selection.
802 *
803 **/
804 GList *
nemo_view_peek_selection(NemoView * view)805 nemo_view_peek_selection (NemoView *view)
806 {
807 g_return_val_if_fail (NEMO_IS_VIEW (view), NULL);
808
809 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->peek_selection (view);
810 }
811
812 // int
813 // nemo_view_get_selection_count (NemoView *view)
814 // {
815 // g_return_val_if_fail (NEMO_IS_VIEW (view), 0);
816
817 // return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection_count (view);
818 // }
819
820 /**
821 * nemo_view_update_menus:
822 *
823 * Update the sensitivity and wording of dynamic menu items.
824 * @view: NemoView in question.
825 */
826 void
nemo_view_update_menus(NemoView * view)827 nemo_view_update_menus (NemoView *view)
828 {
829 g_return_if_fail (NEMO_IS_VIEW (view));
830
831 if (!view->details->active) {
832 return;
833 }
834
835 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->update_menus (view);
836
837 view->details->menu_states_untrustworthy = FALSE;
838 }
839
840 typedef struct {
841 GAppInfo *application;
842 GList *files;
843 NemoView *directory_view;
844 } ApplicationLaunchParameters;
845
846 typedef struct {
847 NemoFile *file;
848 NemoView *directory_view;
849 } ScriptLaunchParameters;
850
851 typedef struct {
852 NemoFile *file;
853 NemoView *directory_view;
854 } CreateTemplateParameters;
855
856 typedef struct {
857 NemoView *view;
858 char *dest_uri;
859 } BookmarkCallbackData;
860
861
862 static BookmarkCallbackData *
bookmark_callback_data_new(NemoView * view,gchar * uri)863 bookmark_callback_data_new (NemoView *view,
864 gchar *uri)
865 {
866 BookmarkCallbackData *result;
867
868 result = g_new0 (BookmarkCallbackData, 1);
869 result->view = view;
870 result->dest_uri = g_strdup(uri);
871 return result;
872 }
873
874 static void
bookmark_callback_data_free(BookmarkCallbackData * data)875 bookmark_callback_data_free (BookmarkCallbackData *data)
876 {
877 g_free ((char *)data->dest_uri);
878 g_free (data);
879 }
880
881 static ApplicationLaunchParameters *
application_launch_parameters_new(GAppInfo * application,GList * files,NemoView * directory_view)882 application_launch_parameters_new (GAppInfo *application,
883 GList *files,
884 NemoView *directory_view)
885 {
886 ApplicationLaunchParameters *result;
887
888 result = g_new0 (ApplicationLaunchParameters, 1);
889 result->application = g_object_ref (application);
890 result->files = nemo_file_list_copy (files);
891
892 if (directory_view != NULL) {
893 g_object_ref (directory_view);
894 result->directory_view = directory_view;
895 }
896
897 return result;
898 }
899
900 static void
application_launch_parameters_free(ApplicationLaunchParameters * parameters)901 application_launch_parameters_free (ApplicationLaunchParameters *parameters)
902 {
903 g_object_unref (parameters->application);
904 nemo_file_list_free (parameters->files);
905
906 if (parameters->directory_view != NULL) {
907 g_object_unref (parameters->directory_view);
908 }
909
910 g_free (parameters);
911 }
912
913 static GList *
file_and_directory_list_to_files(GList * fad_list)914 file_and_directory_list_to_files (GList *fad_list)
915 {
916 GList *res, *l;
917 FileAndDirectory *fad;
918
919 res = NULL;
920 for (l = fad_list; l != NULL; l = l->next) {
921 fad = l->data;
922 res = g_list_prepend (res, nemo_file_ref (fad->file));
923 }
924 return g_list_reverse (res);
925 }
926
927
928 static GList *
file_and_directory_list_from_files(NemoDirectory * directory,GList * files)929 file_and_directory_list_from_files (NemoDirectory *directory, GList *files)
930 {
931 GList *res, *l;
932 FileAndDirectory *fad;
933
934 res = NULL;
935 for (l = files; l != NULL; l = l->next) {
936 fad = g_new0 (FileAndDirectory, 1);
937 fad->directory = nemo_directory_ref (directory);
938 fad->file = nemo_file_ref (l->data);
939 res = g_list_prepend (res, fad);
940 }
941 return g_list_reverse (res);
942 }
943
944 static void
file_and_directory_free(FileAndDirectory * fad)945 file_and_directory_free (FileAndDirectory *fad)
946 {
947 nemo_directory_unref (fad->directory);
948 nemo_file_unref (fad->file);
949 g_free (fad);
950 }
951
952
953 static void
file_and_directory_list_free(GList * list)954 file_and_directory_list_free (GList *list)
955 {
956 GList *l;
957
958 for (l = list; l != NULL; l = l->next) {
959 file_and_directory_free (l->data);
960 }
961
962 g_list_free (list);
963 }
964
965 static gboolean
file_and_directory_equal(gconstpointer v1,gconstpointer v2)966 file_and_directory_equal (gconstpointer v1,
967 gconstpointer v2)
968 {
969 const FileAndDirectory *fad1, *fad2;
970 fad1 = v1;
971 fad2 = v2;
972
973 return (fad1->file == fad2->file &&
974 fad1->directory == fad2->directory);
975 }
976
977 static guint
file_and_directory_hash(gconstpointer v)978 file_and_directory_hash (gconstpointer v)
979 {
980 const FileAndDirectory *fad;
981
982 fad = v;
983 return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory);
984 }
985
986
987
988
989 static ScriptLaunchParameters *
script_launch_parameters_new(NemoFile * file,NemoView * directory_view)990 script_launch_parameters_new (NemoFile *file,
991 NemoView *directory_view)
992 {
993 ScriptLaunchParameters *result;
994
995 result = g_new0 (ScriptLaunchParameters, 1);
996 g_object_ref (directory_view);
997 result->directory_view = directory_view;
998 nemo_file_ref (file);
999 result->file = file;
1000
1001 return result;
1002 }
1003
1004 static void
script_launch_parameters_free(ScriptLaunchParameters * parameters)1005 script_launch_parameters_free (ScriptLaunchParameters *parameters)
1006 {
1007 g_object_unref (parameters->directory_view);
1008 nemo_file_unref (parameters->file);
1009 g_free (parameters);
1010 }
1011
1012 static CreateTemplateParameters *
create_template_parameters_new(NemoFile * file,NemoView * directory_view)1013 create_template_parameters_new (NemoFile *file,
1014 NemoView *directory_view)
1015 {
1016 CreateTemplateParameters *result;
1017
1018 result = g_new0 (CreateTemplateParameters, 1);
1019 g_object_ref (directory_view);
1020 result->directory_view = directory_view;
1021 nemo_file_ref (file);
1022 result->file = file;
1023
1024 return result;
1025 }
1026
1027 static void
create_templates_parameters_free(CreateTemplateParameters * parameters)1028 create_templates_parameters_free (CreateTemplateParameters *parameters)
1029 {
1030 g_object_unref (parameters->directory_view);
1031 nemo_file_unref (parameters->file);
1032 g_free (parameters);
1033 }
1034
1035 NemoWindow *
nemo_view_get_nemo_window(NemoView * view)1036 nemo_view_get_nemo_window (NemoView *view)
1037 {
1038 g_assert (view->details->window != NULL);
1039
1040 return view->details->window;
1041 }
1042
1043 NemoWindowSlot *
nemo_view_get_nemo_window_slot(NemoView * view)1044 nemo_view_get_nemo_window_slot (NemoView *view)
1045 {
1046 g_assert (view->details->slot != NULL);
1047
1048 return view->details->slot;
1049 }
1050
1051 /* Returns the GtkWindow that this directory view occupies, or NULL
1052 * if at the moment this directory view is not in a GtkWindow or the
1053 * GtkWindow cannot be determined. Primarily used for parenting dialogs.
1054 */
1055 static GtkWindow *
nemo_view_get_containing_window(NemoView * view)1056 nemo_view_get_containing_window (NemoView *view)
1057 {
1058 GtkWidget *window;
1059
1060 g_assert (NEMO_IS_VIEW (view));
1061
1062 window = gtk_widget_get_ancestor (GTK_WIDGET (view), GTK_TYPE_WINDOW);
1063 if (window == NULL) {
1064 return NULL;
1065 }
1066
1067 return GTK_WINDOW (window);
1068 }
1069
1070 static gboolean
nemo_view_confirm_multiple(GtkWindow * parent_window,int count,gboolean tabs)1071 nemo_view_confirm_multiple (GtkWindow *parent_window,
1072 int count,
1073 gboolean tabs)
1074 {
1075 GtkDialog *dialog;
1076 char *prompt;
1077 char *detail;
1078 int response;
1079
1080 if (count <= SILENT_WINDOW_OPEN_LIMIT) {
1081 return TRUE;
1082 }
1083
1084 prompt = _("Are you sure you want to open all files?");
1085 if (tabs) {
1086 detail = g_strdup_printf (ngettext("This will open %'d separate tab.",
1087 "This will open %'d separate tabs.", count), count);
1088 } else {
1089 detail = g_strdup_printf (ngettext("This will open %'d separate window.",
1090 "This will open %'d separate windows.", count), count);
1091 }
1092 dialog = eel_show_yes_no_dialog (prompt, detail,
1093 GTK_STOCK_OK, GTK_STOCK_CANCEL,
1094 parent_window);
1095 g_free (detail);
1096
1097 response = gtk_dialog_run (dialog);
1098 gtk_widget_destroy (GTK_WIDGET (dialog));
1099
1100 return response == GTK_RESPONSE_YES;
1101 }
1102
1103 static gboolean
selection_contains_one_item_in_menu_callback(NemoView * view,GList * selection)1104 selection_contains_one_item_in_menu_callback (NemoView *view, GList *selection)
1105 {
1106 if (g_list_length (selection) == 1) {
1107 return TRUE;
1108 }
1109
1110 /* If we've requested a menu update that hasn't yet occurred, then
1111 * the mismatch here doesn't surprise us, and we won't complain.
1112 * Otherwise, we will complain.
1113 */
1114 if (!view->details->menu_states_untrustworthy) {
1115 g_warning ("Expected one selected item, found %'d. No action will be performed.",
1116 g_list_length (selection));
1117 }
1118
1119 return FALSE;
1120 }
1121
1122 static gboolean
selection_not_empty_in_menu_callback(NemoView * view,GList * selection)1123 selection_not_empty_in_menu_callback (NemoView *view, GList *selection)
1124 {
1125 if (selection != NULL) {
1126 return TRUE;
1127 }
1128
1129 /* If we've requested a menu update that hasn't yet occurred, then
1130 * the mismatch here doesn't surprise us, and we won't complain.
1131 * Otherwise, we will complain.
1132 */
1133 if (!view->details->menu_states_untrustworthy) {
1134 g_warning ("Empty selection found when selection was expected. No action will be performed.");
1135 }
1136
1137 return FALSE;
1138 }
1139
1140 static char *
get_view_directory(NemoView * view)1141 get_view_directory (NemoView *view)
1142 {
1143 char *uri, *path;
1144 GFile *f;
1145
1146 uri = nemo_directory_get_uri (view->details->model);
1147 if (eel_uri_is_desktop (uri)) {
1148 g_free (uri);
1149 uri = nemo_get_desktop_directory_uri ();
1150
1151 }
1152 f = g_file_new_for_uri (uri);
1153 path = g_file_get_path (f);
1154 g_object_unref (f);
1155 g_free (uri);
1156
1157 return path;
1158 }
1159
1160 static gboolean
get_is_desktop_view(NemoView * view)1161 get_is_desktop_view (NemoView *view)
1162 {
1163 gchar *uri;
1164 gboolean ret;
1165
1166 uri = nemo_directory_get_uri (view->details->model);
1167 ret = eel_uri_is_desktop (uri);
1168 g_free (uri);
1169
1170 return ret;
1171 }
1172
1173 void
nemo_view_preview_files(NemoView * view,GList * files,GArray * locations)1174 nemo_view_preview_files (NemoView *view,
1175 GList *files,
1176 GArray *locations)
1177 {
1178 NemoPreviewer *previewer;
1179 gchar *uri;
1180 guint xid;
1181 GtkWidget *toplevel;
1182
1183 previewer = nemo_previewer_get_singleton ();
1184 uri = nemo_file_get_uri (files->data);
1185 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
1186
1187 xid = gdk_x11_window_get_xid (gtk_widget_get_window (toplevel));
1188 nemo_previewer_call_show_file (previewer, uri, xid, TRUE);
1189
1190 g_free (uri);
1191 }
1192
1193 void
nemo_view_activate_files(NemoView * view,GList * files,NemoWindowOpenFlags flags,gboolean confirm_multiple)1194 nemo_view_activate_files (NemoView *view,
1195 GList *files,
1196 NemoWindowOpenFlags flags,
1197 gboolean confirm_multiple)
1198 {
1199 char *path;
1200
1201 path = get_view_directory (view);
1202 nemo_mime_activate_files (nemo_view_get_containing_window (view),
1203 view->details->slot,
1204 files,
1205 path,
1206 flags,
1207 confirm_multiple);
1208
1209 if (get_is_desktop_view(view)) {
1210 nemo_view_set_selection(view, NULL);
1211 }
1212
1213 g_free (path);
1214 }
1215
1216 void
nemo_view_activate_file(NemoView * view,NemoFile * file,NemoWindowOpenFlags flags)1217 nemo_view_activate_file (NemoView *view,
1218 NemoFile *file,
1219 NemoWindowOpenFlags flags)
1220 {
1221 char *path;
1222
1223 path = get_view_directory (view);
1224 nemo_mime_activate_file (nemo_view_get_containing_window (view),
1225 view->details->slot,
1226 file,
1227 path,
1228 flags);
1229
1230 if (get_is_desktop_view(view)) {
1231 nemo_view_set_selection(view, NULL);
1232 }
1233
1234 g_free (path);
1235 }
1236
1237 static void
action_open_callback(GtkAction * action,gpointer callback_data)1238 action_open_callback (GtkAction *action,
1239 gpointer callback_data)
1240 {
1241 GList *selection;
1242 NemoView *view;
1243
1244 view = NEMO_VIEW (callback_data);
1245
1246 selection = nemo_view_get_selection (view);
1247 nemo_view_activate_files (view,
1248 selection,
1249 0,
1250 TRUE);
1251 nemo_file_list_free (selection);
1252 }
1253
1254 static void
action_open_close_parent_callback(GtkAction * action,gpointer callback_data)1255 action_open_close_parent_callback (GtkAction *action,
1256 gpointer callback_data)
1257 {
1258 GList *selection;
1259 NemoView *view;
1260
1261 view = NEMO_VIEW (callback_data);
1262
1263 selection = nemo_view_get_selection (view);
1264 nemo_view_activate_files (view,
1265 selection,
1266 NEMO_WINDOW_OPEN_FLAG_CLOSE_BEHIND,
1267 TRUE);
1268 nemo_file_list_free (selection);
1269 }
1270
1271
1272 static void
action_open_alternate_callback(GtkAction * action,gpointer callback_data)1273 action_open_alternate_callback (GtkAction *action,
1274 gpointer callback_data)
1275 {
1276 NemoView *view;
1277 GList *selection;
1278 GtkWindow *window;
1279
1280 view = NEMO_VIEW (callback_data);
1281 selection = nemo_view_get_selection (view);
1282
1283 window = nemo_view_get_containing_window (view);
1284
1285 if (nemo_view_confirm_multiple (window, g_list_length (selection), FALSE)) {
1286 g_list_foreach (selection, open_one_in_new_window, view);
1287 }
1288
1289 nemo_file_list_free (selection);
1290 }
1291
1292 static void
action_open_new_tab_callback(GtkAction * action,gpointer callback_data)1293 action_open_new_tab_callback (GtkAction *action,
1294 gpointer callback_data)
1295 {
1296 NemoView *view;
1297 GList *selection;
1298 GtkWindow *window;
1299
1300 view = NEMO_VIEW (callback_data);
1301 selection = nemo_view_get_selection (view);
1302
1303 window = nemo_view_get_containing_window (view);
1304
1305 if (nemo_view_confirm_multiple (window, g_list_length (selection), TRUE)) {
1306 nemo_view_activate_files (view,
1307 selection,
1308 NEMO_WINDOW_OPEN_FLAG_NEW_TAB,
1309 FALSE);
1310 }
1311
1312 nemo_file_list_free (selection);
1313 }
1314
1315 static void
app_chooser_dialog_response_cb(GtkDialog * dialog,gint response_id,gpointer user_data)1316 app_chooser_dialog_response_cb (GtkDialog *dialog,
1317 gint response_id,
1318 gpointer user_data)
1319 {
1320 GtkWindow *parent_window;
1321 NemoFile *file;
1322 GAppInfo *info;
1323 GList files;
1324
1325 parent_window = user_data;
1326
1327 if (response_id != GTK_RESPONSE_OK) {
1328 gtk_widget_destroy (GTK_WIDGET (dialog));
1329 return;
1330 }
1331
1332 GtkWidget *content = gtk_dialog_get_content_area (dialog);
1333 GList *children = gtk_container_get_children (GTK_CONTAINER (content));
1334
1335 NemoMimeApplicationChooser *chooser = children->data;
1336
1337 g_list_free (children);
1338
1339 info = nemo_mime_application_chooser_get_info (chooser);
1340 file = nemo_file_get_by_uri (nemo_mime_application_chooser_get_uri (chooser));
1341
1342 g_signal_emit_by_name (nemo_signaller_get_current (), "mime_data_changed");
1343
1344 files.next = NULL;
1345 files.prev = NULL;
1346 files.data = file;
1347 nemo_launch_application (info, &files, parent_window);
1348
1349 gtk_widget_destroy (GTK_WIDGET (dialog));
1350 g_object_unref (info);
1351 }
1352
1353 static void
choose_program(NemoView * view,NemoFile * file)1354 choose_program (NemoView *view,
1355 NemoFile *file)
1356 {
1357 GtkWidget *dialog;
1358 GtkWidget *ok_button;
1359
1360 char *mime_type;
1361 char *uri = NULL;
1362 GList *uris = NULL;
1363
1364 g_assert (NEMO_IS_VIEW (view));
1365 g_assert (NEMO_IS_FILE (file));
1366
1367 mime_type = nemo_file_get_mime_type (file);
1368 uri = nemo_file_get_uri (file);
1369
1370 dialog = gtk_dialog_new_with_buttons (_("Open with"),
1371 nemo_view_get_containing_window (view),
1372 GTK_DIALOG_DESTROY_WITH_PARENT,
1373 GTK_STOCK_CANCEL,
1374 GTK_RESPONSE_CANCEL,
1375 NULL);
1376 ok_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
1377 GTK_STOCK_OK,
1378 GTK_RESPONSE_OK);
1379
1380 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
1381
1382 GtkWidget *chooser = nemo_mime_application_chooser_new (uri, uris, mime_type, ok_button);
1383
1384 GtkWidget *content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
1385
1386 gtk_box_pack_start (GTK_BOX (content), chooser, TRUE, TRUE, 0);
1387
1388 gtk_widget_show_all (dialog);
1389
1390 g_signal_connect_object (dialog, "response",
1391 G_CALLBACK (app_chooser_dialog_response_cb),
1392 nemo_view_get_containing_window (view), 0);
1393 }
1394
1395 static void
open_with_other_program(NemoView * view)1396 open_with_other_program (NemoView *view)
1397 {
1398 GList *selection;
1399
1400 g_assert (NEMO_IS_VIEW (view));
1401
1402 selection = nemo_view_get_selection (view);
1403
1404 if (selection_contains_one_item_in_menu_callback (view, selection)) {
1405 choose_program (view, NEMO_FILE (selection->data));
1406 }
1407
1408 nemo_file_list_free (selection);
1409 }
1410
1411 static void
action_other_application_callback(GtkAction * action,gpointer callback_data)1412 action_other_application_callback (GtkAction *action,
1413 gpointer callback_data)
1414 {
1415 g_assert (NEMO_IS_VIEW (callback_data));
1416
1417 open_with_other_program (NEMO_VIEW (callback_data));
1418 }
1419
1420 static void
trash_or_delete_selected_files(NemoView * view)1421 trash_or_delete_selected_files (NemoView *view)
1422 {
1423 GList *selection;
1424
1425 /* This might be rapidly called multiple times for the same selection
1426 * when using keybindings. So we remember if the current selection
1427 * was already removed (but the view doesn't know about it yet).
1428 */
1429 if (!view->details->selection_was_removed) {
1430 selection = nemo_view_get_selection_for_file_transfer (view);
1431
1432 if (selection == NULL) {
1433 return;
1434 }
1435
1436 trash_or_delete_files (nemo_view_get_containing_window (view),
1437 selection, TRUE,
1438 view);
1439 nemo_file_list_free (selection);
1440 view->details->selection_was_removed = TRUE;
1441 }
1442 }
1443
1444 static gboolean
real_trash(NemoView * view)1445 real_trash (NemoView *view)
1446 {
1447 GtkAction *action;
1448
1449 action = gtk_action_group_get_action (view->details->dir_action_group,
1450 NEMO_ACTION_TRASH);
1451 if ((gtk_action_get_sensitive (action) && gtk_action_get_visible (action)) ||
1452 (showing_favorites_directory (view) || showing_recent_directory (view))) {
1453 trash_or_delete_selected_files (view);
1454 return TRUE;
1455 }
1456 return FALSE;
1457 }
1458
1459 static void
action_trash_callback(GtkAction * action,gpointer callback_data)1460 action_trash_callback (GtkAction *action,
1461 gpointer callback_data)
1462 {
1463 trash_or_delete_selected_files (NEMO_VIEW (callback_data));
1464 }
1465
1466 static void
delete_selected_files(NemoView * view)1467 delete_selected_files (NemoView *view)
1468 {
1469 GList *selection;
1470 GList *node;
1471 GList *locations;
1472
1473 selection = nemo_view_get_selection_for_file_transfer (view);
1474 if (selection == NULL) {
1475 return;
1476 }
1477
1478 locations = NULL;
1479 for (node = selection; node != NULL; node = node->next) {
1480 locations = g_list_prepend (locations,
1481 nemo_file_get_location ((NemoFile *) node->data));
1482 }
1483 locations = g_list_reverse (locations);
1484
1485 nemo_file_operations_delete (locations, nemo_view_get_containing_window (view), NULL, NULL);
1486
1487 g_list_free_full (locations, g_object_unref);
1488 nemo_file_list_free (selection);
1489 }
1490
1491 static void
action_delete_callback(GtkAction * action,gpointer callback_data)1492 action_delete_callback (GtkAction *action,
1493 gpointer callback_data)
1494 {
1495 delete_selected_files (NEMO_VIEW (callback_data));
1496 }
1497
1498 static void
action_restore_from_trash_callback(GtkAction * action,gpointer callback_data)1499 action_restore_from_trash_callback (GtkAction *action,
1500 gpointer callback_data)
1501 {
1502 NemoView *view;
1503 GList *selection;
1504
1505 view = NEMO_VIEW (callback_data);
1506
1507 selection = nemo_view_get_selection_for_file_transfer (view);
1508 nemo_restore_files_from_trash (selection,
1509 nemo_view_get_containing_window (view));
1510
1511 nemo_file_list_free (selection);
1512
1513 }
1514
1515 static gboolean
real_delete(NemoView * view)1516 real_delete (NemoView *view)
1517 {
1518 GtkAction *action;
1519
1520 action = gtk_action_group_get_action (view->details->dir_action_group,
1521 NEMO_ACTION_DELETE);
1522 if (gtk_action_get_sensitive (action) &&
1523 gtk_action_get_visible (action)) {
1524 delete_selected_files (view);
1525 return TRUE;
1526 }
1527 return FALSE;
1528 }
1529
1530 static void
action_duplicate_callback(GtkAction * action,gpointer callback_data)1531 action_duplicate_callback (GtkAction *action,
1532 gpointer callback_data)
1533 {
1534 NemoView *view;
1535 GList *selection;
1536 GArray *selected_item_locations;
1537
1538 view = NEMO_VIEW (callback_data);
1539 selection = nemo_view_get_selection_for_file_transfer (view);
1540 if (selection_not_empty_in_menu_callback (view, selection)) {
1541 /* FIXME bugzilla.gnome.org 45061:
1542 * should change things here so that we use a get_icon_locations (view, selection).
1543 * Not a problem in this case but in other places the selection may change by
1544 * the time we go and retrieve the icon positions, relying on the selection
1545 * staying intact to ensure the right sequence and count of positions is fragile.
1546 */
1547 selected_item_locations = nemo_view_get_selected_icon_locations (view);
1548 nemo_view_duplicate_selection (view, selection, selected_item_locations);
1549 g_array_free (selected_item_locations, TRUE);
1550 }
1551
1552 nemo_file_list_free (selection);
1553 }
1554
1555 static void
action_create_link_callback(GtkAction * action,gpointer callback_data)1556 action_create_link_callback (GtkAction *action,
1557 gpointer callback_data)
1558 {
1559 NemoView *view;
1560 GList *selection;
1561 GArray *selected_item_locations;
1562
1563 g_assert (NEMO_IS_VIEW (callback_data));
1564
1565 view = NEMO_VIEW (callback_data);
1566 selection = nemo_view_get_selection (view);
1567 if (selection_not_empty_in_menu_callback (view, selection)) {
1568 selected_item_locations = nemo_view_get_selected_icon_locations (view);
1569 nemo_view_create_links_for_files (view, selection, selected_item_locations);
1570 g_array_free (selected_item_locations, TRUE);
1571 }
1572
1573 nemo_file_list_free (selection);
1574 }
1575
1576 static void
action_pin_unpin_file_callback(GtkAction * action,gpointer callback_data)1577 action_pin_unpin_file_callback (GtkAction *action,
1578 gpointer callback_data)
1579 {
1580 NemoView *view;
1581 GList *selection;
1582 gboolean to_pin;
1583
1584 g_assert (NEMO_IS_VIEW (callback_data));
1585
1586 view = NEMO_VIEW (callback_data);
1587
1588 selection = nemo_view_get_selection (view);
1589
1590 if (g_list_length (selection) < 1) {
1591 g_warning ("No selection to pin - why?");
1592 return;
1593 }
1594
1595 /* Apply pinning according to the current state of the first
1596 * selected file. */
1597 to_pin = !nemo_file_get_pinning (NEMO_FILE (selection->data));
1598
1599 if (selection_not_empty_in_menu_callback (view, selection)) {
1600 NemoFile *file;
1601 GList *iter;
1602
1603 for (iter = selection; iter != NULL; iter = iter->next) {
1604 file = NEMO_FILE (iter->data);
1605
1606 nemo_file_set_pinning (file, to_pin);
1607 }
1608 }
1609
1610 nemo_file_list_free (selection);
1611 }
1612
1613 static void
action_favorite_unfavorite_file_callback(GtkAction * action,gpointer callback_data)1614 action_favorite_unfavorite_file_callback (GtkAction *action,
1615 gpointer callback_data)
1616 {
1617 NemoView *view;
1618 GList *selection;
1619 gboolean to_favorite;
1620
1621 g_assert (NEMO_IS_VIEW (callback_data));
1622
1623 view = NEMO_VIEW (callback_data);
1624
1625 selection = nemo_view_get_selection (view);
1626
1627 if (g_list_length (selection) < 1) {
1628 g_warning ("Favorites - no selection - why?");
1629 return;
1630 }
1631
1632 /* Apply favorite according to the current state of the first
1633 * selected file. */
1634 to_favorite = !nemo_file_get_is_favorite (NEMO_FILE (selection->data));
1635
1636 if (selection_not_empty_in_menu_callback (view, selection)) {
1637 NemoFile *file;
1638 GList *iter;
1639
1640 for (iter = selection; iter != NULL; iter = iter->next) {
1641 file = NEMO_FILE (iter->data);
1642
1643 nemo_file_set_is_favorite (file, to_favorite);
1644 }
1645 }
1646
1647 nemo_file_list_free (selection);
1648 }
1649
1650 static void
action_select_all_callback(GtkAction * action,gpointer callback_data)1651 action_select_all_callback (GtkAction *action,
1652 gpointer callback_data)
1653 {
1654 g_assert (NEMO_IS_VIEW (callback_data));
1655
1656 nemo_view_select_all (callback_data);
1657 }
1658
1659 static void
action_invert_selection_callback(GtkAction * action,gpointer callback_data)1660 action_invert_selection_callback (GtkAction *action,
1661 gpointer callback_data)
1662 {
1663 g_assert (NEMO_IS_VIEW (callback_data));
1664
1665 nemo_view_invert_selection (callback_data);
1666 }
1667
1668 static void
pattern_select_response_cb(GtkWidget * dialog,int response,gpointer user_data)1669 pattern_select_response_cb (GtkWidget *dialog, int response, gpointer user_data)
1670 {
1671 NemoView *view;
1672 NemoDirectory *directory;
1673 GtkWidget *entry;
1674 GList *selection;
1675 GError *error;
1676
1677 view = NEMO_VIEW (user_data);
1678
1679 switch (response) {
1680 case GTK_RESPONSE_OK :
1681 entry = g_object_get_data (G_OBJECT (dialog), "entry");
1682 directory = nemo_view_get_model (view);
1683 selection = nemo_directory_match_pattern (directory,
1684 gtk_entry_get_text (GTK_ENTRY (entry)));
1685
1686 if (selection) {
1687 nemo_view_call_set_selection (view, selection);
1688 nemo_file_list_free (selection);
1689
1690 nemo_view_reveal_selection(view);
1691 }
1692 /* fall through */
1693 case GTK_RESPONSE_NONE :
1694 case GTK_RESPONSE_DELETE_EVENT :
1695 case GTK_RESPONSE_CANCEL :
1696 gtk_widget_destroy (GTK_WIDGET (dialog));
1697 break;
1698 case GTK_RESPONSE_HELP :
1699 error = NULL;
1700 gtk_show_uri (gtk_window_get_screen (GTK_WINDOW (dialog)),
1701 "help:gnome-help/files-select",
1702 gtk_get_current_event_time (), &error);
1703 if (error) {
1704 eel_show_error_dialog (_("There was an error displaying help."), error->message,
1705 GTK_WINDOW (dialog));
1706 g_error_free (error);
1707 }
1708 break;
1709 default :
1710 g_assert_not_reached ();
1711 }
1712 }
1713
1714 static void
select_pattern(NemoView * view)1715 select_pattern (NemoView *view)
1716 {
1717 GtkWidget *dialog;
1718 GtkWidget *label;
1719 GtkWidget *example;
1720 GtkWidget *grid;
1721 GtkWidget *entry;
1722 char *example_pattern;
1723
1724 dialog = gtk_dialog_new_with_buttons (_("Select Items Matching"),
1725 nemo_view_get_containing_window (view),
1726 GTK_DIALOG_DESTROY_WITH_PARENT,
1727 GTK_STOCK_HELP,
1728 GTK_RESPONSE_HELP,
1729 GTK_STOCK_CANCEL,
1730 GTK_RESPONSE_CANCEL,
1731 GTK_STOCK_OK,
1732 GTK_RESPONSE_OK,
1733 NULL);
1734 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
1735 GTK_RESPONSE_OK);
1736 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1737 gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
1738
1739 label = gtk_label_new_with_mnemonic (_("_Pattern:"));
1740 gtk_widget_set_halign (label, GTK_ALIGN_START);
1741
1742 example = gtk_label_new (NULL);
1743 gtk_widget_set_halign (example, GTK_ALIGN_START);
1744 example_pattern = g_strdup_printf ("<b>%s</b><i>%s</i> ",
1745 _("Examples: "),
1746 "*.png, file\?\?.txt, pict*.\?\?\?");
1747 gtk_label_set_markup (GTK_LABEL (example), example_pattern);
1748 g_free (example_pattern);
1749
1750 entry = gtk_entry_new ();
1751 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
1752 gtk_widget_set_hexpand (entry, TRUE);
1753
1754 grid = gtk_grid_new ();
1755 g_object_set (grid,
1756 "orientation", GTK_ORIENTATION_VERTICAL,
1757 "border-width", 6,
1758 "row-spacing", 6,
1759 "column-spacing", 12,
1760 NULL);
1761
1762 gtk_container_add (GTK_CONTAINER (grid), label);
1763 gtk_grid_attach_next_to (GTK_GRID (grid), entry, label,
1764 GTK_POS_RIGHT, 1, 1);
1765 gtk_grid_attach_next_to (GTK_GRID (grid), example, entry,
1766 GTK_POS_BOTTOM, 1, 1);
1767
1768 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
1769 gtk_widget_show_all (grid);
1770 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid);
1771 g_object_set_data (G_OBJECT (dialog), "entry", entry);
1772 g_signal_connect (dialog, "response",
1773 G_CALLBACK (pattern_select_response_cb),
1774 view);
1775 gtk_widget_show_all (dialog);
1776 }
1777
1778 static void
action_select_pattern_callback(GtkAction * action,gpointer callback_data)1779 action_select_pattern_callback (GtkAction *action,
1780 gpointer callback_data)
1781 {
1782 g_assert (NEMO_IS_VIEW (callback_data));
1783
1784 select_pattern(callback_data);
1785 }
1786
1787 static void
action_reset_to_defaults_callback(GtkAction * action,gpointer callback_data)1788 action_reset_to_defaults_callback (GtkAction *action,
1789 gpointer callback_data)
1790 {
1791 g_assert (NEMO_IS_VIEW (callback_data));
1792
1793 nemo_view_reset_to_defaults (callback_data);
1794 }
1795
1796
1797 static void
hidden_files_mode_changed(NemoWindow * window,gpointer callback_data)1798 hidden_files_mode_changed (NemoWindow *window,
1799 gpointer callback_data)
1800 {
1801 NemoView *directory_view;
1802
1803 directory_view = NEMO_VIEW (callback_data);
1804
1805 nemo_view_init_show_hidden_files (directory_view);
1806 }
1807
1808 static void
action_save_search_callback(GtkAction * action,gpointer callback_data)1809 action_save_search_callback (GtkAction *action,
1810 gpointer callback_data)
1811 {
1812 NemoSearchDirectory *search;
1813 NemoView *directory_view;
1814
1815 directory_view = NEMO_VIEW (callback_data);
1816
1817 if (directory_view->details->model &&
1818 NEMO_IS_SEARCH_DIRECTORY (directory_view->details->model)) {
1819 search = NEMO_SEARCH_DIRECTORY (directory_view->details->model);
1820 nemo_search_directory_save_search (search);
1821
1822 /* Save search is disabled */
1823 schedule_update_menus (directory_view);
1824 }
1825 }
1826
1827 static void
query_name_entry_changed_cb(GtkWidget * entry,GtkWidget * button)1828 query_name_entry_changed_cb (GtkWidget *entry, GtkWidget *button)
1829 {
1830 const char *text;
1831 gboolean sensitive;
1832
1833 text = gtk_entry_get_text (GTK_ENTRY (entry));
1834
1835 sensitive = (text != NULL) && (*text != 0);
1836
1837 gtk_widget_set_sensitive (button, sensitive);
1838 }
1839
1840
1841 static void
action_save_search_as_callback(GtkAction * action,gpointer callback_data)1842 action_save_search_as_callback (GtkAction *action,
1843 gpointer callback_data)
1844 {
1845 NemoView *directory_view;
1846 NemoSearchDirectory *search;
1847 GtkWidget *dialog, *grid, *label, *entry, *chooser, *save_button;
1848 const char *entry_text;
1849 char *filename, *filename_utf8, *dirname, *path, *uri;
1850 GFile *location;
1851
1852 directory_view = NEMO_VIEW (callback_data);
1853
1854 if (directory_view->details->model &&
1855 NEMO_IS_SEARCH_DIRECTORY (directory_view->details->model)) {
1856 search = NEMO_SEARCH_DIRECTORY (directory_view->details->model);
1857
1858 dialog = gtk_dialog_new_with_buttons (_("Save Search as"),
1859 nemo_view_get_containing_window (directory_view),
1860 0,
1861 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1862 NULL);
1863 save_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
1864 GTK_STOCK_SAVE, GTK_RESPONSE_OK);
1865 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
1866 GTK_RESPONSE_OK);
1867 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1868 gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
1869 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
1870
1871 grid = gtk_grid_new ();
1872 g_object_set (grid,
1873 "orientation", GTK_ORIENTATION_VERTICAL,
1874 "border-width", 5,
1875 "row-spacing", 6,
1876 "column-spacing", 12,
1877 NULL);
1878 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid, TRUE, TRUE, 0);
1879 gtk_widget_show (grid);
1880
1881 label = gtk_label_new_with_mnemonic (_("Search _name:"));
1882 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1883 gtk_container_add (GTK_CONTAINER (grid), label);
1884 gtk_widget_show (label);
1885
1886 entry = gtk_entry_new ();
1887 gtk_widget_set_hexpand (entry, TRUE);
1888 gtk_grid_attach_next_to (GTK_GRID (grid), entry, label,
1889 GTK_POS_RIGHT, 1, 1);
1890 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
1891 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
1892
1893 gtk_widget_set_sensitive (save_button, FALSE);
1894 g_signal_connect (entry, "changed",
1895 G_CALLBACK (query_name_entry_changed_cb), save_button);
1896
1897 gtk_widget_show (entry);
1898 label = gtk_label_new_with_mnemonic (_("_Folder:"));
1899 gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.5);
1900 gtk_container_add (GTK_CONTAINER (grid), label);
1901 gtk_widget_show (label);
1902
1903 chooser = gtk_file_chooser_button_new (_("Select Folder to Save Search In"),
1904 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
1905 gtk_widget_set_hexpand (chooser, TRUE);
1906 gtk_grid_attach_next_to (GTK_GRID (grid), chooser, label,
1907 GTK_POS_RIGHT, 1, 1);
1908 gtk_label_set_mnemonic_widget (GTK_LABEL (label), chooser);
1909 gtk_widget_show (chooser);
1910
1911 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
1912
1913 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
1914 g_get_home_dir ());
1915
1916 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1917 entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
1918 if (g_str_has_suffix (entry_text, NEMO_SAVED_SEARCH_EXTENSION)) {
1919 filename_utf8 = g_strdup (entry_text);
1920 } else {
1921 filename_utf8 = g_strconcat (entry_text, NEMO_SAVED_SEARCH_EXTENSION, NULL);
1922 }
1923
1924 filename = g_filename_from_utf8 (filename_utf8, -1, NULL, NULL, NULL);
1925 g_free (filename_utf8);
1926
1927 dirname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
1928
1929 path = g_build_filename (dirname, filename, NULL);
1930 g_free (filename);
1931 g_free (dirname);
1932
1933 uri = g_filename_to_uri (path, NULL, NULL);
1934 g_free (path);
1935
1936 nemo_search_directory_save_to_file (search, uri);
1937 location = g_file_new_for_uri (uri);
1938 nemo_file_changes_queue_file_added (location);
1939 g_object_unref (location);
1940 nemo_file_changes_consume_changes (TRUE);
1941 g_free (uri);
1942 }
1943
1944 gtk_widget_destroy (dialog);
1945 }
1946 }
1947
1948
1949 static void
action_empty_trash_callback(GtkAction * action,gpointer callback_data)1950 action_empty_trash_callback (GtkAction *action,
1951 gpointer callback_data)
1952 {
1953 g_assert (NEMO_IS_VIEW (callback_data));
1954
1955 nemo_file_operations_empty_trash (GTK_WIDGET (callback_data));
1956 }
1957
1958 typedef struct {
1959 NemoView *view;
1960 NemoFile *new_file;
1961 } RenameData;
1962
1963 static gboolean
delayed_rename_file_hack_callback(RenameData * data)1964 delayed_rename_file_hack_callback (RenameData *data)
1965 {
1966 NemoView *view;
1967 NemoFile *new_file;
1968
1969 view = data->view;
1970 new_file = data->new_file;
1971
1972 if (view->details->window != NULL &&
1973 view->details->active) {
1974 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->start_renaming_file (view, new_file, FALSE);
1975 nemo_view_reveal_selection (view);
1976 }
1977
1978 view->details->delayed_rename_file_id = 0;
1979 return FALSE;
1980 }
1981
1982 static void
delayed_rename_file_hack_removed(RenameData * data)1983 delayed_rename_file_hack_removed (RenameData *data)
1984 {
1985 g_object_unref (data->view);
1986 nemo_file_unref (data->new_file);
1987 g_free (data);
1988 }
1989
1990
1991 static void
rename_file(NemoView * view,NemoFile * new_file)1992 rename_file (NemoView *view, NemoFile *new_file)
1993 {
1994 RenameData *data;
1995
1996 /* HACK!!!!
1997 This is a work around bug in listview. After the rename is
1998 enabled we will get file changes due to info about the new
1999 file being read, which will cause the model to change. When
2000 the model changes GtkTreeView clears the editing. This hack just
2001 delays editing for some time to try to avoid this problem.
2002 A major problem is that the selection of the row causes us
2003 to load the slow mimetype for the file, which leads to a
2004 file_changed. So, before we delay we select the row.
2005 */
2006 if (NEMO_IS_LIST_VIEW (view)) {
2007 nemo_view_select_file (view, new_file);
2008
2009 data = g_new (RenameData, 1);
2010 data->view = g_object_ref (view);
2011 data->new_file = nemo_file_ref (new_file);
2012 if (view->details->delayed_rename_file_id != 0) {
2013 g_source_remove (view->details->delayed_rename_file_id);
2014 }
2015 view->details->delayed_rename_file_id =
2016 g_timeout_add_full (G_PRIORITY_DEFAULT,
2017 100, (GSourceFunc)delayed_rename_file_hack_callback,
2018 data, (GDestroyNotify) delayed_rename_file_hack_removed);
2019
2020 return;
2021 }
2022
2023 /* no need to select because start_renaming_file selects
2024 * nemo_view_select_file (view, new_file);
2025 */
2026 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->start_renaming_file (view, new_file, FALSE);
2027 nemo_view_reveal_selection (view);
2028 }
2029
2030 static void
reveal_newly_added_folder(NemoView * view,NemoFile * new_file,NemoDirectory * directory,GFile * target_location)2031 reveal_newly_added_folder (NemoView *view, NemoFile *new_file,
2032 NemoDirectory *directory, GFile *target_location)
2033 {
2034 GFile *location;
2035
2036 location = nemo_file_get_location (new_file);
2037 if (g_file_equal (location, target_location)) {
2038 g_signal_handlers_disconnect_by_func (view,
2039 G_CALLBACK (reveal_newly_added_folder),
2040 (void *) target_location);
2041 rename_file (view, new_file);
2042 }
2043 g_object_unref (location);
2044 }
2045
2046 typedef struct {
2047 NemoView *directory_view;
2048 GHashTable *added_locations;
2049 } NewFolderData;
2050
2051
2052 static void
track_newly_added_locations(NemoView * view,NemoFile * new_file,NemoDirectory * directory,gpointer user_data)2053 track_newly_added_locations (NemoView *view, NemoFile *new_file,
2054 NemoDirectory *directory, gpointer user_data)
2055 {
2056 NewFolderData *data;
2057
2058 data = user_data;
2059
2060 g_hash_table_insert (data->added_locations, nemo_file_get_location (new_file), NULL);
2061 }
2062
2063 static void
new_folder_done(GFile * new_folder,gboolean success,gpointer user_data)2064 new_folder_done (GFile *new_folder,
2065 gboolean success,
2066 gpointer user_data)
2067 {
2068 NemoView *directory_view;
2069 NemoFile *file;
2070 char screen_string[32];
2071 GdkScreen *screen;
2072 NewFolderData *data;
2073
2074 data = (NewFolderData *)user_data;
2075
2076 directory_view = data->directory_view;
2077
2078 if (directory_view == NULL) {
2079 goto fail;
2080 }
2081
2082 g_signal_handlers_disconnect_by_func (directory_view,
2083 G_CALLBACK (track_newly_added_locations),
2084 (void *) data);
2085
2086 if (new_folder == NULL) {
2087 goto fail;
2088 }
2089
2090 screen = gtk_widget_get_screen (GTK_WIDGET (directory_view));
2091 g_snprintf (screen_string, sizeof (screen_string), "%d", gdk_screen_get_number (screen));
2092
2093
2094 file = nemo_file_get (new_folder);
2095
2096 if (g_hash_table_lookup_extended (data->added_locations, new_folder, NULL, NULL)) {
2097 /* The file was already added */
2098 rename_file (directory_view, file);
2099 } else {
2100 /* We need to run after the default handler adds the folder we want to
2101 * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we
2102 * must use connect_after.
2103 */
2104 g_signal_connect_data (directory_view,
2105 "add_file",
2106 G_CALLBACK (reveal_newly_added_folder),
2107 g_object_ref (new_folder),
2108 (GClosureNotify)g_object_unref,
2109 G_CONNECT_AFTER);
2110 }
2111 nemo_file_unref (file);
2112
2113 fail:
2114 g_hash_table_destroy (data->added_locations);
2115
2116 if (data->directory_view != NULL) {
2117 g_object_remove_weak_pointer (G_OBJECT (data->directory_view),
2118 (gpointer *) &data->directory_view);
2119 }
2120
2121 g_free (data);
2122 }
2123
2124
2125 static NewFolderData *
new_folder_data_new(NemoView * directory_view)2126 new_folder_data_new (NemoView *directory_view)
2127 {
2128 NewFolderData *data;
2129
2130 data = g_new (NewFolderData, 1);
2131 data->directory_view = directory_view;
2132 data->added_locations = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal,
2133 g_object_unref, NULL);
2134 g_object_add_weak_pointer (G_OBJECT (data->directory_view),
2135 (gpointer *) &data->directory_view);
2136
2137 return data;
2138 }
2139
2140 static GdkPoint *
context_menu_to_file_operation_position(NemoView * view)2141 context_menu_to_file_operation_position (NemoView *view)
2142 {
2143 g_return_val_if_fail (NEMO_IS_VIEW (view), NULL);
2144
2145 if (nemo_view_using_manual_layout (view)
2146 && view->details->context_menu_position.x >= 0
2147 && view->details->context_menu_position.y >= 0) {
2148 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->widget_to_file_operation_position
2149 (view, &view->details->context_menu_position);
2150 return &view->details->context_menu_position;
2151 } else {
2152 return NULL;
2153 }
2154 }
2155
2156 void
nemo_view_new_folder(NemoView * view)2157 nemo_view_new_folder (NemoView *view)
2158 {
2159 char *parent_uri;
2160 NewFolderData *data;
2161 GdkPoint *pos;
2162
2163 data = new_folder_data_new (view);
2164
2165 g_signal_connect_data (view,
2166 "add_file",
2167 G_CALLBACK (track_newly_added_locations),
2168 data,
2169 (GClosureNotify)NULL,
2170 G_CONNECT_AFTER);
2171
2172 pos = context_menu_to_file_operation_position (view);
2173
2174 parent_uri = nemo_view_get_backing_uri (view);
2175 nemo_file_operations_new_folder (GTK_WIDGET (view),
2176 pos, parent_uri,
2177 new_folder_done, data);
2178
2179 g_free (parent_uri);
2180 }
2181
2182 static NewFolderData *
setup_new_folder_data(NemoView * directory_view)2183 setup_new_folder_data (NemoView *directory_view)
2184 {
2185 NewFolderData *data;
2186
2187 data = new_folder_data_new (directory_view);
2188
2189 g_signal_connect_data (directory_view,
2190 "add_file",
2191 G_CALLBACK (track_newly_added_locations),
2192 data,
2193 (GClosureNotify)NULL,
2194 G_CONNECT_AFTER);
2195
2196 return data;
2197 }
2198
2199 void
nemo_view_new_file_with_initial_contents(NemoView * view,const char * parent_uri,const char * filename,const char * initial_contents,int length,GdkPoint * pos)2200 nemo_view_new_file_with_initial_contents (NemoView *view,
2201 const char *parent_uri,
2202 const char *filename,
2203 const char *initial_contents,
2204 int length,
2205 GdkPoint *pos)
2206 {
2207 NewFolderData *data;
2208
2209 g_assert (parent_uri != NULL);
2210
2211 data = setup_new_folder_data (view);
2212
2213 if (pos == NULL) {
2214 pos = context_menu_to_file_operation_position (view);
2215 }
2216
2217 nemo_file_operations_new_file (GTK_WIDGET (view),
2218 pos, parent_uri, filename,
2219 initial_contents, length,
2220 new_folder_done, data);
2221 }
2222
2223 static void
nemo_view_new_file(NemoView * directory_view,const char * parent_uri,NemoFile * source)2224 nemo_view_new_file (NemoView *directory_view,
2225 const char *parent_uri,
2226 NemoFile *source)
2227 {
2228 GdkPoint *pos;
2229 NewFolderData *data;
2230 char *source_uri;
2231 char *container_uri;
2232
2233 container_uri = NULL;
2234 if (parent_uri == NULL) {
2235 container_uri = nemo_view_get_backing_uri (directory_view);
2236 g_assert (container_uri != NULL);
2237 }
2238
2239 if (source == NULL) {
2240 nemo_view_new_file_with_initial_contents (directory_view,
2241 parent_uri != NULL ? parent_uri : container_uri,
2242 NULL,
2243 NULL,
2244 0,
2245 NULL);
2246 g_free (container_uri);
2247 return;
2248 }
2249
2250 g_return_if_fail (nemo_file_is_local (source));
2251
2252 pos = context_menu_to_file_operation_position (directory_view);
2253
2254 data = setup_new_folder_data (directory_view);
2255
2256 source_uri = nemo_file_get_uri (source);
2257
2258 nemo_file_operations_new_file_from_template (GTK_WIDGET (directory_view),
2259 pos,
2260 parent_uri != NULL ? parent_uri : container_uri,
2261 NULL,
2262 source_uri,
2263 new_folder_done, data);
2264
2265 g_free (source_uri);
2266 g_free (container_uri);
2267 }
2268
2269 static void
action_new_folder_callback(GtkAction * action,gpointer callback_data)2270 action_new_folder_callback (GtkAction *action,
2271 gpointer callback_data)
2272 {
2273 g_assert (NEMO_IS_VIEW (callback_data));
2274
2275 nemo_view_new_folder (NEMO_VIEW (callback_data));
2276 }
2277
2278 static void
action_new_empty_file_callback(GtkAction * action,gpointer callback_data)2279 action_new_empty_file_callback (GtkAction *action,
2280 gpointer callback_data)
2281 {
2282 g_assert (NEMO_IS_VIEW (callback_data));
2283
2284 nemo_view_new_file (NEMO_VIEW (callback_data), NULL, NULL);
2285 }
2286
2287 static void
action_properties_callback(GtkAction * action,gpointer callback_data)2288 action_properties_callback (GtkAction *action,
2289 gpointer callback_data)
2290 {
2291 NemoView *view;
2292 GList *selection;
2293 GList *files;
2294
2295 g_assert (NEMO_IS_VIEW (callback_data));
2296
2297 view = NEMO_VIEW (callback_data);
2298 selection = nemo_view_get_selection (view);
2299 if (g_list_length (selection) == 0) {
2300 if (view->details->directory_as_file != NULL) {
2301 files = g_list_append (NULL, nemo_file_ref (view->details->directory_as_file));
2302
2303 nemo_properties_window_present (files, GTK_WIDGET (view), NULL);
2304
2305 nemo_file_list_free (files);
2306 }
2307 } else {
2308 nemo_properties_window_present (selection, GTK_WIDGET (view), NULL);
2309 }
2310 nemo_file_list_free (selection);
2311 }
2312
2313 static void
action_location_properties_callback(GtkAction * action,gpointer callback_data)2314 action_location_properties_callback (GtkAction *action,
2315 gpointer callback_data)
2316 {
2317 NemoView *view;
2318 GList *files;
2319
2320 g_assert (NEMO_IS_VIEW (callback_data));
2321
2322 view = NEMO_VIEW (callback_data);
2323 g_assert (NEMO_IS_FILE (view->details->location_popup_directory_as_file));
2324
2325 files = g_list_append (NULL, nemo_file_ref (view->details->location_popup_directory_as_file));
2326
2327 nemo_properties_window_present (files, GTK_WIDGET (view), NULL);
2328
2329 nemo_file_list_free (files);
2330 }
2331
2332 static gboolean
all_files_in_trash(GList * files)2333 all_files_in_trash (GList *files)
2334 {
2335 GList *node;
2336
2337 /* Result is ambiguous if called on NULL, so disallow. */
2338 g_return_val_if_fail (files != NULL, FALSE);
2339
2340 for (node = files; node != NULL; node = node->next) {
2341 if (!nemo_file_is_in_trash (NEMO_FILE (node->data))) {
2342 return FALSE;
2343 }
2344 }
2345
2346 return TRUE;
2347 }
2348
2349 static gboolean
all_selected_items_in_trash(NemoView * view,GList * selection)2350 all_selected_items_in_trash (NemoView *view, GList *selection)
2351 {
2352 gboolean result;
2353
2354 /* If the contents share a parent directory, we need only
2355 * check that parent directory. Otherwise we have to inspect
2356 * each selected item.
2357 */
2358
2359 result = (selection == NULL) ? FALSE : all_files_in_trash (selection);
2360
2361 return result;
2362 }
2363
2364 static void
click_policy_changed_callback(gpointer callback_data)2365 click_policy_changed_callback (gpointer callback_data)
2366 {
2367 NemoView *view;
2368
2369 view = NEMO_VIEW (callback_data);
2370
2371 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->click_policy_changed (view);
2372 }
2373
2374 static void
click_to_rename_changed_callback(gpointer callback_data)2375 click_to_rename_changed_callback (gpointer callback_data)
2376 {
2377 NemoView *view;
2378
2379 view = NEMO_VIEW (callback_data);
2380
2381 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->click_to_rename_mode_changed (view);
2382 }
2383
2384 static void
nemo_to_menu_preferences_changed_callback(NemoView * view)2385 nemo_to_menu_preferences_changed_callback (NemoView *view)
2386 {
2387 view->details->showing_bookmarks_in_to_menus = g_settings_get_boolean (nemo_preferences,
2388 NEMO_PREFERENCES_SHOW_BOOKMARKS_IN_TO_MENUS);
2389 view->details->showing_places_in_to_menus = g_settings_get_boolean (nemo_preferences,
2390 NEMO_PREFERENCES_SHOW_PLACES_IN_TO_MENUS);
2391 }
2392
2393 gboolean
nemo_view_should_sort_directories_first(NemoView * view)2394 nemo_view_should_sort_directories_first (NemoView *view)
2395 {
2396 return view->details->sort_directories_first;
2397 }
2398
2399 static void
sort_directories_first_changed_callback(gpointer callback_data)2400 sort_directories_first_changed_callback (gpointer callback_data)
2401 {
2402 NemoView *view;
2403 gboolean preference_value;
2404
2405 view = NEMO_VIEW (callback_data);
2406
2407 preference_value =
2408 g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST);
2409
2410 if (preference_value != view->details->sort_directories_first) {
2411 view->details->sort_directories_first = preference_value;
2412 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->sort_directories_first_changed (view);
2413 }
2414 }
2415
2416 static void
swap_delete_keybinding_changed_callback(gpointer callback_data)2417 swap_delete_keybinding_changed_callback (gpointer callback_data)
2418 {
2419 GtkBindingSet *binding_set = gtk_binding_set_find ("NemoView");
2420
2421 gboolean swap_keys = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SWAP_TRASH_DELETE);
2422
2423 gtk_binding_entry_remove (binding_set, GDK_KEY_Delete, 0);
2424 gtk_binding_entry_remove (binding_set, GDK_KEY_KP_Delete, 0);
2425 gtk_binding_entry_remove (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK);
2426 gtk_binding_entry_remove (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK);
2427
2428 if (swap_keys) {
2429 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0,
2430 "delete", 0);
2431 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0,
2432 "delete", 0);
2433 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK,
2434 "trash", 0);
2435 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK,
2436 "trash", 0);
2437 } else {
2438 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0,
2439 "trash", 0);
2440 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0,
2441 "trash", 0);
2442 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK,
2443 "delete", 0);
2444 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK,
2445 "delete", 0);
2446 }
2447 }
2448
2449 static gboolean
set_up_scripts_directory_global(void)2450 set_up_scripts_directory_global (void)
2451 {
2452 char *scripts_directory_path;
2453
2454 if (scripts_directory_uri != NULL) {
2455 return TRUE;
2456 }
2457
2458 scripts_directory_path = nemo_get_scripts_directory_path ();
2459
2460 if (g_mkdir_with_parents (scripts_directory_path, 0755) == 0) {
2461 scripts_directory_uri = g_filename_to_uri (scripts_directory_path, NULL, NULL);
2462 scripts_directory_uri_length = strlen (scripts_directory_uri);
2463 }
2464
2465 g_free (scripts_directory_path);
2466
2467 return (scripts_directory_uri != NULL) ? TRUE : FALSE;
2468 }
2469
2470 static void
scripts_added_or_changed_callback(NemoDirectory * directory,GList * files,gpointer callback_data)2471 scripts_added_or_changed_callback (NemoDirectory *directory,
2472 GList *files,
2473 gpointer callback_data)
2474 {
2475 NemoView *view;
2476
2477 view = NEMO_VIEW (callback_data);
2478
2479 view->details->scripts_invalid = TRUE;
2480 if (view->details->active) {
2481 schedule_update_menus (view);
2482 }
2483 }
2484
2485 static void
templates_added_or_changed_callback(NemoDirectory * directory,GList * files,gpointer callback_data)2486 templates_added_or_changed_callback (NemoDirectory *directory,
2487 GList *files,
2488 gpointer callback_data)
2489 {
2490 NemoView *view;
2491
2492 view = NEMO_VIEW (callback_data);
2493
2494 view->details->templates_invalid = TRUE;
2495 if (view->details->active) {
2496 schedule_update_menus (view);
2497 }
2498 }
2499
2500 static void
actions_added_or_changed_callback(NemoView * view)2501 actions_added_or_changed_callback (NemoView *view)
2502 {
2503 view->details->actions_invalid = TRUE;
2504 if (view->details->active) {
2505 schedule_update_menus (view);
2506 }
2507 }
2508
2509 static void
add_directory_to_directory_list(NemoView * view,NemoDirectory * directory,GList ** directory_list,GCallback changed_callback)2510 add_directory_to_directory_list (NemoView *view,
2511 NemoDirectory *directory,
2512 GList **directory_list,
2513 GCallback changed_callback)
2514 {
2515 NemoFileAttributes attributes;
2516
2517 if (g_list_find (*directory_list, directory) == NULL) {
2518 nemo_directory_ref (directory);
2519
2520 attributes =
2521 NEMO_FILE_ATTRIBUTES_FOR_ICON |
2522 NEMO_FILE_ATTRIBUTE_INFO |
2523 NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT;
2524
2525 nemo_directory_file_monitor_add (directory, directory_list,
2526 FALSE, attributes,
2527 (NemoDirectoryCallback)changed_callback, view);
2528
2529 g_signal_connect_object (directory, "files_added",
2530 G_CALLBACK (changed_callback), view, 0);
2531 g_signal_connect_object (directory, "files_changed",
2532 G_CALLBACK (changed_callback), view, 0);
2533
2534 *directory_list = g_list_append (*directory_list, directory);
2535 }
2536 }
2537
2538 static void
remove_directory_from_directory_list(NemoView * view,NemoDirectory * directory,GList ** directory_list,GCallback changed_callback)2539 remove_directory_from_directory_list (NemoView *view,
2540 NemoDirectory *directory,
2541 GList **directory_list,
2542 GCallback changed_callback)
2543 {
2544 *directory_list = g_list_remove (*directory_list, directory);
2545
2546 g_signal_handlers_disconnect_by_func (directory,
2547 G_CALLBACK (changed_callback),
2548 view);
2549
2550 nemo_directory_file_monitor_remove (directory, directory_list);
2551
2552 nemo_directory_unref (directory);
2553 }
2554
2555 static void
add_directory_to_scripts_directory_list(NemoView * view,NemoDirectory * directory)2556 add_directory_to_scripts_directory_list (NemoView *view,
2557 NemoDirectory *directory)
2558 {
2559 add_directory_to_directory_list (view, directory,
2560 &view->details->scripts_directory_list,
2561 G_CALLBACK (scripts_added_or_changed_callback));
2562 }
2563
2564 static void
remove_directory_from_scripts_directory_list(NemoView * view,NemoDirectory * directory)2565 remove_directory_from_scripts_directory_list (NemoView *view,
2566 NemoDirectory *directory)
2567 {
2568 remove_directory_from_directory_list (view, directory,
2569 &view->details->scripts_directory_list,
2570 G_CALLBACK (scripts_added_or_changed_callback));
2571 }
2572
2573 static void
add_directory_to_templates_directory_list(NemoView * view,NemoDirectory * directory)2574 add_directory_to_templates_directory_list (NemoView *view,
2575 NemoDirectory *directory)
2576 {
2577 add_directory_to_directory_list (view, directory,
2578 &view->details->templates_directory_list,
2579 G_CALLBACK (templates_added_or_changed_callback));
2580 }
2581
2582 static void
remove_directory_from_templates_directory_list(NemoView * view,NemoDirectory * directory)2583 remove_directory_from_templates_directory_list (NemoView *view,
2584 NemoDirectory *directory)
2585 {
2586 remove_directory_from_directory_list (view, directory,
2587 &view->details->templates_directory_list,
2588 G_CALLBACK (templates_added_or_changed_callback));
2589 }
2590
2591 static void
slot_active(NemoWindowSlot * slot,NemoView * view)2592 slot_active (NemoWindowSlot *slot,
2593 NemoView *view)
2594 {
2595 if (view->details->active) {
2596 return;
2597 }
2598
2599 view->details->active = TRUE;
2600
2601 nemo_view_merge_menus (view);
2602 schedule_update_menus (view);
2603 }
2604
2605 static void
slot_inactive(NemoWindowSlot * slot,NemoView * view)2606 slot_inactive (NemoWindowSlot *slot,
2607 NemoView *view)
2608 {
2609 if (!view->details->active) {
2610 return;
2611 }
2612
2613 view->details->active = FALSE;
2614
2615 nemo_view_unmerge_menus (view);
2616 remove_update_menus_timeout_callback (view);
2617 }
2618
slot_changed_pane(NemoWindowSlot * slot,NemoView * view)2619 static void slot_changed_pane (NemoWindowSlot *slot,
2620 NemoView *view)
2621 {
2622 g_signal_handlers_disconnect_matched (view->details->window,
2623 G_SIGNAL_MATCH_DATA, 0, 0,
2624 NULL, NULL, view);
2625
2626 view->details->window = nemo_window_slot_get_window (slot);
2627 schedule_update_menus (view);
2628
2629 g_signal_connect_object (view->details->window,
2630 "hidden-files-mode-changed", G_CALLBACK (hidden_files_mode_changed),
2631 view, 0);
2632 hidden_files_mode_changed (view->details->window, view);
2633 }
2634
2635 static void
plugin_prefs_changed(GSettings * settings,gchar * key,gpointer user_data)2636 plugin_prefs_changed (GSettings *settings, gchar *key, gpointer user_data)
2637 {
2638 scripts_added_or_changed_callback (NULL, NULL, user_data);
2639 }
2640
2641 void
nemo_view_grab_focus(NemoView * view)2642 nemo_view_grab_focus (NemoView *view)
2643 {
2644 /* focus the child of the scrolled window if it exists */
2645 GtkWidget *child;
2646 child = gtk_bin_get_child (GTK_BIN (view));
2647 if (child) {
2648 gtk_widget_grab_focus (GTK_WIDGET (child));
2649 }
2650 }
2651
2652 int
nemo_view_get_selection_count(NemoView * view)2653 nemo_view_get_selection_count (NemoView *view)
2654 {
2655 /* FIXME: This could be faster if we special cased it in subclasses */
2656 GList *files;
2657 int len;
2658
2659 files = nemo_view_get_selection (NEMO_VIEW (view));
2660 len = g_list_length (files);
2661 nemo_file_list_free (files);
2662
2663 return len;
2664 }
2665
2666 static void
update_undo_actions(NemoView * view)2667 update_undo_actions (NemoView *view)
2668 {
2669 NemoFileUndoInfo *info;
2670 NemoFileUndoManagerState undo_state;
2671 GtkAction *action;
2672 const gchar *label, *tooltip;
2673 gboolean available;
2674 gboolean undo_active, redo_active;
2675 gchar *undo_label, *undo_description, *redo_label, *redo_description;
2676
2677 undo_label = undo_description = redo_label = redo_description = NULL;
2678
2679 undo_active = FALSE;
2680 redo_active = FALSE;
2681
2682 info = nemo_file_undo_manager_get_action ();
2683 undo_state = nemo_file_undo_manager_get_state ();
2684
2685 if (info != NULL &&
2686 (undo_state > NEMO_FILE_UNDO_MANAGER_STATE_NONE)) {
2687 if (undo_state == NEMO_FILE_UNDO_MANAGER_STATE_UNDO) {
2688 undo_active = TRUE;
2689 } else {
2690 redo_active = TRUE;
2691 }
2692
2693 nemo_file_undo_info_get_strings (info,
2694 &undo_label, &undo_description,
2695 &redo_label, &redo_description);
2696 }
2697
2698 /* Update undo entry */
2699 action = gtk_action_group_get_action (view->details->dir_action_group,
2700 "Undo");
2701 available = undo_active;
2702 if (available) {
2703 label = undo_label;
2704 tooltip = undo_description;
2705 } else {
2706 /* Reset to default info */
2707 label = _("Undo");
2708 tooltip = _("Undo last action");
2709 }
2710
2711 g_object_set (action,
2712 "label", label,
2713 "tooltip", tooltip,
2714 NULL);
2715 gtk_action_set_sensitive (action, available);
2716
2717 /* Update redo entry */
2718 action = gtk_action_group_get_action (view->details->dir_action_group,
2719 "Redo");
2720 available = redo_active;
2721 if (available) {
2722 label = redo_label;
2723 tooltip = redo_description;
2724 } else {
2725 /* Reset to default info */
2726 label = _("Redo");
2727 tooltip = _("Redo last undone action");
2728 }
2729
2730 g_object_set (action,
2731 "label", label,
2732 "tooltip", tooltip,
2733 NULL);
2734 gtk_action_set_sensitive (action, available);
2735
2736 g_free (undo_label);
2737 g_free (undo_description);
2738 g_free (redo_label);
2739 g_free (redo_description);
2740 }
2741
2742 static void
undo_manager_changed_cb(NemoFileUndoManager * manager,NemoView * view)2743 undo_manager_changed_cb (NemoFileUndoManager* manager,
2744 NemoView *view)
2745 {
2746 if (view->details->dir_action_group == NULL) {
2747 return;
2748 }
2749
2750 update_undo_actions (view);
2751 }
2752
2753 void
nemo_view_set_selection(NemoView * nemo_view,GList * selection)2754 nemo_view_set_selection (NemoView *nemo_view,
2755 GList *selection)
2756 {
2757 NemoView *view;
2758
2759 view = NEMO_VIEW (nemo_view);
2760
2761 if (!view->details->loading) {
2762 /* If we aren't still loading, set the selection right now,
2763 * and reveal the new selection.
2764 */
2765 view->details->selection_change_is_due_to_shell = TRUE;
2766 nemo_view_call_set_selection (view, selection);
2767 view->details->selection_change_is_due_to_shell = FALSE;
2768 nemo_view_reveal_selection (view);
2769 } else {
2770 /* If we are still loading, set the list of pending URIs instead.
2771 * done_loading() will eventually select the pending URIs and reveal them.
2772 */
2773 g_list_free_full (view->details->pending_selection, g_object_unref);
2774 view->details->pending_selection =
2775 eel_g_object_list_copy (selection);
2776 }
2777 }
2778
2779 static char *
get_bulk_rename_tool(void)2780 get_bulk_rename_tool (void)
2781 {
2782 char *bulk_rename_tool;
2783 g_settings_get (nemo_preferences, NEMO_PREFERENCES_BULK_RENAME_TOOL, "^ay", &bulk_rename_tool);
2784 return g_strstrip (bulk_rename_tool);
2785 }
2786
2787 static gboolean
have_bulk_rename_tool(void)2788 have_bulk_rename_tool (void)
2789 {
2790 char *bulk_rename_tool;
2791 gboolean have_tool;
2792
2793 bulk_rename_tool = get_bulk_rename_tool ();
2794 have_tool = ((bulk_rename_tool != NULL) && (*bulk_rename_tool != '\0'));
2795 g_free (bulk_rename_tool);
2796 return have_tool;
2797 }
2798
2799 static void
nemo_view_init(NemoView * view)2800 nemo_view_init (NemoView *view)
2801 {
2802 AtkObject *atk_object;
2803 NemoDirectory *scripts_directory;
2804 NemoDirectory *templates_directory;
2805 char *templates_uri;
2806 NemoFileUndoManager* manager;
2807 view->details = G_TYPE_INSTANCE_GET_PRIVATE (view, NEMO_TYPE_VIEW,
2808 NemoViewDetails);
2809
2810 view->details->load_timer = g_timer_new ();
2811
2812 /* Default to true; desktop-icon-view sets to false */
2813 view->details->show_foreign_files = TRUE;
2814
2815 view->details->non_ready_files =
2816 g_hash_table_new_full (file_and_directory_hash,
2817 file_and_directory_equal,
2818 (GDestroyNotify)file_and_directory_free,
2819 NULL);
2820
2821 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
2822 GTK_POLICY_AUTOMATIC,
2823 GTK_POLICY_AUTOMATIC);
2824 gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (view), NULL);
2825 gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (view), NULL);
2826 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (view), GTK_SHADOW_NONE);
2827
2828 gtk_style_context_set_junction_sides (gtk_widget_get_style_context (GTK_WIDGET (view)),
2829 GTK_JUNCTION_TOP | GTK_JUNCTION_LEFT);
2830
2831 if (set_up_scripts_directory_global ()) {
2832 scripts_directory = nemo_directory_get_by_uri (scripts_directory_uri);
2833 add_directory_to_scripts_directory_list (view, scripts_directory);
2834 nemo_directory_unref (scripts_directory);
2835 } else {
2836 g_warning ("Ignoring scripts directory, it may be a broken link\n");
2837 }
2838
2839 if (nemo_should_use_templates_directory ()) {
2840 templates_uri = nemo_get_templates_directory_uri ();
2841 templates_directory = nemo_directory_get_by_uri (templates_uri);
2842 g_free (templates_uri);
2843 add_directory_to_templates_directory_list (view, templates_directory);
2844 nemo_directory_unref (templates_directory);
2845 }
2846 update_templates_directory (view);
2847 g_signal_connect_object (nemo_signaller_get_current (),
2848 "user_dirs_changed",
2849 G_CALLBACK (user_dirs_changed),
2850 view, G_CONNECT_SWAPPED);
2851
2852 view->details->sort_directories_first =
2853 g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST);
2854
2855 g_signal_connect_object (nemo_trash_monitor_get (), "trash_state_changed",
2856 G_CALLBACK (nemo_view_trash_state_changed_callback), view, 0);
2857
2858 /* React to clipboard changes */
2859 g_signal_connect_object (nemo_clipboard_monitor_get (), "clipboard_changed",
2860 G_CALLBACK (clipboard_changed_callback), view, 0);
2861
2862 /* Register to menu provider extension signal managing menu updates */
2863 g_signal_connect_object (nemo_signaller_get_current (), "popup_menu_changed",
2864 G_CALLBACK (nemo_view_update_menus), view, G_CONNECT_SWAPPED);
2865
2866 gtk_widget_show (GTK_WIDGET (view));
2867
2868 g_signal_connect_swapped (nemo_preferences,
2869 "changed::" NEMO_PREFERENCES_ENABLE_DELETE,
2870 G_CALLBACK (schedule_update_menus_callback), view);
2871 g_signal_connect_swapped (nemo_menu_config_preferences,
2872 "changed",
2873 G_CALLBACK (schedule_update_menus_callback), view);
2874 g_signal_connect_swapped (nemo_preferences,
2875 "changed::" NEMO_PREFERENCES_SWAP_TRASH_DELETE,
2876 G_CALLBACK (swap_delete_keybinding_changed_callback), view);
2877 g_signal_connect_swapped (nemo_preferences,
2878 "changed::" NEMO_PREFERENCES_CLICK_POLICY,
2879 G_CALLBACK(click_policy_changed_callback),
2880 view);
2881 g_signal_connect_swapped (nemo_preferences,
2882 "changed::" NEMO_PREFERENCES_CLICK_TO_RENAME,
2883 G_CALLBACK(click_to_rename_changed_callback),
2884 view);
2885 g_signal_connect_swapped (nemo_preferences,
2886 "changed::" NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST,
2887 G_CALLBACK(sort_directories_first_changed_callback), view);
2888 g_signal_connect_swapped (gnome_lockdown_preferences,
2889 "changed::" NEMO_PREFERENCES_LOCKDOWN_COMMAND_LINE,
2890 G_CALLBACK (schedule_update_menus), view);
2891
2892 g_signal_connect_swapped (nemo_window_state,
2893 "changed::" NEMO_WINDOW_STATE_START_WITH_STATUS_BAR,
2894 G_CALLBACK (nemo_view_display_selection_info), view);
2895
2896 g_signal_connect_swapped (nemo_preferences,
2897 "changed::" NEMO_PREFERENCES_SHOW_BOOKMARKS_IN_TO_MENUS,
2898 G_CALLBACK (nemo_to_menu_preferences_changed_callback), view);
2899 g_signal_connect_swapped (nemo_preferences,
2900 "changed::" NEMO_PREFERENCES_SHOW_PLACES_IN_TO_MENUS,
2901 G_CALLBACK (nemo_to_menu_preferences_changed_callback), view);
2902
2903 nemo_to_menu_preferences_changed_callback (view);
2904
2905 manager = nemo_file_undo_manager_get ();
2906 g_signal_connect_object (manager, "undo-changed",
2907 G_CALLBACK (undo_manager_changed_cb), view, 0);
2908
2909 g_signal_connect (nemo_plugin_preferences,
2910 "changed::" NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS,
2911 G_CALLBACK (plugin_prefs_changed), view);
2912
2913 /* Accessibility */
2914 atk_object = gtk_widget_get_accessible (GTK_WIDGET (view));
2915 atk_object_set_name (atk_object, _("Content View"));
2916 atk_object_set_description (atk_object, _("View of the current folder"));
2917
2918 view->details->action_manager = nemo_action_manager_new ();
2919
2920 view->details->action_manager_changed_id =
2921 g_signal_connect_swapped (view->details->action_manager, "changed",
2922 G_CALLBACK (actions_added_or_changed_callback),
2923 view);
2924
2925 view->details->bookmarks = nemo_bookmark_list_get_default ();
2926
2927 view->details->bookmarks_changed_id =
2928 g_signal_connect_swapped (view->details->bookmarks, "changed",
2929 G_CALLBACK (schedule_update_menus),
2930 view);
2931 }
2932
2933 static void
disconnect_action_activate(NemoAction * action,NemoView * view)2934 disconnect_action_activate (NemoAction *action, NemoView *view)
2935 {
2936 g_signal_handlers_disconnect_by_func (action, run_action_callback, view);
2937 }
2938
2939 static void
real_unmerge_menus(NemoView * view)2940 real_unmerge_menus (NemoView *view)
2941 {
2942 GtkUIManager *ui_manager;
2943
2944 if (view->details->window == NULL) {
2945 return;
2946 }
2947 if (GTK_IS_ACTION_GROUP (view->details->copy_move_action_groups[0])) {
2948 disconnect_bookmark_signals (view);
2949 }
2950
2951 ui_manager = nemo_window_get_ui_manager (view->details->window);
2952
2953 nemo_ui_unmerge_ui (ui_manager,
2954 &view->details->dir_merge_id,
2955 &view->details->dir_action_group);
2956 nemo_ui_unmerge_ui (ui_manager,
2957 &view->details->extensions_menu_merge_id,
2958 &view->details->extensions_menu_action_group);
2959 nemo_ui_unmerge_ui (ui_manager,
2960 &view->details->open_with_merge_id,
2961 &view->details->open_with_action_group);
2962 nemo_ui_unmerge_ui (ui_manager,
2963 &view->details->scripts_merge_id,
2964 &view->details->scripts_action_group);
2965 nemo_ui_unmerge_ui (ui_manager,
2966 &view->details->templates_merge_id,
2967 &view->details->templates_action_group);
2968
2969 if (view->details->actions_action_group) {
2970 GList *action_list;
2971
2972 action_list = gtk_action_group_list_actions (view->details->actions_action_group);
2973 g_list_foreach (action_list, (GFunc) disconnect_action_activate, view);
2974
2975 g_list_free (action_list);
2976 }
2977
2978 nemo_ui_unmerge_ui (ui_manager,
2979 &view->details->actions_merge_id,
2980 &view->details->actions_action_group);
2981 int i;
2982 for (i = 0; i < 4; i++) {
2983 nemo_ui_unmerge_ui (ui_manager,
2984 &view->details->copy_move_merge_ids[i],
2985 &view->details->copy_move_action_groups[i]);
2986 }
2987 }
2988
2989 static void
nemo_view_destroy(GtkWidget * object)2990 nemo_view_destroy (GtkWidget *object)
2991 {
2992 NemoView *view;
2993 GList *node, *next;
2994
2995 view = NEMO_VIEW (object);
2996
2997 disconnect_model_handlers (view);
2998
2999 if (view->details->bookmarks_changed_id != 0) {
3000 g_signal_handler_disconnect (view->details->bookmarks,
3001 view->details->bookmarks_changed_id);
3002 view->details->bookmarks_changed_id = 0;
3003 }
3004
3005 if (view->details->action_manager_changed_id != 0) {
3006 g_signal_handler_disconnect (view->details->action_manager,
3007 view->details->action_manager_changed_id);
3008 view->details->action_manager_changed_id = 0;
3009 }
3010 g_clear_object (&view->details->action_manager);
3011
3012 nemo_view_unmerge_menus (view);
3013
3014 /* We don't own the window, so no unref */
3015 view->details->slot = NULL;
3016 view->details->window = NULL;
3017
3018 nemo_view_stop_loading (view);
3019
3020 for (node = view->details->scripts_directory_list; node != NULL; node = next) {
3021 next = node->next;
3022 remove_directory_from_scripts_directory_list (view, node->data);
3023 }
3024
3025 for (node = view->details->templates_directory_list; node != NULL; node = next) {
3026 next = node->next;
3027 remove_directory_from_templates_directory_list (view, node->data);
3028 }
3029
3030 while (view->details->subdirectory_list != NULL) {
3031 nemo_view_remove_subdirectory (view,
3032 view->details->subdirectory_list->data);
3033 }
3034
3035 remove_update_menus_timeout_callback (view);
3036 remove_update_status_idle_callback (view);
3037
3038 if (view->details->display_selection_idle_id != 0) {
3039 g_source_remove (view->details->display_selection_idle_id);
3040 view->details->display_selection_idle_id = 0;
3041 }
3042
3043 if (view->details->reveal_selection_idle_id != 0) {
3044 g_source_remove (view->details->reveal_selection_idle_id);
3045 view->details->reveal_selection_idle_id = 0;
3046 }
3047
3048 if (view->details->delayed_rename_file_id != 0) {
3049 g_source_remove (view->details->delayed_rename_file_id);
3050 view->details->delayed_rename_file_id = 0;
3051 }
3052
3053 if (view->details->model) {
3054 nemo_directory_unref (view->details->model);
3055 view->details->model = NULL;
3056 }
3057
3058 if (view->details->directory_as_file) {
3059 nemo_file_unref (view->details->directory_as_file);
3060 view->details->directory_as_file = NULL;
3061 }
3062
3063 g_signal_handlers_disconnect_by_func (nemo_plugin_preferences, G_CALLBACK (plugin_prefs_changed), view);
3064
3065 GTK_WIDGET_CLASS (nemo_view_parent_class)->destroy (object);
3066 }
3067
3068 static void
nemo_view_finalize(GObject * object)3069 nemo_view_finalize (GObject *object)
3070 {
3071 NemoView *view;
3072
3073 view = NEMO_VIEW (object);
3074
3075 g_signal_handlers_disconnect_by_func (nemo_preferences,
3076 schedule_update_menus_callback, view);
3077 g_signal_handlers_disconnect_by_func (nemo_preferences,
3078 click_policy_changed_callback, view);
3079 g_signal_handlers_disconnect_by_func (nemo_preferences,
3080 click_to_rename_changed_callback, view);
3081 g_signal_handlers_disconnect_by_func (nemo_preferences,
3082 sort_directories_first_changed_callback, view);
3083 g_signal_handlers_disconnect_by_func (nemo_window_state,
3084 nemo_view_display_selection_info, view);
3085 g_signal_handlers_disconnect_by_func (nemo_menu_config_preferences,
3086 schedule_update_menus_callback, view);
3087
3088 g_signal_handlers_disconnect_by_func (gnome_lockdown_preferences,
3089 schedule_update_menus, view);
3090
3091 g_signal_handlers_disconnect_by_func (nemo_preferences,
3092 nemo_to_menu_preferences_changed_callback, view);
3093
3094 g_signal_handlers_disconnect_by_func (nemo_preferences,
3095 schedule_update_menus, view);
3096
3097 unschedule_pop_up_location_context_menu (view);
3098 if (view->details->location_popup_event != NULL) {
3099 gdk_event_free ((GdkEvent *) view->details->location_popup_event);
3100 }
3101
3102 g_clear_pointer (&view->details->load_timer, g_timer_destroy);
3103
3104 g_hash_table_destroy (view->details->non_ready_files);
3105
3106 G_OBJECT_CLASS (nemo_view_parent_class)->finalize (object);
3107 }
3108
3109 /**
3110 * nemo_view_display_selection_info:
3111 *
3112 * Display information about the current selection, and notify the view frame of the changed selection.
3113 * @view: NemoView for which to display selection info.
3114 *
3115 **/
3116 void
nemo_view_display_selection_info(NemoView * view)3117 nemo_view_display_selection_info (NemoView *view)
3118 {
3119 GList *selection;
3120 goffset non_folder_size;
3121 gboolean non_folder_size_known;
3122 guint non_folder_count, folder_count, folder_item_count;
3123 gboolean folder_item_count_known;
3124 guint file_item_count;
3125 GList *p;
3126 char *first_item_name;
3127 char *non_folder_str;
3128 char *folder_count_str;
3129 char *folder_item_count_str;
3130 char *status_string;
3131 char *view_status_string;
3132 char *free_space_str;
3133 char *obj_selected_free_space_str;
3134 NemoFile *file;
3135
3136 g_return_if_fail (NEMO_IS_VIEW (view));
3137
3138 selection = nemo_view_get_selection (view);
3139
3140 folder_item_count_known = TRUE;
3141 folder_count = 0;
3142 folder_item_count = 0;
3143 non_folder_count = 0;
3144 non_folder_size_known = FALSE;
3145 non_folder_size = 0;
3146 first_item_name = NULL;
3147 folder_count_str = NULL;
3148 non_folder_str = NULL;
3149 folder_item_count_str = NULL;
3150 free_space_str = NULL;
3151 obj_selected_free_space_str = NULL;
3152 status_string = NULL;
3153 view_status_string = NULL;
3154
3155 for (p = selection; p != NULL; p = p->next) {
3156 file = p->data;
3157 if (nemo_file_is_directory (file)) {
3158 folder_count++;
3159 if (nemo_file_get_directory_item_count (file, &file_item_count, NULL)) {
3160 folder_item_count += file_item_count;
3161 } else {
3162 folder_item_count_known = FALSE;
3163 }
3164 } else {
3165 non_folder_count++;
3166 if (!nemo_file_can_get_size (file)) {
3167 non_folder_size_known = TRUE;
3168 non_folder_size += nemo_file_get_size (file);
3169 }
3170 }
3171
3172 if (first_item_name == NULL) {
3173 first_item_name = nemo_file_get_display_name (file);
3174 }
3175 }
3176
3177 nemo_file_list_free (selection);
3178
3179 /* Break out cases for localization's sake. But note that there are still pieces
3180 * being assembled in a particular order, which may be a problem for some localizers.
3181 */
3182
3183 if (folder_count != 0) {
3184 if (folder_count == 1 && non_folder_count == 0) {
3185 folder_count_str = g_strdup_printf (_("\"%s\" selected"), first_item_name);
3186 } else {
3187 folder_count_str = g_strdup_printf (ngettext("%'d folder selected",
3188 "%'d folders selected",
3189 folder_count),
3190 folder_count);
3191 }
3192
3193 if (folder_count == 1) {
3194 if (!folder_item_count_known) {
3195 folder_item_count_str = g_strdup ("");
3196 } else {
3197 folder_item_count_str = g_strdup_printf (ngettext(" (containing %'d item)",
3198 " (containing %'d items)",
3199 folder_item_count),
3200 folder_item_count);
3201 }
3202 }
3203 else {
3204 if (!folder_item_count_known) {
3205 folder_item_count_str = g_strdup ("");
3206 } else {
3207 /* translators: this is preceded with a string of form 'N folders' (N more than 1) */
3208 folder_item_count_str = g_strdup_printf (ngettext(" (containing a total of %'d item)",
3209 " (containing a total of %'d items)",
3210 folder_item_count),
3211 folder_item_count);
3212 }
3213
3214 }
3215 }
3216
3217 if (non_folder_count != 0) {
3218 char *items_string;
3219
3220 if (folder_count == 0) {
3221 if (non_folder_count == 1) {
3222 items_string = g_strdup_printf (_("\"%s\" selected"),
3223 first_item_name);
3224 } else {
3225 items_string = g_strdup_printf (ngettext("%'d item selected",
3226 "%'d items selected",
3227 non_folder_count),
3228 non_folder_count);
3229 }
3230 } else {
3231 /* Folders selected also, use "other" terminology */
3232 items_string = g_strdup_printf (ngettext("%'d other item selected",
3233 "%'d other items selected",
3234 non_folder_count),
3235 non_folder_count);
3236 }
3237
3238 if (non_folder_size_known) {
3239 char *size_string;
3240 int prefix;
3241
3242 prefix = nemo_global_preferences_get_size_prefix_preference ();
3243 size_string = g_format_size_full (non_folder_size, prefix);
3244 /* This is marked for translation in case a localiser
3245 * needs to use something other than parentheses. The
3246 * first message gives the number of items selected;
3247 * the message in parentheses the size of those items.
3248 */
3249 non_folder_str = g_strdup_printf (_("%s (%s)"),
3250 items_string,
3251 size_string);
3252
3253 g_free (size_string);
3254 g_free (items_string);
3255 } else {
3256 non_folder_str = items_string;
3257 }
3258 }
3259
3260 free_space_str = nemo_file_get_volume_free_space (view->details->directory_as_file);
3261 if (free_space_str != NULL) {
3262 obj_selected_free_space_str = g_strdup_printf (_("Free space: %s"), free_space_str);
3263 }
3264 if (folder_count == 0 && non_folder_count == 0) {
3265 char *item_count_str;
3266 guint item_count;
3267
3268 item_count = nemo_view_get_item_count (view);
3269
3270 item_count_str = g_strdup_printf (ngettext ("%'u item", "%'u items", item_count), item_count);
3271
3272 if (free_space_str != NULL) {
3273 status_string = g_strdup_printf (_("%s, Free space: %s"), item_count_str, free_space_str);
3274 g_free (item_count_str);
3275 } else {
3276 status_string = item_count_str;
3277 }
3278
3279 } else if (folder_count == 0) {
3280 view_status_string = g_strdup (non_folder_str);
3281
3282 if (free_space_str != NULL) {
3283 /* Marking this for translation, since you
3284 * might want to change "," to something else.
3285 * After the comma the amount of free space will
3286 * be shown.
3287 */
3288 status_string = g_strdup_printf (_("%s, %s"),
3289 non_folder_str,
3290 obj_selected_free_space_str);
3291 }
3292 } else if (non_folder_count == 0) {
3293 /* No use marking this for translation, since you
3294 * can't reorder the strings, which is the main thing
3295 * you'd want to do.
3296 */
3297 view_status_string = g_strdup_printf ("%s%s",
3298 folder_count_str,
3299 folder_item_count_str);
3300
3301 if (free_space_str != NULL) {
3302 /* Marking this for translation, since you
3303 * might want to change "," to something else.
3304 * After the comma the amount of free space will
3305 * be shown.
3306 */
3307 status_string = g_strdup_printf (_("%s%s, %s"),
3308 folder_count_str,
3309 folder_item_count_str,
3310 obj_selected_free_space_str);
3311 }
3312 } else {
3313 /* This is marked for translation in case a localizer
3314 * needs to change ", " to something else. The comma
3315 * is between the message about the number of folders
3316 * and the number of items in those folders and the
3317 * message about the number of other items and the
3318 * total size of those items.
3319 */
3320 view_status_string = g_strdup_printf (_("%s%s, %s"),
3321 folder_count_str,
3322 folder_item_count_str,
3323 non_folder_str);
3324
3325 if (obj_selected_free_space_str != NULL) {
3326 /* This is marked for translation in case a localizer
3327 * needs to change ", " to something else. The first comma
3328 * is between the message about the number of folders
3329 * and the number of items in those folders and the
3330 * message about the number of other items and the
3331 * total size of those items. After the second comma
3332 * the free space is written.
3333 */
3334 status_string = g_strdup_printf (_("%s%s, %s, %s"),
3335 folder_count_str,
3336 folder_item_count_str,
3337 non_folder_str,
3338 obj_selected_free_space_str);
3339 }
3340 }
3341
3342 g_free (free_space_str);
3343 g_free (obj_selected_free_space_str);
3344 g_free (first_item_name);
3345 g_free (folder_count_str);
3346 g_free (folder_item_count_str);
3347 g_free (non_folder_str);
3348
3349 if (status_string == NULL) {
3350 status_string = g_strdup (view_status_string);
3351 }
3352
3353 nemo_window_slot_set_status (view->details->slot,
3354 status_string,
3355 view_status_string);
3356
3357 g_free (status_string);
3358 g_free (view_status_string);
3359 }
3360
3361 static void
nemo_view_send_selection_change(NemoView * view)3362 nemo_view_send_selection_change (NemoView *view)
3363 {
3364 g_signal_emit (view, signals[SELECTION_CHANGED], 0);
3365
3366 view->details->send_selection_change_to_shell = FALSE;
3367 }
3368
3369 void
nemo_view_load_location(NemoView * nemo_view,GFile * location)3370 nemo_view_load_location (NemoView *nemo_view,
3371 GFile *location)
3372 {
3373 NemoDirectory *directory;
3374 NemoView *directory_view;
3375
3376 directory_view = NEMO_VIEW (nemo_view);
3377
3378 directory = nemo_directory_get (location);
3379 load_directory (directory_view, directory);
3380 nemo_directory_unref (directory);
3381 }
3382
3383 static gboolean
reveal_selection_idle_callback(gpointer data)3384 reveal_selection_idle_callback (gpointer data)
3385 {
3386 NemoView *view;
3387
3388 view = NEMO_VIEW (data);
3389
3390 view->details->reveal_selection_idle_id = 0;
3391 nemo_view_reveal_selection (view);
3392
3393 return FALSE;
3394 }
3395
3396 static gboolean
idle_timer_report(gpointer user_data)3397 idle_timer_report (gpointer user_data)
3398 {
3399 g_return_val_if_fail (NEMO_IS_VIEW (user_data), G_SOURCE_REMOVE);
3400
3401 NemoView *view = NEMO_VIEW (user_data);
3402
3403 g_printerr ("Idle...Folder load time: %f seconds\n", g_timer_elapsed (view->details->load_timer, NULL));
3404
3405 return G_SOURCE_REMOVE;
3406 }
3407
3408 static void
done_loading(NemoView * view,gboolean all_files_seen)3409 done_loading (NemoView *view,
3410 gboolean all_files_seen)
3411 {
3412 GList *selection;
3413
3414 if (!view->details->loading) {
3415 return;
3416 }
3417
3418 /* This can be called during destruction, in which case there
3419 * is no NemoWindow any more.
3420 */
3421 if (view->details->window != NULL) {
3422 if (all_files_seen) {
3423 nemo_window_report_load_complete (view->details->window, NEMO_VIEW (view));
3424 }
3425
3426 schedule_update_menus (view);
3427 schedule_update_status (view);
3428 reset_update_interval (view);
3429
3430 selection = view->details->pending_selection;
3431 if (selection != NULL && all_files_seen) {
3432 view->details->pending_selection = NULL;
3433
3434 view->details->selection_change_is_due_to_shell = TRUE;
3435 nemo_view_call_set_selection (view, selection);
3436 view->details->selection_change_is_due_to_shell = FALSE;
3437
3438 if (NEMO_IS_LIST_VIEW (view)) {
3439 /* HACK: We should be able to directly call reveal_selection here,
3440 * but at this point the GtkTreeView hasn't allocated the new nodes
3441 * yet, and it has a bug in the scroll calculation dealing with this
3442 * special case. It would always make the selection the top row, even
3443 * if no scrolling would be neccessary to reveal it. So we let it
3444 * allocate before revealing.
3445 */
3446 if (view->details->reveal_selection_idle_id != 0) {
3447 g_source_remove (view->details->reveal_selection_idle_id);
3448 }
3449 view->details->reveal_selection_idle_id =
3450 g_idle_add (reveal_selection_idle_callback, view);
3451 } else {
3452 nemo_view_reveal_selection (view);
3453 }
3454 }
3455 g_list_free_full (selection, g_object_unref);
3456 nemo_view_display_selection_info (view);
3457 }
3458
3459 view->details->loading = FALSE;
3460 g_signal_emit (view, signals[END_LOADING], 0, all_files_seen);
3461
3462 if (g_getenv("NEMO_BENCHMARK_LOADING")) {
3463 if (nemo_startup_timer != NULL) {
3464 g_printerr ("Nemo startup time: %f seconds\n", g_timer_elapsed (nemo_startup_timer, NULL));
3465 g_clear_pointer (&nemo_startup_timer, g_timer_destroy);
3466 }
3467
3468 g_printerr ("Folder load time: %f seconds\n", g_timer_elapsed (view->details->load_timer, NULL));
3469
3470 g_idle_add_full (1000, (GSourceFunc) idle_timer_report, view, NULL);
3471 }
3472 }
3473
3474 typedef struct {
3475 GHashTable *debuting_files;
3476 GList *added_files;
3477 } DebutingFilesData;
3478
3479 static void
debuting_files_data_free(DebutingFilesData * data)3480 debuting_files_data_free (DebutingFilesData *data)
3481 {
3482 g_hash_table_unref (data->debuting_files);
3483 nemo_file_list_free (data->added_files);
3484 g_free (data);
3485 }
3486
3487 /* This signal handler watch for the arrival of the icons created
3488 * as the result of a file operation. Once the last one is detected
3489 * it selects and reveals them all.
3490 */
3491 static void
debuting_files_add_file_callback(NemoView * view,NemoFile * new_file,NemoDirectory * directory,DebutingFilesData * data)3492 debuting_files_add_file_callback (NemoView *view,
3493 NemoFile *new_file,
3494 NemoDirectory *directory,
3495 DebutingFilesData *data)
3496 {
3497 GFile *location;
3498
3499 location = nemo_file_get_location (new_file);
3500
3501 if (g_hash_table_remove (data->debuting_files, location)) {
3502 nemo_file_ref (new_file);
3503 data->added_files = g_list_prepend (data->added_files, new_file);
3504
3505 if (g_hash_table_size (data->debuting_files) == 0) {
3506 nemo_view_call_set_selection (view, data->added_files);
3507 nemo_view_reveal_selection (view);
3508 g_signal_handlers_disconnect_by_func (view,
3509 G_CALLBACK (debuting_files_add_file_callback),
3510 data);
3511 }
3512 }
3513
3514 g_object_unref (location);
3515 }
3516
3517 typedef struct {
3518 GList *added_files;
3519 NemoView *directory_view;
3520 } CopyMoveDoneData;
3521
3522 static void
copy_move_done_data_free(CopyMoveDoneData * data)3523 copy_move_done_data_free (CopyMoveDoneData *data)
3524 {
3525 g_assert (data != NULL);
3526
3527 if (data->directory_view != NULL) {
3528 g_object_remove_weak_pointer (G_OBJECT (data->directory_view),
3529 (gpointer *) &data->directory_view);
3530 }
3531
3532 nemo_file_list_free (data->added_files);
3533 g_free (data);
3534 }
3535
3536 static void
pre_copy_move_add_file_callback(NemoView * view,NemoFile * new_file,NemoDirectory * directory,CopyMoveDoneData * data)3537 pre_copy_move_add_file_callback (NemoView *view,
3538 NemoFile *new_file,
3539 NemoDirectory *directory,
3540 CopyMoveDoneData *data)
3541 {
3542 nemo_file_ref (new_file);
3543 data->added_files = g_list_prepend (data->added_files, new_file);
3544 }
3545
3546 /* This needs to be called prior to nemo_file_operations_copy_move.
3547 * It hooks up a signal handler to catch any icons that get added before
3548 * the copy_done_callback is invoked. The return value should be passed
3549 * as the data for uri_copy_move_done_callback.
3550 */
3551 static CopyMoveDoneData *
pre_copy_move(NemoView * directory_view)3552 pre_copy_move (NemoView *directory_view)
3553 {
3554 CopyMoveDoneData *copy_move_done_data;
3555
3556 copy_move_done_data = g_new0 (CopyMoveDoneData, 1);
3557 copy_move_done_data->directory_view = directory_view;
3558
3559 g_object_add_weak_pointer (G_OBJECT (copy_move_done_data->directory_view),
3560 (gpointer *) ©_move_done_data->directory_view);
3561
3562 /* We need to run after the default handler adds the folder we want to
3563 * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we
3564 * must use connect_after.
3565 */
3566 g_signal_connect (directory_view, "add_file",
3567 G_CALLBACK (pre_copy_move_add_file_callback), copy_move_done_data);
3568
3569 return copy_move_done_data;
3570 }
3571
3572 /* This function is used to pull out any debuting uris that were added
3573 * and (as a side effect) remove them from the debuting uri hash table.
3574 */
3575 static gboolean
copy_move_done_partition_func(gpointer data,gpointer callback_data)3576 copy_move_done_partition_func (gpointer data, gpointer callback_data)
3577 {
3578 GFile *location;
3579 gboolean result;
3580
3581 location = nemo_file_get_location (NEMO_FILE (data));
3582 result = g_hash_table_remove ((GHashTable *) callback_data, location);
3583 g_object_unref (location);
3584
3585 return result;
3586 }
3587
3588 static gboolean
remove_not_really_moved_files(gpointer key,gpointer value,gpointer callback_data)3589 remove_not_really_moved_files (gpointer key,
3590 gpointer value,
3591 gpointer callback_data)
3592 {
3593 GList **added_files;
3594 GFile *loc;
3595
3596 loc = key;
3597
3598 if (GPOINTER_TO_INT (value)) {
3599 return FALSE;
3600 }
3601
3602 added_files = callback_data;
3603 *added_files = g_list_prepend (*added_files,
3604 nemo_file_get (loc));
3605 return TRUE;
3606 }
3607
3608
3609 /* When this function is invoked, the file operation is over, but all
3610 * the icons may not have been added to the directory view yet, so
3611 * we can't select them yet.
3612 *
3613 * We're passed a hash table of the uri's to look out for, we hook
3614 * up a signal handler to await their arrival.
3615 */
3616 static void
copy_move_done_callback(GHashTable * debuting_files,gboolean success,gpointer data)3617 copy_move_done_callback (GHashTable *debuting_files,
3618 gboolean success,
3619 gpointer data)
3620 {
3621 NemoView *directory_view;
3622 CopyMoveDoneData *copy_move_done_data;
3623 DebutingFilesData *debuting_files_data;
3624
3625 copy_move_done_data = (CopyMoveDoneData *) data;
3626 directory_view = copy_move_done_data->directory_view;
3627
3628 if (directory_view != NULL) {
3629 g_assert (NEMO_IS_VIEW (directory_view));
3630
3631 debuting_files_data = g_new (DebutingFilesData, 1);
3632 debuting_files_data->debuting_files = g_hash_table_ref (debuting_files);
3633 debuting_files_data->added_files = eel_g_list_partition
3634 (copy_move_done_data->added_files,
3635 copy_move_done_partition_func,
3636 debuting_files,
3637 ©_move_done_data->added_files);
3638
3639 /* We're passed the same data used by pre_copy_move_add_file_callback, so disconnecting
3640 * it will free data. We've already siphoned off the added_files we need, and stashed the
3641 * directory_view pointer.
3642 */
3643 g_signal_handlers_disconnect_by_func (directory_view,
3644 G_CALLBACK (pre_copy_move_add_file_callback),
3645 data);
3646
3647 /* Any items in the debuting_files hash table that have
3648 * "FALSE" as their value aren't really being copied
3649 * or moved, so we can't wait for an add_file signal
3650 * to come in for those.
3651 */
3652 g_hash_table_foreach_remove (debuting_files,
3653 remove_not_really_moved_files,
3654 &debuting_files_data->added_files);
3655
3656 if (g_hash_table_size (debuting_files) == 0) {
3657 /* on the off-chance that all the icons have already been added */
3658 if (debuting_files_data->added_files != NULL) {
3659 nemo_view_call_set_selection (directory_view,
3660 debuting_files_data->added_files);
3661 nemo_view_reveal_selection (directory_view);
3662 }
3663 debuting_files_data_free (debuting_files_data);
3664 } else {
3665 /* We need to run after the default handler adds the folder we want to
3666 * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we
3667 * must use connect_after.
3668 */
3669 g_signal_connect_data (directory_view,
3670 "add_file",
3671 G_CALLBACK (debuting_files_add_file_callback),
3672 debuting_files_data,
3673 (GClosureNotify) debuting_files_data_free,
3674 G_CONNECT_AFTER);
3675 }
3676 /* Schedule menu update for undo items */
3677 schedule_update_menus (directory_view);
3678 }
3679
3680 copy_move_done_data_free (copy_move_done_data);
3681 }
3682
3683 static gboolean
view_file_still_belongs(NemoView * view,NemoFile * file,NemoDirectory * directory)3684 view_file_still_belongs (NemoView *view,
3685 NemoFile *file,
3686 NemoDirectory *directory)
3687 {
3688 if (view->details->model != directory &&
3689 g_list_find (view->details->subdirectory_list, directory) == NULL) {
3690 return FALSE;
3691 }
3692
3693 return nemo_directory_contains_file (directory, file);
3694 }
3695
3696 static gboolean
still_should_show_file(NemoView * view,NemoFile * file,NemoDirectory * directory)3697 still_should_show_file (NemoView *view, NemoFile *file, NemoDirectory *directory)
3698 {
3699 return nemo_view_should_show_file (view, file) &&
3700 view_file_still_belongs (view, file, directory);
3701 }
3702
3703 static gboolean
ready_to_load(NemoFile * file)3704 ready_to_load (NemoFile *file)
3705 {
3706 return nemo_file_check_if_ready (file,
3707 NEMO_FILE_ATTRIBUTES_FOR_ICON);
3708 }
3709
3710 static int
compare_files_cover(gconstpointer a,gconstpointer b,gpointer callback_data)3711 compare_files_cover (gconstpointer a, gconstpointer b, gpointer callback_data)
3712 {
3713 const FileAndDirectory *fad1, *fad2;
3714 NemoView *view;
3715
3716 view = callback_data;
3717 fad1 = a; fad2 = b;
3718
3719 if (fad1->directory < fad2->directory) {
3720 return -1;
3721 } else if (fad1->directory > fad2->directory) {
3722 return 1;
3723 } else {
3724 return NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compare_files (view, fad1->file, fad2->file);
3725 }
3726 }
3727 static void
sort_files(NemoView * view,GList ** list)3728 sort_files (NemoView *view, GList **list)
3729 {
3730 *list = g_list_sort_with_data (*list, compare_files_cover, view);
3731
3732 }
3733
3734 /* Go through all the new added and changed files.
3735 * Put any that are not ready to load in the non_ready_files hash table.
3736 * Add all the rest to the old_added_files and old_changed_files lists.
3737 * Sort the old_*_files lists if anything was added to them.
3738 */
3739 static void
process_new_files(NemoView * view)3740 process_new_files (NemoView *view)
3741 {
3742 GList *new_added_files, *new_changed_files, *old_added_files, *old_changed_files;
3743 GHashTable *non_ready_files;
3744 GList *node, *next;
3745 FileAndDirectory *pending;
3746 gboolean in_non_ready;
3747
3748 new_added_files = view->details->new_added_files;
3749 view->details->new_added_files = NULL;
3750 new_changed_files = view->details->new_changed_files;
3751 view->details->new_changed_files = NULL;
3752
3753 non_ready_files = view->details->non_ready_files;
3754
3755 old_added_files = view->details->old_added_files;
3756 old_changed_files = view->details->old_changed_files;
3757
3758 /* Newly added files go into the old_added_files list if they're
3759 * ready, and into the hash table if they're not.
3760 */
3761 for (node = new_added_files; node != NULL; node = next) {
3762 next = node->next;
3763 pending = (FileAndDirectory *)node->data;
3764 in_non_ready = g_hash_table_lookup (non_ready_files, pending) != NULL;
3765 if (nemo_view_should_show_file (view, pending->file)) {
3766 if (ready_to_load (pending->file)) {
3767 if (in_non_ready) {
3768 g_hash_table_remove (non_ready_files, pending);
3769 }
3770 new_added_files = g_list_delete_link (new_added_files, node);
3771 old_added_files = g_list_prepend (old_added_files, pending);
3772 } else {
3773 if (!in_non_ready) {
3774 new_added_files = g_list_delete_link (new_added_files, node);
3775 g_hash_table_insert (non_ready_files, pending, pending);
3776 }
3777 }
3778 }
3779 }
3780 file_and_directory_list_free (new_added_files);
3781
3782 /* Newly changed files go into the old_added_files list if they're ready
3783 * and were seen non-ready in the past, into the old_changed_files list
3784 * if they are read and were not seen non-ready in the past, and into
3785 * the hash table if they're not ready.
3786 */
3787 for (node = new_changed_files; node != NULL; node = next) {
3788 next = node->next;
3789 pending = (FileAndDirectory *)node->data;
3790 if (!still_should_show_file (view, pending->file, pending->directory) || ready_to_load (pending->file)) {
3791 if (g_hash_table_lookup (non_ready_files, pending) != NULL) {
3792 g_hash_table_remove (non_ready_files, pending);
3793 if (still_should_show_file (view, pending->file, pending->directory)) {
3794 new_changed_files = g_list_delete_link (new_changed_files, node);
3795 old_added_files = g_list_prepend (old_added_files, pending);
3796 }
3797 } else if (nemo_view_should_show_file (view, pending->file)) {
3798 new_changed_files = g_list_delete_link (new_changed_files, node);
3799 old_changed_files = g_list_prepend (old_changed_files, pending);
3800 }
3801 }
3802 }
3803 file_and_directory_list_free (new_changed_files);
3804
3805 /* If any files were added to old_added_files, then resort it. */
3806 if (old_added_files != view->details->old_added_files) {
3807 view->details->old_added_files = old_added_files;
3808 sort_files (view, &view->details->old_added_files);
3809 }
3810
3811 /* Resort old_changed_files too, since file attributes
3812 * relevant to sorting could have changed.
3813 */
3814 if (old_changed_files != view->details->old_changed_files) {
3815 view->details->old_changed_files = old_changed_files;
3816 sort_files (view, &view->details->old_changed_files);
3817 }
3818
3819 }
3820
3821 static void
process_old_files(NemoView * view)3822 process_old_files (NemoView *view)
3823 {
3824 GList *files_added, *files_changed, *node;
3825 FileAndDirectory *pending;
3826 GList *selection, *files;
3827 gboolean send_selection_change;
3828
3829 files_added = view->details->old_added_files;
3830 files_changed = view->details->old_changed_files;
3831
3832 send_selection_change = FALSE;
3833
3834 if (files_added != NULL || files_changed != NULL) {
3835 g_signal_emit (view, signals[BEGIN_FILE_CHANGES], 0);
3836
3837 for (node = files_added; node != NULL; node = node->next) {
3838 pending = node->data;
3839 g_signal_emit (view,
3840 signals[ADD_FILE], 0, pending->file, pending->directory);
3841 }
3842
3843 for (node = files_changed; node != NULL; node = node->next) {
3844 pending = node->data;
3845 g_signal_emit (view,
3846 signals[still_should_show_file (view, pending->file, pending->directory)
3847 ? FILE_CHANGED : REMOVE_FILE], 0,
3848 pending->file, pending->directory);
3849 }
3850
3851 g_signal_emit (view, signals[END_FILE_CHANGES], 0);
3852
3853 if (files_changed != NULL) {
3854 selection = nemo_view_get_selection (view);
3855 files = file_and_directory_list_to_files (files_changed);
3856 send_selection_change = eel_g_lists_sort_and_check_for_intersection
3857 (&files, &selection);
3858 nemo_file_list_free (files);
3859 nemo_file_list_free (selection);
3860 }
3861
3862 file_and_directory_list_free (view->details->old_added_files);
3863 view->details->old_added_files = NULL;
3864
3865 file_and_directory_list_free (view->details->old_changed_files);
3866 view->details->old_changed_files = NULL;
3867 }
3868
3869 if (send_selection_change) {
3870 /* Send a selection change since some file names could
3871 * have changed.
3872 */
3873 nemo_view_send_selection_change (view);
3874 }
3875 }
3876
3877 static void
display_pending_files(NemoView * view)3878 display_pending_files (NemoView *view)
3879 {
3880
3881 /* Don't dispatch any updates while the view is frozen. */
3882 if (view->details->updates_frozen) {
3883 return;
3884 }
3885
3886 process_new_files (view);
3887 process_old_files (view);
3888
3889 if (view->details->model != NULL
3890 && nemo_directory_are_all_files_seen (view->details->model)
3891 && g_hash_table_size (view->details->non_ready_files) == 0) {
3892 done_loading (view, TRUE);
3893 }
3894 }
3895
3896 void
nemo_view_freeze_updates(NemoView * view)3897 nemo_view_freeze_updates (NemoView *view)
3898 {
3899 view->details->updates_frozen = TRUE;
3900 view->details->updates_queued = 0;
3901 view->details->needs_reload = FALSE;
3902 }
3903
3904 void
nemo_view_unfreeze_updates(NemoView * view)3905 nemo_view_unfreeze_updates (NemoView *view)
3906 {
3907 view->details->updates_frozen = FALSE;
3908
3909 if (view->details->needs_reload) {
3910 view->details->needs_reload = FALSE;
3911 if (view->details->model != NULL) {
3912 load_directory (view, view->details->model);
3913 }
3914 } else {
3915 schedule_idle_display_of_pending_files (view);
3916 }
3917 }
3918
3919 static gboolean
display_selection_info_idle_callback(gpointer data)3920 display_selection_info_idle_callback (gpointer data)
3921 {
3922 NemoView *view;
3923
3924 view = NEMO_VIEW (data);
3925
3926 g_object_ref (G_OBJECT (view));
3927
3928 view->details->display_selection_idle_id = 0;
3929 nemo_view_display_selection_info (view);
3930 if (view->details->send_selection_change_to_shell) {
3931 nemo_view_send_selection_change (view);
3932 }
3933
3934 g_object_unref (G_OBJECT (view));
3935
3936 return FALSE;
3937 }
3938
3939 static void
remove_update_menus_timeout_callback(NemoView * view)3940 remove_update_menus_timeout_callback (NemoView *view)
3941 {
3942 if (view->details->update_menus_timeout_id != 0) {
3943 g_source_remove (view->details->update_menus_timeout_id);
3944 view->details->update_menus_timeout_id = 0;
3945 }
3946 }
3947
3948 static void
update_menus_if_pending(NemoView * view)3949 update_menus_if_pending (NemoView *view)
3950 {
3951 if (!view->details->menu_states_untrustworthy) {
3952 return;
3953 }
3954
3955 remove_update_menus_timeout_callback (view);
3956 nemo_view_update_menus (view);
3957 }
3958
3959 static gboolean
update_menus_timeout_callback(gpointer data)3960 update_menus_timeout_callback (gpointer data)
3961 {
3962 NemoView *view;
3963 view = NEMO_VIEW (data);
3964
3965 g_object_ref (G_OBJECT (view));
3966
3967 view->details->update_menus_timeout_id = 0;
3968 nemo_view_update_menus (view);
3969
3970 g_object_unref (G_OBJECT (view));
3971
3972 return FALSE;
3973 }
3974
3975 static gboolean
display_pending_callback(gpointer data)3976 display_pending_callback (gpointer data)
3977 {
3978 NemoView *view;
3979
3980 view = NEMO_VIEW (data);
3981
3982 g_object_ref (G_OBJECT (view));
3983
3984 view->details->display_pending_source_id = 0;
3985
3986 display_pending_files (view);
3987
3988 g_object_unref (G_OBJECT (view));
3989
3990 return FALSE;
3991 }
3992
3993 static void
schedule_idle_display_of_pending_files(NemoView * view)3994 schedule_idle_display_of_pending_files (NemoView *view)
3995 {
3996 /* Get rid of a pending source as it might be a timeout */
3997 unschedule_display_of_pending_files (view);
3998
3999 /* We want higher priority than the idle that handles the relayout
4000 to avoid a resort on each add. But we still want to allow repaints
4001 and other hight prio events while we have pending files to show. */
4002 view->details->display_pending_source_id =
4003 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20,
4004 display_pending_callback, view, NULL);
4005 }
4006
4007 static void
schedule_timeout_display_of_pending_files(NemoView * view,guint interval)4008 schedule_timeout_display_of_pending_files (NemoView *view, guint interval)
4009 {
4010 /* No need to schedule an update if there's already one pending. */
4011 if (view->details->display_pending_source_id != 0) {
4012 return;
4013 }
4014
4015 view->details->display_pending_source_id =
4016 g_timeout_add (interval, display_pending_callback, view);
4017 }
4018
4019 static void
unschedule_display_of_pending_files(NemoView * view)4020 unschedule_display_of_pending_files (NemoView *view)
4021 {
4022 /* Get rid of source if it's active. */
4023 if (view->details->display_pending_source_id != 0) {
4024 g_source_remove (view->details->display_pending_source_id);
4025 view->details->display_pending_source_id = 0;
4026 }
4027 }
4028
4029 static void
queue_pending_files(NemoView * view,NemoDirectory * directory,GList * files,GList ** pending_list)4030 queue_pending_files (NemoView *view,
4031 NemoDirectory *directory,
4032 GList *files,
4033 GList **pending_list)
4034 {
4035 if (files == NULL) {
4036 return;
4037 }
4038
4039 /* Don't queue any more updates if we need to reload anyway */
4040 if (view->details->needs_reload) {
4041 return;
4042 }
4043
4044 if (view->details->updates_frozen) {
4045 view->details->updates_queued += g_list_length (files);
4046 /* Mark the directory for reload when there are too much queued
4047 * changes to prevent the pending list from growing infinitely.
4048 */
4049 if (view->details->updates_queued > MAX_QUEUED_UPDATES) {
4050 view->details->needs_reload = TRUE;
4051 return;
4052 }
4053 }
4054
4055 *pending_list = g_list_concat (file_and_directory_list_from_files (directory, files),
4056 *pending_list);
4057
4058 schedule_timeout_display_of_pending_files (view, view->details->update_interval);
4059 }
4060
4061 static void
remove_changes_timeout_callback(NemoView * view)4062 remove_changes_timeout_callback (NemoView *view)
4063 {
4064 if (view->details->changes_timeout_id != 0) {
4065 g_source_remove (view->details->changes_timeout_id);
4066 view->details->changes_timeout_id = 0;
4067 }
4068 }
4069
4070 static void
reset_update_interval(NemoView * view)4071 reset_update_interval (NemoView *view)
4072 {
4073 view->details->update_interval = UPDATE_INTERVAL_MIN;
4074 remove_changes_timeout_callback (view);
4075 /* Reschedule a pending timeout to idle */
4076 if (view->details->display_pending_source_id != 0) {
4077 schedule_idle_display_of_pending_files (view);
4078 }
4079 }
4080
4081 static gboolean
changes_timeout_callback(gpointer data)4082 changes_timeout_callback (gpointer data)
4083 {
4084 gint64 now;
4085 gint64 time_delta;
4086 gboolean ret;
4087 NemoView *view;
4088 view = NEMO_VIEW (data);
4089
4090 g_object_ref (G_OBJECT (view));
4091
4092 now = g_get_monotonic_time ();
4093 time_delta = now - view->details->last_queued;
4094
4095 if (time_delta < UPDATE_INTERVAL_RESET*1000) {
4096 if (view->details->update_interval < UPDATE_INTERVAL_MAX &&
4097 view->details->loading) {
4098 /* Increase */
4099 view->details->update_interval += UPDATE_INTERVAL_INC;
4100 }
4101 ret = TRUE;
4102 } else {
4103 /* Reset */
4104 reset_update_interval (view);
4105 ret = FALSE;
4106 }
4107
4108 g_object_unref (G_OBJECT (view));
4109
4110 return ret;
4111 }
4112
4113 static void
schedule_changes(NemoView * view)4114 schedule_changes (NemoView *view)
4115 {
4116 /* Remember when the change was queued */
4117 view->details->last_queued = g_get_monotonic_time ();
4118
4119 /* No need to schedule if there are already changes pending or during loading */
4120 if (view->details->changes_timeout_id != 0 ||
4121 view->details->loading) {
4122 return;
4123 }
4124
4125 view->details->changes_timeout_id =
4126 g_timeout_add (UPDATE_INTERVAL_TIMEOUT_INTERVAL, changes_timeout_callback, view);
4127 }
4128
4129 static void
files_added_callback(NemoDirectory * directory,GList * files,gpointer callback_data)4130 files_added_callback (NemoDirectory *directory,
4131 GList *files,
4132 gpointer callback_data)
4133 {
4134 NemoView *view;
4135 GtkWindow *window;
4136 char *uri;
4137
4138 view = NEMO_VIEW (callback_data);
4139
4140 window = nemo_view_get_containing_window (view);
4141 uri = nemo_view_get_uri (view);
4142 DEBUG_FILES (files, "Files added in window %p: %s",
4143 window, uri ? uri : "(no directory)");
4144 g_free (uri);
4145
4146 schedule_changes (view);
4147
4148 queue_pending_files (view, directory, files, &view->details->new_added_files);
4149
4150 /* The number of items could have changed */
4151 schedule_update_status (view);
4152 }
4153
4154 static void
files_changed_callback(NemoDirectory * directory,GList * files,gpointer callback_data)4155 files_changed_callback (NemoDirectory *directory,
4156 GList *files,
4157 gpointer callback_data)
4158 {
4159 NemoView *view;
4160 GtkWindow *window;
4161 char *uri;
4162
4163 view = NEMO_VIEW (callback_data);
4164
4165 window = nemo_view_get_containing_window (view);
4166 uri = nemo_view_get_uri (view);
4167 DEBUG_FILES (files, "Files changed in window %p: %s",
4168 window, uri ? uri : "(no directory)");
4169 g_free (uri);
4170
4171 schedule_changes (view);
4172
4173 queue_pending_files (view, directory, files, &view->details->new_changed_files);
4174
4175 /* The free space or the number of items could have changed */
4176 schedule_update_status (view);
4177
4178 /* A change in MIME type could affect the Open with menu, for
4179 * one thing, so we need to update menus when files change.
4180 */
4181 schedule_update_menus (view);
4182 }
4183
4184 static void
done_loading_callback(NemoDirectory * directory,gpointer callback_data)4185 done_loading_callback (NemoDirectory *directory,
4186 gpointer callback_data)
4187 {
4188 NemoView *view;
4189
4190 view = NEMO_VIEW (callback_data);
4191
4192 process_new_files (view);
4193 if (g_hash_table_size (view->details->non_ready_files) == 0) {
4194 /* Unschedule a pending update and schedule a new one with the minimal
4195 * update interval. This gives the view a short chance at gathering the
4196 * (cached) deep counts.
4197 */
4198 unschedule_display_of_pending_files (view);
4199 schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN);
4200 }
4201 }
4202
4203 static void
load_error_callback(NemoDirectory * directory,GError * error,gpointer callback_data)4204 load_error_callback (NemoDirectory *directory,
4205 GError *error,
4206 gpointer callback_data)
4207 {
4208 NemoView *view;
4209
4210 view = NEMO_VIEW (callback_data);
4211
4212 /* FIXME: By doing a stop, we discard some pending files. Is
4213 * that OK?
4214 */
4215 nemo_view_stop_loading (view);
4216
4217 nemo_window_back_or_forward (NEMO_WINDOW (view->details->window),
4218 TRUE, 0, FALSE);
4219
4220 /* Emit a signal to tell subclasses that a load error has
4221 * occurred, so they can handle it in the UI.
4222 */
4223 g_signal_emit (view,
4224 signals[LOAD_ERROR], 0, error);
4225 }
4226
4227 static void
real_load_error(NemoView * view,GError * error)4228 real_load_error (NemoView *view, GError *error)
4229 {
4230 /* Report only one error per failed directory load (from the UI
4231 * point of view, not from the NemoDirectory point of view).
4232 * Otherwise you can get multiple identical errors caused by
4233 * unrelated code that just happens to try to iterate this
4234 * directory.
4235 */
4236 if (!view->details->reported_load_error) {
4237 nemo_report_error_loading_directory
4238 (nemo_view_get_directory_as_file (view),
4239 error,
4240 nemo_view_get_containing_window (view));
4241 }
4242 view->details->reported_load_error = TRUE;
4243 }
4244
4245 void
nemo_view_add_subdirectory(NemoView * view,NemoDirectory * directory)4246 nemo_view_add_subdirectory (NemoView *view,
4247 NemoDirectory*directory)
4248 {
4249 NemoFileAttributes attributes;
4250
4251 g_assert (!g_list_find (view->details->subdirectory_list, directory));
4252
4253 nemo_directory_ref (directory);
4254
4255 attributes =
4256 NEMO_FILE_ATTRIBUTES_FOR_ICON |
4257 NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
4258 NEMO_FILE_ATTRIBUTE_INFO |
4259 NEMO_FILE_ATTRIBUTE_LINK_INFO |
4260 NEMO_FILE_ATTRIBUTE_MOUNT |
4261 NEMO_FILE_ATTRIBUTE_EXTENSION_INFO;
4262
4263 nemo_directory_file_monitor_add (directory,
4264 &view->details->model,
4265 view->details->show_hidden_files,
4266 attributes,
4267 files_added_callback, view);
4268
4269 g_signal_connect
4270 (directory, "files_added",
4271 G_CALLBACK (files_added_callback), view);
4272 g_signal_connect
4273 (directory, "files_changed",
4274 G_CALLBACK (files_changed_callback), view);
4275
4276 view->details->subdirectory_list = g_list_prepend (
4277 view->details->subdirectory_list, directory);
4278 }
4279
4280 void
nemo_view_remove_subdirectory(NemoView * view,NemoDirectory * directory)4281 nemo_view_remove_subdirectory (NemoView *view,
4282 NemoDirectory*directory)
4283 {
4284 g_assert (g_list_find (view->details->subdirectory_list, directory));
4285
4286 view->details->subdirectory_list = g_list_remove (
4287 view->details->subdirectory_list, directory);
4288
4289 g_signal_handlers_disconnect_by_func (directory,
4290 G_CALLBACK (files_added_callback),
4291 view);
4292 g_signal_handlers_disconnect_by_func (directory,
4293 G_CALLBACK (files_changed_callback),
4294 view);
4295
4296 nemo_directory_file_monitor_remove (directory, &view->details->model);
4297
4298 nemo_directory_unref (directory);
4299 }
4300
4301 /**
4302 * nemo_view_get_loading:
4303 * @view: an #NemoView.
4304 *
4305 * Return value: #gboolean inicating whether @view is currently loaded.
4306 *
4307 **/
4308 gboolean
nemo_view_get_loading(NemoView * view)4309 nemo_view_get_loading (NemoView *view)
4310 {
4311 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
4312
4313 return view->details->loading;
4314 }
4315
4316 GtkUIManager *
nemo_view_get_ui_manager(NemoView * view)4317 nemo_view_get_ui_manager (NemoView *view)
4318 {
4319 if (view->details->window == NULL) {
4320 return NULL;
4321 }
4322 return nemo_window_get_ui_manager (view->details->window);
4323 }
4324
4325 /**
4326 * nemo_view_get_model:
4327 *
4328 * Get the model for this NemoView.
4329 * @view: NemoView of interest.
4330 *
4331 * Return value: NemoDirectory for this view.
4332 *
4333 **/
4334 NemoDirectory *
nemo_view_get_model(NemoView * view)4335 nemo_view_get_model (NemoView *view)
4336 {
4337 g_return_val_if_fail (NEMO_IS_VIEW (view), NULL);
4338
4339 return view->details->model;
4340 }
4341
4342 GdkAtom
nemo_view_get_copied_files_atom(NemoView * view)4343 nemo_view_get_copied_files_atom (NemoView *view)
4344 {
4345 g_return_val_if_fail (NEMO_IS_VIEW (view), GDK_NONE);
4346
4347 return copied_files_atom;
4348 }
4349
4350 static void
prepend_uri_one(gpointer data,gpointer callback_data)4351 prepend_uri_one (gpointer data, gpointer callback_data)
4352 {
4353 NemoFile *file;
4354 GList **result;
4355
4356 g_assert (NEMO_IS_FILE (data));
4357 g_assert (callback_data != NULL);
4358
4359 result = (GList **) callback_data;
4360 file = (NemoFile *) data;
4361 *result = g_list_prepend (*result, nemo_file_get_uri (file));
4362 }
4363
4364 static void
offset_drop_points(GArray * relative_item_points,int x_offset,int y_offset)4365 offset_drop_points (GArray *relative_item_points,
4366 int x_offset, int y_offset)
4367 {
4368 guint index;
4369
4370 if (relative_item_points == NULL) {
4371 return;
4372 }
4373
4374 for (index = 0; index < relative_item_points->len; index++) {
4375 g_array_index (relative_item_points, GdkPoint, index).x += x_offset;
4376 g_array_index (relative_item_points, GdkPoint, index).y += y_offset;
4377 }
4378 }
4379
4380 static void
nemo_view_create_links_for_files(NemoView * view,GList * files,GArray * relative_item_points)4381 nemo_view_create_links_for_files (NemoView *view, GList *files,
4382 GArray *relative_item_points)
4383 {
4384 GList *uris;
4385 char *dir_uri;
4386 CopyMoveDoneData *copy_move_done_data;
4387 g_assert (relative_item_points->len == 0
4388 || g_list_length (files) == relative_item_points->len);
4389
4390 g_assert (NEMO_IS_VIEW (view));
4391 g_assert (files != NULL);
4392
4393 /* create a list of URIs */
4394 uris = NULL;
4395 g_list_foreach (files, prepend_uri_one, &uris);
4396 uris = g_list_reverse (uris);
4397
4398 g_assert (g_list_length (uris) == g_list_length (files));
4399
4400 /* offset the drop locations a bit so that we don't pile
4401 * up the icons on top of each other
4402 */
4403 offset_drop_points (relative_item_points,
4404 DUPLICATE_HORIZONTAL_ICON_OFFSET,
4405 DUPLICATE_VERTICAL_ICON_OFFSET);
4406
4407 copy_move_done_data = pre_copy_move (view);
4408 dir_uri = nemo_view_get_backing_uri (view);
4409 nemo_file_operations_copy_move (uris, relative_item_points, dir_uri, GDK_ACTION_LINK,
4410 GTK_WIDGET (view), copy_move_done_callback, copy_move_done_data);
4411 g_free (dir_uri);
4412 g_list_free_full (uris, g_free);
4413 }
4414
4415 static void
nemo_view_duplicate_selection(NemoView * view,GList * files,GArray * relative_item_points)4416 nemo_view_duplicate_selection (NemoView *view, GList *files,
4417 GArray *relative_item_points)
4418 {
4419 GList *uris;
4420 CopyMoveDoneData *copy_move_done_data;
4421
4422 g_assert (NEMO_IS_VIEW (view));
4423 g_assert (files != NULL);
4424 g_assert (g_list_length (files) == relative_item_points->len
4425 || relative_item_points->len == 0);
4426
4427 /* create a list of URIs */
4428 uris = NULL;
4429 g_list_foreach (files, prepend_uri_one, &uris);
4430 uris = g_list_reverse (uris);
4431
4432 g_assert (g_list_length (uris) == g_list_length (files));
4433
4434 /* offset the drop locations a bit so that we don't pile
4435 * up the icons on top of each other
4436 */
4437 offset_drop_points (relative_item_points,
4438 DUPLICATE_HORIZONTAL_ICON_OFFSET,
4439 DUPLICATE_VERTICAL_ICON_OFFSET);
4440
4441 copy_move_done_data = pre_copy_move (view);
4442 nemo_file_operations_copy_move (uris, relative_item_points, NULL, GDK_ACTION_COPY,
4443 GTK_WIDGET (view), copy_move_done_callback, copy_move_done_data);
4444 g_list_free_full (uris, g_free);
4445 }
4446
4447 /* special_link_in_selection
4448 *
4449 * Return TRUE if one of our special links is in the selection.
4450 * Special links include the following:
4451 * NEMO_DESKTOP_LINK_TRASH, NEMO_DESKTOP_LINK_HOME, NEMO_DESKTOP_LINK_MOUNT
4452 */
4453
4454 static gboolean
special_link_in_selection(NemoView * view,GList * selection)4455 special_link_in_selection (NemoView *view, GList *selection)
4456 {
4457 gboolean saw_link;
4458 GList *node;
4459 NemoFile *file;
4460
4461 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
4462
4463 saw_link = FALSE;
4464
4465 for (node = selection; node != NULL; node = node->next) {
4466 file = NEMO_FILE (node->data);
4467
4468 saw_link = NEMO_IS_DESKTOP_ICON_FILE (file);
4469
4470 if (saw_link) {
4471 break;
4472 }
4473 }
4474
4475 return saw_link;
4476 }
4477
4478 /* desktop_or_home_dir_in_selection
4479 *
4480 * Return TRUE if either the desktop or the home directory is in the selection.
4481 */
4482
4483 static gboolean
desktop_or_home_dir_in_selection(NemoView * view,GList * selection)4484 desktop_or_home_dir_in_selection (NemoView *view, GList *selection)
4485 {
4486 gboolean saw_desktop_or_home_dir;
4487 GList *node;
4488 NemoFile *file;
4489
4490 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
4491
4492 saw_desktop_or_home_dir = FALSE;
4493
4494 for (node = selection; node != NULL; node = node->next) {
4495 file = NEMO_FILE (node->data);
4496
4497 saw_desktop_or_home_dir =
4498 nemo_file_is_home (file)
4499 || nemo_file_is_desktop_directory (file);
4500
4501 if (saw_desktop_or_home_dir) {
4502 break;
4503 }
4504 }
4505
4506 return saw_desktop_or_home_dir;
4507 }
4508
4509 /* directory_in_selection
4510 *
4511 * Return TRUE if selection contains a directory.
4512 */
4513
4514 static gboolean
directory_in_selection(NemoView * view,GList * selection)4515 directory_in_selection (NemoView *view, GList *selection)
4516 {
4517 gboolean has_dir;
4518 GList *node;
4519 NemoFile *file;
4520
4521 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
4522
4523 has_dir = FALSE;
4524
4525 for (node = selection; node != NULL; node = node->next) {
4526 file = NEMO_FILE (node->data);
4527
4528 has_dir = nemo_file_is_directory (file);
4529 if (has_dir) {
4530 break;
4531 }
4532 }
4533
4534 return has_dir;
4535 }
4536
4537 static void
trash_or_delete_done_cb(GHashTable * debuting_uris,gboolean user_cancel,NemoView * view)4538 trash_or_delete_done_cb (GHashTable *debuting_uris,
4539 gboolean user_cancel,
4540 NemoView *view)
4541 {
4542 if (user_cancel) {
4543 view->details->selection_was_removed = FALSE;
4544 }
4545 }
4546
4547 static void
trash_or_delete_files(GtkWindow * parent_window,const GList * files,gboolean delete_if_all_already_in_trash,NemoView * view)4548 trash_or_delete_files (GtkWindow *parent_window,
4549 const GList *files,
4550 gboolean delete_if_all_already_in_trash,
4551 NemoView *view)
4552 {
4553 GList *locations;
4554 const GList *node;
4555
4556 locations = NULL;
4557 for (node = files; node != NULL; node = node->next) {
4558 locations = g_list_prepend (locations,
4559 nemo_file_get_location ((NemoFile *) node->data));
4560 }
4561
4562 locations = g_list_reverse (locations);
4563
4564 nemo_file_operations_trash_or_delete (locations,
4565 parent_window,
4566 (NemoDeleteCallback) trash_or_delete_done_cb,
4567 view);
4568 g_list_free_full (locations, g_object_unref);
4569 }
4570
4571 static gboolean
can_rename_file(NemoView * view,NemoFile * file)4572 can_rename_file (NemoView *view, NemoFile *file)
4573 {
4574 return nemo_file_can_rename (file);
4575 }
4576
4577 gboolean
nemo_view_get_is_renaming(NemoView * view)4578 nemo_view_get_is_renaming (NemoView *view)
4579 {
4580 return view->details->is_renaming;
4581 }
4582
4583 void
nemo_view_set_is_renaming(NemoView * view,gboolean is_renaming)4584 nemo_view_set_is_renaming (NemoView *view,
4585 gboolean is_renaming)
4586 {
4587 view->details->is_renaming = is_renaming;
4588 }
4589
4590 static void
start_renaming_file(NemoView * view,NemoFile * file,gboolean select_all)4591 start_renaming_file (NemoView *view,
4592 NemoFile *file,
4593 gboolean select_all)
4594 {
4595 view->details->is_renaming = TRUE;
4596
4597 if (file != NULL) {
4598 nemo_view_select_file (view, file);
4599 }
4600 }
4601
4602 static void
update_context_menu_position_from_event(NemoView * view,GdkEventButton * event)4603 update_context_menu_position_from_event (NemoView *view,
4604 GdkEventButton *event)
4605 {
4606 g_return_if_fail (NEMO_IS_VIEW (view));
4607
4608 if (event != NULL) {
4609 view->details->context_menu_position.x = event->x;
4610 view->details->context_menu_position.y = event->y;
4611 } else {
4612 view->details->context_menu_position.x = -1;
4613 view->details->context_menu_position.y = -1;
4614 }
4615 }
4616
4617 /* handle the open command */
4618
4619 static void
open_one_in_new_window(gpointer data,gpointer callback_data)4620 open_one_in_new_window (gpointer data, gpointer callback_data)
4621 {
4622 g_assert (NEMO_IS_FILE (data));
4623 g_assert (NEMO_IS_VIEW (callback_data));
4624
4625 nemo_view_activate_file (NEMO_VIEW (callback_data),
4626 NEMO_FILE (data),
4627 NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW);
4628 }
4629
4630 NemoFile *
nemo_view_get_directory_as_file(NemoView * view)4631 nemo_view_get_directory_as_file (NemoView *view)
4632 {
4633 g_assert (NEMO_IS_VIEW (view));
4634
4635 return view->details->directory_as_file;
4636 }
4637
4638 static void
open_with_launch_application_callback(GtkAction * action,gpointer callback_data)4639 open_with_launch_application_callback (GtkAction *action,
4640 gpointer callback_data)
4641 {
4642 ApplicationLaunchParameters *launch_parameters;
4643
4644 launch_parameters = (ApplicationLaunchParameters *) callback_data;
4645 nemo_launch_application
4646 (launch_parameters->application,
4647 launch_parameters->files,
4648 nemo_view_get_containing_window (launch_parameters->directory_view));
4649 }
4650
4651 static char *
escape_action_name(const char * action_name,const char * prefix)4652 escape_action_name (const char *action_name,
4653 const char *prefix)
4654 {
4655 GString *s;
4656
4657 if (action_name == NULL) {
4658 return NULL;
4659 }
4660
4661 s = g_string_new (prefix);
4662
4663 while (*action_name != 0) {
4664 switch (*action_name) {
4665 case '\\':
4666 g_string_append (s, "\\\\");
4667 break;
4668 case '/':
4669 g_string_append (s, "\\s");
4670 break;
4671 case '&':
4672 g_string_append (s, "\\a");
4673 break;
4674 case '"':
4675 g_string_append (s, "\\q");
4676 break;
4677 default:
4678 g_string_append_c (s, *action_name);
4679 }
4680
4681 action_name ++;
4682 }
4683 return g_string_free (s, FALSE);
4684 }
4685
4686 static char *
escape_action_path(const char * action_path)4687 escape_action_path (const char *action_path)
4688 {
4689 GString *s;
4690
4691 if (action_path == NULL) {
4692 return NULL;
4693 }
4694
4695 s = g_string_sized_new (strlen (action_path) + 2);
4696
4697 while (*action_path != 0) {
4698 switch (*action_path) {
4699 case '\\':
4700 g_string_append (s, "\\\\");
4701 break;
4702 case '&':
4703 g_string_append (s, "\\a");
4704 break;
4705 case '"':
4706 g_string_append (s, "\\q");
4707 break;
4708 default:
4709 g_string_append_c (s, *action_path);
4710 }
4711
4712 action_path ++;
4713 }
4714 return g_string_free (s, FALSE);
4715 }
4716
4717
4718 static void
add_submenu(GtkUIManager * ui_manager,GtkActionGroup * action_group,guint merge_id,const char * parent_path,const char * uri,const char * label,GdkPixbuf * pixbuf,gboolean add_action)4719 add_submenu (GtkUIManager *ui_manager,
4720 GtkActionGroup *action_group,
4721 guint merge_id,
4722 const char *parent_path,
4723 const char *uri,
4724 const char *label,
4725 GdkPixbuf *pixbuf,
4726 gboolean add_action)
4727 {
4728 char *escaped_label;
4729 char *action_name;
4730 char *submenu_name;
4731 char *escaped_submenu_name;
4732 GtkAction *action;
4733
4734 if (parent_path != NULL) {
4735 action_name = escape_action_name (uri, "submenu_");
4736 submenu_name = g_path_get_basename (uri);
4737 escaped_submenu_name = escape_action_path (submenu_name);
4738 escaped_label = eel_str_double_underscores (label);
4739
4740 if (add_action) {
4741 action = gtk_action_new (action_name,
4742 escaped_label,
4743 NULL,
4744 NULL);
4745 if (pixbuf != NULL) {
4746 gtk_action_set_gicon (action, G_ICON (pixbuf));
4747 }
4748
4749 g_object_set (action, "hide-if-empty", FALSE, NULL);
4750
4751 gtk_action_group_add_action (action_group,
4752 action);
4753 g_object_unref (action);
4754 }
4755
4756 gtk_ui_manager_add_ui (ui_manager,
4757 merge_id,
4758 parent_path,
4759 escaped_submenu_name,
4760 action_name,
4761 GTK_UI_MANAGER_MENU,
4762 FALSE);
4763 g_free (action_name);
4764 g_free (escaped_label);
4765 g_free (submenu_name);
4766 g_free (escaped_submenu_name);
4767 }
4768 }
4769
4770 static void
menu_item_show_image(GtkUIManager * ui_manager,const char * parent_path,const char * action_name,gboolean ignore_gtk_pref)4771 menu_item_show_image (GtkUIManager *ui_manager,
4772 const char *parent_path,
4773 const char *action_name,
4774 gboolean ignore_gtk_pref)
4775 {
4776 GtkImageMenuItem *menuitem;
4777 char *path;
4778 gboolean show = TRUE;
4779
4780 path = g_strdup_printf ("%s/%s", parent_path, action_name);
4781 menuitem = GTK_IMAGE_MENU_ITEM (gtk_ui_manager_get_widget (ui_manager,
4782 path));
4783 g_free (path);
4784
4785 if (!ignore_gtk_pref) {
4786 g_object_get (gtk_settings_get_default (), "gtk-menu-images", &show, NULL);
4787
4788 if (!show && !gtk_image_menu_item_get_always_show_image (menuitem)) {
4789 return;
4790 }
4791 }
4792
4793 if (menuitem != NULL) {
4794 gtk_image_menu_item_set_always_show_image (menuitem, show);
4795 }
4796 }
4797
4798 static void
add_application_to_open_with_menu(NemoView * view,GAppInfo * application,GList * files,int index,const char * menu_placeholder,const char * popup_placeholder,const gboolean submenu)4799 add_application_to_open_with_menu (NemoView *view,
4800 GAppInfo *application,
4801 GList *files,
4802 int index,
4803 const char *menu_placeholder,
4804 const char *popup_placeholder,
4805 const gboolean submenu)
4806 {
4807 ApplicationLaunchParameters *launch_parameters;
4808 char *tip;
4809 char *label;
4810 char *action_name;
4811 char *escaped_app;
4812 GtkAction *action;
4813 GIcon *app_icon;
4814 GtkUIManager *ui_manager;
4815
4816 launch_parameters = application_launch_parameters_new
4817 (application, files, view);
4818 escaped_app = eel_str_double_underscores (g_app_info_get_name (application));
4819 if (submenu)
4820 label = g_strdup_printf ("%s", escaped_app);
4821 else
4822 label = g_strdup_printf (_("Open With %s"), escaped_app);
4823
4824 tip = g_strdup_printf (ngettext ("Use \"%s\" to open the selected item",
4825 "Use \"%s\" to open the selected items",
4826 g_list_length (files)),
4827 escaped_app);
4828 g_free (escaped_app);
4829
4830 action_name = g_strdup_printf ("open_with_%d", index);
4831
4832 action = gtk_action_new (action_name,
4833 label,
4834 tip,
4835 NULL);
4836
4837 app_icon = g_app_info_get_icon (application);
4838 if (app_icon != NULL) {
4839 g_object_ref (app_icon);
4840 } else {
4841 app_icon = g_themed_icon_new ("application-x-executable");
4842 }
4843
4844 gtk_action_set_gicon (action, app_icon);
4845 g_object_unref (app_icon);
4846
4847 g_signal_connect_data (action, "activate",
4848 G_CALLBACK (open_with_launch_application_callback),
4849 launch_parameters,
4850 (GClosureNotify)application_launch_parameters_free, 0);
4851
4852 gtk_action_group_add_action (view->details->open_with_action_group,
4853 action);
4854 g_object_unref (action);
4855
4856 ui_manager = nemo_window_get_ui_manager (view->details->window);
4857 gtk_ui_manager_add_ui (ui_manager,
4858 view->details->open_with_merge_id,
4859 menu_placeholder,
4860 action_name,
4861 action_name,
4862 GTK_UI_MANAGER_MENUITEM,
4863 FALSE);
4864
4865 menu_item_show_image (ui_manager, menu_placeholder, action_name, TRUE);
4866
4867 gtk_ui_manager_add_ui (ui_manager,
4868 view->details->open_with_merge_id,
4869 popup_placeholder,
4870 action_name,
4871 action_name,
4872 GTK_UI_MANAGER_MENUITEM,
4873 FALSE);
4874
4875 menu_item_show_image (ui_manager, popup_placeholder, action_name, TRUE);
4876
4877 g_free (action_name);
4878 g_free (label);
4879 g_free (tip);
4880 }
4881
4882 static void
get_x_content_async_callback(const char ** content,gpointer user_data)4883 get_x_content_async_callback (const char **content,
4884 gpointer user_data)
4885 {
4886 NemoView *view;
4887
4888 view = NEMO_VIEW (user_data);
4889
4890 if (view->details->window != NULL) {
4891 schedule_update_menus (view);
4892 }
4893 g_object_unref (view);
4894 }
4895
4896 static void
add_x_content_apps(NemoView * view,NemoFile * file,GList ** applications)4897 add_x_content_apps (NemoView *view, NemoFile *file, GList **applications)
4898 {
4899 GMount *mount;
4900 char **x_content_types;
4901 unsigned int n;
4902
4903 g_return_if_fail (applications != NULL);
4904
4905 mount = nemo_file_get_mount (file);
4906
4907 if (mount == NULL) {
4908 return;
4909 }
4910
4911 x_content_types = nemo_get_cached_x_content_types_for_mount (mount);
4912 if (x_content_types != NULL) {
4913 for (n = 0; x_content_types[n] != NULL; n++) {
4914 char *x_content_type = x_content_types[n];
4915 GList *app_info_for_x_content_type;
4916
4917 app_info_for_x_content_type = g_app_info_get_all_for_type (x_content_type);
4918 *applications = g_list_concat (*applications, app_info_for_x_content_type);
4919 }
4920 g_strfreev (x_content_types);
4921 } else {
4922 nemo_get_x_content_types_for_mount_async (mount,
4923 get_x_content_async_callback,
4924 NULL,
4925 g_object_ref (view));
4926
4927 }
4928
4929 g_object_unref (mount);
4930 }
4931
4932 static void
reset_open_with_menu(NemoView * view,GList * selection,gboolean filter_default)4933 reset_open_with_menu (NemoView *view, GList *selection, gboolean filter_default)
4934 {
4935 GList *applications, *node;
4936 NemoFile *file;
4937 gboolean submenu_visible;
4938 int num_applications;
4939 int index;
4940 gboolean other_applications_visible;
4941 gboolean open_with_chooser_visible;
4942 GtkUIManager *ui_manager;
4943 GtkAction *action;
4944 GAppInfo *default_app;
4945
4946 /* Clear any previous inserted items in the applications and viewers placeholders */
4947
4948 ui_manager = nemo_window_get_ui_manager (view->details->window);
4949 nemo_ui_unmerge_ui (ui_manager,
4950 &view->details->open_with_merge_id,
4951 &view->details->open_with_action_group);
4952
4953 nemo_ui_prepare_merge_ui (ui_manager,
4954 "OpenWithGroup",
4955 &view->details->open_with_merge_id,
4956 &view->details->open_with_action_group);
4957
4958 other_applications_visible = (selection != NULL);
4959
4960 for (node = selection; node != NULL; node = node->next) {
4961
4962 file = NEMO_FILE (node->data);
4963
4964 other_applications_visible &= (!nemo_mime_file_opens_in_view (file) ||
4965 nemo_file_is_directory (file));
4966 }
4967
4968 default_app = NULL;
4969 if (filter_default && selection != NULL) {
4970 default_app = nemo_mime_get_default_application_for_files (selection);
4971 }
4972
4973 applications = NULL;
4974 if (other_applications_visible) {
4975 applications = nemo_mime_get_applications_for_files (selection);
4976 }
4977
4978 if (g_list_length (selection) == 1) {
4979 add_x_content_apps (view, NEMO_FILE (selection->data), &applications);
4980 }
4981
4982
4983 num_applications = g_list_length (applications);
4984
4985 if (file_list_all_are_folders (selection)) {
4986 submenu_visible = (num_applications > 0);
4987 } else {
4988 submenu_visible = (num_applications > 1);
4989 }
4990
4991 for (node = applications, index = 0; node != NULL; node = node->next, index++) {
4992 GAppInfo *application;
4993 char *menu_path;
4994 char *popup_path;
4995
4996 application = node->data;
4997
4998 if (default_app != NULL && g_app_info_equal (default_app, application)) {
4999 continue;
5000 }
5001
5002 if (submenu_visible) {
5003 menu_path = (char *)NEMO_VIEW_MENU_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER;
5004 popup_path = (char *)NEMO_VIEW_POPUP_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER;
5005 } else {
5006 menu_path = (char *)NEMO_VIEW_MENU_PATH_APPLICATIONS_PLACEHOLDER;
5007 popup_path = (char *)NEMO_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER;
5008 }
5009
5010 gtk_ui_manager_add_ui (nemo_window_get_ui_manager (view->details->window),
5011 view->details->open_with_merge_id,
5012 menu_path,
5013 "separator",
5014 NULL,
5015 GTK_UI_MANAGER_SEPARATOR,
5016 FALSE);
5017
5018 add_application_to_open_with_menu (view,
5019 node->data,
5020 selection,
5021 index,
5022 menu_path, popup_path, submenu_visible);
5023 }
5024 g_list_free_full (applications, g_object_unref);
5025 if (default_app != NULL) {
5026 g_object_unref (default_app);
5027 }
5028
5029 open_with_chooser_visible = other_applications_visible &&
5030 g_list_length (selection) == 1;
5031
5032 if (submenu_visible) {
5033 action = gtk_action_group_get_action (view->details->dir_action_group,
5034 NEMO_ACTION_OTHER_APPLICATION1);
5035 gtk_action_set_visible (action, open_with_chooser_visible);
5036 action = gtk_action_group_get_action (view->details->dir_action_group,
5037 NEMO_ACTION_OTHER_APPLICATION2);
5038 gtk_action_set_visible (action, FALSE);
5039 } else {
5040 action = gtk_action_group_get_action (view->details->dir_action_group,
5041 NEMO_ACTION_OTHER_APPLICATION1);
5042 gtk_action_set_visible (action, FALSE);
5043 action = gtk_action_group_get_action (view->details->dir_action_group,
5044 NEMO_ACTION_OTHER_APPLICATION2);
5045 gtk_action_set_visible (action, open_with_chooser_visible);
5046 }
5047 }
5048
5049 static void
move_copy_selection_to_location(NemoView * view,int copy_action,char * target_uri)5050 move_copy_selection_to_location (NemoView *view,
5051 int copy_action,
5052 char *target_uri)
5053 {
5054 GList *selection, *uris, *l;
5055
5056 selection = nemo_view_get_selection_for_file_transfer (view);
5057 if (selection == NULL) {
5058 return;
5059 }
5060
5061 uris = NULL;
5062 for (l = selection; l != NULL; l = l->next) {
5063 uris = g_list_prepend (uris,
5064 nemo_file_get_uri ((NemoFile *) l->data));
5065 }
5066 uris = g_list_reverse (uris);
5067
5068 nemo_view_move_copy_items (view, uris, NULL, target_uri,
5069 copy_action,
5070 0, 0);
5071
5072 g_list_free_full (uris, g_free);
5073 nemo_file_list_free (selection);
5074 }
5075
5076 static void
action_move_bookmark_callback(GtkAction * action,gpointer callback_data)5077 action_move_bookmark_callback (GtkAction *action, gpointer callback_data)
5078 {
5079 NemoView *view;
5080 BookmarkCallbackData *data;
5081
5082 data = (BookmarkCallbackData *) callback_data;
5083 view = NEMO_VIEW(data->view);
5084 move_copy_selection_to_location (view, GDK_ACTION_MOVE, data->dest_uri);
5085 }
5086
5087 static void
action_copy_bookmark_callback(GtkAction * action,gpointer callback_data)5088 action_copy_bookmark_callback (GtkAction *action, gpointer callback_data)
5089 {
5090 NemoView *view;
5091 BookmarkCallbackData *data;
5092
5093 data = (BookmarkCallbackData *) callback_data;
5094 view = NEMO_VIEW(data->view);
5095 move_copy_selection_to_location (view, GDK_ACTION_COPY, data->dest_uri);
5096 }
5097
5098 static void
setup_bookmark_action(char * action_name,const char * bookmark_name,const char * icon_name,char * mount_uri,GtkUIManager * ui_manager,gboolean move,GtkActionGroup * action_group,gint merge_id,const char * path,NemoView * view)5099 setup_bookmark_action( char *action_name,
5100 const char *bookmark_name,
5101 const char *icon_name,
5102 char *mount_uri,
5103 GtkUIManager *ui_manager,
5104 gboolean move,
5105 GtkActionGroup *action_group,
5106 gint merge_id,
5107 const char *path,
5108 NemoView *view)
5109 {
5110
5111 GtkAction *action;
5112 action = gtk_action_new (action_name,
5113 bookmark_name,
5114 NULL,
5115 NULL);
5116 gtk_action_set_icon_name (action, icon_name);
5117
5118 if (move) {
5119 g_signal_connect_data (action, "activate",
5120 G_CALLBACK (action_move_bookmark_callback),
5121 bookmark_callback_data_new(view, mount_uri),
5122 (GClosureNotify)bookmark_callback_data_free, 0);
5123 } else {
5124 g_signal_connect_data (action, "activate",
5125 G_CALLBACK (action_copy_bookmark_callback),
5126 bookmark_callback_data_new(view, mount_uri),
5127 (GClosureNotify)bookmark_callback_data_free, 0);
5128 }
5129
5130 gtk_action_group_add_action (action_group, action);
5131
5132 gtk_ui_manager_add_ui ( ui_manager,
5133 merge_id,
5134 path,
5135 action_name,
5136 action_name,
5137 GTK_UI_MANAGER_MENUITEM,
5138 FALSE);
5139 g_object_unref (action);
5140 g_free (action_name);
5141 }
5142
5143 static void
add_bookmark_to_action(NemoView * view,const gchar * bookmark_name,const gchar * icon_name,gchar * mount_uri,gint index)5144 add_bookmark_to_action (NemoView *view, const gchar *bookmark_name, const gchar *icon_name, gchar *mount_uri, gint index)
5145 {
5146 GtkUIManager *ui_manager;
5147 ui_manager = nemo_window_get_ui_manager (view->details->window);
5148
5149 setup_bookmark_action(g_strdup_printf ("BM_MOVETO_POPUP_%d", index),
5150 bookmark_name,
5151 icon_name,
5152 mount_uri,
5153 ui_manager,
5154 TRUE,
5155 view->details->copy_move_action_groups[0],
5156 view->details->copy_move_merge_ids[0],
5157 NEMO_VIEW_POPUP_PATH_BOOKMARK_MOVETO_ENTRIES_PLACEHOLDER,
5158 view);
5159
5160 setup_bookmark_action(g_strdup_printf ("BM_COPYTO_POPUP_%d", index),
5161 bookmark_name,
5162 icon_name,
5163 mount_uri,
5164 ui_manager,
5165 FALSE,
5166 view->details->copy_move_action_groups[1],
5167 view->details->copy_move_merge_ids[1],
5168 NEMO_VIEW_POPUP_PATH_BOOKMARK_COPYTO_ENTRIES_PLACEHOLDER,
5169 view);
5170
5171 setup_bookmark_action(g_strdup_printf ("BM_MOVETO_MENU_%d", index),
5172 bookmark_name,
5173 icon_name,
5174 mount_uri,
5175 ui_manager,
5176 TRUE,
5177 view->details->copy_move_action_groups[2],
5178 view->details->copy_move_merge_ids[2],
5179 NEMO_VIEW_MENU_PATH_BOOKMARK_MOVETO_ENTRIES_PLACEHOLDER,
5180 view);
5181
5182 setup_bookmark_action(g_strdup_printf ("BM_COPYTO_MENU_%d", index),
5183 bookmark_name,
5184 icon_name,
5185 mount_uri,
5186 ui_manager,
5187 FALSE,
5188 view->details->copy_move_action_groups[3],
5189 view->details->copy_move_merge_ids[3],
5190 NEMO_VIEW_MENU_PATH_BOOKMARK_COPYTO_ENTRIES_PLACEHOLDER,
5191 view);
5192 }
5193
5194 static void
add_place_to_action(NemoView * view,const gchar * bookmark_name,const gchar * icon_name,gchar * mount_uri,gint index)5195 add_place_to_action (NemoView *view, const gchar *bookmark_name, const gchar *icon_name, gchar *mount_uri, gint index)
5196 {
5197 GtkUIManager *ui_manager;
5198 ui_manager = nemo_window_get_ui_manager (view->details->window);
5199
5200 setup_bookmark_action(g_strdup_printf ("PLACE_MOVETO_POPUP_%d", index),
5201 bookmark_name,
5202 icon_name,
5203 mount_uri,
5204 ui_manager,
5205 TRUE,
5206 view->details->copy_move_action_groups[0],
5207 view->details->copy_move_merge_ids[0],
5208 NEMO_VIEW_POPUP_PATH_PLACES_MOVETO_ENTRIES_PLACEHOLDER,
5209 view);
5210
5211 setup_bookmark_action(g_strdup_printf ("PLACE_COPYTO_POPUP_%d", index),
5212 bookmark_name,
5213 icon_name,
5214 mount_uri,
5215 ui_manager,
5216 FALSE,
5217 view->details->copy_move_action_groups[1],
5218 view->details->copy_move_merge_ids[1],
5219 NEMO_VIEW_POPUP_PATH_PLACES_COPYTO_ENTRIES_PLACEHOLDER,
5220 view);
5221
5222 setup_bookmark_action(g_strdup_printf ("PLACE_MOVETO_MENU_%d", index),
5223 bookmark_name,
5224 icon_name,
5225 mount_uri,
5226 ui_manager,
5227 TRUE,
5228 view->details->copy_move_action_groups[2],
5229 view->details->copy_move_merge_ids[2],
5230 NEMO_VIEW_MENU_PATH_PLACES_MOVETO_ENTRIES_PLACEHOLDER,
5231 view);
5232
5233 setup_bookmark_action(g_strdup_printf ("PLACE_COPYTO_MENU_%d", index),
5234 bookmark_name,
5235 icon_name,
5236 mount_uri,
5237 ui_manager,
5238 FALSE,
5239 view->details->copy_move_action_groups[3],
5240 view->details->copy_move_merge_ids[3],
5241 NEMO_VIEW_MENU_PATH_PLACES_COPYTO_ENTRIES_PLACEHOLDER,
5242 view);
5243 }
5244
5245 static void
reset_move_copy_to_menu(NemoView * view)5246 reset_move_copy_to_menu (NemoView *view)
5247 {
5248 NemoBookmark *bookmark;
5249 NemoFile *file;
5250 int bookmark_count, index;
5251 GtkUIManager *ui_manager;
5252 GFile *root;
5253 const gchar *bookmark_name;
5254 gchar *icon_name;
5255 char *mount_uri;
5256
5257 ui_manager = nemo_window_get_ui_manager (view->details->window);
5258
5259 int i;
5260
5261 for (i = 0; i < 4; i++) {
5262 nemo_ui_unmerge_ui (ui_manager,
5263 &view->details->copy_move_merge_ids[i],
5264 &view->details->copy_move_action_groups[i]);
5265 gchar *id = g_strdup_printf ("MoveCopyMenuGroup_%d", i);
5266 nemo_ui_prepare_merge_ui (ui_manager,
5267 id,
5268 &view->details->copy_move_merge_ids[i],
5269 &view->details->copy_move_action_groups[i]);
5270 g_free (id);
5271 }
5272
5273 GtkAction *action;
5274
5275 mount_uri = nemo_get_home_directory_uri ();
5276 file = nemo_file_get_by_uri (mount_uri);
5277 g_free (mount_uri);
5278
5279 icon_name = nemo_file_get_control_icon_name (file);
5280
5281 action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_COPY_TO_HOME);
5282 gtk_action_set_icon_name (action, icon_name);
5283
5284 action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_MOVE_TO_HOME);
5285 gtk_action_set_icon_name (action, icon_name);
5286
5287 g_clear_pointer (&icon_name, g_free);
5288 g_object_unref (file);
5289
5290 mount_uri = nemo_get_desktop_directory_uri ();
5291 file = nemo_file_get_by_uri (mount_uri);
5292 g_free (mount_uri);
5293
5294 icon_name = nemo_file_get_control_icon_name (file);
5295
5296 action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_COPY_TO_DESKTOP);
5297 gtk_action_set_icon_name (action, icon_name);
5298
5299 action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_MOVE_TO_DESKTOP);
5300 gtk_action_set_icon_name (action, icon_name);
5301
5302 g_clear_pointer (&icon_name, g_free);
5303 g_object_unref (file);
5304
5305 if (view->details->showing_bookmarks_in_to_menus) {
5306 bookmark_count = nemo_bookmark_list_length (view->details->bookmarks);
5307 for (index = 0; index < bookmark_count; ++index) {
5308 bookmark = nemo_bookmark_list_item_at (view->details->bookmarks, index);
5309
5310 /* Unlike the sidebar or the bookmarks menu, we are using bookmarks as
5311 file operation targets, not locations to open. As such, we should
5312 never show unmounted/invalid locations in the move-to/copy-to menu */
5313 if (!nemo_bookmark_uri_get_exists (bookmark)) {
5314 continue;
5315 }
5316
5317 root = nemo_bookmark_get_location (bookmark);
5318 file = nemo_file_get (root);
5319
5320 nemo_file_unref (file);
5321
5322 bookmark_name = nemo_bookmark_get_name (bookmark);
5323 icon_name = nemo_bookmark_get_icon_name (bookmark);
5324 mount_uri = nemo_bookmark_get_uri (bookmark);
5325
5326 add_bookmark_to_action (view,
5327 bookmark_name,
5328 icon_name,
5329 mount_uri,
5330 index);
5331
5332 g_object_unref (root);
5333 g_free (icon_name);
5334 g_free (mount_uri);
5335 }
5336 }
5337
5338 if (view->details->showing_places_in_to_menus) {
5339
5340 GList *mounts, *l, *ll, *drives, *volumes;
5341 GVolumeMonitor *volume_monitor;
5342 GMount *mount;
5343 GVolume *volume;
5344 GDrive *drive;
5345 GList *network_mounts = NULL;
5346 GList *network_volumes = NULL;
5347 gchar *name, *identifier;
5348 index = 0;
5349
5350 /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
5351 volume_monitor = g_volume_monitor_get ();
5352 mounts = g_volume_monitor_get_mounts (volume_monitor);
5353
5354 for (l = mounts; l != NULL; l = l->next) {
5355 mount = l->data;
5356 if (g_mount_is_shadowed (mount)) {
5357 g_object_unref (mount);
5358 continue;
5359 }
5360 volume = g_mount_get_volume (mount);
5361 if (volume != NULL) {
5362 g_object_unref (volume);
5363 g_object_unref (mount);
5364 continue;
5365 }
5366 root = g_mount_get_default_location (mount);
5367
5368 if (!g_file_is_native (root)) {
5369 gboolean really_network = TRUE;
5370 gchar *path = g_file_get_path (root);
5371 if (!path) {
5372 network_mounts = g_list_prepend (network_mounts, mount);
5373 g_object_unref (root);
5374 continue;
5375 }
5376 gchar *escaped1 = g_uri_unescape_string (path, "");
5377 gchar *escaped2 = g_uri_unescape_string (escaped1, "");
5378 gchar *ptr = g_strrstr (escaped2, "file://");
5379 if (ptr != NULL) {
5380 GFile *actual_file = g_file_new_for_uri (ptr);
5381 if (g_file_is_native(actual_file)) {
5382 really_network = FALSE;
5383 }
5384 g_object_unref(actual_file);
5385 }
5386 g_free (path);
5387 g_free (escaped1);
5388 g_free (escaped2);
5389 if (really_network) {
5390 network_mounts = g_list_prepend (network_mounts, mount);
5391 g_object_unref (root);
5392 continue;
5393 }
5394 }
5395
5396 icon_name = nemo_get_mount_icon_name (mount);
5397 mount_uri = g_file_get_uri (root);
5398 name = g_mount_get_name (mount);
5399
5400 add_place_to_action (view,
5401 name,
5402 icon_name,
5403 mount_uri,
5404 index);
5405
5406 g_object_unref (root);
5407 g_object_unref (mount);
5408 g_free (icon_name);
5409 g_free (name);
5410 g_free (mount_uri);
5411
5412 index++;
5413 }
5414 g_list_free (mounts);
5415
5416 /* first go through all connected drives */
5417 drives = g_volume_monitor_get_connected_drives (volume_monitor);
5418
5419 for (l = drives; l != NULL; l = l->next) {
5420 drive = l->data;
5421
5422 volumes = g_drive_get_volumes (drive);
5423 if (volumes != NULL) {
5424 for (ll = volumes; ll != NULL; ll = ll->next) {
5425 volume = ll->data;
5426 identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS);
5427
5428 if (g_strcmp0 (identifier, "network") == 0) {
5429 g_free (identifier);
5430 network_volumes = g_list_prepend (network_volumes, volume);
5431 continue;
5432 }
5433 g_free (identifier);
5434
5435 mount = g_volume_get_mount (volume);
5436 if (mount != NULL) {
5437 /* Show mounted volume in the sidebar */
5438 icon_name = nemo_get_mount_icon_name (mount);
5439 root = g_mount_get_default_location (mount);
5440 mount_uri = g_file_get_uri (root);
5441 name = g_mount_get_name (mount);
5442
5443 add_place_to_action (view,
5444 name,
5445 icon_name,
5446 mount_uri,
5447 index);
5448
5449 g_object_unref (root);
5450 g_object_unref (mount);
5451 g_free (icon_name);
5452 g_free (name);
5453 g_free (mount_uri);
5454 index++;
5455 }
5456 g_object_unref (volume);
5457 }
5458 g_list_free (volumes);
5459 }
5460 g_object_unref (drive);
5461 }
5462 g_list_free (drives);
5463
5464 /* add all volumes that is not associated with a drive */
5465 volumes = g_volume_monitor_get_volumes (volume_monitor);
5466 for (l = volumes; l != NULL; l = l->next) {
5467 volume = l->data;
5468 drive = g_volume_get_drive (volume);
5469 if (drive != NULL) {
5470 g_object_unref (volume);
5471 g_object_unref (drive);
5472 continue;
5473 }
5474
5475 identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS);
5476
5477 if (g_strcmp0 (identifier, "network") == 0) {
5478 g_free (identifier);
5479 network_volumes = g_list_prepend (network_volumes, volume);
5480 continue;
5481 }
5482 g_free (identifier);
5483
5484 mount = g_volume_get_mount (volume);
5485 if (mount != NULL) {
5486 icon_name = nemo_get_mount_icon_name (mount);
5487 root = g_mount_get_default_location (mount);
5488 mount_uri = g_file_get_uri (root);
5489
5490 g_object_unref (root);
5491 name = g_mount_get_name (mount);
5492
5493 add_place_to_action (view,
5494 name,
5495 icon_name,
5496 mount_uri,
5497 index);
5498
5499 g_object_unref (mount);
5500 g_free (icon_name);
5501 g_free (name);
5502 g_free (mount_uri);
5503 index++;
5504 }
5505 g_object_unref (volume);
5506 }
5507 g_list_free (volumes);
5508 g_object_unref (volume_monitor);
5509
5510 network_volumes = g_list_reverse (network_volumes);
5511 for (l = network_volumes; l != NULL; l = l->next) {
5512 volume = l->data;
5513 mount = g_volume_get_mount (volume);
5514
5515 if (mount != NULL) {
5516 network_mounts = g_list_prepend (network_mounts, mount);
5517 continue;
5518 }
5519 }
5520
5521 g_list_free_full (network_volumes, g_object_unref);
5522
5523 network_mounts = g_list_reverse (network_mounts);
5524 for (l = network_mounts; l != NULL; l = l->next) {
5525 mount = l->data;
5526 root = g_mount_get_default_location (mount);
5527 icon_name = nemo_get_mount_icon_name (mount);
5528 mount_uri = g_file_get_uri (root);
5529 name = g_mount_get_name (mount);
5530
5531 add_place_to_action (view,
5532 name,
5533 icon_name,
5534 mount_uri,
5535 index);
5536
5537 g_object_unref (root);
5538 g_free (icon_name);
5539 g_free (name);
5540 g_free (mount_uri);
5541 index++;
5542 }
5543
5544 g_list_free_full (network_mounts, g_object_unref);
5545 }
5546 }
5547
5548 static void
disconnect_bookmark(gpointer data,gpointer callback_data)5549 disconnect_bookmark (gpointer data, gpointer callback_data)
5550 {
5551 GtkAction *action = GTK_ACTION (data);
5552 g_signal_handlers_disconnect_matched (action,
5553 G_SIGNAL_MATCH_FUNC, 0, 0,
5554 NULL, action_move_bookmark_callback, NULL);
5555 g_signal_handlers_disconnect_matched (action,
5556 G_SIGNAL_MATCH_FUNC, 0, 0,
5557 NULL, action_copy_bookmark_callback, NULL);
5558 }
5559
5560 static void
disconnect_bookmark_signals(NemoView * view)5561 disconnect_bookmark_signals (NemoView *view)
5562 {
5563 int i;
5564 GList *list;
5565 GtkActionGroup *group;
5566 for (i = 0; i < 4; i++) {
5567 group = GTK_ACTION_GROUP (view->details->copy_move_action_groups[i]);
5568 list = gtk_action_group_list_actions (group);
5569 g_list_foreach (list, disconnect_bookmark, NULL);
5570 g_list_free (list);
5571 }
5572 }
5573
5574 static GList *
get_all_extension_menu_items(GtkWidget * window,GList * selection)5575 get_all_extension_menu_items (GtkWidget *window,
5576 GList *selection)
5577 {
5578 GList *items;
5579 GList *providers;
5580 GList *l;
5581
5582 providers = nemo_module_get_extensions_for_type (NEMO_TYPE_MENU_PROVIDER);
5583 items = NULL;
5584
5585 for (l = providers; l != NULL; l = l->next) {
5586 NemoMenuProvider *provider;
5587 GList *file_items;
5588
5589 provider = NEMO_MENU_PROVIDER (l->data);
5590 file_items = nemo_menu_provider_get_file_items (provider,
5591 window,
5592 selection);
5593 items = g_list_concat (items, file_items);
5594 }
5595
5596 nemo_module_extension_list_free (providers);
5597
5598 return items;
5599 }
5600
5601 typedef struct
5602 {
5603 NemoMenuItem *item;
5604 NemoView *view;
5605 GList *selection;
5606 GtkAction *action;
5607 } ExtensionActionCallbackData;
5608
5609
5610 static void
extension_action_callback_data_free(ExtensionActionCallbackData * data)5611 extension_action_callback_data_free (ExtensionActionCallbackData *data)
5612 {
5613 g_object_unref (data->item);
5614 nemo_file_list_free (data->selection);
5615
5616 g_free (data);
5617 }
5618
5619 static gboolean
search_in_menu_items(GList * items,const char * item_name)5620 search_in_menu_items (GList* items, const char *item_name)
5621 {
5622 GList* list;
5623
5624 for (list = items; list != NULL; list = list->next) {
5625 NemoMenu* menu;
5626 char *name;
5627
5628 g_object_get (list->data, "name", &name, NULL);
5629 if (strcmp (name, item_name) == 0) {
5630 g_free (name);
5631 return TRUE;
5632 }
5633 g_free (name);
5634
5635 menu = NULL;
5636 g_object_get (list->data, "menu", &menu, NULL);
5637 if (menu != NULL) {
5638 gboolean ret;
5639 GList* submenus;
5640
5641 submenus = nemo_menu_get_items (menu);
5642 ret = search_in_menu_items (submenus, item_name);
5643 nemo_menu_item_list_free (submenus);
5644 g_object_unref (menu);
5645 if (ret) {
5646 return TRUE;
5647 }
5648 }
5649 }
5650 return FALSE;
5651 }
5652
5653 static void
extension_action_callback(GtkAction * action,gpointer callback_data)5654 extension_action_callback (GtkAction *action,
5655 gpointer callback_data)
5656 {
5657 ExtensionActionCallbackData *data;
5658 char *item_name;
5659 gboolean is_valid;
5660 GList *l;
5661 GList *items;
5662
5663 data = callback_data;
5664
5665 /* Make sure the selected menu item is valid for the final sniffed
5666 * mime type */
5667 g_object_get (data->item, "name", &item_name, NULL);
5668 items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (data->view)),
5669 data->selection);
5670
5671 is_valid = search_in_menu_items (items, item_name);
5672
5673 for (l = items; l != NULL; l = l->next) {
5674 g_object_unref (l->data);
5675 }
5676 g_list_free (items);
5677
5678 g_free (item_name);
5679
5680 if (is_valid) {
5681 nemo_menu_item_activate (data->item);
5682 }
5683 }
5684
5685 static GdkPixbuf *
get_menu_icon_for_file(NemoFile * file,GtkWidget * widget)5686 get_menu_icon_for_file (NemoFile *file,
5687 GtkWidget *widget)
5688 {
5689 NemoIconInfo *info;
5690 GdkPixbuf *pixbuf;
5691 int size, scale;
5692
5693 size = nemo_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU);
5694 scale = gtk_widget_get_scale_factor (widget);
5695
5696 info = nemo_file_get_icon (file, size, 0, scale, 0);
5697 pixbuf = nemo_icon_info_get_pixbuf_nodefault_at_size (info, size);
5698 nemo_icon_info_unref (info);
5699
5700 return pixbuf;
5701 }
5702
5703 static GtkAction *
add_extension_action_for_files(NemoView * view,NemoMenuItem * item,GList * files)5704 add_extension_action_for_files (NemoView *view,
5705 NemoMenuItem *item,
5706 GList *files)
5707 {
5708 GtkAction *ret = NULL;
5709 char *name, *label, *tip, *icon;
5710 gboolean sensitive, priority;
5711 gboolean separator;
5712 GtkAction *action;
5713 GtkWidget *widget_a, *widget_b;
5714 ExtensionActionCallbackData *data;
5715
5716 g_object_get (G_OBJECT (item),
5717 "name", &name, "label", &label,
5718 "tip", &tip, "icon", &icon,
5719 "sensitive", &sensitive,
5720 "priority", &priority,
5721 "widget-a", &widget_a,
5722 "widget-b", &widget_b,
5723 "separator", &separator,
5724 NULL);
5725
5726 if (widget_a == NULL && !separator) {
5727 action = gtk_action_new (name,
5728 label,
5729 tip,
5730 NULL);
5731 if (icon != NULL) {
5732 GIcon *gicon;
5733
5734 if (g_path_is_absolute (icon)) {
5735 GFile *file;
5736
5737 file = g_file_new_for_path (icon);
5738 gicon = g_file_icon_new (file);
5739
5740 g_object_unref (file);
5741 } else if (icon) {
5742 gicon = g_themed_icon_new (icon);
5743 } else {
5744 gicon = NULL;
5745 }
5746
5747 gtk_action_set_gicon (action, gicon);
5748
5749 g_clear_object (&gicon);
5750 }
5751 } else if (separator) {
5752 action = nemo_separator_action_new (name);
5753 } else {
5754 action = nemo_widget_action_new (name, widget_a, widget_b);
5755 }
5756
5757 gtk_action_set_sensitive (action, sensitive);
5758 g_object_set (action, "is-important", priority, NULL);
5759
5760 data = g_new0 (ExtensionActionCallbackData, 1);
5761 data->item = g_object_ref (item);
5762 data->view = view;
5763 data->selection = nemo_file_list_copy (files);
5764 data->action = action;
5765
5766 g_signal_connect_data (action, "activate",
5767 G_CALLBACK (extension_action_callback),
5768 data,
5769 (GClosureNotify)extension_action_callback_data_free, 0);
5770
5771 if (gtk_action_group_get_action (view->details->extensions_menu_action_group, gtk_action_get_name (GTK_ACTION (action))) == NULL) {
5772 gtk_action_group_add_action (view->details->extensions_menu_action_group,
5773 GTK_ACTION (action));
5774 ret = action;
5775 }
5776
5777 g_object_unref (action);
5778
5779 g_free (name);
5780 g_free (label);
5781 g_free (tip);
5782 g_free (icon);
5783
5784 return ret;
5785 }
5786
5787 static void
add_extension_menu_items(NemoView * view,GList * files,GList * menu_items,const char * subdirectory)5788 add_extension_menu_items (NemoView *view,
5789 GList *files,
5790 GList *menu_items,
5791 const char *subdirectory)
5792 {
5793 GtkUIManager *ui_manager;
5794 GList *l;
5795
5796 ui_manager = nemo_window_get_ui_manager (view->details->window);
5797
5798 for (l = menu_items; l; l = l->next) {
5799 NemoMenuItem *item;
5800 NemoMenu *menu;
5801 GtkAction *action = NULL;
5802 char *path;
5803
5804 item = NEMO_MENU_ITEM (l->data);
5805
5806 g_object_get (item, "menu", &menu, NULL);
5807
5808 action = add_extension_action_for_files (view, item, files);
5809
5810 if (action) {
5811 GtkUIManagerItemType item_type;
5812
5813 if (G_OBJECT_TYPE (action) == NEMO_TYPE_SEPARATOR_ACTION)
5814 item_type = GTK_UI_MANAGER_SEPARATOR;
5815 else {
5816 item_type = (menu != NULL) ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM;
5817 }
5818 path = g_build_path ("/", NEMO_VIEW_POPUP_PATH_EXTENSION_ACTIONS, subdirectory, NULL);
5819 gtk_ui_manager_add_ui (ui_manager,
5820 view->details->extensions_menu_merge_id,
5821 path,
5822 gtk_action_get_name (action),
5823 gtk_action_get_name (action),
5824 item_type,
5825 FALSE);
5826 g_free (path);
5827
5828 path = g_build_path ("/", NEMO_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER, subdirectory, NULL);
5829 gtk_ui_manager_add_ui (ui_manager,
5830 view->details->extensions_menu_merge_id,
5831 path,
5832 gtk_action_get_name (action),
5833 gtk_action_get_name (action),
5834 item_type,
5835 FALSE);
5836 g_free (path);
5837
5838 /* recursively fill the menu */
5839 if (menu != NULL) {
5840 char *subdir;
5841 GList *children;
5842
5843 children = nemo_menu_get_items (menu);
5844
5845 subdir = g_build_path ("/", subdirectory, gtk_action_get_name (action), NULL);
5846 add_extension_menu_items (view,
5847 files,
5848 children,
5849 subdir);
5850
5851 nemo_menu_item_list_free (children);
5852 g_free (subdir);
5853 }
5854 }
5855 }
5856 }
5857
5858 static void
reset_extension_actions_menu(NemoView * view,GList * selection)5859 reset_extension_actions_menu (NemoView *view, GList *selection)
5860 {
5861 GList *items;
5862 GtkUIManager *ui_manager;
5863
5864 /* Clear any previous inserted items in the extension actions placeholder */
5865 ui_manager = nemo_window_get_ui_manager (view->details->window);
5866
5867 nemo_ui_unmerge_ui (ui_manager,
5868 &view->details->extensions_menu_merge_id,
5869 &view->details->extensions_menu_action_group);
5870
5871 nemo_ui_prepare_merge_ui (ui_manager,
5872 "DirExtensionsMenuGroup",
5873 &view->details->extensions_menu_merge_id,
5874 &view->details->extensions_menu_action_group);
5875
5876 items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (view)),
5877 selection);
5878 if (items != NULL) {
5879 add_extension_menu_items (view, selection, items, "");
5880
5881 g_list_foreach (items, (GFunc) g_object_unref, NULL);
5882 g_list_free (items);
5883 }
5884 }
5885
5886 static char *
change_to_view_directory(NemoView * view)5887 change_to_view_directory (NemoView *view)
5888 {
5889 char *path;
5890 char *old_path;
5891
5892 old_path = g_get_current_dir ();
5893
5894 path = get_view_directory (view);
5895
5896 /* FIXME: What to do about non-local directories? */
5897 if (path != NULL) {
5898 g_chdir (path);
5899 }
5900
5901 g_free (path);
5902
5903 return old_path;
5904 }
5905
5906 static char **
get_file_names_as_parameter_array(GList * selection,NemoDirectory * model)5907 get_file_names_as_parameter_array (GList *selection,
5908 NemoDirectory *model)
5909 {
5910 NemoFile *file;
5911 char **parameters;
5912 GList *node;
5913 GFile *file_location;
5914 GFile *model_location;
5915 int i;
5916
5917 if (model == NULL) {
5918 return NULL;
5919 }
5920
5921 parameters = g_new (char *, g_list_length (selection) + 1);
5922
5923 model_location = nemo_directory_get_location (model);
5924
5925 for (node = selection, i = 0; node != NULL; node = node->next, i++) {
5926 file = NEMO_FILE (node->data);
5927
5928 if (!nemo_file_is_local (file)) {
5929 parameters[i] = NULL;
5930 g_strfreev (parameters);
5931 return NULL;
5932 }
5933
5934 file_location = nemo_file_get_location (NEMO_FILE (node->data));
5935 parameters[i] = g_file_get_relative_path (model_location, file_location);
5936 if (parameters[i] == NULL) {
5937 parameters[i] = g_file_get_path (file_location);
5938 }
5939 g_object_unref (file_location);
5940 }
5941
5942 g_object_unref (model_location);
5943
5944 parameters[i] = NULL;
5945 return parameters;
5946 }
5947
5948 static char *
get_file_paths_or_uris_as_newline_delimited_string(GList * selection,gboolean get_paths)5949 get_file_paths_or_uris_as_newline_delimited_string (GList *selection, gboolean get_paths)
5950 {
5951 char *path;
5952 char *uri;
5953 char *result;
5954 NemoDesktopLink *link;
5955 GString *expanding_string;
5956 GList *node;
5957 GFile *location;
5958
5959 expanding_string = g_string_new ("");
5960 for (node = selection; node != NULL; node = node->next) {
5961 uri = NULL;
5962 if (NEMO_IS_DESKTOP_ICON_FILE (node->data)) {
5963 link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (node->data));
5964 if (link != NULL) {
5965 location = nemo_desktop_link_get_activation_location (link);
5966 uri = g_file_get_uri (location);
5967 g_object_unref (location);
5968 g_object_unref (G_OBJECT (link));
5969 }
5970 } else {
5971 uri = nemo_file_get_uri (NEMO_FILE (node->data));
5972 }
5973 if (uri == NULL) {
5974 continue;
5975 }
5976
5977 if (get_paths) {
5978 path = g_filename_from_uri (uri, NULL, NULL);
5979 if (path != NULL) {
5980 g_string_append (expanding_string, path);
5981 g_free (path);
5982 g_string_append (expanding_string, "\n");
5983 }
5984 } else {
5985 g_string_append (expanding_string, uri);
5986 g_string_append (expanding_string, "\n");
5987 }
5988 g_free (uri);
5989 }
5990
5991 result = expanding_string->str;
5992 g_string_free (expanding_string, FALSE);
5993
5994 return result;
5995 }
5996
5997 static char *
get_file_paths_as_newline_delimited_string(GList * selection)5998 get_file_paths_as_newline_delimited_string (GList *selection)
5999 {
6000 return get_file_paths_or_uris_as_newline_delimited_string (selection, TRUE);
6001 }
6002
6003 static char *
get_file_uris_as_newline_delimited_string(GList * selection)6004 get_file_uris_as_newline_delimited_string (GList *selection)
6005 {
6006 return get_file_paths_or_uris_as_newline_delimited_string (selection, FALSE);
6007 }
6008
6009 /* returns newly allocated strings for setting the environment variables */
6010 static void
get_strings_for_environment_variables(NemoView * view,GList * selected_files,char ** file_paths,char ** uris,char ** uri)6011 get_strings_for_environment_variables (NemoView *view, GList *selected_files,
6012 char **file_paths, char **uris, char **uri)
6013 {
6014 char *directory_uri;
6015
6016 /* We need to check that the directory uri starts with "file:" since
6017 * nemo_directory_is_local returns FALSE for nfs.
6018 */
6019 directory_uri = nemo_directory_get_uri (view->details->model);
6020 if (g_str_has_prefix (directory_uri, "file:") ||
6021 eel_uri_is_desktop (directory_uri) ||
6022 eel_uri_is_trash (directory_uri)) {
6023 *file_paths = get_file_paths_as_newline_delimited_string (selected_files);
6024 } else {
6025 *file_paths = g_strdup ("");
6026 }
6027 g_free (directory_uri);
6028
6029 *uris = get_file_uris_as_newline_delimited_string (selected_files);
6030
6031 *uri = nemo_directory_get_uri (view->details->model);
6032 if (eel_uri_is_desktop (*uri)) {
6033 g_free (*uri);
6034 *uri = nemo_get_desktop_directory_uri ();
6035 }
6036 }
6037
6038 static NemoView *
get_directory_view_of_extra_pane(NemoView * view)6039 get_directory_view_of_extra_pane (NemoView *view)
6040 {
6041 NemoWindowSlot *slot;
6042 NemoView *next_view;
6043
6044 slot = nemo_window_get_extra_slot (nemo_view_get_nemo_window (view));
6045 if (slot != NULL) {
6046 next_view = nemo_window_slot_get_current_view (slot);
6047
6048 if (NEMO_IS_VIEW (next_view)) {
6049 return NEMO_VIEW (next_view);
6050 }
6051 }
6052 return NULL;
6053 }
6054
6055 /*
6056 * Set up some environment variables that scripts can use
6057 * to take advantage of the current Nemo state.
6058 */
6059 static void
set_script_environment_variables(NemoView * view,GList * selected_files)6060 set_script_environment_variables (NemoView *view, GList *selected_files)
6061 {
6062 char *file_paths;
6063 char *uris;
6064 char *uri;
6065 char *geometry_string;
6066 NemoView *next_view;
6067
6068 get_strings_for_environment_variables (view, selected_files,
6069 &file_paths, &uris, &uri);
6070
6071 g_setenv ("NEMO_SCRIPT_SELECTED_FILE_PATHS", file_paths, TRUE);
6072 g_free (file_paths);
6073
6074 g_setenv ("NEMO_SCRIPT_SELECTED_URIS", uris, TRUE);
6075 g_free (uris);
6076
6077 g_setenv ("NEMO_SCRIPT_CURRENT_URI", uri, TRUE);
6078 g_free (uri);
6079
6080 geometry_string = eel_gtk_window_get_geometry_string
6081 (GTK_WINDOW (nemo_view_get_containing_window (view)));
6082 g_setenv ("NEMO_SCRIPT_WINDOW_GEOMETRY", geometry_string, TRUE);
6083 g_free (geometry_string);
6084
6085 /* next pane */
6086 next_view = get_directory_view_of_extra_pane (view);
6087 if (next_view) {
6088 GList *next_pane_selected_files;
6089 next_pane_selected_files = nemo_view_get_selection (next_view);
6090
6091 get_strings_for_environment_variables (next_view, next_pane_selected_files,
6092 &file_paths, &uris, &uri);
6093 nemo_file_list_free (next_pane_selected_files);
6094 } else {
6095 file_paths = g_strdup("");
6096 uris = g_strdup("");
6097 uri = g_strdup("");
6098 }
6099
6100 g_setenv ("NEMO_SCRIPT_NEXT_PANE_SELECTED_FILE_PATHS", file_paths, TRUE);
6101 g_free (file_paths);
6102
6103 g_setenv ("NEMO_SCRIPT_NEXT_PANE_SELECTED_URIS", uris, TRUE);
6104 g_free (uris);
6105
6106 g_setenv ("NEMO_SCRIPT_NEXT_PANE_CURRENT_URI", uri, TRUE);
6107 g_free (uri);
6108 }
6109
6110 /* Unset all the special script environment variables. */
6111 static void
unset_script_environment_variables(void)6112 unset_script_environment_variables (void)
6113 {
6114 g_unsetenv ("NEMO_SCRIPT_SELECTED_FILE_PATHS");
6115 g_unsetenv ("NEMO_SCRIPT_SELECTED_URIS");
6116 g_unsetenv ("NEMO_SCRIPT_CURRENT_URI");
6117 g_unsetenv ("NEMO_SCRIPT_WINDOW_GEOMETRY");
6118 g_unsetenv ("NEMO_SCRIPT_NEXT_PANE_SELECTED_FILE_PATHS");
6119 g_unsetenv ("NEMO_SCRIPT_NEXT_PANE_SELECTED_URIS");
6120 g_unsetenv ("NEMO_SCRIPT_NEXT_PANE_CURRENT_URI");
6121 }
6122
6123 static void
run_script_callback(GtkAction * action,gpointer callback_data)6124 run_script_callback (GtkAction *action, gpointer callback_data)
6125 {
6126 ScriptLaunchParameters *launch_parameters;
6127 GdkScreen *screen;
6128 GList *selected_files;
6129 char *file_uri;
6130 char *local_file_path;
6131 char *quoted_path;
6132 char *old_working_dir;
6133 char **parameters;
6134
6135 launch_parameters = (ScriptLaunchParameters *) callback_data;
6136
6137 file_uri = nemo_file_get_uri (launch_parameters->file);
6138 local_file_path = g_filename_from_uri (file_uri, NULL, NULL);
6139 g_assert (local_file_path != NULL);
6140 g_free (file_uri);
6141
6142 quoted_path = g_shell_quote (local_file_path);
6143 g_free (local_file_path);
6144
6145 old_working_dir = change_to_view_directory (launch_parameters->directory_view);
6146
6147 selected_files = nemo_view_get_selection (launch_parameters->directory_view);
6148 set_script_environment_variables (launch_parameters->directory_view, selected_files);
6149
6150 parameters = get_file_names_as_parameter_array (selected_files,
6151 launch_parameters->directory_view->details->model);
6152
6153 screen = gtk_widget_get_screen (GTK_WIDGET (launch_parameters->directory_view));
6154
6155 DEBUG ("run_script_callback, script_path=\"%s\" (omitting script parameters)",
6156 local_file_path);
6157
6158 nemo_launch_application_from_command_array (screen, quoted_path, FALSE,
6159 (const char * const *) parameters);
6160 g_strfreev (parameters);
6161
6162 nemo_file_list_free (selected_files);
6163 unset_script_environment_variables ();
6164 g_chdir (old_working_dir);
6165 g_free (old_working_dir);
6166 g_free (quoted_path);
6167 }
6168
6169 static void
add_script_to_scripts_menus(NemoView * directory_view,NemoFile * file,const char * menu_path,const char * popup_path,const char * popup_bg_path)6170 add_script_to_scripts_menus (NemoView *directory_view,
6171 NemoFile *file,
6172 const char *menu_path,
6173 const char *popup_path,
6174 const char *popup_bg_path)
6175 {
6176 ScriptLaunchParameters *launch_parameters;
6177 char *tip;
6178 char *name;
6179 char *uri;
6180 char *action_name;
6181 char *escaped_label;
6182 GdkPixbuf *pixbuf;
6183 GtkUIManager *ui_manager;
6184 GtkAction *action;
6185
6186 name = nemo_file_get_display_name (file);
6187 uri = nemo_file_get_uri (file);
6188 tip = g_strdup_printf (_("Run \"%s\" on any selected items"), name);
6189
6190 launch_parameters = script_launch_parameters_new (file, directory_view);
6191
6192 action_name = escape_action_name (uri, "script_");
6193 escaped_label = eel_str_double_underscores (name);
6194
6195 action = gtk_action_new (action_name,
6196 escaped_label,
6197 tip,
6198 NULL);
6199
6200 pixbuf = get_menu_icon_for_file (file, GTK_WIDGET (directory_view));
6201 if (pixbuf != NULL) {
6202 gtk_action_set_gicon (action, G_ICON (pixbuf));
6203 g_object_unref (pixbuf);
6204 }
6205
6206 g_signal_connect_data (action, "activate",
6207 G_CALLBACK (run_script_callback),
6208 launch_parameters,
6209 (GClosureNotify)script_launch_parameters_free, 0);
6210
6211 gtk_action_group_add_action_with_accel (directory_view->details->scripts_action_group,
6212 action, NULL);
6213 g_object_unref (action);
6214
6215 ui_manager = nemo_window_get_ui_manager (directory_view->details->window);
6216
6217 gtk_ui_manager_add_ui (ui_manager,
6218 directory_view->details->scripts_merge_id,
6219 menu_path,
6220 action_name,
6221 action_name,
6222 GTK_UI_MANAGER_MENUITEM,
6223 FALSE);
6224 gtk_ui_manager_add_ui (ui_manager,
6225 directory_view->details->scripts_merge_id,
6226 popup_path,
6227 action_name,
6228 action_name,
6229 GTK_UI_MANAGER_MENUITEM,
6230 FALSE);
6231 gtk_ui_manager_add_ui (ui_manager,
6232 directory_view->details->scripts_merge_id,
6233 popup_bg_path,
6234 action_name,
6235 action_name,
6236 GTK_UI_MANAGER_MENUITEM,
6237 FALSE);
6238
6239 menu_item_show_image (ui_manager, menu_path, action_name, FALSE);
6240 menu_item_show_image (ui_manager, popup_path, action_name, FALSE);
6241 menu_item_show_image (ui_manager, popup_bg_path, action_name, FALSE);
6242
6243 g_free (name);
6244 g_free (uri);
6245 g_free (tip);
6246 g_free (action_name);
6247 g_free (escaped_label);
6248 }
6249
6250 static void
add_submenu_to_directory_menus(NemoView * directory_view,GtkActionGroup * action_group,guint merge_id,NemoFile * file,const char * menu_path,const char * popup_path,const char * popup_bg_path)6251 add_submenu_to_directory_menus (NemoView *directory_view,
6252 GtkActionGroup *action_group,
6253 guint merge_id,
6254 NemoFile *file,
6255 const char *menu_path,
6256 const char *popup_path,
6257 const char *popup_bg_path)
6258 {
6259 char *name;
6260 GdkPixbuf *pixbuf;
6261 char *uri;
6262 GtkUIManager *ui_manager;
6263
6264 ui_manager = nemo_window_get_ui_manager (directory_view->details->window);
6265 uri = nemo_file_get_uri (file);
6266 name = nemo_file_get_display_name (file);
6267 pixbuf = get_menu_icon_for_file (file, GTK_WIDGET (directory_view));
6268 add_submenu (ui_manager, action_group, merge_id, menu_path, uri, name, pixbuf, TRUE);
6269 add_submenu (ui_manager, action_group, merge_id, popup_path, uri, name, pixbuf, FALSE);
6270 add_submenu (ui_manager, action_group, merge_id, popup_bg_path, uri, name, pixbuf, FALSE);
6271 if (pixbuf) {
6272 g_object_unref (pixbuf);
6273 }
6274 g_free (name);
6275 g_free (uri);
6276 }
6277
6278 static gboolean
directory_belongs_in_scripts_menu(const char * uri)6279 directory_belongs_in_scripts_menu (const char *uri)
6280 {
6281 int num_levels;
6282 int i;
6283
6284 if (!g_str_has_prefix (uri, scripts_directory_uri)) {
6285 return FALSE;
6286 }
6287
6288 num_levels = 0;
6289 for (i = scripts_directory_uri_length; uri[i] != '\0'; i++) {
6290 if (uri[i] == '/') {
6291 num_levels++;
6292 }
6293 }
6294
6295 if (num_levels > MAX_MENU_LEVELS) {
6296 return FALSE;
6297 }
6298
6299 return TRUE;
6300 }
6301
6302 static gboolean
update_directory_in_scripts_menu(NemoView * view,NemoDirectory * directory)6303 update_directory_in_scripts_menu (NemoView *view, NemoDirectory *directory)
6304 {
6305 char *menu_path, *popup_path, *popup_bg_path;
6306 GList *file_list, *filtered, *node;
6307 gboolean any_scripts;
6308 NemoFile *file;
6309 NemoDirectory *dir;
6310 char *uri;
6311 char *escaped_path;
6312
6313 uri = nemo_directory_get_uri (directory);
6314 escaped_path = escape_action_path (uri + scripts_directory_uri_length);
6315 g_free (uri);
6316 menu_path = g_strconcat (NEMO_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER,
6317 escaped_path,
6318 NULL);
6319 popup_path = g_strconcat (NEMO_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER,
6320 escaped_path,
6321 NULL);
6322 popup_bg_path = g_strconcat (NEMO_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_PLACEHOLDER,
6323 escaped_path,
6324 NULL);
6325 g_free (escaped_path);
6326
6327 file_list = nemo_directory_get_file_list (directory);
6328 filtered = nemo_file_list_filter_hidden (file_list, FALSE);
6329 nemo_file_list_free (file_list);
6330
6331 file_list = nemo_file_list_sort_by_display_name (filtered);
6332
6333 any_scripts = FALSE;
6334 for (node = file_list; node != NULL; node = node->next) {
6335 file = node->data;
6336
6337 if (nemo_file_is_launchable (file) &&
6338 nemo_global_preferences_should_load_plugin (nemo_file_peek_name (file), NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS)) {
6339 add_script_to_scripts_menus (view, file, menu_path, popup_path, popup_bg_path);
6340 any_scripts = TRUE;
6341 } else if (nemo_file_is_directory (file)) {
6342 uri = nemo_file_get_uri (file);
6343 if (directory_belongs_in_scripts_menu (uri)) {
6344 dir = nemo_directory_get_by_uri (uri);
6345 add_directory_to_scripts_directory_list (view, dir);
6346 nemo_directory_unref (dir);
6347
6348 add_submenu_to_directory_menus (view,
6349 view->details->scripts_action_group,
6350 view->details->scripts_merge_id,
6351 file, menu_path, popup_path, popup_bg_path);
6352
6353 any_scripts = TRUE;
6354 }
6355 g_free (uri);
6356 }
6357 }
6358
6359 nemo_file_list_free (file_list);
6360
6361 g_free (popup_path);
6362 g_free (popup_bg_path);
6363 g_free (menu_path);
6364
6365 return any_scripts;
6366 }
6367
6368 static void
update_scripts_menu(NemoView * view)6369 update_scripts_menu (NemoView *view)
6370 {
6371 gboolean any_scripts;
6372 GList *sorted_copy, *node;
6373 NemoDirectory *directory;
6374 char *uri;
6375 GtkUIManager *ui_manager;
6376 GtkAction *action;
6377
6378 /* There is a race condition here. If we don't mark the scripts menu as
6379 valid before we begin our task then we can lose script menu updates that
6380 occur before we finish. */
6381 view->details->scripts_invalid = FALSE;
6382
6383 ui_manager = nemo_window_get_ui_manager (view->details->window);
6384 nemo_ui_unmerge_ui (ui_manager,
6385 &view->details->scripts_merge_id,
6386 &view->details->scripts_action_group);
6387
6388 nemo_ui_prepare_merge_ui (ui_manager,
6389 "ScriptsGroup",
6390 &view->details->scripts_merge_id,
6391 &view->details->scripts_action_group);
6392
6393 /* As we walk through the directories, remove any that no longer belong. */
6394 any_scripts = FALSE;
6395 sorted_copy = nemo_directory_list_sort_by_uri
6396 (nemo_directory_list_copy (view->details->scripts_directory_list));
6397 for (node = sorted_copy; node != NULL; node = node->next) {
6398 directory = node->data;
6399
6400 uri = nemo_directory_get_uri (directory);
6401 if (!directory_belongs_in_scripts_menu (uri)) {
6402 remove_directory_from_scripts_directory_list (view, directory);
6403 } else if (update_directory_in_scripts_menu (view, directory)) {
6404 any_scripts = TRUE;
6405 }
6406 g_free (uri);
6407 }
6408 nemo_directory_list_free (sorted_copy);
6409
6410 action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_SCRIPTS);
6411 gtk_action_set_visible (action, any_scripts);
6412 }
6413
6414 static void
run_action_callback(NemoAction * action,gpointer callback_data)6415 run_action_callback (NemoAction *action, gpointer callback_data)
6416 {
6417
6418 NemoView *view = NEMO_VIEW (callback_data);
6419 GList *selected_files;
6420
6421 selected_files = nemo_view_get_selection (view);
6422 NemoFile *parent = nemo_view_get_directory_as_file (view);
6423
6424 nemo_action_activate (action, selected_files, parent);
6425
6426 nemo_file_list_free (selected_files);
6427 }
6428
6429 typedef struct {
6430 NemoView *view;
6431 GList *selection;
6432 } ActionVisibilityData;
6433
6434 static void
determine_visibility(gpointer data,gpointer callback_data)6435 determine_visibility (gpointer data, gpointer callback_data)
6436 {
6437 NemoAction *action = NEMO_ACTION (data);
6438 ActionVisibilityData *av_data = (ActionVisibilityData *) callback_data;
6439 GList *selection;
6440 NemoView *view;
6441
6442 view = av_data->view;
6443 selection = av_data->selection;
6444
6445 NemoFile *parent = nemo_view_get_directory_as_file (view);
6446
6447 if (nemo_action_get_visibility (action, selection, parent, FALSE)) {
6448 gchar *label, *tt;
6449
6450 label = nemo_action_get_label (action, selection, parent);
6451 tt = nemo_action_get_tt (action, selection, parent);
6452
6453 gtk_action_set_label (GTK_ACTION (action), label);
6454 gtk_action_set_tooltip (GTK_ACTION (action), tt);
6455
6456 g_free (label);
6457 g_free (tt);
6458
6459 gtk_action_set_visible (GTK_ACTION (action), TRUE);
6460 } else {
6461 gtk_action_set_visible (GTK_ACTION (action), FALSE);
6462 }
6463 }
6464
6465 static void
update_actions_visibility(NemoView * view,GList * selection)6466 update_actions_visibility (NemoView *view, GList *selection)
6467 {
6468 GList *actions = gtk_action_group_list_actions (view->details->actions_action_group);
6469 ActionVisibilityData data;
6470
6471 data.view = view;
6472 data.selection = selection;
6473
6474 g_list_foreach (actions, determine_visibility, &data);
6475
6476 g_list_free (actions);
6477 }
6478
6479 static void
add_action_to_action_menus(NemoView * directory_view,NemoAction * action,const char * menu_path,const char * popup_path,const char * popup_bg_path)6480 add_action_to_action_menus (NemoView *directory_view,
6481 NemoAction *action,
6482 const char *menu_path,
6483 const char *popup_path,
6484 const char *popup_bg_path)
6485 {
6486 GtkUIManager *ui_manager;
6487
6488 const gchar *action_name = gtk_action_get_name (GTK_ACTION (action));
6489
6490 gtk_action_group_add_action (directory_view->details->actions_action_group,
6491 GTK_ACTION (action));
6492
6493 gtk_action_set_visible (GTK_ACTION (action), FALSE);
6494
6495 g_signal_handlers_disconnect_by_func (action,
6496 run_action_callback,
6497 directory_view);
6498
6499 g_signal_connect (action, "activate",
6500 G_CALLBACK (run_action_callback),
6501 directory_view);
6502
6503 ui_manager = nemo_window_get_ui_manager (directory_view->details->window);
6504
6505 gtk_ui_manager_add_ui (ui_manager,
6506 directory_view->details->actions_merge_id,
6507 menu_path,
6508 action_name,
6509 action_name,
6510 GTK_UI_MANAGER_MENUITEM,
6511 FALSE);
6512 gtk_ui_manager_add_ui (ui_manager,
6513 directory_view->details->actions_merge_id,
6514 popup_path,
6515 action_name,
6516 action_name,
6517 GTK_UI_MANAGER_MENUITEM,
6518 FALSE);
6519 gtk_ui_manager_add_ui (ui_manager,
6520 directory_view->details->actions_merge_id,
6521 popup_bg_path,
6522 action_name,
6523 action_name,
6524 GTK_UI_MANAGER_MENUITEM,
6525 FALSE);
6526 }
6527
6528 static void
update_actions(NemoView * view)6529 update_actions (NemoView *view)
6530 {
6531 NemoAction *action;
6532 GList *action_list, *node;
6533
6534 action_list = nemo_action_manager_list_actions (view->details->action_manager);
6535
6536 for (node = action_list; node != NULL; node = node->next) {
6537 action = node->data;
6538 add_action_to_action_menus (view, action, NEMO_VIEW_MENU_PATH_ACTIONS_PLACEHOLDER,
6539 NEMO_VIEW_POPUP_PATH_ACTIONS_PLACEHOLDER,
6540 NEMO_VIEW_POPUP_PATH_BACKGROUND_ACTIONS_PLACEHOLDER);
6541 }
6542 }
6543
6544 static void
update_actions_menu(NemoView * view)6545 update_actions_menu (NemoView *view)
6546 {
6547 GtkUIManager *ui_manager;
6548
6549 view->details->actions_invalid = FALSE;
6550
6551 ui_manager = nemo_window_get_ui_manager (view->details->window);
6552 nemo_ui_unmerge_ui (ui_manager,
6553 &view->details->actions_merge_id,
6554 &view->details->actions_action_group);
6555
6556 nemo_ui_prepare_merge_ui (ui_manager,
6557 "ActionsGroup",
6558 &view->details->actions_merge_id,
6559 &view->details->actions_action_group);
6560
6561 update_actions (view);
6562 }
6563
6564 static void
create_template_callback(GtkAction * action,gpointer callback_data)6565 create_template_callback (GtkAction *action, gpointer callback_data)
6566 {
6567 CreateTemplateParameters *parameters;
6568
6569 parameters = callback_data;
6570
6571 nemo_view_new_file (parameters->directory_view, NULL, parameters->file);
6572 }
6573
6574 static void
add_template_to_templates_menus(NemoView * directory_view,NemoFile * file,const char * menu_path,const char * popup_bg_path)6575 add_template_to_templates_menus (NemoView *directory_view,
6576 NemoFile *file,
6577 const char *menu_path,
6578 const char *popup_bg_path)
6579 {
6580 char *tmp, *tip, *uri, *name;
6581 char *escaped_label;
6582 GdkPixbuf *pixbuf;
6583 char *action_name;
6584 CreateTemplateParameters *parameters;
6585 GtkUIManager *ui_manager;
6586 GtkAction *action;
6587
6588 tmp = nemo_file_get_display_name (file);
6589 name = eel_filename_strip_extension (tmp);
6590 g_free (tmp);
6591
6592 uri = nemo_file_get_uri (file);
6593 tip = g_strdup_printf (_("Create a new document from template \"%s\""), name);
6594
6595 action_name = escape_action_name (uri, "template_");
6596 escaped_label = eel_str_double_underscores (name);
6597
6598 parameters = create_template_parameters_new (file, directory_view);
6599
6600 action = gtk_action_new (action_name,
6601 escaped_label,
6602 tip,
6603 NULL);
6604
6605 pixbuf = get_menu_icon_for_file (file, GTK_WIDGET (directory_view));
6606 if (pixbuf != NULL) {
6607 gtk_action_set_gicon (action, G_ICON (pixbuf));
6608 g_object_unref (pixbuf);
6609 }
6610
6611 g_signal_connect_data (action, "activate",
6612 G_CALLBACK (create_template_callback),
6613 parameters,
6614 (GClosureNotify)create_templates_parameters_free, 0);
6615
6616 gtk_action_group_add_action (directory_view->details->templates_action_group,
6617 action);
6618 g_object_unref (action);
6619
6620 ui_manager = nemo_window_get_ui_manager (directory_view->details->window);
6621
6622 gtk_ui_manager_add_ui (ui_manager,
6623 directory_view->details->templates_merge_id,
6624 menu_path,
6625 action_name,
6626 action_name,
6627 GTK_UI_MANAGER_MENUITEM,
6628 FALSE);
6629
6630 gtk_ui_manager_add_ui (ui_manager,
6631 directory_view->details->templates_merge_id,
6632 popup_bg_path,
6633 action_name,
6634 action_name,
6635 GTK_UI_MANAGER_MENUITEM,
6636 FALSE);
6637
6638 menu_item_show_image (ui_manager, menu_path, action_name, TRUE);
6639 menu_item_show_image (ui_manager, popup_bg_path, action_name, TRUE);
6640
6641 g_free (escaped_label);
6642 g_free (name);
6643 g_free (tip);
6644 g_free (uri);
6645 g_free (action_name);
6646 }
6647
6648 static void
update_templates_directory(NemoView * view)6649 update_templates_directory (NemoView *view)
6650 {
6651 NemoDirectory *templates_directory;
6652 GList *node, *next;
6653 char *templates_uri;
6654
6655 for (node = view->details->templates_directory_list; node != NULL; node = next) {
6656 next = node->next;
6657 remove_directory_from_templates_directory_list (view, node->data);
6658 }
6659
6660 if (nemo_should_use_templates_directory ()) {
6661 templates_uri = nemo_get_templates_directory_uri ();
6662 templates_directory = nemo_directory_get_by_uri (templates_uri);
6663 g_free (templates_uri);
6664 add_directory_to_templates_directory_list (view, templates_directory);
6665 nemo_directory_unref (templates_directory);
6666 }
6667 }
6668
6669 static void
user_dirs_changed(NemoView * view)6670 user_dirs_changed (NemoView *view)
6671 {
6672 update_templates_directory (view);
6673 view->details->templates_invalid = TRUE;
6674 schedule_update_menus (view);
6675 }
6676
6677 static gboolean
directory_belongs_in_templates_menu(const char * templates_directory_uri,const char * uri)6678 directory_belongs_in_templates_menu (const char *templates_directory_uri,
6679 const char *uri)
6680 {
6681 int num_levels;
6682 int i;
6683
6684 if (templates_directory_uri == NULL) {
6685 return FALSE;
6686 }
6687
6688 if (!g_str_has_prefix (uri, templates_directory_uri)) {
6689 return FALSE;
6690 }
6691
6692 num_levels = 0;
6693 for (i = strlen (templates_directory_uri); uri[i] != '\0'; i++) {
6694 if (uri[i] == '/') {
6695 num_levels++;
6696 }
6697 }
6698
6699 if (num_levels > MAX_MENU_LEVELS) {
6700 return FALSE;
6701 }
6702
6703 return TRUE;
6704 }
6705
6706 static gboolean
update_directory_in_templates_menu(NemoView * view,const char * templates_directory_uri,NemoDirectory * directory)6707 update_directory_in_templates_menu (NemoView *view,
6708 const char *templates_directory_uri,
6709 NemoDirectory *directory)
6710 {
6711 char *menu_path, *popup_bg_path;
6712 GList *file_list, *filtered, *node;
6713 gboolean any_templates;
6714 NemoFile *file;
6715 NemoDirectory *dir;
6716 char *escaped_path;
6717 char *uri;
6718 int num;
6719
6720 /* We know this directory belongs to the template dir, so it must exist */
6721 g_assert (templates_directory_uri);
6722
6723 uri = nemo_directory_get_uri (directory);
6724 escaped_path = escape_action_path (uri + strlen (templates_directory_uri));
6725 g_free (uri);
6726 menu_path = g_strconcat (NEMO_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER,
6727 escaped_path,
6728 NULL);
6729 popup_bg_path = g_strconcat (NEMO_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER,
6730 escaped_path,
6731 NULL);
6732 g_free (escaped_path);
6733
6734 file_list = nemo_directory_get_file_list (directory);
6735 filtered = nemo_file_list_filter_hidden (file_list, FALSE);
6736 nemo_file_list_free (file_list);
6737
6738 file_list = nemo_file_list_sort_by_display_name (filtered);
6739
6740 num = 0;
6741 any_templates = FALSE;
6742 for (node = file_list; num < TEMPLATE_LIMIT && node != NULL; node = node->next, num++) {
6743 file = node->data;
6744
6745 if (nemo_file_is_directory (file)) {
6746 uri = nemo_file_get_uri (file);
6747 if (directory_belongs_in_templates_menu (templates_directory_uri, uri)) {
6748 dir = nemo_directory_get_by_uri (uri);
6749 add_directory_to_templates_directory_list (view, dir);
6750 nemo_directory_unref (dir);
6751
6752 add_submenu_to_directory_menus (view,
6753 view->details->templates_action_group,
6754 view->details->templates_merge_id,
6755 file, menu_path, NULL, popup_bg_path);
6756
6757 any_templates = TRUE;
6758 }
6759 g_free (uri);
6760 } else if (nemo_file_can_read (file)) {
6761 add_template_to_templates_menus (view, file, menu_path, popup_bg_path);
6762 any_templates = TRUE;
6763 }
6764 }
6765
6766 nemo_file_list_free (file_list);
6767
6768 g_free (popup_bg_path);
6769 g_free (menu_path);
6770
6771 return any_templates;
6772 }
6773
6774
6775
6776 static void
update_templates_menu(NemoView * view)6777 update_templates_menu (NemoView *view)
6778 {
6779 gboolean any_templates;
6780 GList *sorted_copy, *node;
6781 NemoDirectory *directory;
6782 GtkUIManager *ui_manager;
6783 char *uri;
6784 GtkAction *action;
6785 char *templates_directory_uri;
6786
6787 if (nemo_should_use_templates_directory ()) {
6788 templates_directory_uri = nemo_get_templates_directory_uri ();
6789 } else {
6790 templates_directory_uri = NULL;
6791 }
6792
6793 /* There is a race condition here. If we don't mark the scripts menu as
6794 valid before we begin our task then we can lose template menu updates that
6795 occur before we finish. */
6796 view->details->templates_invalid = FALSE;
6797
6798 ui_manager = nemo_window_get_ui_manager (view->details->window);
6799 nemo_ui_unmerge_ui (ui_manager,
6800 &view->details->templates_merge_id,
6801 &view->details->templates_action_group);
6802
6803 nemo_ui_prepare_merge_ui (ui_manager,
6804 "TemplatesGroup",
6805 &view->details->templates_merge_id,
6806 &view->details->templates_action_group);
6807
6808 /* As we walk through the directories, remove any that no longer belong. */
6809 any_templates = FALSE;
6810 sorted_copy = nemo_directory_list_sort_by_uri
6811 (nemo_directory_list_copy (view->details->templates_directory_list));
6812 for (node = sorted_copy; node != NULL; node = node->next) {
6813 directory = node->data;
6814
6815 uri = nemo_directory_get_uri (directory);
6816 if (!directory_belongs_in_templates_menu (templates_directory_uri, uri)) {
6817 remove_directory_from_templates_directory_list (view, directory);
6818 } else if (update_directory_in_templates_menu (view,
6819 templates_directory_uri,
6820 directory)) {
6821 any_templates = TRUE;
6822 }
6823 g_free (uri);
6824 }
6825 nemo_directory_list_free (sorted_copy);
6826
6827 action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_NO_TEMPLATES);
6828 gtk_action_set_visible (action, !any_templates);
6829
6830 g_free (templates_directory_uri);
6831 }
6832
6833 static GtkMenu *
create_popup_menu(NemoView * view,const char * popup_path)6834 create_popup_menu (NemoView *view, const char *popup_path)
6835 {
6836 GtkWidget *menu;
6837
6838 menu = gtk_ui_manager_get_widget (nemo_window_get_ui_manager (view->details->window),
6839 popup_path);
6840 gtk_menu_set_screen (GTK_MENU (menu),
6841 gtk_widget_get_screen (GTK_WIDGET (view)));
6842 gtk_widget_show (GTK_WIDGET (menu));
6843
6844 return GTK_MENU (menu);
6845 }
6846
6847 static void
copy_or_cut_files(NemoView * view,GList * clipboard_contents,gboolean cut)6848 copy_or_cut_files (NemoView *view,
6849 GList *clipboard_contents,
6850 gboolean cut)
6851 {
6852 int count;
6853 char *status_string, *name;
6854 NemoClipboardInfo info;
6855 GtkTargetList *target_list;
6856 GtkTargetEntry *targets;
6857 int n_targets;
6858
6859 info.files = clipboard_contents;
6860 info.cut = cut;
6861
6862 target_list = gtk_target_list_new (NULL, 0);
6863 gtk_target_list_add (target_list, copied_files_atom, 0, 0);
6864 gtk_target_list_add_uri_targets (target_list, 0);
6865 gtk_target_list_add_text_targets (target_list, 0);
6866
6867 targets = gtk_target_table_new_from_list (target_list, &n_targets);
6868 gtk_target_list_unref (target_list);
6869
6870 gtk_clipboard_set_with_data (nemo_clipboard_get (GTK_WIDGET (view)),
6871 targets, n_targets,
6872 nemo_get_clipboard_callback, nemo_clear_clipboard_callback,
6873 NULL);
6874 gtk_target_table_free (targets, n_targets);
6875
6876 nemo_clipboard_monitor_set_clipboard_info (nemo_clipboard_monitor_get (), &info);
6877
6878 count = g_list_length (clipboard_contents);
6879 if (count == 1) {
6880 name = nemo_file_get_display_name (clipboard_contents->data);
6881 if (cut) {
6882 status_string = g_strdup_printf (_("\"%s\" will be moved "
6883 "if you select the Paste command"),
6884 name);
6885 } else {
6886 status_string = g_strdup_printf (_("\"%s\" will be copied "
6887 "if you select the Paste command"),
6888 name);
6889 }
6890 g_free (name);
6891 } else {
6892 if (cut) {
6893 status_string = g_strdup_printf (ngettext("The %'d selected item will be moved "
6894 "if you select the Paste command",
6895 "The %'d selected items will be moved "
6896 "if you select the Paste command",
6897 count),
6898 count);
6899 } else {
6900 status_string = g_strdup_printf (ngettext("The %'d selected item will be copied "
6901 "if you select the Paste command",
6902 "The %'d selected items will be copied "
6903 "if you select the Paste command",
6904 count),
6905 count);
6906 }
6907 }
6908
6909 nemo_window_slot_set_status (view->details->slot,
6910 status_string, NULL);
6911 g_free (status_string);
6912 }
6913
6914 static void
action_copy_files_callback(GtkAction * action,gpointer callback_data)6915 action_copy_files_callback (GtkAction *action,
6916 gpointer callback_data)
6917 {
6918 NemoView *view;
6919 GList *selection;
6920
6921 view = NEMO_VIEW (callback_data);
6922
6923 selection = nemo_view_get_selection_for_file_transfer (view);
6924 copy_or_cut_files (view, selection, FALSE);
6925 nemo_file_list_free (selection);
6926 }
6927
6928 static void
move_copy_selection_to_next_pane(NemoView * view,int copy_action)6929 move_copy_selection_to_next_pane (NemoView *view,
6930 int copy_action)
6931 {
6932 NemoWindowSlot *slot;
6933 char *dest_location;
6934
6935 slot = nemo_window_get_extra_slot (nemo_view_get_nemo_window (view));
6936 g_return_if_fail (slot != NULL);
6937
6938 dest_location = nemo_window_slot_get_current_uri (slot);
6939 g_return_if_fail (dest_location != NULL);
6940
6941 move_copy_selection_to_location (view, copy_action, dest_location);
6942 }
6943
6944 static void
action_copy_to_next_pane_callback(GtkAction * action,gpointer callback_data)6945 action_copy_to_next_pane_callback (GtkAction *action, gpointer callback_data)
6946 {
6947 NemoView *view;
6948
6949 view = NEMO_VIEW (callback_data);
6950 move_copy_selection_to_next_pane (view,
6951 GDK_ACTION_COPY);
6952 }
6953
6954 static void
action_move_to_next_pane_callback(GtkAction * action,gpointer callback_data)6955 action_move_to_next_pane_callback (GtkAction *action, gpointer callback_data)
6956 {
6957 NemoWindowSlot *slot;
6958 char *dest_location;
6959 NemoView *view;
6960
6961 view = NEMO_VIEW (callback_data);
6962
6963 slot = nemo_window_get_extra_slot (nemo_view_get_nemo_window (view));
6964 g_return_if_fail (slot != NULL);
6965
6966 dest_location = nemo_window_slot_get_current_uri (slot);
6967 g_return_if_fail (dest_location != NULL);
6968
6969 move_copy_selection_to_location (view, GDK_ACTION_MOVE, dest_location);
6970 }
6971
6972 static void
action_copy_to_home_callback(GtkAction * action,gpointer callback_data)6973 action_copy_to_home_callback (GtkAction *action, gpointer callback_data)
6974 {
6975 NemoView *view;
6976 char *dest_location;
6977
6978 view = NEMO_VIEW (callback_data);
6979
6980 dest_location = nemo_get_home_directory_uri ();
6981 move_copy_selection_to_location (view, GDK_ACTION_COPY, dest_location);
6982 g_free (dest_location);
6983 }
6984
6985 static void
action_move_to_home_callback(GtkAction * action,gpointer callback_data)6986 action_move_to_home_callback (GtkAction *action, gpointer callback_data)
6987 {
6988 NemoView *view;
6989 char *dest_location;
6990
6991 view = NEMO_VIEW (callback_data);
6992
6993 dest_location = nemo_get_home_directory_uri ();
6994 move_copy_selection_to_location (view, GDK_ACTION_MOVE, dest_location);
6995 g_free (dest_location);
6996 }
6997
6998 static void
action_copy_to_desktop_callback(GtkAction * action,gpointer callback_data)6999 action_copy_to_desktop_callback (GtkAction *action, gpointer callback_data)
7000 {
7001 NemoView *view;
7002 char *dest_location;
7003
7004 view = NEMO_VIEW (callback_data);
7005
7006 dest_location = nemo_get_desktop_directory_uri ();
7007 move_copy_selection_to_location (view, GDK_ACTION_COPY, dest_location);
7008 g_free (dest_location);
7009 }
7010
7011 static void
action_move_to_desktop_callback(GtkAction * action,gpointer callback_data)7012 action_move_to_desktop_callback (GtkAction *action, gpointer callback_data)
7013 {
7014 NemoView *view;
7015 char *dest_location;
7016
7017 view = NEMO_VIEW (callback_data);
7018
7019 dest_location = nemo_get_desktop_directory_uri ();
7020 move_copy_selection_to_location (view, GDK_ACTION_MOVE, dest_location);
7021 g_free (dest_location);
7022 }
7023
7024 static void
browse_move_to_response_cb(GtkDialog * dialog,gint response,NemoView * view)7025 browse_move_to_response_cb (GtkDialog *dialog, gint response, NemoView *view)
7026 {
7027 gchar *uri;
7028
7029 switch (response) {
7030 case GTK_RESPONSE_OK:
7031 uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
7032 move_copy_selection_to_location (view, GDK_ACTION_MOVE, uri);
7033 g_free (uri);
7034 break;
7035 case GTK_RESPONSE_CANCEL:
7036 default:
7037 break;
7038 }
7039
7040 gtk_widget_destroy (GTK_WIDGET (dialog));
7041 }
7042
7043 static void
browse_copy_to_response_cb(GtkDialog * dialog,gint response,NemoView * view)7044 browse_copy_to_response_cb (GtkDialog *dialog, gint response, NemoView *view)
7045 {
7046 gchar *uri;
7047
7048 switch (response) {
7049 case GTK_RESPONSE_OK:
7050 uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
7051 move_copy_selection_to_location (view, GDK_ACTION_COPY, uri);
7052 g_free (uri);
7053 break;
7054 case GTK_RESPONSE_CANCEL:
7055 default:
7056 break;
7057 }
7058
7059 gtk_widget_destroy (GTK_WIDGET (dialog));
7060 }
7061
7062 static void
action_browse_for_move_to_folder_callback(GtkAction * action,gpointer callback_data)7063 action_browse_for_move_to_folder_callback (GtkAction *action, gpointer callback_data)
7064 {
7065 GtkWidget *dialog;
7066 NemoView *view;
7067
7068 view = NEMO_VIEW (callback_data);
7069
7070 dialog = gtk_file_chooser_dialog_new (_("Select Target Folder For Move"),
7071 nemo_view_get_containing_window (view),
7072 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
7073 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
7074 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
7075 NULL);
7076
7077 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
7078
7079 g_signal_connect (dialog, "response",
7080 G_CALLBACK (browse_move_to_response_cb), view);
7081
7082 gtk_widget_show (dialog);
7083 }
7084
7085 static void
action_browse_for_copy_to_folder_callback(GtkAction * action,gpointer callback_data)7086 action_browse_for_copy_to_folder_callback (GtkAction *action, gpointer callback_data)
7087 {
7088 GtkWidget *dialog;
7089 NemoView *view;
7090
7091 view = NEMO_VIEW (callback_data);
7092
7093 dialog = gtk_file_chooser_dialog_new (_("Select Target Folder For Copy"),
7094 nemo_view_get_containing_window (view),
7095 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
7096 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
7097 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
7098 NULL);
7099
7100 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
7101
7102 g_signal_connect (dialog, "response",
7103 G_CALLBACK (browse_copy_to_response_cb), view);
7104
7105 gtk_widget_show (dialog);
7106 }
7107
7108 static void
action_cut_files_callback(GtkAction * action,gpointer callback_data)7109 action_cut_files_callback (GtkAction *action,
7110 gpointer callback_data)
7111 {
7112 NemoView *view;
7113 GList *selection;
7114
7115 view = NEMO_VIEW (callback_data);
7116
7117 selection = nemo_view_get_selection_for_file_transfer (view);
7118 copy_or_cut_files (view, selection, TRUE);
7119 nemo_file_list_free (selection);
7120 }
7121
7122 static void
paste_clipboard_data(NemoView * view,GtkSelectionData * selection_data,char * destination_uri)7123 paste_clipboard_data (NemoView *view,
7124 GtkSelectionData *selection_data,
7125 char *destination_uri)
7126 {
7127 gboolean cut;
7128 GList *item_uris;
7129
7130 cut = FALSE;
7131 item_uris = nemo_clipboard_get_uri_list_from_selection_data (selection_data, &cut,
7132 copied_files_atom);
7133
7134 if (item_uris == NULL|| destination_uri == NULL) {
7135 nemo_window_slot_set_status (view->details->slot,
7136 _("There is nothing on the clipboard to paste."),
7137 NULL);
7138 } else {
7139 nemo_view_move_copy_items (view, item_uris, NULL, destination_uri,
7140 cut ? GDK_ACTION_MOVE : GDK_ACTION_COPY,
7141 0, 0);
7142
7143 /* If items are cut then remove from clipboard */
7144 if (cut) {
7145 gtk_clipboard_clear (nemo_clipboard_get (GTK_WIDGET (view)));
7146 }
7147
7148 g_list_free_full (item_uris, g_free);
7149 }
7150 }
7151
7152 static void
paste_clipboard_received_callback(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer data)7153 paste_clipboard_received_callback (GtkClipboard *clipboard,
7154 GtkSelectionData *selection_data,
7155 gpointer data)
7156 {
7157 NemoView *view;
7158 char *view_uri;
7159
7160 view = NEMO_VIEW (data);
7161
7162 view_uri = nemo_view_get_backing_uri (view);
7163
7164 if (view->details->window != NULL) {
7165 paste_clipboard_data (view, selection_data, view_uri);
7166 }
7167
7168 g_free (view_uri);
7169
7170 g_object_unref (view);
7171 }
7172
7173 typedef struct {
7174 NemoView *view;
7175 NemoFile *target;
7176 } PasteIntoData;
7177
7178 static void
paste_into_clipboard_received_callback(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer callback_data)7179 paste_into_clipboard_received_callback (GtkClipboard *clipboard,
7180 GtkSelectionData *selection_data,
7181 gpointer callback_data)
7182 {
7183 PasteIntoData *data;
7184 NemoView *view;
7185 char *directory_uri;
7186
7187 data = (PasteIntoData *) callback_data;
7188
7189 view = NEMO_VIEW (data->view);
7190
7191 if (view->details->window != NULL) {
7192 directory_uri = nemo_file_get_activation_uri (data->target);
7193
7194 paste_clipboard_data (view, selection_data, directory_uri);
7195
7196 g_free (directory_uri);
7197 }
7198
7199 g_object_unref (view);
7200 nemo_file_unref (data->target);
7201 g_free (data);
7202 }
7203
7204 static void
action_paste_files_callback(GtkAction * action,gpointer callback_data)7205 action_paste_files_callback (GtkAction *action,
7206 gpointer callback_data)
7207 {
7208 NemoView *view;
7209
7210 view = NEMO_VIEW (callback_data);
7211
7212 g_object_ref (view);
7213 gtk_clipboard_request_contents (nemo_clipboard_get (GTK_WIDGET (view)),
7214 copied_files_atom,
7215 paste_clipboard_received_callback,
7216 view);
7217 }
7218
7219 static void
paste_into(NemoView * view,NemoFile * target)7220 paste_into (NemoView *view,
7221 NemoFile *target)
7222 {
7223 PasteIntoData *data;
7224
7225 g_assert (NEMO_IS_VIEW (view));
7226 g_assert (NEMO_IS_FILE (target));
7227
7228 data = g_new (PasteIntoData, 1);
7229
7230 data->view = g_object_ref (view);
7231 data->target = nemo_file_ref (target);
7232
7233 gtk_clipboard_request_contents (nemo_clipboard_get (GTK_WIDGET (view)),
7234 copied_files_atom,
7235 paste_into_clipboard_received_callback,
7236 data);
7237 }
7238
7239 static void
cb_open_as_root_watch(GPid pid,gint status,gpointer user_data)7240 cb_open_as_root_watch (GPid pid, gint status, gpointer user_data)
7241 {
7242 g_spawn_close_pid(pid);
7243 }
7244
7245 static void
open_as_root(const gchar * path)7246 open_as_root (const gchar *path)
7247 {
7248 gchar *argv[4];
7249 argv[0] = (gchar *)"pkexec";
7250 argv[1] = (gchar *)"nemo";
7251 argv[2] = g_strdup (path);
7252 argv[3] = NULL;
7253 GPid pid;
7254 g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
7255 NULL, NULL, &pid, NULL);
7256 g_child_watch_add(pid, (GChildWatchFunc)cb_open_as_root_watch, NULL);
7257 g_free (argv[2]);
7258 }
7259
7260 static void
open_in_terminal(const gchar * path)7261 open_in_terminal (const gchar *path)
7262 {
7263 gchar *argv[2];
7264 argv[0] = g_settings_get_string (gnome_terminal_preferences,
7265 GNOME_DESKTOP_TERMINAL_EXEC);
7266 argv[1] = NULL;
7267 g_spawn_async(path, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
7268 }
7269
7270 static void
action_paste_files_into_callback(GtkAction * action,gpointer callback_data)7271 action_paste_files_into_callback (GtkAction *action,
7272 gpointer callback_data)
7273 {
7274 NemoView *view;
7275 GList *selection;
7276
7277 view = NEMO_VIEW (callback_data);
7278 selection = nemo_view_get_selection (view);
7279 if (selection != NULL) {
7280 paste_into (view, NEMO_FILE (selection->data));
7281 nemo_file_list_free (selection);
7282 }
7283
7284 }
7285
7286 static void
action_open_as_root_callback(GtkAction * action,gpointer callback_data)7287 action_open_as_root_callback (GtkAction *action,
7288 gpointer callback_data)
7289 {
7290 NemoView *view;
7291 GList *selection;
7292
7293 view = NEMO_VIEW (callback_data);
7294 selection = nemo_view_get_selection (view);
7295 if (selection != NULL) {
7296 gchar *path = nemo_file_get_path (NEMO_FILE (selection->data));
7297 open_as_root (path);
7298 nemo_file_list_free (selection);
7299 g_free (path);
7300 } else {
7301 gchar *path;
7302 gchar *uri = nemo_view_get_uri (view);
7303 GFile *gfile = g_file_new_for_uri (uri);
7304 if (g_file_has_uri_scheme (gfile, "x-nemo-desktop")) {
7305 path = nemo_get_desktop_directory ();
7306 } else {
7307 path = g_file_get_path (gfile);
7308 }
7309 open_as_root (path);
7310 g_free (uri);
7311 g_free (path);
7312 g_object_unref (gfile);
7313 }
7314
7315 }
7316
7317 static void
action_follow_symlink_callback(GtkAction * action,gpointer callback_data)7318 action_follow_symlink_callback (GtkAction *action,
7319 gpointer callback_data)
7320 {
7321 NemoView *view;
7322 GList *selection;
7323
7324 view = NEMO_VIEW (callback_data);
7325 selection = nemo_view_get_selection (view);
7326 if (nemo_file_is_symbolic_link (selection->data)) {
7327 gchar *uri = nemo_file_get_symbolic_link_target_uri (selection->data);
7328 gchar *view_uri = nemo_view_get_uri (view);
7329 GFile *location = g_file_new_for_uri (uri);
7330 GFile *parent = g_file_get_parent (location);
7331 GFile *current = g_file_new_for_uri (view_uri);
7332
7333 if (g_file_equal (current, parent)) {
7334 nemo_view_scroll_to_file (view, uri);
7335 GList *l = NULL;
7336 l = g_list_append (l, nemo_file_get_existing (location));
7337 nemo_view_set_selection (view, l);
7338 } else {
7339 if (get_is_desktop_view (view)) {
7340 nemo_mime_launch_fm_and_select_file (location);
7341 } else {
7342 nemo_window_slot_open_location (view->details->slot, location, 0);
7343 }
7344 }
7345
7346 g_free (uri);
7347 g_free (view_uri);
7348 g_object_unref (location);
7349 g_object_unref (parent);
7350 g_object_unref (current);
7351 }
7352
7353 nemo_file_list_free (selection);
7354 }
7355
7356 static void
action_open_containing_folder_callback(GtkAction * action,gpointer callback_data)7357 action_open_containing_folder_callback (GtkAction *action,
7358 gpointer callback_data)
7359 {
7360 NemoView *view;
7361 GList *selection;
7362 NemoFile *item;
7363 GFile *activation_location;
7364 NemoFile *activation_file;
7365 NemoFile *location;
7366
7367 view = NEMO_VIEW (callback_data);
7368 selection = nemo_view_get_selection (view);
7369
7370 item = NEMO_FILE (selection->data);
7371 activation_location = nemo_file_get_activation_location (item);
7372 activation_file = nemo_file_get (activation_location);
7373 location = nemo_file_get_parent (activation_file);
7374
7375 nemo_view_activate_file (view, location, 0);
7376
7377 nemo_file_unref (location);
7378 nemo_file_unref (activation_file);
7379 g_object_unref (activation_location);
7380 }
7381
7382 static void
action_open_in_terminal_callback(GtkAction * action,gpointer callback_data)7383 action_open_in_terminal_callback(GtkAction *action,
7384 gpointer callback_data)
7385 {
7386 NemoView *view;
7387 GList *selection;
7388
7389 view = NEMO_VIEW (callback_data);
7390 selection = nemo_view_get_selection (view);
7391 if (selection != NULL) {
7392 gchar *path;
7393 if (nemo_file_is_directory (NEMO_FILE (selection->data))) {
7394 path = nemo_file_get_path (NEMO_FILE (selection->data));
7395 } else {
7396 NemoFile *location = nemo_file_get_parent (NEMO_FILE (selection->data));
7397 path = nemo_file_get_path (location);
7398 nemo_file_unref (location);
7399 }
7400 open_in_terminal (path);
7401 g_free (path);
7402 nemo_file_list_free (selection);
7403 } else {
7404 gchar *path;
7405 gchar *uri = nemo_view_get_uri (view);
7406 GFile *gfile = g_file_new_for_uri (uri);
7407 if (g_file_has_uri_scheme (gfile, "x-nemo-desktop")) {
7408 path = nemo_get_desktop_directory ();
7409 } else {
7410 path = g_file_get_path (gfile);
7411 }
7412 open_in_terminal (path);
7413 g_free (uri);
7414 g_free (path);
7415 g_object_unref (gfile);
7416 }
7417 }
7418
7419 static void
invoke_external_bulk_rename_utility(NemoView * view,GList * selection)7420 invoke_external_bulk_rename_utility (NemoView *view,
7421 GList *selection)
7422 {
7423 GString *cmd;
7424 char *parameter;
7425 char *quoted_parameter;
7426 char *bulk_rename_tool;
7427 GList *walk;
7428 NemoFile *file;
7429
7430 /* assemble command line */
7431 bulk_rename_tool = get_bulk_rename_tool ();
7432 cmd = g_string_new (bulk_rename_tool);
7433 g_free (bulk_rename_tool);
7434 for (walk = selection; walk; walk = walk->next) {
7435 file = walk->data;
7436 parameter = nemo_file_get_uri (file);
7437 quoted_parameter = g_shell_quote (parameter);
7438 g_free (parameter);
7439 cmd = g_string_append (cmd, " ");
7440 cmd = g_string_append (cmd, quoted_parameter);
7441 g_free (quoted_parameter);
7442 }
7443
7444 guint i = 0;
7445
7446 // Escape percents
7447 for (i = 0; i < strlen(cmd->str); i++) {
7448 if (cmd->str[i] == '%') {
7449 g_string_insert_c(cmd, i++, '%');
7450 }
7451 }
7452
7453 /* spawning and error handling */
7454 nemo_launch_application_from_command (gtk_widget_get_screen (GTK_WIDGET (view)),
7455 cmd->str, FALSE, NULL);
7456 g_string_free (cmd, TRUE);
7457 }
7458
7459 static void
real_action_undo(NemoView * view)7460 real_action_undo (NemoView *view)
7461 {
7462 GtkWidget *toplevel;
7463
7464 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
7465 nemo_file_undo_manager_undo (GTK_WINDOW (toplevel));
7466 }
7467
7468 static void
real_action_redo(NemoView * view)7469 real_action_redo (NemoView *view)
7470 {
7471 GtkWidget *toplevel;
7472
7473 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
7474 nemo_file_undo_manager_redo (GTK_WINDOW (toplevel));
7475 }
7476
7477 static void
action_undo_callback(GtkAction * action,gpointer callback_data)7478 action_undo_callback (GtkAction *action,
7479 gpointer callback_data)
7480 {
7481 real_action_undo (NEMO_VIEW (callback_data));
7482 }
7483
7484 static void
action_redo_callback(GtkAction * action,gpointer callback_data)7485 action_redo_callback (GtkAction *action,
7486 gpointer callback_data)
7487 {
7488 real_action_redo (NEMO_VIEW (callback_data));
7489 }
7490
7491 static void
real_action_rename(NemoView * view,gboolean select_all)7492 real_action_rename (NemoView *view,
7493 gboolean select_all)
7494 {
7495 NemoFile *file;
7496 GList *selection;
7497
7498 g_assert (NEMO_IS_VIEW (view));
7499
7500 selection = nemo_view_get_selection (view);
7501
7502 if (selection_not_empty_in_menu_callback (view, selection)) {
7503 /* If there is more than one file selected, invoke a batch renamer */
7504 if (selection->next != NULL) {
7505 if (have_bulk_rename_tool ()) {
7506 invoke_external_bulk_rename_utility (view, selection);
7507 }
7508 } else {
7509 file = NEMO_FILE (selection->data);
7510 if (!select_all) {
7511 /* directories don't have a file extension, so
7512 * they are always pre-selected as a whole */
7513 select_all = nemo_file_is_directory (file);
7514 }
7515 NEMO_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->start_renaming_file (view, file, select_all);
7516 }
7517 }
7518
7519 nemo_file_list_free (selection);
7520 }
7521
7522 static void
action_rename_callback(GtkAction * action,gpointer callback_data)7523 action_rename_callback (GtkAction *action,
7524 gpointer callback_data)
7525 {
7526 real_action_rename (NEMO_VIEW (callback_data), FALSE);
7527 }
7528
7529 static void
action_rename_select_all_callback(GtkAction * action,gpointer callback_data)7530 action_rename_select_all_callback (GtkAction *action,
7531 gpointer callback_data)
7532 {
7533 real_action_rename (NEMO_VIEW (callback_data), TRUE);
7534 }
7535
7536 static void
file_mount_callback(NemoFile * file,GFile * result_location,GError * error,gpointer callback_data)7537 file_mount_callback (NemoFile *file,
7538 GFile *result_location,
7539 GError *error,
7540 gpointer callback_data)
7541 {
7542 if (error != NULL &&
7543 (error->domain != G_IO_ERROR ||
7544 (error->code != G_IO_ERROR_CANCELLED &&
7545 error->code != G_IO_ERROR_FAILED_HANDLED &&
7546 error->code != G_IO_ERROR_ALREADY_MOUNTED))) {
7547 eel_show_error_dialog (_("Unable to mount location"),
7548 error->message, NULL);
7549 }
7550 }
7551
7552 static void
file_unmount_callback(NemoFile * file,GFile * result_location,GError * error,gpointer callback_data)7553 file_unmount_callback (NemoFile *file,
7554 GFile *result_location,
7555 GError *error,
7556 gpointer callback_data)
7557 {
7558 NemoView *view;
7559
7560 view = NEMO_VIEW (callback_data);
7561 g_object_unref (view);
7562
7563 if (error != NULL &&
7564 (error->domain != G_IO_ERROR ||
7565 (error->code != G_IO_ERROR_CANCELLED &&
7566 error->code != G_IO_ERROR_FAILED_HANDLED))) {
7567 eel_show_error_dialog (_("Unable to unmount location"),
7568 error->message, NULL);
7569 }
7570 }
7571
7572 static void
file_eject_callback(NemoFile * file,GFile * result_location,GError * error,gpointer callback_data)7573 file_eject_callback (NemoFile *file,
7574 GFile *result_location,
7575 GError *error,
7576 gpointer callback_data)
7577 {
7578 NemoView *view;
7579
7580 view = NEMO_VIEW (callback_data);
7581 g_object_unref (view);
7582
7583 if (error != NULL &&
7584 (error->domain != G_IO_ERROR ||
7585 (error->code != G_IO_ERROR_CANCELLED &&
7586 error->code != G_IO_ERROR_FAILED_HANDLED))) {
7587 eel_show_error_dialog (_("Unable to eject location"),
7588 error->message, NULL);
7589 }
7590 }
7591
7592 static void
file_stop_callback(NemoFile * file,GFile * result_location,GError * error,gpointer callback_data)7593 file_stop_callback (NemoFile *file,
7594 GFile *result_location,
7595 GError *error,
7596 gpointer callback_data)
7597 {
7598 if (error != NULL &&
7599 (error->domain != G_IO_ERROR ||
7600 (error->code != G_IO_ERROR_CANCELLED &&
7601 error->code != G_IO_ERROR_FAILED_HANDLED))) {
7602 eel_show_error_dialog (_("Unable to stop drive"),
7603 error->message, NULL);
7604 }
7605 }
7606
7607 static void
action_mount_volume_callback(GtkAction * action,gpointer data)7608 action_mount_volume_callback (GtkAction *action,
7609 gpointer data)
7610 {
7611 NemoFile *file;
7612 GList *selection, *l;
7613 NemoView *view;
7614 GMountOperation *mount_op;
7615
7616 view = NEMO_VIEW (data);
7617
7618 selection = nemo_view_get_selection (view);
7619 for (l = selection; l != NULL; l = l->next) {
7620 file = NEMO_FILE (l->data);
7621
7622 if (nemo_file_can_mount (file)) {
7623 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7624 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
7625 nemo_file_mount (file, mount_op, NULL,
7626 file_mount_callback, NULL);
7627 g_object_unref (mount_op);
7628 }
7629 }
7630 nemo_file_list_free (selection);
7631 }
7632
7633 static void
action_unmount_volume_callback(GtkAction * action,gpointer data)7634 action_unmount_volume_callback (GtkAction *action,
7635 gpointer data)
7636 {
7637 NemoFile *file;
7638 GList *selection, *l;
7639 NemoView *view;
7640
7641 view = NEMO_VIEW (data);
7642
7643 selection = nemo_view_get_selection (view);
7644
7645 for (l = selection; l != NULL; l = l->next) {
7646 file = NEMO_FILE (l->data);
7647 if (nemo_file_can_unmount (file)) {
7648 GMountOperation *mount_op;
7649 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7650 nemo_file_unmount (file, mount_op, NULL,
7651 file_unmount_callback, g_object_ref (view));
7652 g_object_unref (mount_op);
7653 }
7654 }
7655 nemo_file_list_free (selection);
7656 }
7657
7658 static void
action_eject_volume_callback(GtkAction * action,gpointer data)7659 action_eject_volume_callback (GtkAction *action,
7660 gpointer data)
7661 {
7662 NemoFile *file;
7663 GList *selection, *l;
7664 NemoView *view;
7665
7666 view = NEMO_VIEW (data);
7667
7668 selection = nemo_view_get_selection (view);
7669 for (l = selection; l != NULL; l = l->next) {
7670 file = NEMO_FILE (l->data);
7671
7672 if (nemo_file_can_eject (file)) {
7673 GMountOperation *mount_op;
7674 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7675 nemo_file_eject (file, mount_op, NULL,
7676 file_eject_callback, g_object_ref (view));
7677 g_object_unref (mount_op);
7678 }
7679 }
7680 nemo_file_list_free (selection);
7681 }
7682
7683 static void
file_start_callback(NemoFile * file,GFile * result_location,GError * error,gpointer callback_data)7684 file_start_callback (NemoFile *file,
7685 GFile *result_location,
7686 GError *error,
7687 gpointer callback_data)
7688 {
7689 if (error != NULL &&
7690 (error->domain != G_IO_ERROR ||
7691 (error->code != G_IO_ERROR_CANCELLED &&
7692 error->code != G_IO_ERROR_FAILED_HANDLED &&
7693 error->code != G_IO_ERROR_ALREADY_MOUNTED))) {
7694 eel_show_error_dialog (_("Unable to start location"),
7695 error->message, NULL);
7696 }
7697 }
7698
7699 static void
action_start_volume_callback(GtkAction * action,gpointer data)7700 action_start_volume_callback (GtkAction *action,
7701 gpointer data)
7702 {
7703 NemoFile *file;
7704 GList *selection, *l;
7705 NemoView *view;
7706 GMountOperation *mount_op;
7707
7708 view = NEMO_VIEW (data);
7709
7710 selection = nemo_view_get_selection (view);
7711 for (l = selection; l != NULL; l = l->next) {
7712 file = NEMO_FILE (l->data);
7713
7714 if (nemo_file_can_start (file) || nemo_file_can_start_degraded (file)) {
7715 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7716 nemo_file_start (file, mount_op, NULL,
7717 file_start_callback, NULL);
7718 g_object_unref (mount_op);
7719 }
7720 }
7721 nemo_file_list_free (selection);
7722 }
7723
7724 static void
action_stop_volume_callback(GtkAction * action,gpointer data)7725 action_stop_volume_callback (GtkAction *action,
7726 gpointer data)
7727 {
7728 NemoFile *file;
7729 GList *selection, *l;
7730 NemoView *view;
7731
7732 view = NEMO_VIEW (data);
7733
7734 selection = nemo_view_get_selection (view);
7735 for (l = selection; l != NULL; l = l->next) {
7736 file = NEMO_FILE (l->data);
7737
7738 if (nemo_file_can_stop (file)) {
7739 GMountOperation *mount_op;
7740 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7741 nemo_file_stop (file, mount_op, NULL,
7742 file_stop_callback, NULL);
7743 g_object_unref (mount_op);
7744 }
7745 }
7746 nemo_file_list_free (selection);
7747 }
7748
7749 static void
action_detect_media_callback(GtkAction * action,gpointer data)7750 action_detect_media_callback (GtkAction *action,
7751 gpointer data)
7752 {
7753 NemoFile *file;
7754 GList *selection, *l;
7755 NemoView *view;
7756
7757 view = NEMO_VIEW (data);
7758
7759 selection = nemo_view_get_selection (view);
7760 for (l = selection; l != NULL; l = l->next) {
7761 file = NEMO_FILE (l->data);
7762
7763 if (nemo_file_can_poll_for_media (file) && !nemo_file_is_media_check_automatic (file)) {
7764 nemo_file_poll_for_media (file);
7765 }
7766 }
7767 nemo_file_list_free (selection);
7768 }
7769
7770 static void
action_self_mount_volume_callback(GtkAction * action,gpointer data)7771 action_self_mount_volume_callback (GtkAction *action,
7772 gpointer data)
7773 {
7774 NemoFile *file;
7775 NemoView *view;
7776 GMountOperation *mount_op;
7777
7778 view = NEMO_VIEW (data);
7779
7780 file = nemo_view_get_directory_as_file (view);
7781 if (file == NULL) {
7782 return;
7783 }
7784
7785 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7786 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
7787 nemo_file_mount (file, mount_op, NULL, file_mount_callback, NULL);
7788 g_object_unref (mount_op);
7789 }
7790
7791 static void
action_self_unmount_volume_callback(GtkAction * action,gpointer data)7792 action_self_unmount_volume_callback (GtkAction *action,
7793 gpointer data)
7794 {
7795 NemoFile *file;
7796 NemoView *view;
7797 GMountOperation *mount_op;
7798
7799 view = NEMO_VIEW (data);
7800
7801 file = nemo_view_get_directory_as_file (view);
7802 if (file == NULL) {
7803 return;
7804 }
7805
7806 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7807 nemo_file_unmount (file, mount_op, NULL, file_unmount_callback, g_object_ref (view));
7808 g_object_unref (mount_op);
7809 }
7810
7811 static void
action_self_eject_volume_callback(GtkAction * action,gpointer data)7812 action_self_eject_volume_callback (GtkAction *action,
7813 gpointer data)
7814 {
7815 NemoFile *file;
7816 NemoView *view;
7817 GMountOperation *mount_op;
7818
7819 view = NEMO_VIEW (data);
7820
7821 file = nemo_view_get_directory_as_file (view);
7822 if (file == NULL) {
7823 return;
7824 }
7825
7826 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7827 nemo_file_eject (file, mount_op, NULL, file_eject_callback, g_object_ref (view));
7828 g_object_unref (mount_op);
7829 }
7830
7831 static void
action_self_start_volume_callback(GtkAction * action,gpointer data)7832 action_self_start_volume_callback (GtkAction *action,
7833 gpointer data)
7834 {
7835 NemoFile *file;
7836 NemoView *view;
7837 GMountOperation *mount_op;
7838
7839 view = NEMO_VIEW (data);
7840
7841 file = nemo_view_get_directory_as_file (view);
7842 if (file == NULL) {
7843 return;
7844 }
7845
7846 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7847 nemo_file_start (file, mount_op, NULL, file_start_callback, NULL);
7848 g_object_unref (mount_op);
7849 }
7850
7851 static void
action_self_stop_volume_callback(GtkAction * action,gpointer data)7852 action_self_stop_volume_callback (GtkAction *action,
7853 gpointer data)
7854 {
7855 NemoFile *file;
7856 NemoView *view;
7857 GMountOperation *mount_op;
7858
7859 view = NEMO_VIEW (data);
7860
7861 file = nemo_view_get_directory_as_file (view);
7862 if (file == NULL) {
7863 return;
7864 }
7865
7866 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7867 nemo_file_stop (file, mount_op, NULL,
7868 file_stop_callback, NULL);
7869 g_object_unref (mount_op);
7870 }
7871
7872 static void
action_self_detect_media_callback(GtkAction * action,gpointer data)7873 action_self_detect_media_callback (GtkAction *action,
7874 gpointer data)
7875 {
7876 NemoFile *file;
7877 NemoView *view;
7878
7879 view = NEMO_VIEW (data);
7880
7881 file = nemo_view_get_directory_as_file (view);
7882 if (file == NULL) {
7883 return;
7884 }
7885
7886 nemo_file_poll_for_media (file);
7887 }
7888
7889 static void
action_location_mount_volume_callback(GtkAction * action,gpointer data)7890 action_location_mount_volume_callback (GtkAction *action,
7891 gpointer data)
7892 {
7893 NemoFile *file;
7894 NemoView *view;
7895 GMountOperation *mount_op;
7896
7897 view = NEMO_VIEW (data);
7898
7899 file = view->details->location_popup_directory_as_file;
7900 if (file == NULL) {
7901 return;
7902 }
7903
7904 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7905 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
7906 nemo_file_mount (file, mount_op, NULL, file_mount_callback, NULL);
7907 g_object_unref (mount_op);
7908 }
7909
7910 static void
action_location_unmount_volume_callback(GtkAction * action,gpointer data)7911 action_location_unmount_volume_callback (GtkAction *action,
7912 gpointer data)
7913 {
7914 NemoFile *file;
7915 NemoView *view;
7916 GMountOperation *mount_op;
7917
7918 view = NEMO_VIEW (data);
7919
7920 file = view->details->location_popup_directory_as_file;
7921 if (file == NULL) {
7922 return;
7923 }
7924
7925 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7926 nemo_file_unmount (file, mount_op, NULL,
7927 file_unmount_callback, g_object_ref (view));
7928 g_object_unref (mount_op);
7929 }
7930
7931 static void
action_location_eject_volume_callback(GtkAction * action,gpointer data)7932 action_location_eject_volume_callback (GtkAction *action,
7933 gpointer data)
7934 {
7935 NemoFile *file;
7936 NemoView *view;
7937 GMountOperation *mount_op;
7938
7939 view = NEMO_VIEW (data);
7940
7941 file = view->details->location_popup_directory_as_file;
7942 if (file == NULL) {
7943 return;
7944 }
7945
7946 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7947 nemo_file_eject (file, mount_op, NULL,
7948 file_eject_callback, g_object_ref (view));
7949 g_object_unref (mount_op);
7950 }
7951
7952 static void
action_location_start_volume_callback(GtkAction * action,gpointer data)7953 action_location_start_volume_callback (GtkAction *action,
7954 gpointer data)
7955 {
7956 NemoFile *file;
7957 NemoView *view;
7958 GMountOperation *mount_op;
7959
7960 view = NEMO_VIEW (data);
7961
7962 file = view->details->location_popup_directory_as_file;
7963 if (file == NULL) {
7964 return;
7965 }
7966
7967 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7968 nemo_file_start (file, mount_op, NULL, file_start_callback, NULL);
7969 g_object_unref (mount_op);
7970 }
7971
7972 static void
action_location_stop_volume_callback(GtkAction * action,gpointer data)7973 action_location_stop_volume_callback (GtkAction *action,
7974 gpointer data)
7975 {
7976 NemoFile *file;
7977 NemoView *view;
7978 GMountOperation *mount_op;
7979
7980 view = NEMO_VIEW (data);
7981
7982 file = view->details->location_popup_directory_as_file;
7983 if (file == NULL) {
7984 return;
7985 }
7986
7987 mount_op = gtk_mount_operation_new (nemo_view_get_containing_window (view));
7988 nemo_file_stop (file, mount_op, NULL,
7989 file_stop_callback, NULL);
7990 g_object_unref (mount_op);
7991 }
7992
7993 static void
action_location_detect_media_callback(GtkAction * action,gpointer data)7994 action_location_detect_media_callback (GtkAction *action,
7995 gpointer data)
7996 {
7997 NemoFile *file;
7998 NemoView *view;
7999
8000 view = NEMO_VIEW (data);
8001
8002 file = view->details->location_popup_directory_as_file;
8003 if (file == NULL) {
8004 return;
8005 }
8006
8007 nemo_file_poll_for_media (file);
8008 }
8009
8010 static void
connect_to_server_response_callback(GtkDialog * dialog,int response_id,gpointer data)8011 connect_to_server_response_callback (GtkDialog *dialog,
8012 int response_id,
8013 gpointer data)
8014 {
8015 #ifdef GIO_CONVERSION_DONE
8016 GtkEntry *entry;
8017 char *uri;
8018 const char *name;
8019 char *icon;
8020
8021 entry = GTK_ENTRY (data);
8022
8023 switch (response_id) {
8024 case GTK_RESPONSE_OK:
8025 uri = g_object_get_data (G_OBJECT (dialog), "link-uri");
8026 icon = g_object_get_data (G_OBJECT (dialog), "link-icon");
8027 name = gtk_entry_get_text (entry);
8028 gnome_vfs_connect_to_server (uri, (char *)name, icon);
8029 gtk_widget_destroy (GTK_WIDGET (dialog));
8030 break;
8031 case GTK_RESPONSE_NONE:
8032 case GTK_RESPONSE_DELETE_EVENT:
8033 case GTK_RESPONSE_CANCEL:
8034 gtk_widget_destroy (GTK_WIDGET (dialog));
8035 break;
8036 default :
8037 g_assert_not_reached ();
8038 }
8039 #endif
8040 /* FIXME: the above code should make a server connection permanent */
8041 gtk_widget_destroy (GTK_WIDGET (dialog));
8042 }
8043
8044 static void
entry_activate_callback(GtkEntry * entry,gpointer user_data)8045 entry_activate_callback (GtkEntry *entry,
8046 gpointer user_data)
8047 {
8048 GtkDialog *dialog;
8049
8050 dialog = GTK_DIALOG (user_data);
8051 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
8052 }
8053
8054 static void
action_connect_to_server_link_callback(GtkAction * action,gpointer data)8055 action_connect_to_server_link_callback (GtkAction *action,
8056 gpointer data)
8057 {
8058 NemoFile *file;
8059 GList *selection;
8060 NemoView *view;
8061 char *uri;
8062 NemoIconInfo *icon;
8063 const char *icon_name;
8064 char *name;
8065 GtkWidget *dialog;
8066 GtkWidget *label;
8067 GtkWidget *entry;
8068 GtkWidget *box;
8069 char *title;
8070
8071 view = NEMO_VIEW (data);
8072
8073 selection = nemo_view_get_selection (view);
8074
8075 if (g_list_length (selection) != 1) {
8076 nemo_file_list_free (selection);
8077 return;
8078 }
8079
8080 file = NEMO_FILE (selection->data);
8081
8082 uri = nemo_file_get_activation_uri (file);
8083 icon = nemo_file_get_icon (file, NEMO_ICON_SIZE_STANDARD, 0, gtk_widget_get_scale_factor (GTK_WIDGET (view)), 0);
8084 icon_name = nemo_icon_info_get_used_name (icon);
8085 name = nemo_file_get_display_name (file);
8086
8087 if (uri != NULL) {
8088 title = g_strdup_printf (_("Connect to Server %s"), name);
8089 dialog = gtk_dialog_new_with_buttons (title,
8090 nemo_view_get_containing_window (view),
8091 0,
8092 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
8093 _("_Connect"), GTK_RESPONSE_OK,
8094 NULL);
8095
8096 g_object_set_data_full (G_OBJECT (dialog), "link-uri", g_strdup (uri), g_free);
8097 g_object_set_data_full (G_OBJECT (dialog), "link-icon", g_strdup (icon_name), g_free);
8098
8099 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
8100 gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
8101
8102 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
8103 gtk_widget_show (box);
8104 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
8105 box, TRUE, TRUE, 0);
8106
8107 label = gtk_label_new_with_mnemonic (_("Link _name:"));
8108 gtk_widget_show (label);
8109
8110 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 12);
8111
8112 entry = gtk_entry_new ();
8113 if (name) {
8114 gtk_entry_set_text (GTK_ENTRY (entry), name);
8115 }
8116 g_signal_connect (entry,
8117 "activate",
8118 G_CALLBACK (entry_activate_callback),
8119 dialog);
8120
8121 gtk_widget_show (entry);
8122 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
8123
8124 gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 12);
8125
8126 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
8127 GTK_RESPONSE_OK);
8128 g_signal_connect (dialog, "response",
8129 G_CALLBACK (connect_to_server_response_callback),
8130 entry);
8131 gtk_widget_show (dialog);
8132 }
8133
8134 g_free (uri);
8135 nemo_icon_info_unref (icon);
8136 g_free (name);
8137 }
8138
8139 static void
action_location_open_alternate_callback(GtkAction * action,gpointer callback_data)8140 action_location_open_alternate_callback (GtkAction *action,
8141 gpointer callback_data)
8142 {
8143 NemoView *view;
8144 NemoFile *file;
8145
8146 view = NEMO_VIEW (callback_data);
8147
8148 file = view->details->location_popup_directory_as_file;
8149 if (file == NULL) {
8150 return;
8151 }
8152 nemo_view_activate_file (view,
8153 file,
8154 NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW);
8155 }
8156
8157 static void
action_location_open_in_new_tab_callback(GtkAction * action,gpointer callback_data)8158 action_location_open_in_new_tab_callback (GtkAction *action,
8159 gpointer callback_data)
8160 {
8161 NemoView *view;
8162 NemoFile *file;
8163
8164 view = NEMO_VIEW (callback_data);
8165
8166 file = view->details->location_popup_directory_as_file;
8167 if (file == NULL) {
8168 return;
8169 }
8170
8171 nemo_view_activate_file (view,
8172 file,
8173 NEMO_WINDOW_OPEN_FLAG_NEW_TAB);
8174 }
8175
8176 static void
action_location_cut_callback(GtkAction * action,gpointer callback_data)8177 action_location_cut_callback (GtkAction *action,
8178 gpointer callback_data)
8179 {
8180 NemoView *view;
8181 NemoFile *file;
8182 GList *files;
8183
8184 view = NEMO_VIEW (callback_data);
8185
8186 file = view->details->location_popup_directory_as_file;
8187 g_return_if_fail (file != NULL);
8188
8189 files = g_list_append (NULL, file);
8190 copy_or_cut_files (view, files, TRUE);
8191 g_list_free (files);
8192 }
8193
8194 static void
action_location_copy_callback(GtkAction * action,gpointer callback_data)8195 action_location_copy_callback (GtkAction *action,
8196 gpointer callback_data)
8197 {
8198 NemoView *view;
8199 NemoFile *file;
8200 GList *files;
8201
8202 view = NEMO_VIEW (callback_data);
8203
8204 file = view->details->location_popup_directory_as_file;
8205 g_return_if_fail (file != NULL);
8206
8207 files = g_list_append (NULL, file);
8208 copy_or_cut_files (view, files, FALSE);
8209 g_list_free (files);
8210 }
8211
8212 static void
action_location_paste_files_into_callback(GtkAction * action,gpointer callback_data)8213 action_location_paste_files_into_callback (GtkAction *action,
8214 gpointer callback_data)
8215 {
8216 NemoView *view;
8217 NemoFile *file;
8218
8219 view = NEMO_VIEW (callback_data);
8220
8221 file = view->details->location_popup_directory_as_file;
8222 g_return_if_fail (file != NULL);
8223
8224 paste_into (view, file);
8225 }
8226
8227 static void
action_location_trash_callback(GtkAction * action,gpointer callback_data)8228 action_location_trash_callback (GtkAction *action,
8229 gpointer callback_data)
8230 {
8231 NemoView *view;
8232 NemoFile *file;
8233 GList *files;
8234
8235 view = NEMO_VIEW (callback_data);
8236
8237 file = view->details->location_popup_directory_as_file;
8238 g_return_if_fail (file != NULL);
8239
8240 files = g_list_append (NULL, file);
8241 trash_or_delete_files (nemo_view_get_containing_window (view),
8242 files, TRUE,
8243 view);
8244 g_list_free (files);
8245 }
8246
8247 static void
action_location_delete_callback(GtkAction * action,gpointer callback_data)8248 action_location_delete_callback (GtkAction *action,
8249 gpointer callback_data)
8250 {
8251 NemoView *view;
8252 NemoFile *file;
8253 GFile *location;
8254 GList *files;
8255
8256 view = NEMO_VIEW (callback_data);
8257
8258 file = view->details->location_popup_directory_as_file;
8259 g_return_if_fail (file != NULL);
8260
8261 location = nemo_file_get_location (file);
8262
8263 files = g_list_append (NULL, location);
8264 nemo_file_operations_delete (files, nemo_view_get_containing_window (view),
8265 NULL, NULL);
8266
8267 g_list_free_full (files, g_object_unref);
8268 }
8269
8270 static void
action_location_restore_from_trash_callback(GtkAction * action,gpointer callback_data)8271 action_location_restore_from_trash_callback (GtkAction *action,
8272 gpointer callback_data)
8273 {
8274 NemoView *view;
8275 NemoFile *file;
8276 GList l;
8277
8278 view = NEMO_VIEW (callback_data);
8279 file = view->details->location_popup_directory_as_file;
8280
8281 l.prev = NULL;
8282 l.next = NULL;
8283 l.data = file;
8284 nemo_restore_files_from_trash (&l,
8285 nemo_view_get_containing_window (view));
8286 }
8287
8288 static void
nemo_view_init_show_hidden_files(NemoView * view)8289 nemo_view_init_show_hidden_files (NemoView *view)
8290 {
8291 NemoWindowShowHiddenFilesMode mode;
8292 gboolean show_hidden_changed;
8293
8294 if (view->details->ignore_hidden_file_preferences) {
8295 return;
8296 }
8297
8298 mode = nemo_window_get_hidden_files_mode (view->details->window);
8299
8300 if (mode == NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE) {
8301 show_hidden_changed = !view->details->show_hidden_files;
8302 view->details->show_hidden_files = TRUE;
8303 } else {
8304 show_hidden_changed = view->details->show_hidden_files;
8305 view->details->show_hidden_files = FALSE;
8306 }
8307
8308 if (show_hidden_changed && (view->details->model != NULL)) {
8309 load_directory (view, view->details->model);
8310 }
8311 }
8312
8313 static const GtkActionEntry directory_view_entries[] = {
8314 /* name, stock id, label */ { "New Documents", "document-new-symbolic", N_("Create New _Document") },
8315 /* name, stock id, label */ { "Open With", NULL, N_("Open Wit_h"),
8316 NULL, N_("Choose a program with which to open the selected item") },
8317 /* name, stock id */ { "Properties", "document-properties-symbolic",
8318 /* label, accelerator */ N_("_Properties"), "<alt>Return",
8319 /* tooltip */ N_("View or modify the properties of each selected item"),
8320 G_CALLBACK (action_properties_callback) },
8321 /* name, stock id */ { "PropertiesAccel", NULL,
8322 /* label, accelerator */ "PropertiesAccel", "<control>I",
8323 /* tooltip */ NULL,
8324 G_CALLBACK (action_properties_callback) },
8325 /* name, stock id */ { "New Folder", "folder-new-symbolic",
8326 /* label, accelerator */ N_("Create New _Folder"), "<control><shift>N",
8327 /* tooltip */ N_("Create a new empty folder inside this folder"),
8328 G_CALLBACK (action_new_folder_callback) },
8329 /* name, stock id, label */ { "No Templates", NULL, N_("No templates installed") },
8330 /* name, stock id */ { "New Empty Document", NULL,
8331 /* translators: this is used to indicate that a document doesn't contain anything */
8332 /* label, accelerator */ N_("_Empty Document"), NULL,
8333 /* tooltip */ N_("Create a new empty document inside this folder"),
8334 G_CALLBACK (action_new_empty_file_callback) },
8335 /* name, stock id */ { "Open", NULL,
8336 /* label, accelerator */ N_("_Open"), "<control>o",
8337 /* tooltip */ N_("Open the selected item in this window"),
8338 G_CALLBACK (action_open_callback) },
8339 /* name, stock id */ { "OpenAccel", NULL,
8340 /* label, accelerator */ "OpenAccel", "<alt>Down",
8341 /* tooltip */ NULL,
8342 G_CALLBACK (action_open_callback) },
8343 /* name, stock id */ { "OpenAlternate", NULL,
8344 /* label, accelerator */ N_("Open in Navigation Window"), "<control><shift>o",
8345 /* tooltip */ N_("Open each selected item in a navigation window"),
8346 G_CALLBACK (action_open_alternate_callback) },
8347 /* name, stock id */ { "OpenInNewTab", NULL,
8348 /* label, accelerator */ N_("Open in New _Tab"), "<control><shift>t",
8349 /* tooltip */ N_("Open each selected item in a new tab"),
8350 G_CALLBACK (action_open_new_tab_callback) },
8351 /* name, stock id */ { NEMO_ACTION_OPEN_IN_TERMINAL, "utilities-terminal-symbolic",
8352 /* label, accelerator */ N_("Open in Terminal"), "",
8353 /* tooltip */ N_("Open terminal in the selected folder"),
8354 G_CALLBACK (action_open_in_terminal_callback) },
8355 /* name, stock id */ { NEMO_ACTION_OPEN_AS_ROOT, "dialog-password-symbolic",
8356 /* label, accelerator */ N_("Open as Root"), "",
8357 /* tooltip */ N_("Open the folder with administration privileges"),
8358 G_CALLBACK (action_open_as_root_callback) },
8359
8360 /* name, stock id */ { NEMO_ACTION_FOLLOW_SYMLINK, "go-jump-symbolic",
8361 /* label, accelerator */ N_("Follow link to original file"), "",
8362 /* tooltip */ N_("Navigate to the original file that this symbolic link points to"),
8363 G_CALLBACK (action_follow_symlink_callback) },
8364 /* name, stock id */ { NEMO_ACTION_OPEN_CONTAINING_FOLDER, "go-jump-symbolic",
8365 /* label, accelerator */ N_("Open containing folder"), "<control><alt>O",
8366 /* tooltip */ N_("Navigate to the folder that the selected item is stored in"),
8367 G_CALLBACK (action_open_containing_folder_callback) },
8368 /* name, stock id */ { "OtherApplication1", NULL,
8369 /* label, accelerator */ N_("Other _Application..."), NULL,
8370 /* tooltip */ N_("Choose another application with which to open the selected item"),
8371 G_CALLBACK (action_other_application_callback) },
8372 /* name, stock id */ { "OtherApplication2", NULL,
8373 /* label, accelerator */ N_("Open With Other _Application..."), NULL,
8374 /* tooltip */ N_("Choose another application with which to open the selected item"),
8375 G_CALLBACK (action_other_application_callback) },
8376 /* name, stock id */ { "Empty Trash", NULL,
8377 /* label, accelerator */ N_("E_mpty Trash"), NULL,
8378 /* tooltip */ N_("Delete all items in the Trash"),
8379 G_CALLBACK (action_empty_trash_callback) },
8380 /* name, stock id */ { "Cut", "edit-cut-symbolic",
8381 /* label, accelerator */ N_("Cu_t"), "<control>X",
8382 /* tooltip */ N_("Prepare the selected files to be moved with a Paste command"),
8383 G_CALLBACK (action_cut_files_callback) },
8384 /* name, stock id */ { "Copy", "edit-copy-symbolic",
8385 /* label, accelerator */ N_("_Copy"), "<control>C",
8386 /* tooltip */ N_("Prepare the selected files to be copied with a Paste command"),
8387 G_CALLBACK (action_copy_files_callback) },
8388 /* name, stock id */ { "Paste", "edit-paste-symbolic",
8389 /* label, accelerator */ N_("_Paste"), "<control>V",
8390 /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command"),
8391 G_CALLBACK (action_paste_files_callback) },
8392 /* We make accelerator "" instead of null here to not inherit the stock
8393 accelerator for paste */
8394 /* name, stock id */ { "Paste Files Into", "edit-paste-symbolic",
8395 /* label, accelerator */ N_("_Paste Into Folder"), "",
8396 /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command into the selected folder"),
8397 G_CALLBACK (action_paste_files_into_callback) },
8398 /* name, stock id, label */ { "CopyToMenu", NULL, N_("Cop_y to") },
8399 /* name, stock id, label */ { "MoveToMenu", NULL, N_("M_ove to") },
8400 /* name, stock id */ { "Select All", NULL,
8401 /* label, accelerator */ N_("Select _All"), "<control>A",
8402 /* tooltip */ N_("Select all items in this window"),
8403 G_CALLBACK (action_select_all_callback) },
8404 /* name, stock id */ { "Select Pattern", NULL,
8405 /* label, accelerator */ N_("Select I_tems Matching..."), "<control>S",
8406 /* tooltip */ N_("Select items in this window matching a given pattern"),
8407 G_CALLBACK (action_select_pattern_callback) },
8408 /* name, stock id */ { "Invert Selection", NULL,
8409 /* label, accelerator */ N_("_Invert Selection"), "<control><shift>I",
8410 /* tooltip */ N_("Select all and only the items that are not currently selected"),
8411 G_CALLBACK (action_invert_selection_callback) },
8412 /* name, stock id */ { "Duplicate", NULL,
8413 /* label, accelerator */ N_("D_uplicate"), NULL,
8414 /* tooltip */ N_("Duplicate each selected item"),
8415 G_CALLBACK (action_duplicate_callback) },
8416 /* name, stock id */ { "Create Link", NULL,
8417 /* label, accelerator */ N_("Ma_ke Link"), "<control>M",
8418 /* tooltip */ N_("Create a symbolic link for each selected item"),
8419 G_CALLBACK (action_create_link_callback) },
8420 /* name, stock id */ { "Rename", NULL,
8421 /* label, accelerator */ N_("_Rename..."), "F2",
8422 /* tooltip */ N_("Rename selected item"),
8423 G_CALLBACK (action_rename_callback) },
8424 /* name, stock id */ { "RenameSelectAll", NULL,
8425 /* label, accelerator */ "RenameSelectAll", "<shift>F2",
8426 /* tooltip */ NULL,
8427 G_CALLBACK (action_rename_select_all_callback) },
8428 /* name, stock id */ { "Trash", NULL,
8429 /* label, accelerator */ N_("Mo_ve to Trash"), NULL,
8430 /* tooltip */ N_("Move each selected item to the Trash"),
8431 G_CALLBACK (action_trash_callback) },
8432 /* name, stock id */ { "Delete", NULL,
8433 /* label, accelerator */ N_("_Delete"), NULL,
8434 /* tooltip */ N_("Delete each selected item, without moving to the Trash"),
8435 G_CALLBACK (action_delete_callback) },
8436 /* name, stock id */ { "Restore From Trash", NULL,
8437 /* label, accelerator */ N_("_Restore"), NULL,
8438 NULL,
8439 G_CALLBACK (action_restore_from_trash_callback) },
8440 /* name, stock id */ { "Undo", "edit-undo-symbolic",
8441 /* label, accelerator */ N_("_Undo"), "<control>Z",
8442 /* tooltip */ N_("Undo the last action"),
8443 G_CALLBACK (action_undo_callback) },
8444 /* name, stock id */ { "Redo", "edit-redo-symbolic",
8445 /* label, accelerator */ N_("_Redo"), "<control>Y",
8446 /* tooltip */ N_("Redo the last undone action"),
8447 G_CALLBACK (action_redo_callback) },
8448 /*
8449 * multiview-TODO: decide whether "Reset to Defaults" should
8450 * be window-wide, and not just view-wide.
8451 * Since this also resets the "Show hidden files" mode,
8452 * it is a mixture of both ATM.
8453 */
8454 /* name, stock id */ { "Reset to Defaults", NULL,
8455 /* label, accelerator */ N_("Reset View to _Defaults"), NULL,
8456 /* tooltip */ N_("Reset sorting order and zoom level to match preferences for this view"),
8457 G_CALLBACK (action_reset_to_defaults_callback) },
8458 /* name, stock id */ { "Connect To Server Link", NULL,
8459 /* label, accelerator */ N_("Connect To This Server"), NULL,
8460 /* tooltip */ N_("Make a permanent connection to this server"),
8461 G_CALLBACK (action_connect_to_server_link_callback) },
8462 /* name, stock id */ { "Mount Volume", "media-mount-symbolic",
8463 /* label, accelerator */ N_("_Mount"), NULL,
8464 /* tooltip */ N_("Mount the selected volume"),
8465 G_CALLBACK (action_mount_volume_callback) },
8466 /* name, stock id */ { "Unmount Volume", "media-eject-symbolic",
8467 /* label, accelerator */ N_("_Unmount"), NULL,
8468 /* tooltip */ N_("Unmount the selected volume"),
8469 G_CALLBACK (action_unmount_volume_callback) },
8470 /* name, stock id */ { "Eject Volume", "media-eject-symbolic",
8471 /* label, accelerator */ N_("_Eject"), NULL,
8472 /* tooltip */ N_("Eject the selected volume"),
8473 G_CALLBACK (action_eject_volume_callback) },
8474 /* name, stock id */ { "Start Volume", NULL,
8475 /* label, accelerator */ N_("_Start"), NULL,
8476 /* tooltip */ N_("Start the selected volume"),
8477 G_CALLBACK (action_start_volume_callback) },
8478 /* name, stock id */ { "Stop Volume", NULL,
8479 /* label, accelerator */ N_("_Stop"), NULL,
8480 /* tooltip */ N_("Stop the selected volume"),
8481 G_CALLBACK (action_stop_volume_callback) },
8482 /* name, stock id */ { "Poll", NULL,
8483 /* label, accelerator */ N_("_Detect Media"), NULL,
8484 /* tooltip */ N_("Detect media in the selected drive"),
8485 G_CALLBACK (action_detect_media_callback) },
8486 /* name, stock id */ { "Self Mount Volume", "media-mount-symbolic",
8487 /* label, accelerator */ N_("_Mount"), NULL,
8488 /* tooltip */ N_("Mount the volume associated with the open folder"),
8489 G_CALLBACK (action_self_mount_volume_callback) },
8490 /* name, stock id */ { "Self Unmount Volume", "media-eject-symbolic",
8491 /* label, accelerator */ N_("_Unmount"), NULL,
8492 /* tooltip */ N_("Unmount the volume associated with the open folder"),
8493 G_CALLBACK (action_self_unmount_volume_callback) },
8494 /* name, stock id */ { "Self Eject Volume", "media-eject-symbolic",
8495 /* label, accelerator */ N_("_Eject"), NULL,
8496 /* tooltip */ N_("Eject the volume associated with the open folder"),
8497 G_CALLBACK (action_self_eject_volume_callback) },
8498 /* name, stock id */ { "Self Start Volume", NULL,
8499 /* label, accelerator */ N_("_Start"), NULL,
8500 /* tooltip */ N_("Start the volume associated with the open folder"),
8501 G_CALLBACK (action_self_start_volume_callback) },
8502 /* name, stock id */ { "Self Stop Volume", NULL,
8503 /* label, accelerator */ N_("_Stop"), NULL,
8504 /* tooltip */ N_("Stop the volume associated with the open folder"),
8505 G_CALLBACK (action_self_stop_volume_callback) },
8506 /* name, stock id */ { "Self Poll", NULL,
8507 /* label, accelerator */ N_("_Detect Media"), NULL,
8508 /* tooltip */ N_("Detect media in the selected drive"),
8509 G_CALLBACK (action_self_detect_media_callback) },
8510 /* name, stock id */ { "OpenCloseParent", NULL,
8511 /* label, accelerator */ N_("Open File and Close window"), "<alt><shift>Down",
8512 /* tooltip */ NULL,
8513 G_CALLBACK (action_open_close_parent_callback) },
8514 /* name, stock id */ { "Save Search", NULL,
8515 /* label, accelerator */ N_("Sa_ve Search"), NULL,
8516 /* tooltip */ N_("Save the edited search"),
8517 G_CALLBACK (action_save_search_callback) },
8518 /* name, stock id */ { "Save Search As", NULL,
8519 /* label, accelerator */ N_("Sa_ve Search As..."), NULL,
8520 /* tooltip */ N_("Save the current search as a file"),
8521 G_CALLBACK (action_save_search_as_callback) },
8522
8523 /* Location-specific actions */
8524 /* name, stock id */ { NEMO_ACTION_LOCATION_OPEN_ALTERNATE, NULL,
8525 /* label, accelerator */ N_("Open in Navigation Window"), "",
8526 /* tooltip */ N_("Open this folder in a navigation window"),
8527 G_CALLBACK (action_location_open_alternate_callback) },
8528 /* name, stock id */ { NEMO_ACTION_LOCATION_OPEN_IN_NEW_TAB, NULL,
8529 /* label, accelerator */ N_("Open in New _Tab"), "",
8530 /* tooltip */ N_("Open this folder in a new tab"),
8531 G_CALLBACK (action_location_open_in_new_tab_callback) },
8532
8533 /* name, stock id */ { NEMO_ACTION_LOCATION_CUT, "edit-cut-symbolic",
8534 /* label, accelerator */ N_("Cu_t"), "",
8535 /* tooltip */ N_("Prepare this folder to be moved with a Paste command"),
8536 G_CALLBACK (action_location_cut_callback) },
8537 /* name, stock id */ { NEMO_ACTION_LOCATION_COPY, "edit-copy-symbolic",
8538 /* label, accelerator */ N_("_Copy"), "",
8539 /* tooltip */ N_("Prepare this folder to be copied with a Paste command"),
8540 G_CALLBACK (action_location_copy_callback) },
8541 /* name, stock id */ { NEMO_ACTION_LOCATION_PASTE_FILES_INTO, "edit-paste-symbolic",
8542 /* label, accelerator */ N_("_Paste Into Folder"), "",
8543 /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command into this folder"),
8544 G_CALLBACK (action_location_paste_files_into_callback) },
8545
8546 /* name, stock id */ { NEMO_ACTION_LOCATION_TRASH, NULL,
8547 /* label, accelerator */ N_("Mo_ve to Trash"), "",
8548 /* tooltip */ N_("Move this folder to the Trash"),
8549 G_CALLBACK (action_location_trash_callback) },
8550 /* name, stock id */ { NEMO_ACTION_LOCATION_DELETE, NEMO_ICON_DELETE,
8551 /* label, accelerator */ N_("_Delete"), "",
8552 /* tooltip */ N_("Delete this folder, without moving to the Trash"),
8553 G_CALLBACK (action_location_delete_callback) },
8554 /* name, stock id */ { NEMO_ACTION_LOCATION_RESTORE_FROM_TRASH, NULL,
8555 /* label, accelerator */ N_("_Restore"), NULL, NULL,
8556 G_CALLBACK (action_location_restore_from_trash_callback) },
8557
8558 /* name, stock id */ { "Location Mount Volume", "media-mount-symbolic",
8559 /* label, accelerator */ N_("_Mount"), NULL,
8560 /* tooltip */ N_("Mount the volume associated with this folder"),
8561 G_CALLBACK (action_location_mount_volume_callback) },
8562 /* name, stock id */ { "Location Unmount Volume", "media-eject-symbolic",
8563 /* label, accelerator */ N_("_Unmount"), NULL,
8564 /* tooltip */ N_("Unmount the volume associated with this folder"),
8565 G_CALLBACK (action_location_unmount_volume_callback) },
8566 /* name, stock id */ { "Location Eject Volume", "media-eject-symbolic",
8567 /* label, accelerator */ N_("_Eject"), NULL,
8568 /* tooltip */ N_("Eject the volume associated with this folder"),
8569 G_CALLBACK (action_location_eject_volume_callback) },
8570 /* name, stock id */ { "Location Start Volume", NULL,
8571 /* label, accelerator */ N_("_Start"), NULL,
8572 /* tooltip */ N_("Start the volume associated with this folder"),
8573 G_CALLBACK (action_location_start_volume_callback) },
8574 /* name, stock id */ { "Location Stop Volume", NULL,
8575 /* label, accelerator */ N_("_Stop"), NULL,
8576 /* tooltip */ N_("Stop the volume associated with this folder"),
8577 G_CALLBACK (action_location_stop_volume_callback) },
8578 /* name, stock id */ { "Location Poll", NULL,
8579 /* label, accelerator */ N_("_Detect Media"), NULL,
8580 /* tooltip */ N_("Detect media in the selected drive"),
8581 G_CALLBACK (action_location_detect_media_callback) },
8582
8583 /* name, stock id */ { "LocationProperties", "document-properties-symbolic",
8584 /* label, accelerator */ N_("_Properties"), NULL,
8585 /* tooltip */ N_("View or modify the properties of this folder"),
8586 G_CALLBACK (action_location_properties_callback) },
8587
8588 /* name, stock id, label */ {NEMO_ACTION_COPY_TO_NEXT_PANE, NULL, N_("_Other pane"),
8589 NULL, N_("Copy the current selection to the other pane in the window"),
8590 G_CALLBACK (action_copy_to_next_pane_callback) },
8591 /* name, stock id, label */ {NEMO_ACTION_MOVE_TO_NEXT_PANE, NULL, N_("_Other pane"),
8592 NULL, N_("Move the current selection to the other pane in the window"),
8593 G_CALLBACK (action_move_to_next_pane_callback) },
8594 /* name, stock id, label */ {NEMO_ACTION_COPY_TO_HOME, NULL,
8595 N_("_Home"), NULL,
8596 N_("Copy the current selection to the home folder"),
8597 G_CALLBACK (action_copy_to_home_callback) },
8598 /* name, stock id, label */ {NEMO_ACTION_MOVE_TO_HOME, NULL,
8599 N_("_Home"), NULL,
8600 N_("Move the current selection to the home folder"),
8601 G_CALLBACK (action_move_to_home_callback) },
8602 /* name, stock id, label */ {NEMO_ACTION_COPY_TO_DESKTOP, NULL,
8603 N_("_Desktop"), NULL,
8604 N_("Copy the current selection to the desktop"),
8605 G_CALLBACK (action_copy_to_desktop_callback) },
8606 /* name, stock id, label */ {NEMO_ACTION_MOVE_TO_DESKTOP, NULL,
8607 N_("_Desktop"), NULL,
8608 N_("Move the current selection to the desktop"),
8609 G_CALLBACK (action_move_to_desktop_callback) },
8610 {NEMO_ACTION_BROWSE_MOVE_TO, "document-open-symbolic",
8611 N_("Browse..."), NULL,
8612 N_("Browse for a folder to move the selection to"),
8613 G_CALLBACK (action_browse_for_move_to_folder_callback) },
8614 {NEMO_ACTION_BROWSE_COPY_TO, "document-open-symbolic",
8615 N_("Browse..."), NULL,
8616 N_("Browse for a folder to copy the selection to"),
8617 G_CALLBACK (action_browse_for_copy_to_folder_callback) },
8618 {NEMO_ACTION_PIN_FILE, "xapp-pin-symbolic",
8619 N_("P_in"), "<control><shift>D",
8620 N_("Pin the selected file so it always appears at the top of this location's file list"),
8621 G_CALLBACK (action_pin_unpin_file_callback) },
8622 {NEMO_ACTION_UNPIN_FILE, "xapp-unpin-symbolic",
8623 N_("Unp_in"), "<control><shift>D",
8624 N_("Unpin the selected file from the top of this location's file list"),
8625 G_CALLBACK (action_pin_unpin_file_callback) },
8626 {NEMO_ACTION_FAVORITE_FILE, "xapp-favorite-symbolic",
8627 N_("Add to favorites"), NULL,
8628 N_("Add the selected file to your favorites"),
8629 G_CALLBACK (action_favorite_unfavorite_file_callback) },
8630 {NEMO_ACTION_UNFAVORITE_FILE, "xapp-unfavorite-symbolic",
8631 N_("Remove from favorites"), NULL,
8632 N_("Remove the selected file from your favorites"),
8633 G_CALLBACK (action_favorite_unfavorite_file_callback) }
8634 };
8635
8636 static void
connect_proxy(NemoView * view,GtkAction * action,GtkWidget * proxy,GtkActionGroup * action_group)8637 connect_proxy (NemoView *view,
8638 GtkAction *action,
8639 GtkWidget *proxy,
8640 GtkActionGroup *action_group)
8641 {
8642 if (strcmp (gtk_action_get_name (action), NEMO_ACTION_NEW_EMPTY_DOCUMENT) == 0 &&
8643 GTK_IS_IMAGE_MENU_ITEM (proxy)) {
8644
8645 GtkWidget *image;
8646
8647 image = gtk_image_new_from_icon_name ("text-x-generic", GTK_ICON_SIZE_MENU);
8648 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy), image);
8649 gtk_action_set_always_show_image (action, TRUE);
8650 }
8651 }
8652
8653 static void
pre_activate(NemoView * view,GtkAction * action,GtkActionGroup * action_group)8654 pre_activate (NemoView *view,
8655 GtkAction *action,
8656 GtkActionGroup *action_group)
8657 {
8658 GdkEvent *event;
8659 GtkWidget *proxy;
8660 gboolean activated_from_popup;
8661
8662 /* check whether action was activated through a popup menu.
8663 * If not, unset the last stored context menu popup position */
8664 activated_from_popup = FALSE;
8665
8666 event = gtk_get_current_event ();
8667 proxy = gtk_get_event_widget (event);
8668
8669 if (proxy != NULL) {
8670 GtkWidget *toplevel;
8671 GdkWindowTypeHint hint;
8672
8673 toplevel = gtk_widget_get_toplevel (proxy);
8674
8675 if (GTK_IS_WINDOW (toplevel)) {
8676 hint = gtk_window_get_type_hint (GTK_WINDOW (toplevel));
8677
8678 if (hint == GDK_WINDOW_TYPE_HINT_POPUP_MENU) {
8679 activated_from_popup = TRUE;
8680 }
8681 }
8682 }
8683
8684 if (!activated_from_popup) {
8685 update_context_menu_position_from_event (view, NULL);
8686 }
8687 }
8688
8689 static void
real_merge_menus(NemoView * view)8690 real_merge_menus (NemoView *view)
8691 {
8692 GtkActionGroup *action_group;
8693 GtkUIManager *ui_manager;
8694 GtkAction *action;
8695 char *tooltip;
8696
8697 ui_manager = nemo_window_get_ui_manager (view->details->window);
8698
8699 action_group = gtk_action_group_new ("DirViewActions");
8700 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
8701 view->details->dir_action_group = action_group;
8702
8703 gtk_action_group_add_actions (action_group,
8704 directory_view_entries, G_N_ELEMENTS (directory_view_entries),
8705 view);
8706
8707 tooltip = g_strdup_printf (_("Run scripts"));
8708 /* Create a script action here specially because its tooltip is dynamic */
8709 action = gtk_action_new ("Scripts", _("_Scripts"), tooltip, NULL);
8710 gtk_action_group_add_action (action_group, action);
8711 g_object_unref (action);
8712 g_free (tooltip);
8713
8714 action = gtk_action_group_get_action (action_group, NEMO_ACTION_NO_TEMPLATES);
8715 gtk_action_set_sensitive (action, FALSE);
8716
8717 g_signal_connect_object (action_group, "connect-proxy",
8718 G_CALLBACK (connect_proxy), G_OBJECT (view),
8719 G_CONNECT_SWAPPED);
8720 g_signal_connect_object (action_group, "pre-activate",
8721 G_CALLBACK (pre_activate), G_OBJECT (view),
8722 G_CONNECT_SWAPPED);
8723
8724 /* Insert action group at end so clipboard action group ends up before it */
8725 gtk_ui_manager_insert_action_group (ui_manager, action_group, -1);
8726 g_object_unref (action_group); /* owned by ui manager */
8727
8728 view->details->dir_merge_id = gtk_ui_manager_add_ui_from_resource (ui_manager, "/org/nemo/nemo-directory-view-ui.xml", NULL);
8729
8730 view->details->scripts_invalid = TRUE;
8731 view->details->templates_invalid = TRUE;
8732 view->details->actions_invalid = TRUE;
8733 }
8734
8735 static gboolean
can_paste_into_file(NemoFile * file)8736 can_paste_into_file (NemoFile *file)
8737 {
8738 if (nemo_file_is_directory (file) &&
8739 nemo_file_can_write (file)) {
8740 return TRUE;
8741 }
8742 if (nemo_file_has_activation_uri (file)) {
8743 GFile *location;
8744 NemoFile *activation_file;
8745 gboolean res;
8746
8747 location = nemo_file_get_activation_location (file);
8748 activation_file = nemo_file_get (location);
8749 g_object_unref (location);
8750
8751 /* The target location might not have data for it read yet,
8752 and we can't want to do sync I/O, so treat the unknown
8753 case as can-write */
8754 res = (nemo_file_get_file_type (activation_file) == G_FILE_TYPE_UNKNOWN) ||
8755 (nemo_file_get_file_type (activation_file) == G_FILE_TYPE_DIRECTORY &&
8756 nemo_file_can_write (activation_file));
8757
8758 nemo_file_unref (activation_file);
8759
8760 return res;
8761 }
8762
8763 return FALSE;
8764 }
8765
8766 static void
clipboard_targets_received(GtkClipboard * clipboard,GdkAtom * targets,int n_targets,gpointer user_data)8767 clipboard_targets_received (GtkClipboard *clipboard,
8768 GdkAtom *targets,
8769 int n_targets,
8770 gpointer user_data)
8771 {
8772 NemoView *view;
8773 gboolean can_paste;
8774 int i;
8775 GList *selection;
8776 int count;
8777 GtkAction *action;
8778
8779 view = NEMO_VIEW (user_data);
8780 can_paste = FALSE;
8781
8782 if (view->details->window == NULL ||
8783 !view->details->active) {
8784 /* We've been destroyed or became inactive since call */
8785 g_object_unref (view);
8786 return;
8787 }
8788
8789 if (targets) {
8790 for (i=0; i < n_targets; i++) {
8791 if (targets[i] == copied_files_atom) {
8792 can_paste = TRUE;
8793 }
8794 }
8795 }
8796
8797
8798 selection = nemo_view_get_selection (view);
8799 count = g_list_length (selection);
8800
8801 action = gtk_action_group_get_action (view->details->dir_action_group,
8802 NEMO_ACTION_PASTE);
8803 gtk_action_set_sensitive (action,
8804 can_paste && !nemo_view_is_read_only (view));
8805
8806 action = gtk_action_group_get_action (view->details->dir_action_group,
8807 NEMO_ACTION_PASTE_FILES_INTO);
8808 gtk_action_set_sensitive (action,
8809 can_paste && count == 1 &&
8810 can_paste_into_file (NEMO_FILE (selection->data)));
8811
8812 action = gtk_action_group_get_action (view->details->dir_action_group,
8813 NEMO_ACTION_LOCATION_PASTE_FILES_INTO);
8814 g_object_set_data (G_OBJECT (action),
8815 "can-paste-according-to-clipboard",
8816 GINT_TO_POINTER (can_paste));
8817 gtk_action_set_sensitive (action,
8818 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action),
8819 "can-paste-according-to-clipboard")) &&
8820 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action),
8821 "can-paste-according-to-destination")));
8822
8823 nemo_file_list_free (selection);
8824
8825 g_object_unref (view);
8826 }
8827
8828 static gboolean
should_show_empty_trash(NemoView * view)8829 should_show_empty_trash (NemoView *view)
8830 {
8831 return (showing_trash_directory (view));
8832 }
8833
8834 static gboolean
file_list_all_are_folders(GList * file_list)8835 file_list_all_are_folders (GList *file_list)
8836 {
8837 GList *l;
8838 NemoFile *file, *linked_file;
8839 char *activation_uri;
8840 gboolean is_dir;
8841
8842 for (l = file_list; l != NULL; l = l->next) {
8843 file = NEMO_FILE (l->data);
8844 if (nemo_file_is_nemo_link (file) &&
8845 !NEMO_IS_DESKTOP_ICON_FILE (file)) {
8846 if (nemo_file_is_launcher (file)) {
8847 return FALSE;
8848 }
8849
8850 activation_uri = nemo_file_get_activation_uri (file);
8851
8852 if (activation_uri == NULL) {
8853 g_free (activation_uri);
8854 return FALSE;
8855 }
8856
8857 linked_file = nemo_file_get_existing_by_uri (activation_uri);
8858
8859 /* We might not actually know the type of the linked file yet,
8860 * however we don't want to schedule a read, since that might do things
8861 * like ask for password etc. This is a bit unfortunate, but I don't
8862 * know any way around it, so we do various heuristics here
8863 * to get things mostly right
8864 */
8865 is_dir =
8866 (linked_file != NULL &&
8867 nemo_file_is_directory (linked_file)) ||
8868 (activation_uri != NULL &&
8869 activation_uri[strlen (activation_uri) - 1] == '/');
8870
8871 nemo_file_unref (linked_file);
8872 g_free (activation_uri);
8873
8874 if (!is_dir) {
8875 return FALSE;
8876 }
8877 } else if (!(nemo_file_is_directory (file) ||
8878 NEMO_IS_DESKTOP_ICON_FILE (file))) {
8879 return FALSE;
8880 }
8881 }
8882 return TRUE;
8883 }
8884
8885 static void
file_should_show_foreach(NemoFile * file,gboolean * show_mount,gboolean * show_unmount,gboolean * show_eject,gboolean * show_connect,gboolean * show_start,gboolean * show_stop,gboolean * show_poll,GDriveStartStopType * start_stop_type)8886 file_should_show_foreach (NemoFile *file,
8887 gboolean *show_mount,
8888 gboolean *show_unmount,
8889 gboolean *show_eject,
8890 gboolean *show_connect,
8891 gboolean *show_start,
8892 gboolean *show_stop,
8893 gboolean *show_poll,
8894 GDriveStartStopType *start_stop_type)
8895 {
8896 char *uri;
8897
8898 *show_mount = FALSE;
8899 *show_unmount = FALSE;
8900 *show_eject = FALSE;
8901 *show_connect = FALSE;
8902 *show_start = FALSE;
8903 *show_stop = FALSE;
8904 *show_poll = FALSE;
8905
8906 if (nemo_file_can_eject (file)) {
8907 *show_eject = TRUE;
8908 }
8909
8910 if (nemo_file_can_mount (file)) {
8911 *show_mount = TRUE;
8912 }
8913
8914 if (nemo_file_can_start (file) || nemo_file_can_start_degraded (file)) {
8915 *show_start = TRUE;
8916 }
8917
8918 if (nemo_file_can_stop (file)) {
8919 *show_stop = TRUE;
8920 }
8921
8922 /* Dot not show both Unmount and Eject/Safe Removal; too confusing to
8923 * have too many menu entries */
8924 if (nemo_file_can_unmount (file) && !*show_eject && !*show_stop) {
8925 *show_unmount = TRUE;
8926 }
8927
8928 if (nemo_file_can_poll_for_media (file) && !nemo_file_is_media_check_automatic (file)) {
8929 *show_poll = TRUE;
8930 }
8931
8932 *start_stop_type = nemo_file_get_start_stop_type (file);
8933
8934 if (nemo_file_is_nemo_link (file)) {
8935 uri = nemo_file_get_activation_uri (file);
8936 if (uri != NULL &&
8937 (g_str_has_prefix (uri, "ftp:") ||
8938 g_str_has_prefix (uri, "ssh:") ||
8939 g_str_has_prefix (uri, "sftp:") ||
8940 g_str_has_prefix (uri, "dav:") ||
8941 g_str_has_prefix (uri, "davs:"))) {
8942 *show_connect = TRUE;
8943 }
8944 g_free (uri);
8945 }
8946 }
8947
8948 static void
file_should_show_self(NemoFile * file,gboolean * show_mount,gboolean * show_unmount,gboolean * show_eject,gboolean * show_start,gboolean * show_stop,gboolean * show_poll,GDriveStartStopType * start_stop_type)8949 file_should_show_self (NemoFile *file,
8950 gboolean *show_mount,
8951 gboolean *show_unmount,
8952 gboolean *show_eject,
8953 gboolean *show_start,
8954 gboolean *show_stop,
8955 gboolean *show_poll,
8956 GDriveStartStopType *start_stop_type)
8957 {
8958 *show_mount = FALSE;
8959 *show_unmount = FALSE;
8960 *show_eject = FALSE;
8961 *show_start = FALSE;
8962 *show_stop = FALSE;
8963 *show_poll = FALSE;
8964
8965 if (file == NULL) {
8966 return;
8967 }
8968
8969 if (nemo_file_can_eject (file)) {
8970 *show_eject = TRUE;
8971 }
8972
8973 if (nemo_file_can_mount (file)) {
8974 *show_mount = TRUE;
8975 }
8976
8977 if (nemo_file_can_start (file) || nemo_file_can_start_degraded (file)) {
8978 *show_start = TRUE;
8979 }
8980
8981 if (nemo_file_can_stop (file)) {
8982 *show_stop = TRUE;
8983 }
8984
8985 /* Dot not show both Unmount and Eject/Safe Removal; too confusing to
8986 * have too many menu entries */
8987 if (nemo_file_can_unmount (file) && !*show_eject && !*show_stop) {
8988 *show_unmount = TRUE;
8989 }
8990
8991 if (nemo_file_can_poll_for_media (file) && !nemo_file_is_media_check_automatic (file)) {
8992 *show_poll = TRUE;
8993 }
8994
8995 *start_stop_type = nemo_file_get_start_stop_type (file);
8996
8997 }
8998
8999 static gboolean
files_are_all_directories(GList * files)9000 files_are_all_directories (GList *files)
9001 {
9002 NemoFile *file;
9003 GList *l;
9004 gboolean all_directories;
9005
9006 all_directories = TRUE;
9007
9008 for (l = files; l != NULL; l = l->next) {
9009 file = NEMO_FILE (l->data);
9010 all_directories &= nemo_file_is_directory (file);
9011 }
9012
9013 return all_directories;
9014 }
9015
9016 static gboolean
files_is_none_directory(GList * files)9017 files_is_none_directory (GList *files)
9018 {
9019 NemoFile *file;
9020 GList *l;
9021 gboolean no_directory;
9022
9023 no_directory = TRUE;
9024
9025 for (l = files; l != NULL; l = l->next) {
9026 file = NEMO_FILE (l->data);
9027 no_directory &= !nemo_file_is_directory (file);
9028 }
9029
9030 return no_directory;
9031 }
9032
9033 static void
update_restore_from_trash_action(GtkAction * action,GList * files,gboolean is_self)9034 update_restore_from_trash_action (GtkAction *action,
9035 GList *files,
9036 gboolean is_self)
9037 {
9038 NemoFile *original_file;
9039 NemoFile *original_dir;
9040 GHashTable *original_dirs_hash;
9041 GList *original_dirs;
9042 GFile *original_location;
9043 char *tooltip, *original_name;
9044
9045 original_file = NULL;
9046 original_dir = NULL;
9047 original_dirs = NULL;
9048 original_dirs_hash = NULL;
9049 original_location = NULL;
9050 original_name = NULL;
9051
9052 if (files != NULL) {
9053 if (g_list_length (files) == 1) {
9054 original_file = nemo_file_get_trash_original_file (files->data);
9055 } else {
9056 original_dirs_hash = nemo_trashed_files_get_original_directories (files, NULL);
9057 if (original_dirs_hash != NULL) {
9058 original_dirs = g_hash_table_get_keys (original_dirs_hash);
9059 if (g_list_length (original_dirs) == 1) {
9060 original_dir = nemo_file_ref (NEMO_FILE (original_dirs->data));
9061 }
9062 }
9063 }
9064 }
9065
9066 if (original_file != NULL || original_dirs != NULL) {
9067 gtk_action_set_visible (action, TRUE);
9068
9069 if (original_file != NULL) {
9070 original_location = nemo_file_get_location (original_file);
9071 } else if (original_dir != NULL) {
9072 original_location = nemo_file_get_location (original_dir);
9073 }
9074
9075 if (original_location != NULL) {
9076 original_name = g_file_get_parse_name (original_location);
9077 }
9078
9079 if (is_self) {
9080 g_assert (g_list_length (files) == 1);
9081 g_assert (original_location != NULL);
9082 tooltip = g_strdup_printf (_("Move the open folder out of the trash to \"%s\""), original_name);
9083 } else if (files_are_all_directories (files)) {
9084 if (original_name != NULL) {
9085 tooltip = g_strdup_printf (ngettext ("Move the selected folder out of the trash to \"%s\"",
9086 "Move the selected folders out of the trash to \"%s\"",
9087 g_list_length (files)), original_name);
9088 } else {
9089 tooltip = g_strdup_printf (ngettext ("Move the selected folder out of the trash",
9090 "Move the selected folders out of the trash",
9091 g_list_length (files)));
9092 }
9093 } else if (files_is_none_directory (files)) {
9094 if (original_name != NULL) {
9095 tooltip = g_strdup_printf (ngettext ("Move the selected file out of the trash to \"%s\"",
9096 "Move the selected files out of the trash to \"%s\"",
9097 g_list_length (files)), original_name);
9098 } else {
9099 tooltip = g_strdup_printf (ngettext ("Move the selected file out of the trash",
9100 "Move the selected files out of the trash",
9101 g_list_length (files)));
9102 }
9103 } else {
9104 if (original_name != NULL) {
9105 tooltip = g_strdup_printf (ngettext ("Move the selected item out of the trash to \"%s\"",
9106 "Move the selected items out of the trash to \"%s\"",
9107 g_list_length (files)), original_name);
9108 } else {
9109 tooltip = g_strdup_printf (ngettext ("Move the selected item out of the trash",
9110 "Move the selected items out of the trash",
9111 g_list_length (files)));
9112 }
9113 }
9114 g_free (original_name);
9115
9116 g_object_set (action, "tooltip", tooltip, NULL);
9117 g_free (tooltip);
9118
9119 if (original_location != NULL) {
9120 g_object_unref (original_location);
9121 }
9122 } else {
9123 gtk_action_set_visible (action, FALSE);
9124 }
9125
9126 nemo_file_unref (original_file);
9127 nemo_file_unref (original_dir);
9128 g_list_free (original_dirs);
9129
9130 if (original_dirs_hash != NULL) {
9131 g_hash_table_destroy (original_dirs_hash);
9132 }
9133 }
9134
9135 static void
real_update_menus_volumes(NemoView * view,GList * selection,gint selection_count)9136 real_update_menus_volumes (NemoView *view,
9137 GList *selection,
9138 gint selection_count)
9139 {
9140 GList *l;
9141 NemoFile *file;
9142 gboolean show_mount;
9143 gboolean show_unmount;
9144 gboolean show_eject;
9145 gboolean show_connect;
9146 gboolean show_start;
9147 gboolean show_stop;
9148 gboolean show_poll;
9149 GDriveStartStopType start_stop_type;
9150 gboolean show_self_mount;
9151 gboolean show_self_unmount;
9152 gboolean show_self_eject;
9153 gboolean show_self_start;
9154 gboolean show_self_stop;
9155 gboolean show_self_poll;
9156 GDriveStartStopType self_start_stop_type;
9157 GtkAction *action;
9158
9159 show_mount = (selection != NULL);
9160 show_unmount = (selection != NULL);
9161 show_eject = (selection != NULL);
9162 show_connect = (selection != NULL && selection_count == 1);
9163 show_start = (selection != NULL && selection_count == 1);
9164 show_stop = (selection != NULL && selection_count == 1);
9165 show_poll = (selection != NULL && selection_count == 1);
9166 start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
9167 self_start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
9168
9169 for (l = selection; l != NULL && (show_mount || show_unmount
9170 || show_eject || show_connect
9171 || show_start || show_stop
9172 || show_poll);
9173 l = l->next) {
9174 gboolean show_mount_one;
9175 gboolean show_unmount_one;
9176 gboolean show_eject_one;
9177 gboolean show_connect_one;
9178 gboolean show_start_one;
9179 gboolean show_stop_one;
9180 gboolean show_poll_one;
9181
9182 file = NEMO_FILE (l->data);
9183 file_should_show_foreach (file,
9184 &show_mount_one,
9185 &show_unmount_one,
9186 &show_eject_one,
9187 &show_connect_one,
9188 &show_start_one,
9189 &show_stop_one,
9190 &show_poll_one,
9191 &start_stop_type);
9192
9193 show_mount &= show_mount_one;
9194 show_unmount &= show_unmount_one;
9195 show_eject &= show_eject_one;
9196 show_connect &= show_connect_one;
9197 show_start &= show_start_one;
9198 show_stop &= show_stop_one;
9199 show_poll &= show_poll_one;
9200 }
9201
9202 action = gtk_action_group_get_action (view->details->dir_action_group,
9203 NEMO_ACTION_CONNECT_TO_SERVER_LINK);
9204 gtk_action_set_visible (action, show_connect);
9205
9206 action = gtk_action_group_get_action (view->details->dir_action_group,
9207 NEMO_ACTION_MOUNT_VOLUME);
9208 gtk_action_set_visible (action, show_mount);
9209
9210 action = gtk_action_group_get_action (view->details->dir_action_group,
9211 NEMO_ACTION_UNMOUNT_VOLUME);
9212 gtk_action_set_visible (action, show_unmount);
9213
9214 action = gtk_action_group_get_action (view->details->dir_action_group,
9215 NEMO_ACTION_EJECT_VOLUME);
9216 gtk_action_set_visible (action, show_eject);
9217
9218 action = gtk_action_group_get_action (view->details->dir_action_group,
9219 NEMO_ACTION_START_VOLUME);
9220 gtk_action_set_visible (action, show_start);
9221 if (show_start) {
9222 switch (start_stop_type) {
9223 default:
9224 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
9225 gtk_action_set_label (action, _("_Start"));
9226 gtk_action_set_tooltip (action, _("Start the selected drive"));
9227 break;
9228 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
9229 gtk_action_set_label (action, _("_Start"));
9230 gtk_action_set_tooltip (action, _("Start the selected drive"));
9231 break;
9232 case G_DRIVE_START_STOP_TYPE_NETWORK:
9233 gtk_action_set_label (action, _("_Connect"));
9234 gtk_action_set_tooltip (action, _("Connect to the selected drive"));
9235 break;
9236 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
9237 gtk_action_set_label (action, _("_Start Multi-disk Drive"));
9238 gtk_action_set_tooltip (action, _("Start the selected multi-disk drive"));
9239 break;
9240 case G_DRIVE_START_STOP_TYPE_PASSWORD:
9241 gtk_action_set_label (action, _("U_nlock Drive"));
9242 gtk_action_set_tooltip (action, _("Unlock the selected drive"));
9243 break;
9244 }
9245 }
9246
9247 action = gtk_action_group_get_action (view->details->dir_action_group,
9248 NEMO_ACTION_STOP_VOLUME);
9249 gtk_action_set_visible (action, show_stop);
9250 if (show_stop) {
9251 switch (start_stop_type) {
9252 default:
9253 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
9254 gtk_action_set_label (action, _("_Stop"));
9255 gtk_action_set_tooltip (action, _("Stop the selected drive"));
9256 break;
9257 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
9258 gtk_action_set_label (action, _("_Safely Remove Drive"));
9259 gtk_action_set_tooltip (action, _("Safely remove the selected drive"));
9260 break;
9261 case G_DRIVE_START_STOP_TYPE_NETWORK:
9262 gtk_action_set_label (action, _("_Disconnect"));
9263 gtk_action_set_tooltip (action, _("Disconnect the selected drive"));
9264 break;
9265 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
9266 gtk_action_set_label (action, _("_Stop Multi-disk Drive"));
9267 gtk_action_set_tooltip (action, _("Stop the selected multi-disk drive"));
9268 break;
9269 case G_DRIVE_START_STOP_TYPE_PASSWORD:
9270 gtk_action_set_label (action, _("_Lock Drive"));
9271 gtk_action_set_tooltip (action, _("Lock the selected drive"));
9272 break;
9273 }
9274 }
9275
9276 action = gtk_action_group_get_action (view->details->dir_action_group,
9277 NEMO_ACTION_POLL);
9278 gtk_action_set_visible (action, show_poll);
9279
9280 show_self_mount = show_self_unmount = show_self_eject =
9281 show_self_start = show_self_stop = show_self_poll = FALSE;
9282
9283 file = nemo_view_get_directory_as_file (view);
9284 file_should_show_self (file,
9285 &show_self_mount,
9286 &show_self_unmount,
9287 &show_self_eject,
9288 &show_self_start,
9289 &show_self_stop,
9290 &show_self_poll,
9291 &self_start_stop_type);
9292
9293 action = gtk_action_group_get_action (view->details->dir_action_group,
9294 NEMO_ACTION_SELF_MOUNT_VOLUME);
9295 gtk_action_set_visible (action, show_self_mount);
9296
9297 action = gtk_action_group_get_action (view->details->dir_action_group,
9298 NEMO_ACTION_SELF_UNMOUNT_VOLUME);
9299 gtk_action_set_visible (action, show_self_unmount);
9300
9301 action = gtk_action_group_get_action (view->details->dir_action_group,
9302 NEMO_ACTION_SELF_EJECT_VOLUME);
9303 gtk_action_set_visible (action, show_self_eject);
9304
9305 action = gtk_action_group_get_action (view->details->dir_action_group,
9306 NEMO_ACTION_SELF_START_VOLUME);
9307 gtk_action_set_visible (action, show_self_start);
9308 if (show_self_start) {
9309 switch (self_start_stop_type) {
9310 default:
9311 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
9312 gtk_action_set_label (action, _("_Start"));
9313 gtk_action_set_tooltip (action, _("Start the drive associated with the open folder"));
9314 break;
9315 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
9316 gtk_action_set_label (action, _("_Start"));
9317 gtk_action_set_tooltip (action, _("Start the drive associated with the open folder"));
9318 break;
9319 case G_DRIVE_START_STOP_TYPE_NETWORK:
9320 gtk_action_set_label (action, _("_Connect"));
9321 gtk_action_set_tooltip (action, _("Connect to the drive associated with the open folder"));
9322 break;
9323 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
9324 gtk_action_set_label (action, _("_Start Multi-disk Drive"));
9325 gtk_action_set_tooltip (action, _("Start the multi-disk drive associated with the open folder"));
9326 break;
9327 case G_DRIVE_START_STOP_TYPE_PASSWORD:
9328 gtk_action_set_label (action, _("_Unlock Drive"));
9329 gtk_action_set_tooltip (action, _("Unlock the drive associated with the open folder"));
9330 break;
9331 }
9332 }
9333
9334 action = gtk_action_group_get_action (view->details->dir_action_group,
9335 NEMO_ACTION_SELF_STOP_VOLUME);
9336 gtk_action_set_visible (action, show_self_stop);
9337 if (show_self_stop) {
9338 switch (self_start_stop_type) {
9339 default:
9340 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
9341 gtk_action_set_label (action, _("_Stop"));
9342 gtk_action_set_tooltip (action, _("_Stop the drive associated with the open folder"));
9343 break;
9344 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
9345 gtk_action_set_label (action, _("_Safely Remove Drive"));
9346 gtk_action_set_tooltip (action, _("Safely remove the drive associated with the open folder"));
9347 break;
9348 case G_DRIVE_START_STOP_TYPE_NETWORK:
9349 gtk_action_set_label (action, _("_Disconnect"));
9350 gtk_action_set_tooltip (action, _("Disconnect the drive associated with the open folder"));
9351 break;
9352 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
9353 gtk_action_set_label (action, _("_Stop Multi-disk Drive"));
9354 gtk_action_set_tooltip (action, _("Stop the multi-disk drive associated with the open folder"));
9355 break;
9356 case G_DRIVE_START_STOP_TYPE_PASSWORD:
9357 gtk_action_set_label (action, _("_Lock Drive"));
9358 gtk_action_set_tooltip (action, _("Lock the drive associated with the open folder"));
9359 break;
9360 }
9361 }
9362
9363 action = gtk_action_group_get_action (view->details->dir_action_group,
9364 NEMO_ACTION_SELF_POLL);
9365 gtk_action_set_visible (action, show_self_poll);
9366
9367 }
9368
9369 static void
real_update_location_menu_volumes(NemoView * view)9370 real_update_location_menu_volumes (NemoView *view)
9371 {
9372 GtkAction *action;
9373 NemoFile *file;
9374 gboolean show_mount;
9375 gboolean show_unmount;
9376 gboolean show_eject;
9377 gboolean show_connect;
9378 gboolean show_start;
9379 gboolean show_stop;
9380 gboolean show_poll;
9381 GDriveStartStopType start_stop_type;
9382
9383 g_assert (NEMO_IS_VIEW (view));
9384 g_assert (NEMO_IS_FILE (view->details->location_popup_directory_as_file));
9385
9386 file = NEMO_FILE (view->details->location_popup_directory_as_file);
9387 file_should_show_foreach (file,
9388 &show_mount,
9389 &show_unmount,
9390 &show_eject,
9391 &show_connect,
9392 &show_start,
9393 &show_stop,
9394 &show_poll,
9395 &start_stop_type);
9396
9397 action = gtk_action_group_get_action (view->details->dir_action_group,
9398 NEMO_ACTION_LOCATION_MOUNT_VOLUME);
9399 gtk_action_set_visible (action, show_mount);
9400
9401 action = gtk_action_group_get_action (view->details->dir_action_group,
9402 NEMO_ACTION_LOCATION_UNMOUNT_VOLUME);
9403 gtk_action_set_visible (action, show_unmount);
9404
9405 action = gtk_action_group_get_action (view->details->dir_action_group,
9406 NEMO_ACTION_LOCATION_EJECT_VOLUME);
9407 gtk_action_set_visible (action, show_eject);
9408
9409 action = gtk_action_group_get_action (view->details->dir_action_group,
9410 NEMO_ACTION_LOCATION_START_VOLUME);
9411 gtk_action_set_visible (action, show_start);
9412 if (show_start) {
9413 switch (start_stop_type) {
9414 default:
9415 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
9416 gtk_action_set_label (action, _("_Start"));
9417 gtk_action_set_tooltip (action, _("Start the selected drive"));
9418 break;
9419 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
9420 gtk_action_set_label (action, _("_Start"));
9421 gtk_action_set_tooltip (action, _("Start the selected drive"));
9422 break;
9423 case G_DRIVE_START_STOP_TYPE_NETWORK:
9424 gtk_action_set_label (action, _("_Connect"));
9425 gtk_action_set_tooltip (action, _("Connect to the selected drive"));
9426 break;
9427 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
9428 gtk_action_set_label (action, _("_Start Multi-disk Drive"));
9429 gtk_action_set_tooltip (action, _("Start the selected multi-disk drive"));
9430 break;
9431 case G_DRIVE_START_STOP_TYPE_PASSWORD:
9432 gtk_action_set_label (action, _("_Unlock Drive"));
9433 gtk_action_set_tooltip (action, _("Unlock the selected drive"));
9434 break;
9435 }
9436 }
9437
9438 action = gtk_action_group_get_action (view->details->dir_action_group,
9439 NEMO_ACTION_LOCATION_STOP_VOLUME);
9440 gtk_action_set_visible (action, show_stop);
9441 if (show_stop) {
9442 switch (start_stop_type) {
9443 default:
9444 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
9445 gtk_action_set_label (action, _("_Stop"));
9446 gtk_action_set_tooltip (action, _("Stop the selected volume"));
9447 break;
9448 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
9449 gtk_action_set_label (action, _("_Safely Remove Drive"));
9450 gtk_action_set_tooltip (action, _("Safely remove the selected drive"));
9451 break;
9452 case G_DRIVE_START_STOP_TYPE_NETWORK:
9453 gtk_action_set_label (action, _("_Disconnect"));
9454 gtk_action_set_tooltip (action, _("Disconnect the selected drive"));
9455 break;
9456 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
9457 gtk_action_set_label (action, _("_Stop Multi-disk Drive"));
9458 gtk_action_set_tooltip (action, _("Stop the selected multi-disk drive"));
9459 break;
9460 case G_DRIVE_START_STOP_TYPE_PASSWORD:
9461 gtk_action_set_label (action, _("_Lock Drive"));
9462 gtk_action_set_tooltip (action, _("Lock the selected drive"));
9463 break;
9464 }
9465 }
9466
9467 action = gtk_action_group_get_action (view->details->dir_action_group,
9468 NEMO_ACTION_LOCATION_POLL);
9469 gtk_action_set_visible (action, show_poll);
9470 }
9471
9472 /* TODO: we should split out this routine into two functions:
9473 * Update on clipboard changes
9474 * Update on selection changes
9475 */
9476 static void
real_update_paste_menu(NemoView * view,GList * selection,gint selection_count)9477 real_update_paste_menu (NemoView *view,
9478 GList *selection,
9479 gint selection_count)
9480 {
9481 gboolean can_paste_files_into;
9482 gboolean selection_is_read_only;
9483 gboolean selection_contains_recent;
9484 gboolean selection_contains_favorites;
9485 gboolean is_read_only;
9486 GtkAction *action;
9487
9488 selection_is_read_only = selection_count == 1 &&
9489 (!nemo_file_can_write (NEMO_FILE (selection->data)) &&
9490 !nemo_file_has_activation_uri (NEMO_FILE (selection->data)));
9491
9492 is_read_only = nemo_view_is_read_only (view);
9493
9494 selection_contains_recent = showing_recent_directory (view);
9495 selection_contains_favorites = showing_favorites_directory (view);
9496
9497 can_paste_files_into = (!selection_contains_recent && !selection_contains_favorites &&
9498 selection_count == 1 &&
9499 can_paste_into_file (NEMO_FILE (selection->data)));
9500
9501 action = gtk_action_group_get_action (view->details->dir_action_group,
9502 NEMO_ACTION_PASTE);
9503 gtk_action_set_sensitive (action, !is_read_only);
9504
9505 gtk_action_set_visible (action, !selection_contains_recent && !selection_contains_favorites);
9506
9507 action = gtk_action_group_get_action (view->details->dir_action_group,
9508 NEMO_ACTION_PASTE_FILES_INTO);
9509 gtk_action_set_visible (action, can_paste_files_into);
9510 gtk_action_set_sensitive (action, !selection_is_read_only);
9511
9512 /* Ask the clipboard */
9513 g_object_ref (view); /* Need to keep the object alive until we get the reply */
9514 gtk_clipboard_request_targets (nemo_clipboard_get (GTK_WIDGET (view)),
9515 clipboard_targets_received,
9516 view);
9517 }
9518
9519 static void
real_update_location_menu(NemoView * view)9520 real_update_location_menu (NemoView *view)
9521 {
9522 GtkAction *action;
9523 NemoFile *file;
9524 gboolean is_special_link;
9525 gboolean is_desktop_or_home_dir;
9526 gboolean is_recent;
9527 gboolean can_delete_file, show_delete;
9528 gboolean show_separate_delete_command;
9529 gboolean show_open_in_new_tab;
9530 gboolean show_open_alternate;
9531 GList l;
9532 char *label;
9533 char *tip;
9534
9535 show_open_in_new_tab = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER);
9536 show_open_alternate = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER);
9537
9538 action = gtk_action_group_get_action (view->details->dir_action_group,
9539 NEMO_ACTION_LOCATION_OPEN_ALTERNATE);
9540 gtk_action_set_visible (action, show_open_alternate);
9541
9542 label = _("Open in New _Window");
9543 g_object_set (action,
9544 "label", label,
9545 NULL);
9546
9547 action = gtk_action_group_get_action (view->details->dir_action_group,
9548 NEMO_ACTION_LOCATION_OPEN_IN_NEW_TAB);
9549 gtk_action_set_visible (action, show_open_in_new_tab);
9550
9551 label = _("Open in New _Tab");
9552 g_object_set (action,
9553 "label", label,
9554 NULL);
9555
9556 file = view->details->location_popup_directory_as_file;
9557 g_assert (NEMO_IS_FILE (file));
9558 g_assert (nemo_file_check_if_ready (file, NEMO_FILE_ATTRIBUTE_INFO |
9559 NEMO_FILE_ATTRIBUTE_MOUNT |
9560 NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO));
9561
9562 is_special_link = NEMO_IS_DESKTOP_ICON_FILE (file);
9563 is_desktop_or_home_dir = nemo_file_is_home (file)
9564 || nemo_file_is_desktop_directory (file);
9565
9566 is_recent = nemo_file_is_in_recent (file);
9567
9568 can_delete_file =
9569 nemo_file_can_delete (file) &&
9570 !is_special_link &&
9571 !is_desktop_or_home_dir;
9572
9573 action = gtk_action_group_get_action (view->details->dir_action_group,
9574 NEMO_ACTION_LOCATION_CUT);
9575 gtk_action_set_sensitive (action, !is_recent && can_delete_file);
9576 gtk_action_set_visible (action, !is_recent);
9577
9578 action = gtk_action_group_get_action (view->details->dir_action_group,
9579 NEMO_ACTION_LOCATION_PASTE_FILES_INTO);
9580 g_object_set_data (G_OBJECT (action),
9581 "can-paste-according-to-destination",
9582 GINT_TO_POINTER (can_paste_into_file (file)));
9583 gtk_action_set_sensitive (action,
9584 !is_recent &&
9585 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action),
9586 "can-paste-according-to-clipboard")) &&
9587 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action),
9588 "can-paste-according-to-destination")));
9589
9590 gtk_action_set_visible (action, !is_recent);
9591
9592 show_delete = TRUE;
9593
9594 if (file != NULL &&
9595 nemo_file_is_in_trash (file)) {
9596 if (nemo_file_is_self_owned (file)) {
9597 show_delete = FALSE;
9598 }
9599
9600 label = _("_Delete Permanently");
9601 tip = _("Delete the open folder permanently");
9602 show_separate_delete_command = FALSE;
9603 } else {
9604 label = _("Mo_ve to Trash");
9605 tip = _("Move the open folder to the Trash");
9606 show_separate_delete_command = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ENABLE_DELETE);
9607 }
9608
9609 action = gtk_action_group_get_action (view->details->dir_action_group,
9610 NEMO_ACTION_LOCATION_TRASH);
9611 g_object_set (action,
9612 "label", label,
9613 "tooltip", tip,
9614 "icon-name", (file != NULL &&
9615 nemo_file_is_in_trash (file)) ?
9616 NEMO_ICON_DELETE : NEMO_ICON_SYMBOLIC_TRASH_FULL,
9617 NULL);
9618 gtk_action_set_sensitive (action, can_delete_file);
9619 gtk_action_set_visible (action, show_delete);
9620
9621 action = gtk_action_group_get_action (view->details->dir_action_group,
9622 NEMO_ACTION_LOCATION_DELETE);
9623 gtk_action_set_visible (action, show_separate_delete_command);
9624 if (show_separate_delete_command) {
9625 gtk_action_set_sensitive (action, can_delete_file);
9626 g_object_set (action,
9627 "icon-name", NEMO_ICON_DELETE,
9628 "sensitive", can_delete_file,
9629 NULL);
9630 }
9631
9632 action = gtk_action_group_get_action (view->details->dir_action_group,
9633 NEMO_ACTION_LOCATION_RESTORE_FROM_TRASH);
9634 l.prev = NULL;
9635 l.next = NULL;
9636 l.data = file;
9637 update_restore_from_trash_action (action, &l, TRUE);
9638
9639 real_update_location_menu_volumes (view);
9640 }
9641
9642 static void
clipboard_changed_callback(NemoClipboardMonitor * monitor,NemoView * view)9643 clipboard_changed_callback (NemoClipboardMonitor *monitor, NemoView *view)
9644 {
9645 GList *selection;
9646 gint selection_count;
9647
9648 if (!view->details->active) {
9649 return;
9650 }
9651
9652 selection = nemo_view_get_selection (view);
9653 selection_count = g_list_length (selection);
9654
9655 real_update_paste_menu (view, selection, selection_count);
9656
9657 nemo_file_list_free (selection);
9658 }
9659
9660 static gboolean
can_delete_all(GList * files)9661 can_delete_all (GList *files)
9662 {
9663 NemoFile *file;
9664 GList *l;
9665
9666 for (l = files; l != NULL; l = l->next) {
9667 file = l->data;
9668 if (!nemo_file_can_delete (file)) {
9669 return FALSE;
9670 }
9671 }
9672 return TRUE;
9673 }
9674
9675 static gboolean
has_writable_extra_pane(NemoView * view)9676 has_writable_extra_pane (NemoView *view)
9677 {
9678 NemoView *other_view;
9679
9680 other_view = get_directory_view_of_extra_pane (view);
9681 if (other_view != NULL) {
9682 return !nemo_view_is_read_only (other_view);
9683 }
9684 return FALSE;
9685 }
9686
9687 static void
update_configurable_context_menu_items(NemoView * view)9688 update_configurable_context_menu_items (NemoView *view)
9689 {
9690 GtkUIManager *ui_manager;
9691 GtkWidget *item;
9692 GtkAction *action;
9693 gint i;
9694
9695 ui_manager = nemo_window_get_ui_manager (view->details->window);
9696
9697 for (i = 0; i < CONFIGURABLE_MENU_ITEM_COUNT; i++) {
9698 if (!CONFIGURABLE_MENU_ITEM_INFO[i].action_name) {
9699 continue;
9700 }
9701
9702 item = gtk_ui_manager_get_widget (ui_manager,
9703 CONFIGURABLE_MENU_ITEM_INFO[i].ui_path);
9704
9705 action = gtk_ui_manager_get_action (ui_manager,
9706 CONFIGURABLE_MENU_ITEM_INFO[i].ui_path);
9707
9708 if (!item || !action) {
9709 DEBUG ("Configurable menu item widget or action not found (name: %s, path: %s)",
9710 CONFIGURABLE_MENU_ITEM_INFO[i].action_name,
9711 CONFIGURABLE_MENU_ITEM_INFO[i].ui_path);
9712 continue;
9713 }
9714
9715 gboolean pref_visible = g_settings_get_boolean (nemo_menu_config_preferences,
9716 CONFIGURABLE_MENU_ITEM_INFO[i].settings_key);
9717
9718 gtk_widget_set_visible (item, gtk_action_get_visible (action) && pref_visible);
9719 }
9720 }
9721
9722 static void
real_update_menus(NemoView * view)9723 real_update_menus (NemoView *view)
9724 {
9725 GList *selection, *l;
9726 gint selection_count;
9727 const char *tip, *label;
9728 char *label_with_underscore;
9729 gboolean selection_contains_special_link;
9730 gboolean selection_contains_desktop_or_home_dir;
9731 gboolean selection_contains_recent;
9732 gboolean selection_contains_favorites;
9733 gboolean selection_contains_directory;
9734 gboolean can_create_files;
9735 gboolean can_delete_files;
9736 gboolean can_copy_files;
9737 gboolean can_link_files;
9738 gboolean can_duplicate_files;
9739 gboolean show_separate_delete_command;
9740 gboolean show_open_alternate;
9741 gboolean show_open_in_new_tab;
9742 gboolean can_open;
9743 gboolean show_app;
9744 gboolean showing_search;
9745 gboolean show_save_search;
9746 gboolean save_search_sensitive;
9747 gboolean show_save_search_as;
9748 gboolean show_desktop_target;
9749 gboolean is_desktop_view;
9750 GtkAction *action;
9751 GAppInfo *app;
9752 GIcon *app_icon;
9753 gboolean next_pane_is_writable;
9754 gboolean show_properties;
9755 gboolean first_selected_is_pinned;
9756
9757 selection = nemo_view_get_selection (view);
9758 selection_count = g_list_length (selection);
9759
9760 selection_contains_special_link = special_link_in_selection (view, selection);
9761 selection_contains_desktop_or_home_dir = desktop_or_home_dir_in_selection (view, selection);
9762 selection_contains_recent = showing_recent_directory (view);
9763 selection_contains_favorites = showing_favorites_directory (view);
9764 selection_contains_directory = directory_in_selection (view, selection);
9765 can_create_files = nemo_view_supports_creating_files (view);
9766 can_delete_files =
9767 can_delete_all (selection) &&
9768 selection_count != 0 &&
9769 !selection_contains_special_link &&
9770 !selection_contains_desktop_or_home_dir;
9771 can_copy_files = selection_count != 0
9772 && !selection_contains_special_link;
9773
9774 can_duplicate_files = can_create_files && can_copy_files;
9775 can_link_files = can_create_files && can_copy_files;
9776
9777 is_desktop_view = get_is_desktop_view (view);
9778
9779 action = gtk_action_group_get_action (view->details->dir_action_group,
9780 NEMO_ACTION_RENAME);
9781 /* rename sensitivity depending on selection */
9782 if (selection_count > 1) {
9783 /* If multiple files are selected, sensitivity depends on whether a bulk renamer is registered. */
9784 gtk_action_set_sensitive (action, have_bulk_rename_tool ());
9785 } else {
9786 gtk_action_set_sensitive (action,
9787 selection_count == 1 &&
9788 nemo_view_can_rename_file (view, selection->data));
9789 }
9790
9791 gtk_action_set_visible (action, !selection_contains_recent &&
9792 !selection_contains_special_link);
9793
9794 gboolean no_selection_or_one_dir = ((selection_count == 1 && selection_contains_directory) ||
9795 selection_count == 0);
9796
9797 gboolean show_open_as_root = (geteuid() != 0) && no_selection_or_one_dir;
9798
9799 action = gtk_action_group_get_action (view->details->dir_action_group,
9800 NEMO_ACTION_OPEN_AS_ROOT);
9801 gtk_action_set_visible (action, show_open_as_root);
9802
9803 action = gtk_action_group_get_action (view->details->dir_action_group,
9804 NEMO_ACTION_OPEN_IN_TERMINAL);
9805 gtk_action_set_visible (action, no_selection_or_one_dir);
9806
9807 action = gtk_action_group_get_action (view->details->dir_action_group,
9808 NEMO_ACTION_NEW_FOLDER);
9809 gtk_action_set_sensitive (action, can_create_files);
9810 gtk_action_set_visible (action, !selection_contains_recent && !selection_contains_favorites);
9811
9812 can_open = show_app = selection_count != 0;
9813
9814 for (l = selection; l != NULL; l = l->next) {
9815 NemoFile *file;
9816
9817 file = NEMO_FILE (selection->data);
9818
9819 if (!nemo_mime_file_opens_in_external_app (file)) {
9820 show_app = FALSE;
9821 }
9822
9823 if (!show_app) {
9824 break;
9825 }
9826 }
9827
9828 label_with_underscore = NULL;
9829
9830 app = NULL;
9831 app_icon = NULL;
9832
9833 if (can_open && show_app) {
9834 app = nemo_mime_get_default_application_for_files (selection);
9835 }
9836
9837 if (app != NULL) {
9838 char *escaped_app;
9839
9840 escaped_app = eel_str_double_underscores (g_app_info_get_name (app));
9841 label_with_underscore = g_strdup_printf (_("_Open With %s"),
9842 escaped_app);
9843
9844 app_icon = g_app_info_get_icon (app);
9845 if (app_icon != NULL) {
9846 g_object_ref (app_icon);
9847 }
9848
9849 g_free (escaped_app);
9850 g_object_unref (app);
9851 }
9852
9853 if (app_icon == NULL) {
9854 app_icon = g_themed_icon_new ("folder-open-symbolic");
9855 }
9856
9857 action = gtk_action_group_get_action (view->details->dir_action_group,
9858 NEMO_ACTION_OPEN);
9859 gtk_action_set_sensitive (action, selection_count != 0);
9860
9861 g_object_set (action, "label",
9862 label_with_underscore ? label_with_underscore : _("_Open"),
9863 NULL);
9864
9865 gtk_action_set_gicon (action, app_icon);
9866 gtk_action_set_visible (action, can_open);
9867
9868 g_object_unref (app_icon);
9869 g_free (label_with_underscore);
9870
9871 menu_item_show_image (nemo_window_get_ui_manager (view->details->window),
9872 NEMO_VIEW_MENU_PATH_OPEN_PLACEHOLDER,
9873 NEMO_ACTION_OPEN,
9874 FALSE);
9875
9876 show_open_alternate = file_list_all_are_folders (selection) &&
9877 selection_count > 0 &&
9878 g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER) &&
9879 !is_desktop_view;
9880
9881 action = gtk_action_group_get_action (view->details->dir_action_group,
9882 NEMO_ACTION_OPEN_ALTERNATE);
9883
9884 gtk_action_set_sensitive (action, selection_count != 0);
9885 gtk_action_set_visible (action, show_open_alternate);
9886
9887 if (selection_count == 0 || selection_count == 1) {
9888 label_with_underscore = g_strdup (_("Open in New _Window"));
9889 } else {
9890 label_with_underscore = g_strdup_printf (ngettext("Open in %'d New _Window",
9891 "Open in %'d New _Windows",
9892 selection_count),
9893 selection_count);
9894 }
9895
9896 g_object_set (action, "label",
9897 label_with_underscore,
9898 NULL);
9899 g_free (label_with_underscore);
9900
9901 show_open_in_new_tab = show_open_alternate;
9902 action = gtk_action_group_get_action (view->details->dir_action_group,
9903 NEMO_ACTION_OPEN_IN_NEW_TAB);
9904 gtk_action_set_sensitive (action, selection_count != 0);
9905 gtk_action_set_visible (action, show_open_in_new_tab);
9906
9907 if (selection_count == 0 || selection_count == 1) {
9908 label_with_underscore = g_strdup (_("Open in New _Tab"));
9909 } else {
9910 label_with_underscore = g_strdup_printf (ngettext("Open in %'d New _Tab",
9911 "Open in %'d New _Tabs",
9912 selection_count),
9913 selection_count);
9914 }
9915
9916 g_object_set (action, "label",
9917 label_with_underscore,
9918 NULL);
9919 g_free (label_with_underscore);
9920
9921 /* Broken into its own function just for convenience */
9922 reset_open_with_menu (view, selection, show_app);
9923 reset_extension_actions_menu (view, selection);
9924 reset_move_copy_to_menu (view);
9925
9926 if (all_selected_items_in_trash (view, selection)) {
9927 label = _("_Delete Permanently");
9928 tip = _("Delete all selected items permanently");
9929 show_separate_delete_command = FALSE;
9930 } else {
9931 label = _("Mo_ve to Trash");
9932 tip = _("Move each selected item to the Trash");
9933 show_separate_delete_command = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ENABLE_DELETE);
9934 }
9935
9936 action = gtk_action_group_get_action (view->details->dir_action_group,
9937 NEMO_ACTION_TRASH);
9938 g_object_set (action,
9939 "label", label,
9940 "tooltip", tip,
9941 "icon-name", all_selected_items_in_trash (view, selection) ?
9942 NEMO_ICON_DELETE : NEMO_ICON_SYMBOLIC_TRASH_FULL,
9943 NULL);
9944 gtk_action_set_sensitive (action, can_delete_files);
9945 gtk_action_set_visible (action, !(selection_contains_favorites || selection_contains_recent));
9946
9947 action = gtk_action_group_get_action (view->details->dir_action_group,
9948 NEMO_ACTION_DELETE);
9949 gtk_action_set_visible (action, show_separate_delete_command && !selection_contains_favorites);
9950
9951 if (selection_contains_recent) {
9952 label = _("Remo_ve from Recent");
9953 tip = _("Remove each selected item from the recently used list");
9954 } else {
9955 label = _("_Delete");
9956 tip = _("Delete each selected item, without moving to the Trash");
9957 }
9958
9959 if (show_separate_delete_command) {
9960 g_object_set (action,
9961 "label", label,
9962 "tooltip", tip,
9963 "icon-name", NEMO_ICON_DELETE,
9964 NULL);
9965 }
9966 gtk_action_set_sensitive (action, can_delete_files);
9967
9968 action = gtk_action_group_get_action (view->details->dir_action_group,
9969 NEMO_ACTION_RESTORE_FROM_TRASH);
9970 update_restore_from_trash_action (action, selection, FALSE);
9971
9972 action = gtk_action_group_get_action (view->details->dir_action_group, NEMO_ACTION_DUPLICATE);
9973 gtk_action_set_sensitive (action, can_duplicate_files);
9974 gtk_action_set_visible (action, !selection_contains_recent && !selection_contains_favorites);
9975
9976 action = gtk_action_group_get_action (view->details->dir_action_group,
9977 NEMO_ACTION_CREATE_LINK);
9978 gtk_action_set_sensitive (action, can_link_files);
9979 gtk_action_set_visible (action, !selection_contains_recent && !selection_contains_favorites);
9980 g_object_set (action, "label",
9981 ngettext ("Ma_ke Link",
9982 "Ma_ke Links",
9983 selection_count),
9984 NULL);
9985
9986 show_properties = (!is_desktop_view || selection_count > 0);
9987
9988 action = gtk_action_group_get_action (view->details->dir_action_group,
9989 NEMO_ACTION_PROPERTIES);
9990
9991 gtk_action_set_sensitive (action, show_properties);
9992
9993 if (selection_count == 0) {
9994 gtk_action_set_tooltip (action, _("View or modify the properties of the open folder"));
9995 } else {
9996 gtk_action_set_tooltip (action, _("View or modify the properties of each selected item"));
9997 }
9998
9999 gtk_action_set_visible (action, show_properties);
10000
10001 action = gtk_action_group_get_action (view->details->dir_action_group,
10002 NEMO_ACTION_PROPERTIES_ACCEL);
10003
10004 gtk_action_set_sensitive (action, show_properties);
10005
10006 action = gtk_action_group_get_action (view->details->dir_action_group,
10007 NEMO_ACTION_EMPTY_TRASH);
10008 g_object_set (action,
10009 "label", _("E_mpty Trash"),
10010 NULL);
10011 gtk_action_set_sensitive (action, !nemo_trash_monitor_is_empty ());
10012 gtk_action_set_visible (action, should_show_empty_trash (view));
10013
10014 showing_search = view->details->model && NEMO_IS_SEARCH_DIRECTORY (view->details->model);
10015
10016 show_save_search = FALSE;
10017 save_search_sensitive = FALSE;
10018 show_save_search_as = FALSE;
10019 if (showing_search) {
10020 NemoSearchDirectory *search;
10021
10022 search = NEMO_SEARCH_DIRECTORY (view->details->model);
10023 if (nemo_search_directory_is_saved_search (search)) {
10024 show_save_search = TRUE;
10025 save_search_sensitive = nemo_search_directory_is_modified (search);
10026 } else {
10027 show_save_search_as = TRUE;
10028 }
10029 }
10030 action = gtk_action_group_get_action (view->details->dir_action_group,
10031 NEMO_ACTION_SAVE_SEARCH);
10032 gtk_action_set_visible (action, show_save_search);
10033 gtk_action_set_sensitive (action, save_search_sensitive);
10034 action = gtk_action_group_get_action (view->details->dir_action_group,
10035 NEMO_ACTION_SAVE_SEARCH_AS);
10036 gtk_action_set_visible (action, show_save_search_as);
10037
10038
10039 action = gtk_action_group_get_action (view->details->dir_action_group,
10040 NEMO_ACTION_SELECT_ALL);
10041 gtk_action_set_sensitive (action, !nemo_view_is_empty (view));
10042
10043 action = gtk_action_group_get_action (view->details->dir_action_group,
10044 NEMO_ACTION_SELECT_PATTERN);
10045 gtk_action_set_sensitive (action, !nemo_view_is_empty (view));
10046
10047 action = gtk_action_group_get_action (view->details->dir_action_group,
10048 NEMO_ACTION_INVERT_SELECTION);
10049 gtk_action_set_sensitive (action, !nemo_view_is_empty (view));
10050
10051 action = gtk_action_group_get_action (view->details->dir_action_group,
10052 NEMO_ACTION_CUT);
10053 gtk_action_set_sensitive (action, can_delete_files);
10054 gtk_action_set_visible (action, !selection_contains_recent && !selection_contains_favorites);
10055
10056 action = gtk_action_group_get_action (view->details->dir_action_group,
10057 NEMO_ACTION_COPY);
10058 gtk_action_set_sensitive (action, can_copy_files);
10059
10060 real_update_paste_menu (view, selection, selection_count);
10061
10062 real_update_menus_volumes (view, selection, selection_count);
10063
10064 update_undo_actions (view);
10065
10066 if (view->details->scripts_invalid) {
10067 update_scripts_menu (view);
10068 }
10069
10070 action = gtk_action_group_get_action (view->details->dir_action_group,
10071 NEMO_ACTION_NEW_DOCUMENTS);
10072 gtk_action_set_sensitive (action, can_create_files);
10073 gtk_action_set_visible (action, !selection_contains_recent && !selection_contains_favorites);
10074
10075 if (can_create_files && view->details->templates_invalid) {
10076 update_templates_menu (view);
10077 }
10078
10079 if (view->details->actions_invalid) {
10080 update_actions_menu (view);
10081 }
10082
10083 update_actions_visibility (view, selection);
10084
10085 next_pane_is_writable = has_writable_extra_pane (view);
10086
10087 /* next pane: works if file is copyable, and next pane is writable */
10088 action = gtk_action_group_get_action (view->details->dir_action_group,
10089 NEMO_ACTION_COPY_TO_NEXT_PANE);
10090 gtk_action_set_visible (action, can_copy_files && next_pane_is_writable);
10091
10092 /* move to next pane: works if file is cuttable, and next pane is writable */
10093 action = gtk_action_group_get_action (view->details->dir_action_group,
10094 NEMO_ACTION_MOVE_TO_NEXT_PANE);
10095 gtk_action_set_visible (action, can_delete_files &&
10096 next_pane_is_writable &&
10097 !selection_contains_recent &&
10098 !selection_contains_favorites);
10099
10100 show_desktop_target =
10101 g_settings_get_boolean (nemo_desktop_preferences, NEMO_PREFERENCES_SHOW_DESKTOP) &&
10102 !g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR);
10103
10104 action = gtk_action_group_get_action (view->details->dir_action_group,
10105 NEMO_ACTION_COPY_TO_HOME);
10106 gtk_action_set_sensitive (action, can_copy_files);
10107
10108 action = gtk_action_group_get_action (view->details->dir_action_group,
10109 NEMO_ACTION_COPY_TO_DESKTOP);
10110 gtk_action_set_sensitive (action, can_copy_files);
10111 gtk_action_set_visible (action, show_desktop_target);
10112
10113 action = gtk_action_group_get_action (view->details->dir_action_group,
10114 NEMO_ACTION_MOVE_TO_HOME);
10115 gtk_action_set_sensitive (action, can_delete_files);
10116 gtk_action_set_visible (action, !selection_contains_recent && !selection_contains_favorites);
10117 action = gtk_action_group_get_action (view->details->dir_action_group,
10118 NEMO_ACTION_MOVE_TO_DESKTOP);
10119 gtk_action_set_sensitive (action, can_delete_files);
10120 gtk_action_set_visible (action, show_desktop_target &&
10121 !selection_contains_recent &&
10122 !selection_contains_favorites);
10123
10124 action = gtk_action_group_get_action (view->details->dir_action_group,
10125 "CopyToMenu");
10126 gtk_action_set_sensitive (action, can_copy_files);
10127
10128 action = gtk_action_group_get_action (view->details->dir_action_group,
10129 "MoveToMenu");
10130 gtk_action_set_sensitive (action, can_delete_files);
10131 gtk_action_set_visible (action, !selection_contains_recent && !selection_contains_favorites);
10132
10133 action = gtk_action_group_get_action (view->details->dir_action_group,
10134 NEMO_ACTION_FOLLOW_SYMLINK);
10135 gtk_action_set_visible (action,
10136 selection_count == 1 &&
10137 nemo_file_is_symbolic_link (selection->data) &&
10138 !selection_contains_favorites);
10139
10140 action = gtk_action_group_get_action (view->details->dir_action_group,
10141 NEMO_ACTION_OPEN_CONTAINING_FOLDER);
10142
10143 gtk_action_set_visible (action,
10144 selection_count == 1 &&
10145 (selection_contains_recent || selection_contains_favorites || showing_search));
10146
10147 first_selected_is_pinned = selection_count > 0 &&
10148 nemo_file_get_pinning (NEMO_FILE (selection->data));
10149
10150 action = gtk_action_group_get_action (view->details->dir_action_group,
10151 NEMO_ACTION_PIN_FILE);
10152
10153 gtk_action_set_visible (action, !is_desktop_view && !first_selected_is_pinned && !(selection_contains_recent || selection_contains_favorites));
10154
10155 action = gtk_action_group_get_action (view->details->dir_action_group,
10156 NEMO_ACTION_UNPIN_FILE);
10157
10158 gtk_action_set_visible (action, !is_desktop_view && first_selected_is_pinned && !(selection_contains_recent || selection_contains_favorites));
10159
10160 action = gtk_action_group_get_action (view->details->dir_action_group,
10161 NEMO_ACTION_FAVORITE_FILE);
10162
10163 gboolean first_selected_is_favorite = selection_count > 0 &&
10164 nemo_file_get_is_favorite (NEMO_FILE (selection->data));
10165
10166 if (selection_contains_favorites) {
10167 gtk_action_set_visible (action, FALSE);
10168 } else {
10169 gtk_action_set_visible (action, !is_desktop_view && !first_selected_is_favorite && !selection_contains_recent);
10170 }
10171
10172 action = gtk_action_group_get_action (view->details->dir_action_group,
10173 NEMO_ACTION_UNFAVORITE_FILE);
10174
10175 if (selection_contains_favorites) {
10176 gtk_action_set_visible (action, TRUE);
10177 } else {
10178 gtk_action_set_visible (action, !is_desktop_view && first_selected_is_favorite && !selection_contains_recent);
10179 }
10180
10181 update_configurable_context_menu_items (view);
10182
10183 nemo_file_list_free (selection);
10184 }
10185
10186 /**
10187 * nemo_view_pop_up_selection_context_menu
10188 *
10189 * Pop up a context menu appropriate to the selected items.
10190 * @view: NemoView of interest.
10191 * @event: The event that triggered this context menu.
10192 *
10193 * Return value: NemoDirectory for this view.
10194 *
10195 **/
10196 void
nemo_view_pop_up_selection_context_menu(NemoView * view,GdkEventButton * event)10197 nemo_view_pop_up_selection_context_menu (NemoView *view,
10198 GdkEventButton *event)
10199 {
10200 g_assert (NEMO_IS_VIEW (view));
10201
10202 /* Make the context menu items not flash as they update to proper disabled,
10203 * etc. states by forcing menus to update now.
10204 */
10205 update_menus_if_pending (view);
10206
10207 update_context_menu_position_from_event (view, event);
10208
10209 eel_pop_up_context_menu (create_popup_menu
10210 (view, NEMO_VIEW_POPUP_PATH_SELECTION),
10211 event);
10212 }
10213
10214 /**
10215 * nemo_view_pop_up_background_context_menu
10216 *
10217 * Pop up a context menu appropriate to the view globally at the last right click location.
10218 * @view: NemoView of interest.
10219 *
10220 * Return value: NemoDirectory for this view.
10221 *
10222 **/
10223 void
nemo_view_pop_up_background_context_menu(NemoView * view,GdkEventButton * event)10224 nemo_view_pop_up_background_context_menu (NemoView *view,
10225 GdkEventButton *event)
10226 {
10227 g_assert (NEMO_IS_VIEW (view));
10228
10229 /* Make the context menu items not flash as they update to proper disabled,
10230 * etc. states by forcing menus to update now.
10231 */
10232 update_menus_if_pending (view);
10233
10234 update_context_menu_position_from_event (view, event);
10235
10236
10237 eel_pop_up_context_menu (create_popup_menu
10238 (view, NEMO_VIEW_POPUP_PATH_BACKGROUND),
10239 event);
10240 }
10241
10242 static void
real_pop_up_location_context_menu(NemoView * view)10243 real_pop_up_location_context_menu (NemoView *view)
10244 {
10245 /* always update the menu before showing it. Shouldn't be too expensive. */
10246 real_update_location_menu (view);
10247
10248 update_context_menu_position_from_event (view, view->details->location_popup_event);
10249
10250 eel_pop_up_context_menu (create_popup_menu
10251 (view, NEMO_VIEW_POPUP_PATH_LOCATION),
10252 view->details->location_popup_event);
10253 }
10254
10255 static void
location_popup_file_attributes_ready(NemoFile * file,gpointer data)10256 location_popup_file_attributes_ready (NemoFile *file,
10257 gpointer data)
10258 {
10259 NemoView *view;
10260
10261 view = NEMO_VIEW (data);
10262 g_assert (NEMO_IS_VIEW (view));
10263
10264 g_assert (file == view->details->location_popup_directory_as_file);
10265
10266 real_pop_up_location_context_menu (view);
10267 }
10268
10269 static void
unschedule_pop_up_location_context_menu(NemoView * view)10270 unschedule_pop_up_location_context_menu (NemoView *view)
10271 {
10272 if (view->details->location_popup_directory_as_file != NULL) {
10273 g_assert (NEMO_IS_FILE (view->details->location_popup_directory_as_file));
10274 nemo_file_cancel_call_when_ready (view->details->location_popup_directory_as_file,
10275 location_popup_file_attributes_ready,
10276 view);
10277 nemo_file_unref (view->details->location_popup_directory_as_file);
10278 view->details->location_popup_directory_as_file = NULL;
10279 }
10280 }
10281
10282 static void
schedule_pop_up_location_context_menu(NemoView * view,GdkEventButton * event,NemoFile * file)10283 schedule_pop_up_location_context_menu (NemoView *view,
10284 GdkEventButton *event,
10285 NemoFile *file)
10286 {
10287 g_assert (NEMO_IS_FILE (file));
10288
10289 if (view->details->location_popup_event != NULL) {
10290 gdk_event_free ((GdkEvent *) view->details->location_popup_event);
10291 }
10292 view->details->location_popup_event = (GdkEventButton *) gdk_event_copy ((GdkEvent *)event);
10293
10294 if (file == view->details->location_popup_directory_as_file) {
10295 if (nemo_file_check_if_ready (file, NEMO_FILE_ATTRIBUTE_INFO |
10296 NEMO_FILE_ATTRIBUTE_MOUNT |
10297 NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO)) {
10298 real_pop_up_location_context_menu (view);
10299 }
10300 } else {
10301 unschedule_pop_up_location_context_menu (view);
10302
10303 view->details->location_popup_directory_as_file = nemo_file_ref (file);
10304 nemo_file_call_when_ready (view->details->location_popup_directory_as_file,
10305 NEMO_FILE_ATTRIBUTE_INFO |
10306 NEMO_FILE_ATTRIBUTE_MOUNT |
10307 NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO,
10308 location_popup_file_attributes_ready,
10309 view);
10310 }
10311 }
10312
10313 /**
10314 * nemo_view_pop_up_location_context_menu
10315 *
10316 * Pop up a context menu appropriate to the view globally.
10317 * @view: NemoView of interest.
10318 * @event: GdkEventButton triggering the popup.
10319 * @location: The location the popup-menu should be created for,
10320 * or NULL for the currently displayed location.
10321 *
10322 **/
10323 void
nemo_view_pop_up_location_context_menu(NemoView * view,GdkEventButton * event,const char * location)10324 nemo_view_pop_up_location_context_menu (NemoView *view,
10325 GdkEventButton *event,
10326 const char *location)
10327 {
10328 NemoFile *file;
10329
10330 g_assert (NEMO_IS_VIEW (view));
10331
10332 if (location != NULL) {
10333 file = nemo_file_get_by_uri (location);
10334 } else {
10335 file = nemo_file_ref (view->details->directory_as_file);
10336 }
10337
10338 if (file != NULL) {
10339 schedule_pop_up_location_context_menu (view, event, file);
10340 nemo_file_unref (file);
10341 }
10342 }
10343
10344 static void
schedule_update_menus(NemoView * view)10345 schedule_update_menus (NemoView *view)
10346 {
10347 g_assert (NEMO_IS_VIEW (view));
10348 /* Don't schedule updates after destroy (#349551),
10349 * or if we are not active.
10350 */
10351 if (view->details->window == NULL ||
10352 !view->details->active) {
10353 return;
10354 }
10355
10356 view->details->menu_states_untrustworthy = TRUE;
10357 /* Schedule a menu update with the current update interval */
10358 if (view->details->update_menus_timeout_id != 0) {
10359 g_source_remove (view->details->update_menus_timeout_id);
10360 view->details->update_menus_timeout_id = 0;
10361 }
10362 view->details->update_menus_timeout_id = g_timeout_add (view->details->update_interval,
10363 update_menus_timeout_callback,
10364 view);
10365 }
10366
10367 static void
remove_update_status_idle_callback(NemoView * view)10368 remove_update_status_idle_callback (NemoView *view)
10369 {
10370 if (view->details->update_status_idle_id != 0) {
10371 g_source_remove (view->details->update_status_idle_id);
10372 view->details->update_status_idle_id = 0;
10373 }
10374 }
10375
10376 static gboolean
update_status_idle_callback(gpointer data)10377 update_status_idle_callback (gpointer data)
10378 {
10379 NemoView *view;
10380
10381 view = NEMO_VIEW (data);
10382 nemo_view_display_selection_info (view);
10383 view->details->update_status_idle_id = 0;
10384 return FALSE;
10385 }
10386
10387 static void
schedule_update_status(NemoView * view)10388 schedule_update_status (NemoView *view)
10389 {
10390 g_assert (NEMO_IS_VIEW (view));
10391
10392 /* Make sure we haven't already destroyed it */
10393 if (view->details->window == NULL) {
10394 return;
10395 }
10396
10397 if (view->details->loading) {
10398 /* Don't update status bar while loading the dir */
10399 return;
10400 }
10401
10402 if (view->details->update_status_idle_id == 0) {
10403 view->details->update_status_idle_id =
10404 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20,
10405 update_status_idle_callback, view, NULL);
10406 }
10407 }
10408
10409 /**
10410 * nemo_view_notify_selection_changed:
10411 *
10412 * Notify this view that the selection has changed. This is normally
10413 * called only by subclasses.
10414 * @view: NemoView whose selection has changed.
10415 *
10416 **/
10417 void
nemo_view_notify_selection_changed(NemoView * view)10418 nemo_view_notify_selection_changed (NemoView *view)
10419 {
10420 GtkWindow *window;
10421 GList *selection;
10422
10423 g_return_if_fail (NEMO_IS_VIEW (view));
10424
10425 selection = nemo_view_get_selection (view);
10426 window = nemo_view_get_containing_window (view);
10427 DEBUG_FILES (selection, "Selection changed in window %p", window);
10428 nemo_file_list_free (selection);
10429
10430 view->details->selection_was_removed = FALSE;
10431
10432 if (!view->details->selection_change_is_due_to_shell) {
10433 view->details->send_selection_change_to_shell = TRUE;
10434 }
10435
10436 /* Schedule a display of the new selection. */
10437 if (view->details->display_selection_idle_id != 0) {
10438 g_source_remove (view->details->display_selection_idle_id);
10439 view->details->display_selection_idle_id = 0;
10440 nemo_window_slot_set_status (view->details->slot, "", "");
10441 }
10442 view->details->display_selection_idle_id = g_timeout_add (100,
10443 display_selection_info_idle_callback,
10444 view);
10445
10446 if (view->details->batching_selection_level != 0) {
10447 view->details->selection_changed_while_batched = TRUE;
10448 } else {
10449 /* Here is the work we do only when we're not
10450 * batching selection changes. In other words, it's the slower
10451 * stuff that we don't want to slow down selection techniques
10452 * such as rubberband-selecting in icon view.
10453 */
10454
10455 /* Schedule an update of menu item states to match selection */
10456 schedule_update_menus (view);
10457 }
10458 }
10459
10460 static void
file_changed_callback(NemoFile * file,gpointer callback_data)10461 file_changed_callback (NemoFile *file, gpointer callback_data)
10462 {
10463 NemoView *view = NEMO_VIEW (callback_data);
10464
10465 schedule_changes (view);
10466
10467 schedule_update_menus (view);
10468 schedule_update_status (view);
10469 }
10470
10471 /**
10472 * load_directory:
10473 *
10474 * Switch the displayed location to a new uri. If the uri is not valid,
10475 * the location will not be switched; user feedback will be provided instead.
10476 * @view: NemoView whose location will be changed.
10477 * @uri: A string representing the uri to switch to.
10478 *
10479 **/
10480 static void
load_directory(NemoView * view,NemoDirectory * directory)10481 load_directory (NemoView *view,
10482 NemoDirectory *directory)
10483 {
10484 NemoDirectory *old_directory;
10485 NemoFile *old_file;
10486 NemoFileAttributes attributes;
10487
10488 g_assert (NEMO_IS_VIEW (view));
10489 g_assert (NEMO_IS_DIRECTORY (directory));
10490
10491 nemo_view_stop_loading (view);
10492 g_signal_emit (view, signals[CLEAR], 0);
10493
10494 view->details->loading = TRUE;
10495
10496 /* Update menus when directory is empty, before going to new
10497 * location, so they won't have any false lingering knowledge
10498 * of old selection.
10499 */
10500 schedule_update_menus (view);
10501
10502 while (view->details->subdirectory_list != NULL) {
10503 nemo_view_remove_subdirectory (view,
10504 view->details->subdirectory_list->data);
10505 }
10506
10507 disconnect_model_handlers (view);
10508
10509 old_directory = view->details->model;
10510 nemo_directory_ref (directory);
10511 view->details->model = directory;
10512 nemo_directory_unref (old_directory);
10513
10514 old_file = view->details->directory_as_file;
10515 view->details->directory_as_file =
10516 nemo_directory_get_corresponding_file (directory);
10517 nemo_file_unref (old_file);
10518
10519 view->details->reported_load_error = FALSE;
10520
10521 /* FIXME bugzilla.gnome.org 45062: In theory, we also need to monitor metadata here (as
10522 * well as doing a call when ready), in case external forces
10523 * change the directory's file metadata.
10524 */
10525 attributes =
10526 NEMO_FILE_ATTRIBUTE_INFO |
10527 NEMO_FILE_ATTRIBUTE_MOUNT |
10528 NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO;
10529 view->details->metadata_for_directory_as_file_pending = TRUE;
10530 view->details->metadata_for_files_in_directory_pending = TRUE;
10531 nemo_file_call_when_ready
10532 (view->details->directory_as_file,
10533 attributes,
10534 metadata_for_directory_as_file_ready_callback, view);
10535 nemo_directory_call_when_ready
10536 (view->details->model,
10537 attributes,
10538 FALSE,
10539 metadata_for_files_in_directory_ready_callback, view);
10540
10541 /* If capabilities change, then we need to update the menus
10542 * because of New Folder, and relative emblems.
10543 */
10544 attributes =
10545 NEMO_FILE_ATTRIBUTE_INFO |
10546 NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO;
10547 nemo_file_monitor_add (view->details->directory_as_file,
10548 &view->details->directory_as_file,
10549 attributes);
10550
10551 view->details->file_changed_handler_id = g_signal_connect
10552 (view->details->directory_as_file, "changed",
10553 G_CALLBACK (file_changed_callback), view);
10554 }
10555
10556 static void
finish_loading(NemoView * view)10557 finish_loading (NemoView *view)
10558 {
10559 NemoFileAttributes attributes;
10560
10561 nemo_window_report_load_underway (view->details->window,
10562 NEMO_VIEW (view));
10563
10564 g_timer_start (view->details->load_timer);
10565
10566 /* Tell interested parties that we've begun loading this directory now.
10567 * Subclasses use this to know that the new metadata is now available.
10568 */
10569 g_signal_emit (view, signals[BEGIN_LOADING], 0);
10570
10571 /* Assume we have now all information to show window */
10572 nemo_window_view_visible (view->details->window, NEMO_VIEW (view));
10573
10574 if (nemo_directory_are_all_files_seen (view->details->model)) {
10575 /* Unschedule a pending update and schedule a new one with the minimal
10576 * update interval. This gives the view a short chance at gathering the
10577 * (cached) deep counts.
10578 */
10579 unschedule_display_of_pending_files (view);
10580 schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN);
10581 }
10582
10583 /* Start loading. */
10584
10585 /* Connect handlers to learn about loading progress. */
10586 view->details->done_loading_handler_id = g_signal_connect
10587 (view->details->model, "done_loading",
10588 G_CALLBACK (done_loading_callback), view);
10589 view->details->load_error_handler_id = g_signal_connect
10590 (view->details->model, "load_error",
10591 G_CALLBACK (load_error_callback), view);
10592
10593 /* Monitor the things needed to get the right icon. Also
10594 * monitor a directory's item count because the "size"
10595 * attribute is based on that, and the file's metadata
10596 * and possible custom name.
10597 */
10598 attributes =
10599 NEMO_FILE_ATTRIBUTES_FOR_ICON |
10600 NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
10601 NEMO_FILE_ATTRIBUTE_INFO |
10602 NEMO_FILE_ATTRIBUTE_LINK_INFO |
10603 NEMO_FILE_ATTRIBUTE_MOUNT |
10604 NEMO_FILE_ATTRIBUTE_EXTENSION_INFO |
10605 NEMO_FILE_ATTRIBUTE_BTIME |
10606 NEMO_FILE_ATTRIBUTE_FAVORITE_CHECK;
10607
10608 nemo_directory_file_monitor_add (view->details->model,
10609 &view->details->model,
10610 view->details->show_hidden_files,
10611 attributes,
10612 files_added_callback, view);
10613
10614 view->details->files_added_handler_id = g_signal_connect
10615 (view->details->model, "files_added",
10616 G_CALLBACK (files_added_callback), view);
10617 view->details->files_changed_handler_id = g_signal_connect
10618 (view->details->model, "files_changed",
10619 G_CALLBACK (files_changed_callback), view);
10620 }
10621
10622 static void
finish_loading_if_all_metadata_loaded(NemoView * view)10623 finish_loading_if_all_metadata_loaded (NemoView *view)
10624 {
10625 if (!view->details->metadata_for_directory_as_file_pending &&
10626 !view->details->metadata_for_files_in_directory_pending) {
10627 finish_loading (view);
10628 }
10629 }
10630
10631 static void
metadata_for_directory_as_file_ready_callback(NemoFile * file,gpointer callback_data)10632 metadata_for_directory_as_file_ready_callback (NemoFile *file,
10633 gpointer callback_data)
10634 {
10635 NemoView *view;
10636
10637 view = callback_data;
10638
10639 g_assert (NEMO_IS_VIEW (view));
10640 g_assert (view->details->directory_as_file == file);
10641 g_assert (view->details->metadata_for_directory_as_file_pending);
10642
10643 view->details->metadata_for_directory_as_file_pending = FALSE;
10644
10645 finish_loading_if_all_metadata_loaded (view);
10646 }
10647
10648 static void
metadata_for_files_in_directory_ready_callback(NemoDirectory * directory,GList * files,gpointer callback_data)10649 metadata_for_files_in_directory_ready_callback (NemoDirectory *directory,
10650 GList *files,
10651 gpointer callback_data)
10652 {
10653 NemoView *view;
10654
10655 view = callback_data;
10656
10657 g_assert (NEMO_IS_VIEW (view));
10658 g_assert (view->details->model == directory);
10659 g_assert (view->details->metadata_for_files_in_directory_pending);
10660
10661 view->details->metadata_for_files_in_directory_pending = FALSE;
10662
10663 finish_loading_if_all_metadata_loaded (view);
10664 }
10665
10666 static void
disconnect_handler(GObject * object,guint * id)10667 disconnect_handler (GObject *object, guint *id)
10668 {
10669 if (*id != 0) {
10670 g_signal_handler_disconnect (object, *id);
10671 *id = 0;
10672 }
10673 }
10674
10675 static void
disconnect_directory_handler(NemoView * view,guint * id)10676 disconnect_directory_handler (NemoView *view, guint *id)
10677 {
10678 disconnect_handler (G_OBJECT (view->details->model), id);
10679 }
10680
10681 static void
disconnect_directory_as_file_handler(NemoView * view,guint * id)10682 disconnect_directory_as_file_handler (NemoView *view, guint *id)
10683 {
10684 disconnect_handler (G_OBJECT (view->details->directory_as_file), id);
10685 }
10686
10687 static void
disconnect_model_handlers(NemoView * view)10688 disconnect_model_handlers (NemoView *view)
10689 {
10690 if (view->details->model == NULL) {
10691 return;
10692 }
10693 disconnect_directory_handler (view, &view->details->files_added_handler_id);
10694 disconnect_directory_handler (view, &view->details->files_changed_handler_id);
10695 disconnect_directory_handler (view, &view->details->done_loading_handler_id);
10696 disconnect_directory_handler (view, &view->details->load_error_handler_id);
10697 disconnect_directory_as_file_handler (view, &view->details->file_changed_handler_id);
10698 nemo_file_cancel_call_when_ready (view->details->directory_as_file,
10699 metadata_for_directory_as_file_ready_callback,
10700 view);
10701 nemo_directory_cancel_callback (view->details->model,
10702 metadata_for_files_in_directory_ready_callback,
10703 view);
10704 nemo_directory_file_monitor_remove (view->details->model,
10705 &view->details->model);
10706 nemo_file_monitor_remove (view->details->directory_as_file,
10707 &view->details->directory_as_file);
10708 }
10709
10710 static void
nemo_view_select_file(NemoView * view,NemoFile * file)10711 nemo_view_select_file (NemoView *view, NemoFile *file)
10712 {
10713 GList file_list;
10714
10715 file_list.data = file;
10716 file_list.next = NULL;
10717 file_list.prev = NULL;
10718 nemo_view_call_set_selection (view, &file_list);
10719 }
10720
10721 /**
10722 * nemo_view_stop_loading:
10723 *
10724 * Stop the current ongoing process, such as switching to a new uri.
10725 * @view: NemoView in question.
10726 *
10727 **/
10728 void
nemo_view_stop_loading(NemoView * view)10729 nemo_view_stop_loading (NemoView *view)
10730 {
10731 g_return_if_fail (NEMO_IS_VIEW (view));
10732
10733 unschedule_display_of_pending_files (view);
10734 reset_update_interval (view);
10735
10736 /* Free extra undisplayed files */
10737 file_and_directory_list_free (view->details->new_added_files);
10738 view->details->new_added_files = NULL;
10739
10740 file_and_directory_list_free (view->details->new_changed_files);
10741 view->details->new_changed_files = NULL;
10742
10743 g_hash_table_remove_all (view->details->non_ready_files);
10744
10745 file_and_directory_list_free (view->details->old_added_files);
10746 view->details->old_added_files = NULL;
10747
10748 file_and_directory_list_free (view->details->old_changed_files);
10749 view->details->old_changed_files = NULL;
10750
10751 g_list_free_full (view->details->pending_selection, g_object_unref);
10752 view->details->pending_selection = NULL;
10753
10754 if (view->details->model != NULL) {
10755 nemo_directory_file_monitor_remove (view->details->model, view);
10756 }
10757 done_loading (view, FALSE);
10758 }
10759
10760 gboolean
nemo_view_is_editable(NemoView * view)10761 nemo_view_is_editable (NemoView *view)
10762 {
10763 NemoDirectory *directory;
10764
10765 directory = nemo_view_get_model (view);
10766
10767 if (directory != NULL) {
10768 return nemo_directory_is_editable (directory);
10769 }
10770
10771 return TRUE;
10772 }
10773
10774 static gboolean
real_is_read_only(NemoView * view)10775 real_is_read_only (NemoView *view)
10776 {
10777 NemoFile *file;
10778
10779 if (showing_recent_directory (view)) {
10780 return TRUE;
10781 }
10782
10783 if (showing_favorites_directory (view)) {
10784 return TRUE;
10785 }
10786
10787 if (!nemo_view_is_editable (view)) {
10788 return TRUE;
10789 }
10790
10791 file = nemo_view_get_directory_as_file (view);
10792
10793 if (file != NULL) {
10794 if (nemo_file_is_in_admin (file)) {
10795 return TRUE;
10796 }
10797
10798 return !nemo_file_can_write (file);
10799 }
10800
10801 return FALSE;
10802 }
10803
10804 /**
10805 * nemo_view_should_show_file
10806 *
10807 * Returns whether or not this file should be displayed based on
10808 * current filtering options.
10809 */
10810 gboolean
nemo_view_should_show_file(NemoView * view,NemoFile * file)10811 nemo_view_should_show_file (NemoView *view, NemoFile *file)
10812 {
10813 return nemo_file_should_show (file,
10814 view->details->show_hidden_files,
10815 view->details->show_foreign_files);
10816 }
10817
10818 static gboolean
real_using_manual_layout(NemoView * view)10819 real_using_manual_layout (NemoView *view)
10820 {
10821 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
10822
10823 return FALSE;
10824 }
10825
10826 static void
schedule_update_menus_callback(gpointer callback_data)10827 schedule_update_menus_callback (gpointer callback_data)
10828 {
10829 schedule_update_menus (NEMO_VIEW (callback_data));
10830 }
10831
10832 void
nemo_view_ignore_hidden_file_preferences(NemoView * view)10833 nemo_view_ignore_hidden_file_preferences (NemoView *view)
10834 {
10835 g_return_if_fail (view->details->model == NULL);
10836
10837 if (view->details->ignore_hidden_file_preferences) {
10838 return;
10839 }
10840
10841 view->details->show_hidden_files = FALSE;
10842 view->details->ignore_hidden_file_preferences = TRUE;
10843 }
10844
10845 void
nemo_view_set_show_foreign(NemoView * view,gboolean show_foreign)10846 nemo_view_set_show_foreign (NemoView *view,
10847 gboolean show_foreign)
10848 {
10849 view->details->show_foreign_files = show_foreign;
10850 }
10851
10852 char *
nemo_view_get_uri(NemoView * view)10853 nemo_view_get_uri (NemoView *view)
10854 {
10855 g_return_val_if_fail (NEMO_IS_VIEW (view), NULL);
10856 if (view->details->model == NULL) {
10857 return NULL;
10858 }
10859 return nemo_directory_get_uri (view->details->model);
10860 }
10861
10862 void
nemo_view_move_copy_items(NemoView * view,const GList * item_uris,GArray * relative_item_points,const char * target_uri,int copy_action,int x,int y)10863 nemo_view_move_copy_items (NemoView *view,
10864 const GList *item_uris,
10865 GArray *relative_item_points,
10866 const char *target_uri,
10867 int copy_action,
10868 int x, int y)
10869 {
10870 NemoFile *target_file;
10871
10872 g_assert (relative_item_points == NULL
10873 || relative_item_points->len == 0
10874 || g_list_length ((GList *)item_uris) == relative_item_points->len);
10875
10876 /* add the drop location to the icon offsets */
10877 offset_drop_points (relative_item_points, x, y);
10878
10879 target_file = nemo_file_get_existing_by_uri (target_uri);
10880 /* special-case "command:" here instead of starting a move/copy */
10881 if (target_file != NULL && nemo_file_is_launcher (target_file)) {
10882 nemo_file_unref (target_file);
10883 nemo_launch_desktop_file (
10884 gtk_widget_get_screen (GTK_WIDGET (view)),
10885 target_uri, item_uris,
10886 nemo_view_get_containing_window (view));
10887 return;
10888 } else if (copy_action == GDK_ACTION_COPY &&
10889 nemo_is_file_roller_installed () &&
10890 target_file != NULL &&
10891 nemo_file_is_archive (target_file)) {
10892 char *command, *quoted_uri, *unescaped, *tmp;
10893 const GList *l;
10894 GdkScreen *screen;
10895
10896 /* Handle dropping onto a file-roller archiver file, instead of starting a move/copy */
10897
10898 nemo_file_unref (target_file);
10899
10900 unescaped = g_uri_unescape_string (target_uri, "");
10901 quoted_uri = g_shell_quote (unescaped);
10902
10903 command = g_strconcat ("file-roller -a ", quoted_uri, NULL);
10904
10905 g_clear_pointer ("ed_uri, g_free);
10906 g_clear_pointer (&unescaped, g_free);
10907
10908 for (l = item_uris; l != NULL; l = l->next) {
10909 unescaped = g_uri_unescape_string ((char *) l->data, "");
10910 quoted_uri = g_shell_quote (unescaped);
10911
10912 tmp = g_strconcat (command, " ", quoted_uri, NULL);
10913 g_free (command);
10914 command = tmp;
10915
10916 g_clear_pointer ("ed_uri, g_free);
10917 g_clear_pointer (&unescaped, g_free);
10918 }
10919
10920 screen = gtk_widget_get_screen (GTK_WIDGET (view));
10921 if (screen == NULL) {
10922 screen = gdk_screen_get_default ();
10923 }
10924
10925 nemo_launch_application_from_command (screen, command, FALSE, NULL);
10926 g_free (command);
10927
10928 return;
10929 }
10930 nemo_file_unref (target_file);
10931
10932 nemo_file_operations_copy_move
10933 (item_uris, relative_item_points,
10934 target_uri, copy_action, GTK_WIDGET (view),
10935 copy_move_done_callback, pre_copy_move (view));
10936 }
10937
10938 static void
nemo_view_trash_state_changed_callback(NemoTrashMonitor * trash_monitor,gboolean state,gpointer callback_data)10939 nemo_view_trash_state_changed_callback (NemoTrashMonitor *trash_monitor,
10940 gboolean state, gpointer callback_data)
10941 {
10942 NemoView *view;
10943
10944 view = (NemoView *) callback_data;
10945 g_assert (NEMO_IS_VIEW (view));
10946
10947 schedule_update_menus (view);
10948 }
10949
10950 void
nemo_view_start_batching_selection_changes(NemoView * view)10951 nemo_view_start_batching_selection_changes (NemoView *view)
10952 {
10953 g_return_if_fail (NEMO_IS_VIEW (view));
10954
10955 ++view->details->batching_selection_level;
10956 view->details->selection_changed_while_batched = FALSE;
10957 }
10958
10959 void
nemo_view_stop_batching_selection_changes(NemoView * view)10960 nemo_view_stop_batching_selection_changes (NemoView *view)
10961 {
10962 g_return_if_fail (NEMO_IS_VIEW (view));
10963 g_return_if_fail (view->details->batching_selection_level > 0);
10964
10965 if (--view->details->batching_selection_level == 0) {
10966 if (view->details->selection_changed_while_batched) {
10967 nemo_view_notify_selection_changed (view);
10968 }
10969 }
10970 }
10971
10972 gboolean
nemo_view_get_active(NemoView * view)10973 nemo_view_get_active (NemoView *view)
10974 {
10975 g_assert (NEMO_IS_VIEW (view));
10976 return view->details->active;
10977 }
10978
10979 static GArray *
real_get_selected_icon_locations(NemoView * view)10980 real_get_selected_icon_locations (NemoView *view)
10981 {
10982 /* By default, just return an empty list. */
10983 return g_array_new (FALSE, TRUE, sizeof (GdkPoint));
10984 }
10985
10986 static void
nemo_view_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)10987 nemo_view_set_property (GObject *object,
10988 guint prop_id,
10989 const GValue *value,
10990 GParamSpec *pspec)
10991 {
10992 NemoView *directory_view;
10993 NemoWindowSlot *slot;
10994 NemoWindow *window;
10995
10996 directory_view = NEMO_VIEW (object);
10997
10998 switch (prop_id) {
10999 case PROP_WINDOW_SLOT:
11000 g_assert (directory_view->details->slot == NULL);
11001
11002 slot = NEMO_WINDOW_SLOT (g_value_get_object (value));
11003 window = nemo_window_slot_get_window (slot);
11004
11005 directory_view->details->slot = slot;
11006 directory_view->details->window = window;
11007
11008 g_signal_connect_object (directory_view->details->slot,
11009 "active", G_CALLBACK (slot_active),
11010 directory_view, 0);
11011 g_signal_connect_object (directory_view->details->slot,
11012 "inactive", G_CALLBACK (slot_inactive),
11013 directory_view, 0);
11014 g_signal_connect_object (directory_view->details->slot,
11015 "changed-pane", G_CALLBACK (slot_changed_pane),
11016 directory_view, 0);
11017
11018 g_signal_connect_object (directory_view->details->window,
11019 "hidden-files-mode-changed", G_CALLBACK (hidden_files_mode_changed),
11020 directory_view, 0);
11021 nemo_view_init_show_hidden_files (directory_view);
11022 break;
11023 case PROP_SUPPORTS_ZOOMING:
11024 directory_view->details->supports_zooming = g_value_get_boolean (value);
11025 break;
11026 default:
11027 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
11028 break;
11029 }
11030 }
11031
11032
11033 gboolean
nemo_view_handle_scroll_event(NemoView * directory_view,GdkEventScroll * event)11034 nemo_view_handle_scroll_event (NemoView *directory_view,
11035 GdkEventScroll *event)
11036 {
11037 static gdouble total_delta_y = 0;
11038 gdouble delta_x, delta_y;
11039
11040 if (event->state & GDK_CONTROL_MASK) {
11041 switch (event->direction) {
11042 case GDK_SCROLL_UP:
11043 /* Zoom In */
11044 nemo_view_bump_zoom_level (directory_view, 1);
11045 return TRUE;
11046
11047 case GDK_SCROLL_DOWN:
11048 /* Zoom Out */
11049 nemo_view_bump_zoom_level (directory_view, -1);
11050 return TRUE;
11051
11052 case GDK_SCROLL_SMOOTH:
11053 gdk_event_get_scroll_deltas ((const GdkEvent *) event,
11054 &delta_x, &delta_y);
11055
11056 /* try to emulate a normal scrolling event by summing deltas */
11057 total_delta_y += delta_y;
11058
11059 if (total_delta_y >= 1) {
11060 total_delta_y = 0;
11061 /* emulate scroll down */
11062 nemo_view_bump_zoom_level (directory_view, -1);
11063 return TRUE;
11064 } else if (total_delta_y <= - 1) {
11065 total_delta_y = 0;
11066 /* emulate scroll up */
11067 nemo_view_bump_zoom_level (directory_view, 1);
11068 return TRUE;
11069 } else {
11070 /* eat event */
11071 return TRUE;
11072 }
11073
11074 case GDK_SCROLL_LEFT:
11075 case GDK_SCROLL_RIGHT:
11076 break;
11077
11078 default:
11079 g_assert_not_reached ();
11080 }
11081 }
11082
11083 return FALSE;
11084 }
11085
11086 /* handle Shift+Scroll, which will cause a zoom-in/out */
11087 static gboolean
nemo_view_scroll_event(GtkWidget * widget,GdkEventScroll * event)11088 nemo_view_scroll_event (GtkWidget *widget,
11089 GdkEventScroll *event)
11090 {
11091 NemoView *directory_view;
11092
11093 directory_view = NEMO_VIEW (widget);
11094 if (!get_is_desktop_view (directory_view) &&
11095 nemo_view_handle_scroll_event (directory_view, event)) {
11096 return TRUE;
11097 }
11098
11099 return GTK_WIDGET_CLASS (parent_class)->scroll_event (widget, event);
11100 }
11101
11102
11103 static void
nemo_view_parent_set(GtkWidget * widget,GtkWidget * old_parent)11104 nemo_view_parent_set (GtkWidget *widget,
11105 GtkWidget *old_parent)
11106 {
11107 NemoView *view;
11108 GtkWidget *parent;
11109
11110 view = NEMO_VIEW (widget);
11111
11112 parent = gtk_widget_get_parent (widget);
11113 g_assert (parent == NULL || old_parent == NULL);
11114
11115 if (GTK_WIDGET_CLASS (parent_class)->parent_set != NULL) {
11116 GTK_WIDGET_CLASS (parent_class)->parent_set (widget, old_parent);
11117 }
11118
11119 if (parent != NULL) {
11120 g_assert (old_parent == NULL);
11121
11122 if (view->details->slot ==
11123 nemo_window_get_active_slot (view->details->window)) {
11124 view->details->active = TRUE;
11125
11126 nemo_view_merge_menus (view);
11127 schedule_update_menus (view);
11128 }
11129 } else {
11130 nemo_view_unmerge_menus (view);
11131 remove_update_menus_timeout_callback (view);
11132 }
11133 }
11134
11135 static void
nemo_view_class_init(NemoViewClass * klass)11136 nemo_view_class_init (NemoViewClass *klass)
11137 {
11138 GObjectClass *oclass;
11139 GtkWidgetClass *widget_class;
11140 GtkScrolledWindowClass *scrolled_window_class;
11141 GtkBindingSet *binding_set;
11142
11143 widget_class = GTK_WIDGET_CLASS (klass);
11144 scrolled_window_class = GTK_SCROLLED_WINDOW_CLASS (klass);
11145 oclass = G_OBJECT_CLASS (klass);
11146
11147 oclass->finalize = nemo_view_finalize;
11148 oclass->set_property = nemo_view_set_property;
11149
11150 widget_class->destroy = nemo_view_destroy;
11151 widget_class->scroll_event = nemo_view_scroll_event;
11152 widget_class->parent_set = nemo_view_parent_set;
11153
11154 g_type_class_add_private (klass, sizeof (NemoViewDetails));
11155
11156 /* Get rid of the strange 3-pixel gap that GtkScrolledWindow
11157 * uses by default. It does us no good.
11158 */
11159 scrolled_window_class->scrollbar_spacing = 0;
11160
11161 signals[ADD_FILE] =
11162 g_signal_new ("add_file",
11163 G_TYPE_FROM_CLASS (klass),
11164 G_SIGNAL_RUN_LAST,
11165 G_STRUCT_OFFSET (NemoViewClass, add_file),
11166 NULL, NULL,
11167 g_cclosure_marshal_generic,
11168 G_TYPE_NONE, 2, NEMO_TYPE_FILE, NEMO_TYPE_DIRECTORY);
11169 signals[BEGIN_FILE_CHANGES] =
11170 g_signal_new ("begin_file_changes",
11171 G_TYPE_FROM_CLASS (klass),
11172 G_SIGNAL_RUN_LAST,
11173 G_STRUCT_OFFSET (NemoViewClass, begin_file_changes),
11174 NULL, NULL,
11175 g_cclosure_marshal_VOID__VOID,
11176 G_TYPE_NONE, 0);
11177 signals[BEGIN_LOADING] =
11178 g_signal_new ("begin_loading",
11179 G_TYPE_FROM_CLASS (klass),
11180 G_SIGNAL_RUN_LAST,
11181 G_STRUCT_OFFSET (NemoViewClass, begin_loading),
11182 NULL, NULL,
11183 g_cclosure_marshal_VOID__VOID,
11184 G_TYPE_NONE, 0);
11185 signals[CLEAR] =
11186 g_signal_new ("clear",
11187 G_TYPE_FROM_CLASS (klass),
11188 G_SIGNAL_RUN_LAST,
11189 G_STRUCT_OFFSET (NemoViewClass, clear),
11190 NULL, NULL,
11191 g_cclosure_marshal_VOID__VOID,
11192 G_TYPE_NONE, 0);
11193 signals[END_FILE_CHANGES] =
11194 g_signal_new ("end_file_changes",
11195 G_TYPE_FROM_CLASS (klass),
11196 G_SIGNAL_RUN_LAST,
11197 G_STRUCT_OFFSET (NemoViewClass, end_file_changes),
11198 NULL, NULL,
11199 g_cclosure_marshal_VOID__VOID,
11200 G_TYPE_NONE, 0);
11201 signals[END_LOADING] =
11202 g_signal_new ("end_loading",
11203 G_TYPE_FROM_CLASS (klass),
11204 G_SIGNAL_RUN_LAST,
11205 G_STRUCT_OFFSET (NemoViewClass, end_loading),
11206 NULL, NULL,
11207 g_cclosure_marshal_VOID__BOOLEAN,
11208 G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
11209 signals[FILE_CHANGED] =
11210 g_signal_new ("file_changed",
11211 G_TYPE_FROM_CLASS (klass),
11212 G_SIGNAL_RUN_LAST,
11213 G_STRUCT_OFFSET (NemoViewClass, file_changed),
11214 NULL, NULL,
11215 g_cclosure_marshal_generic,
11216 G_TYPE_NONE, 2, NEMO_TYPE_FILE, NEMO_TYPE_DIRECTORY);
11217 signals[LOAD_ERROR] =
11218 g_signal_new ("load_error",
11219 G_TYPE_FROM_CLASS (klass),
11220 G_SIGNAL_RUN_LAST,
11221 G_STRUCT_OFFSET (NemoViewClass, load_error),
11222 NULL, NULL,
11223 g_cclosure_marshal_VOID__POINTER,
11224 G_TYPE_NONE, 1, G_TYPE_POINTER);
11225 signals[REMOVE_FILE] =
11226 g_signal_new ("remove_file",
11227 G_TYPE_FROM_CLASS (klass),
11228 G_SIGNAL_RUN_LAST,
11229 G_STRUCT_OFFSET (NemoViewClass, remove_file),
11230 NULL, NULL,
11231 g_cclosure_marshal_generic,
11232 G_TYPE_NONE, 2, NEMO_TYPE_FILE, NEMO_TYPE_DIRECTORY);
11233 signals[ZOOM_LEVEL_CHANGED] =
11234 g_signal_new ("zoom-level-changed",
11235 G_TYPE_FROM_CLASS (klass),
11236 G_SIGNAL_RUN_LAST,
11237 0, NULL, NULL,
11238 g_cclosure_marshal_VOID__VOID,
11239 G_TYPE_NONE, 0);
11240 signals[SELECTION_CHANGED] =
11241 g_signal_new ("selection-changed",
11242 G_TYPE_FROM_CLASS (klass),
11243 G_SIGNAL_RUN_LAST,
11244 0,
11245 NULL, NULL,
11246 g_cclosure_marshal_VOID__VOID,
11247 G_TYPE_NONE, 0);
11248 signals[TRASH] =
11249 g_signal_new ("trash",
11250 G_TYPE_FROM_CLASS (klass),
11251 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
11252 G_STRUCT_OFFSET (NemoViewClass, trash),
11253 g_signal_accumulator_true_handled, NULL,
11254 g_cclosure_marshal_generic,
11255 G_TYPE_BOOLEAN, 0);
11256 signals[DELETE] =
11257 g_signal_new ("delete",
11258 G_TYPE_FROM_CLASS (klass),
11259 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
11260 G_STRUCT_OFFSET (NemoViewClass, delete),
11261 g_signal_accumulator_true_handled, NULL,
11262 g_cclosure_marshal_generic,
11263 G_TYPE_BOOLEAN, 0);
11264
11265 klass->get_selected_icon_locations = real_get_selected_icon_locations;
11266 klass->is_read_only = real_is_read_only;
11267 klass->load_error = real_load_error;
11268 klass->can_rename_file = can_rename_file;
11269 klass->start_renaming_file = start_renaming_file;
11270 klass->get_backing_uri = real_get_backing_uri;
11271 klass->using_manual_layout = real_using_manual_layout;
11272 klass->merge_menus = real_merge_menus;
11273 klass->unmerge_menus = real_unmerge_menus;
11274 klass->update_menus = real_update_menus;
11275 klass->trash = real_trash;
11276 klass->delete = real_delete;
11277
11278 copied_files_atom = gdk_atom_intern ("x-special/gnome-copied-files", FALSE);
11279
11280 properties[PROP_WINDOW_SLOT] =
11281 g_param_spec_object ("window-slot",
11282 "Window Slot",
11283 "The parent window slot reference",
11284 NEMO_TYPE_WINDOW_SLOT,
11285 G_PARAM_WRITABLE |
11286 G_PARAM_CONSTRUCT_ONLY);
11287 properties[PROP_SUPPORTS_ZOOMING] =
11288 g_param_spec_boolean ("supports-zooming",
11289 "Supports zooming",
11290 "Whether the view supports zooming",
11291 TRUE,
11292 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
11293 G_PARAM_STATIC_STRINGS);
11294
11295 g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
11296
11297 binding_set = gtk_binding_set_by_class (klass);
11298
11299 gboolean swap_keys = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SWAP_TRASH_DELETE);
11300
11301 if (swap_keys) {
11302 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0,
11303 "delete", 0);
11304 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0,
11305 "delete", 0);
11306 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK,
11307 "trash", 0);
11308 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK,
11309 "trash", 0);
11310 } else {
11311 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0,
11312 "trash", 0);
11313 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0,
11314 "trash", 0);
11315 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK,
11316 "delete", 0);
11317 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK,
11318 "delete", 0);
11319 }
11320 }
11321