No issues found
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* fm-canvas-view.c - implementation of canvas view of directory.
4
5 Copyright (C) 2000, 2001 Eazel, Inc.
6
7 The Gnome Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 The Gnome Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with the Gnome Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
21
22 Authors: John Sullivan <sullivan@eazel.com>
23 */
24
25 #include <config.h>
26
27 #include "nautilus-canvas-view.h"
28
29 #include "nautilus-actions.h"
30 #include "nautilus-canvas-view-container.h"
31 #include "nautilus-desktop-canvas-view.h"
32 #include "nautilus-error-reporting.h"
33 #include "nautilus-view-dnd.h"
34 #include "nautilus-view-factory.h"
35
36 #include <stdlib.h>
37 #include <eel/eel-vfs-extensions.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <gtk/gtk.h>
41 #include <glib/gi18n.h>
42 #include <gio/gio.h>
43 #include <libnautilus-private/nautilus-clipboard-monitor.h>
44 #include <libnautilus-private/nautilus-directory.h>
45 #include <libnautilus-private/nautilus-dnd.h>
46 #include <libnautilus-private/nautilus-file-dnd.h>
47 #include <libnautilus-private/nautilus-file-utilities.h>
48 #include <libnautilus-private/nautilus-ui-utilities.h>
49 #include <libnautilus-private/nautilus-global-preferences.h>
50 #include <libnautilus-private/nautilus-canvas-container.h>
51 #include <libnautilus-private/nautilus-canvas-dnd.h>
52 #include <libnautilus-private/nautilus-link.h>
53 #include <libnautilus-private/nautilus-metadata.h>
54 #include <libnautilus-private/nautilus-clipboard.h>
55 #include <libnautilus-private/nautilus-desktop-icon-file.h>
56
57 #define DEBUG_FLAG NAUTILUS_DEBUG_CANVAS_VIEW
58 #include <libnautilus-private/nautilus-debug.h>
59
60 #include <locale.h>
61 #include <signal.h>
62 #include <stdio.h>
63 #include <sys/types.h>
64 #include <sys/wait.h>
65 #include <unistd.h>
66
67 enum
68 {
69 PROP_SUPPORTS_AUTO_LAYOUT = 1,
70 PROP_SUPPORTS_SCALING,
71 PROP_SUPPORTS_KEEP_ALIGNED,
72 PROP_SUPPORTS_MANUAL_LAYOUT,
73 NUM_PROPERTIES
74 };
75
76 static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
77
78 typedef struct {
79 const NautilusFileSortType sort_type;
80 const char *metadata_text;
81 const char *action;
82 } SortCriterion;
83
84 typedef enum {
85 MENU_ITEM_TYPE_STANDARD,
86 MENU_ITEM_TYPE_CHECK,
87 MENU_ITEM_TYPE_RADIO,
88 MENU_ITEM_TYPE_TREE
89 } MenuItemType;
90
91 struct NautilusCanvasViewDetails
92 {
93 GList *icons_not_positioned;
94
95 guint react_to_canvas_change_idle_id;
96
97 const SortCriterion *sort;
98 gboolean sort_reversed;
99
100 GtkActionGroup *canvas_action_group;
101 guint canvas_merge_id;
102
103 gboolean filter_by_screen;
104 int num_screens;
105
106 gulong clipboard_handler_id;
107
108 GtkWidget *canvas_container;
109
110 gboolean supports_auto_layout;
111 gboolean supports_manual_layout;
112 gboolean supports_scaling;
113 gboolean supports_keep_aligned;
114 };
115
116
117 /* Note that the first item in this list is the default sort,
118 * and that the items show up in the menu in the order they
119 * appear in this list.
120 */
121 static const SortCriterion sort_criteria[] = {
122 {
123 NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
124 "name",
125 "Sort by Name"
126 },
127 {
128 NAUTILUS_FILE_SORT_BY_SIZE,
129 "size",
130 "Sort by Size"
131 },
132 {
133 NAUTILUS_FILE_SORT_BY_TYPE,
134 "type",
135 "Sort by Type"
136 },
137 {
138 NAUTILUS_FILE_SORT_BY_MTIME,
139 "modification date",
140 "Sort by Modification Date"
141 },
142 {
143 NAUTILUS_FILE_SORT_BY_TRASHED_TIME,
144 "trashed",
145 NAUTILUS_ACTION_SORT_TRASH_TIME
146 },
147 {
148 NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE,
149 NULL,
150 NAUTILUS_ACTION_SORT_SEARCH_RELEVANCE,
151 }
152 };
153
154 static void nautilus_canvas_view_set_directory_sort_by (NautilusCanvasView *canvas_view,
155 NautilusFile *file,
156 const char *sort_by);
157 static void nautilus_canvas_view_set_zoom_level (NautilusCanvasView *view,
158 NautilusZoomLevel new_level,
159 gboolean always_emit);
160 static void nautilus_canvas_view_update_click_mode (NautilusCanvasView *canvas_view);
161 static gboolean nautilus_canvas_view_supports_scaling (NautilusCanvasView *canvas_view);
162 static void nautilus_canvas_view_reveal_selection (NautilusView *view);
163 static const SortCriterion *get_sort_criterion_by_sort_type (NautilusFileSortType sort_type);
164 static void set_sort_criterion_by_sort_type (NautilusCanvasView *canvas_view,
165 NautilusFileSortType sort_type);
166 static gboolean set_sort_reversed (NautilusCanvasView *canvas_view,
167 gboolean new_value,
168 gboolean set_metadata);
169 static void switch_to_manual_layout (NautilusCanvasView *view);
170 static void update_layout_menus (NautilusCanvasView *view);
171 static NautilusFileSortType get_default_sort_order (NautilusFile *file,
172 gboolean *reversed);
173 static void nautilus_canvas_view_clear (NautilusView *view);
174
175 G_DEFINE_TYPE (NautilusCanvasView, nautilus_canvas_view, NAUTILUS_TYPE_VIEW);
176
177 static void
178 nautilus_canvas_view_destroy (GtkWidget *object)
179 {
180 NautilusCanvasView *canvas_view;
181
182 canvas_view = NAUTILUS_CANVAS_VIEW (object);
183
184 nautilus_canvas_view_clear (NAUTILUS_VIEW (object));
185
186 if (canvas_view->details->react_to_canvas_change_idle_id != 0) {
187 g_source_remove (canvas_view->details->react_to_canvas_change_idle_id);
188 canvas_view->details->react_to_canvas_change_idle_id = 0;
189 }
190
191 if (canvas_view->details->clipboard_handler_id != 0) {
192 g_signal_handler_disconnect (nautilus_clipboard_monitor_get (),
193 canvas_view->details->clipboard_handler_id);
194 canvas_view->details->clipboard_handler_id = 0;
195 }
196
197 if (canvas_view->details->icons_not_positioned) {
198 nautilus_file_list_free (canvas_view->details->icons_not_positioned);
199 canvas_view->details->icons_not_positioned = NULL;
200 }
201
202 GTK_WIDGET_CLASS (nautilus_canvas_view_parent_class)->destroy (object);
203 }
204
205 static NautilusCanvasContainer *
206 get_canvas_container (NautilusCanvasView *canvas_view)
207 {
208 return NAUTILUS_CANVAS_CONTAINER (canvas_view->details->canvas_container);
209 }
210
211 NautilusCanvasContainer *
212 nautilus_canvas_view_get_canvas_container (NautilusCanvasView *canvas_view)
213 {
214 return get_canvas_container (canvas_view);
215 }
216
217 static gboolean
218 nautilus_canvas_view_supports_manual_layout (NautilusCanvasView *view)
219 {
220 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), FALSE);
221
222 return view->details->supports_manual_layout;
223 }
224
225 static gboolean
226 get_stored_icon_position_callback (NautilusCanvasContainer *container,
227 NautilusFile *file,
228 NautilusCanvasPosition *position,
229 NautilusCanvasView *canvas_view)
230 {
231 char *position_string, *scale_string;
232 gboolean position_good;
233 char c;
234
235 g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
236 g_assert (NAUTILUS_IS_FILE (file));
237 g_assert (position != NULL);
238 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
239
240 if (!nautilus_canvas_view_supports_manual_layout (canvas_view)) {
241 return FALSE;
242 }
243
244 /* Get the current position of this canvas from the metadata. */
245 position_string = nautilus_file_get_metadata
246 (file, NAUTILUS_METADATA_KEY_ICON_POSITION, "");
247 position_good = sscanf
248 (position_string, " %d , %d %c",
249 &position->x, &position->y, &c) == 2;
250 g_free (position_string);
251
252 /* If it is the desktop directory, maybe the gnome-libs metadata has information about it */
253
254 /* Disable scaling if not on the desktop */
255 if (nautilus_canvas_view_supports_scaling (canvas_view)) {
256 /* Get the scale of the canvas from the metadata. */
257 scale_string = nautilus_file_get_metadata
258 (file, NAUTILUS_METADATA_KEY_ICON_SCALE, "1");
259 position->scale = g_ascii_strtod (scale_string, NULL);
260 if (errno != 0) {
261 position->scale = 1.0;
262 }
263
264 g_free (scale_string);
265 } else {
266 position->scale = 1.0;
267 }
268
269 return position_good;
270 }
271
272 static void
273 real_set_sort_criterion (NautilusCanvasView *canvas_view,
274 const SortCriterion *sort,
275 gboolean clear,
276 gboolean set_metadata)
277 {
278 NautilusFile *file;
279
280 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (canvas_view));
281
282 if (clear) {
283 nautilus_file_set_metadata (file,
284 NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY, NULL, NULL);
285 nautilus_file_set_metadata (file,
286 NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED, NULL, NULL);
287 canvas_view->details->sort =
288 get_sort_criterion_by_sort_type (get_default_sort_order
289 (file, &canvas_view->details->sort_reversed));
290 } else if (set_metadata) {
291 /* Store the new sort setting. */
292 nautilus_canvas_view_set_directory_sort_by (canvas_view,
293 file,
294 sort->metadata_text);
295 }
296
297 /* Update the layout menus to match the new sort setting. */
298 update_layout_menus (canvas_view);
299 }
300
301 static void
302 set_sort_criterion (NautilusCanvasView *canvas_view,
303 const SortCriterion *sort,
304 gboolean set_metadata)
305 {
306 if (sort == NULL ||
307 canvas_view->details->sort == sort) {
308 return;
309 }
310
311 canvas_view->details->sort = sort;
312
313 real_set_sort_criterion (canvas_view, sort, FALSE, set_metadata);
314 }
315
316 static void
317 clear_sort_criterion (NautilusCanvasView *canvas_view)
318 {
319 real_set_sort_criterion (canvas_view, NULL, TRUE, TRUE);
320 }
321
322 void
323 nautilus_canvas_view_clean_up_by_name (NautilusCanvasView *canvas_view)
324 {
325 NautilusCanvasContainer *canvas_container;
326 gboolean saved_sort_reversed;
327
328 canvas_container = get_canvas_container (canvas_view);
329
330 /* Hardwire Clean Up to always be by name, in forward order */
331 saved_sort_reversed = canvas_view->details->sort_reversed;
332
333 set_sort_reversed (canvas_view, FALSE, FALSE);
334 set_sort_criterion (canvas_view, &sort_criteria[0], FALSE);
335
336 nautilus_canvas_container_sort (canvas_container);
337 nautilus_canvas_container_freeze_icon_positions (canvas_container);
338
339 set_sort_reversed (canvas_view, saved_sort_reversed, FALSE);
340 }
341
342 static gboolean
343 nautilus_canvas_view_using_auto_layout (NautilusCanvasView *canvas_view)
344 {
345 return nautilus_canvas_container_is_auto_layout
346 (get_canvas_container (canvas_view));
347 }
348
349 static void
350 action_sort_radio_callback (GtkAction *action,
351 GtkRadioAction *current,
352 NautilusCanvasView *view)
353 {
354 NautilusFileSortType sort_type;
355
356 sort_type = gtk_radio_action_get_current_value (current);
357
358 /* Note that id might be a toggle item.
359 * Ignore non-sort ids so that they don't cause sorting.
360 */
361 if (sort_type == NAUTILUS_FILE_SORT_NONE) {
362 switch_to_manual_layout (view);
363 } else {
364 set_sort_criterion_by_sort_type (view, sort_type);
365 }
366 }
367
368 static void
369 list_covers (NautilusCanvasIconData *data, gpointer callback_data)
370 {
371 GSList **file_list;
372
373 file_list = callback_data;
374
375 *file_list = g_slist_prepend (*file_list, data);
376 }
377
378 static void
379 unref_cover (NautilusCanvasIconData *data, gpointer callback_data)
380 {
381 nautilus_file_unref (NAUTILUS_FILE (data));
382 }
383
384 static void
385 nautilus_canvas_view_clear (NautilusView *view)
386 {
387 NautilusCanvasContainer *canvas_container;
388 GSList *file_list;
389
390 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
391
392 canvas_container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view));
393 if (!canvas_container)
394 return;
395
396 /* Clear away the existing icons. */
397 file_list = NULL;
398 nautilus_canvas_container_for_each (canvas_container, list_covers, &file_list);
399 nautilus_canvas_container_clear (canvas_container);
400 g_slist_foreach (file_list, (GFunc)unref_cover, NULL);
401 g_slist_free (file_list);
402 }
403
404 static gboolean
405 should_show_file_on_screen (NautilusView *view, NautilusFile *file)
406 {
407 char *screen_string;
408 int screen_num;
409 NautilusCanvasView *canvas_view;
410 GdkScreen *screen;
411
412 canvas_view = NAUTILUS_CANVAS_VIEW (view);
413
414 if (!nautilus_view_should_show_file (view, file)) {
415 return FALSE;
416 }
417
418 /* Get the screen for this canvas from the metadata. */
419 screen_string = nautilus_file_get_metadata
420 (file, NAUTILUS_METADATA_KEY_SCREEN, "0");
421 screen_num = atoi (screen_string);
422 g_free (screen_string);
423 screen = gtk_widget_get_screen (GTK_WIDGET (view));
424
425 if (screen_num != gdk_screen_get_number (screen) &&
426 (screen_num < canvas_view->details->num_screens ||
427 gdk_screen_get_number (screen) > 0)) {
428 return FALSE;
429 }
430
431 return TRUE;
432 }
433
434 static void
435 nautilus_canvas_view_remove_file (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
436 {
437 NautilusCanvasView *canvas_view;
438
439 /* This used to assert that 'directory == nautilus_view_get_model (view)', but that
440 * resulted in a lot of crash reports (bug #352592). I don't see how that trace happens.
441 * It seems that somehow we get a files_changed event sent to the view from a directory
442 * that isn't the model, but the code disables the monitor and signal callback handlers when
443 * changing directories. Maybe we can get some more information when this happens.
444 * Further discussion in bug #368178.
445 */
446 if (directory != nautilus_view_get_model (view)) {
447 char *file_uri, *dir_uri, *model_uri;
448 file_uri = nautilus_file_get_uri (file);
449 dir_uri = nautilus_directory_get_uri (directory);
450 model_uri = nautilus_directory_get_uri (nautilus_view_get_model (view));
451 g_warning ("nautilus_canvas_view_remove_file() - directory not canvas view model, shouldn't happen.\n"
452 "file: %p:%s, dir: %p:%s, model: %p:%s, view loading: %d\n"
453 "If you see this, please add this info to http://bugzilla.gnome.org/show_bug.cgi?id=368178",
454 file, file_uri, directory, dir_uri, nautilus_view_get_model (view), model_uri, nautilus_view_get_loading (view));
455 g_free (file_uri);
456 g_free (dir_uri);
457 g_free (model_uri);
458 }
459
460 canvas_view = NAUTILUS_CANVAS_VIEW (view);
461
462 if (nautilus_canvas_container_remove (get_canvas_container (canvas_view),
463 NAUTILUS_CANVAS_ICON_DATA (file))) {
464 nautilus_file_unref (file);
465 }
466 }
467
468 static void
469 nautilus_canvas_view_add_file (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
470 {
471 NautilusCanvasView *canvas_view;
472 NautilusCanvasContainer *canvas_container;
473
474 g_assert (directory == nautilus_view_get_model (view));
475
476 canvas_view = NAUTILUS_CANVAS_VIEW (view);
477 canvas_container = get_canvas_container (canvas_view);
478
479 if (canvas_view->details->filter_by_screen &&
480 !should_show_file_on_screen (view, file)) {
481 return;
482 }
483
484 /* Reset scroll region for the first canvas added when loading a directory. */
485 if (nautilus_view_get_loading (view) && nautilus_canvas_container_is_empty (canvas_container)) {
486 nautilus_canvas_container_reset_scroll_region (canvas_container);
487 }
488
489 if (nautilus_canvas_container_add (canvas_container,
490 NAUTILUS_CANVAS_ICON_DATA (file))) {
491 nautilus_file_ref (file);
492 }
493 }
494
495 static void
496 nautilus_canvas_view_file_changed (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
497 {
498 NautilusCanvasView *canvas_view;
499
500 g_assert (directory == nautilus_view_get_model (view));
501
502 g_return_if_fail (view != NULL);
503 canvas_view = NAUTILUS_CANVAS_VIEW (view);
504
505 if (!canvas_view->details->filter_by_screen) {
506 nautilus_canvas_container_request_update
507 (get_canvas_container (canvas_view),
508 NAUTILUS_CANVAS_ICON_DATA (file));
509 return;
510 }
511
512 if (!should_show_file_on_screen (view, file)) {
513 nautilus_canvas_view_remove_file (view, file, directory);
514 } else {
515
516 nautilus_canvas_container_request_update
517 (get_canvas_container (canvas_view),
518 NAUTILUS_CANVAS_ICON_DATA (file));
519 }
520 }
521
522 static gboolean
523 nautilus_canvas_view_supports_auto_layout (NautilusCanvasView *view)
524 {
525 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), FALSE);
526
527 return view->details->supports_auto_layout;
528 }
529
530 static gboolean
531 nautilus_canvas_view_supports_scaling (NautilusCanvasView *view)
532 {
533 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), FALSE);
534
535 return view->details->supports_scaling;
536 }
537
538 static gboolean
539 nautilus_canvas_view_supports_keep_aligned (NautilusCanvasView *view)
540 {
541 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), FALSE);
542
543 return view->details->supports_keep_aligned;
544 }
545
546 static void
547 update_layout_menus (NautilusCanvasView *view)
548 {
549 gboolean is_auto_layout;
550 GtkAction *action;
551 const char *action_name;
552 NautilusFile *file;
553
554 if (view->details->canvas_action_group == NULL) {
555 return;
556 }
557
558 is_auto_layout = nautilus_canvas_view_using_auto_layout (view);
559 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (view));
560
561 if (nautilus_canvas_view_supports_auto_layout (view)) {
562 /* Mark sort criterion. */
563 action_name = is_auto_layout ? view->details->sort->action : NAUTILUS_ACTION_MANUAL_LAYOUT;
564 action = gtk_action_group_get_action (view->details->canvas_action_group,
565 action_name);
566 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
567
568 action = gtk_action_group_get_action (view->details->canvas_action_group,
569 NAUTILUS_ACTION_REVERSED_ORDER);
570 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
571 view->details->sort_reversed);
572 gtk_action_set_sensitive (action, is_auto_layout);
573
574 action = gtk_action_group_get_action (view->details->canvas_action_group,
575 NAUTILUS_ACTION_SORT_TRASH_TIME);
576
577 if (file != NULL && nautilus_file_is_in_trash (file)) {
578 gtk_action_set_visible (action, TRUE);
579 } else {
580 gtk_action_set_visible (action, FALSE);
581 }
582
583 action = gtk_action_group_get_action (view->details->canvas_action_group,
584 NAUTILUS_ACTION_SORT_SEARCH_RELEVANCE);
585
586 if (file != NULL && nautilus_file_is_in_search (file)) {
587 gtk_action_set_visible (action, TRUE);
588 } else {
589 gtk_action_set_visible (action, FALSE);
590 }
591 }
592
593 action = gtk_action_group_get_action (view->details->canvas_action_group,
594 NAUTILUS_ACTION_MANUAL_LAYOUT);
595 gtk_action_set_visible (action,
596 nautilus_canvas_view_supports_manual_layout (view));
597
598 action = gtk_action_group_get_action (view->details->canvas_action_group,
599 NAUTILUS_ACTION_KEEP_ALIGNED);
600 gtk_action_set_visible (action,
601 nautilus_canvas_view_supports_keep_aligned (view));
602 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
603 nautilus_canvas_container_is_keep_aligned (get_canvas_container (view)));
604 gtk_action_set_sensitive (action, !is_auto_layout);
605 }
606
607
608 static char *
609 nautilus_canvas_view_get_directory_sort_by (NautilusCanvasView *canvas_view,
610 NautilusFile *file)
611 {
612 const SortCriterion *default_sort_criterion;
613
614 if (!nautilus_canvas_view_supports_auto_layout (canvas_view)) {
615 return g_strdup ("name");
616 }
617
618 default_sort_criterion = get_sort_criterion_by_sort_type (get_default_sort_order (file, NULL));
619 g_return_val_if_fail (default_sort_criterion != NULL, NULL);
620
621 return nautilus_file_get_metadata
622 (file, NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY,
623 default_sort_criterion->metadata_text);
624 }
625
626 static NautilusFileSortType
627 get_default_sort_order (NautilusFile *file, gboolean *reversed)
628 {
629 NautilusFileSortType retval, default_sort_order;
630 gboolean default_sort_in_reverse_order;
631
632 default_sort_order = g_settings_get_enum (nautilus_preferences,
633 NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER);
634 default_sort_in_reverse_order = g_settings_get_boolean (nautilus_preferences,
635 NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER);
636
637 retval = nautilus_file_get_default_sort_type (file, reversed);
638
639 if (retval == NAUTILUS_FILE_SORT_NONE) {
640
641 if (reversed != NULL) {
642 *reversed = default_sort_in_reverse_order;
643 }
644
645 retval = CLAMP (default_sort_order, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
646 NAUTILUS_FILE_SORT_BY_MTIME);
647 }
648
649 return retval;
650 }
651
652 static void
653 nautilus_canvas_view_set_directory_sort_by (NautilusCanvasView *canvas_view,
654 NautilusFile *file,
655 const char *sort_by)
656 {
657 const SortCriterion *default_sort_criterion;
658
659 if (!nautilus_canvas_view_supports_auto_layout (canvas_view)) {
660 return;
661 }
662
663 default_sort_criterion = get_sort_criterion_by_sort_type (get_default_sort_order (file, NULL));
664 g_return_if_fail (default_sort_criterion != NULL);
665
666 nautilus_file_set_metadata
667 (file, NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY,
668 default_sort_criterion->metadata_text,
669 sort_by);
670 }
671
672 static gboolean
673 nautilus_canvas_view_get_directory_sort_reversed (NautilusCanvasView *canvas_view,
674 NautilusFile *file)
675 {
676 gboolean reversed;
677
678 if (!nautilus_canvas_view_supports_auto_layout (canvas_view)) {
679 return FALSE;
680 }
681
682 get_default_sort_order (file, &reversed);
683 return nautilus_file_get_boolean_metadata
684 (file,
685 NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED,
686 reversed);
687 }
688
689 static void
690 nautilus_canvas_view_set_directory_sort_reversed (NautilusCanvasView *canvas_view,
691 NautilusFile *file,
692 gboolean sort_reversed)
693 {
694 gboolean reversed;
695
696 if (!nautilus_canvas_view_supports_auto_layout (canvas_view)) {
697 return;
698 }
699
700 get_default_sort_order (file, &reversed);
701 nautilus_file_set_boolean_metadata
702 (file,
703 NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED,
704 reversed, sort_reversed);
705 }
706
707 static gboolean
708 get_default_directory_keep_aligned (void)
709 {
710 return TRUE;
711 }
712
713 static gboolean
714 nautilus_canvas_view_get_directory_keep_aligned (NautilusCanvasView *canvas_view,
715 NautilusFile *file)
716 {
717 if (!nautilus_canvas_view_supports_keep_aligned (canvas_view)) {
718 return FALSE;
719 }
720
721 return nautilus_file_get_boolean_metadata
722 (file,
723 NAUTILUS_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED,
724 get_default_directory_keep_aligned ());
725 }
726
727 static void
728 nautilus_canvas_view_set_directory_keep_aligned (NautilusCanvasView *canvas_view,
729 NautilusFile *file,
730 gboolean keep_aligned)
731 {
732 if (!nautilus_canvas_view_supports_keep_aligned (canvas_view)) {
733 return;
734 }
735
736 nautilus_file_set_boolean_metadata
737 (file, NAUTILUS_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED,
738 get_default_directory_keep_aligned (),
739 keep_aligned);
740 }
741
742 static gboolean
743 nautilus_canvas_view_get_directory_auto_layout (NautilusCanvasView *canvas_view,
744 NautilusFile *file)
745 {
746 if (!nautilus_canvas_view_supports_auto_layout (canvas_view)) {
747 return FALSE;
748 }
749
750 if (!nautilus_canvas_view_supports_manual_layout (canvas_view)) {
751 return TRUE;
752 }
753
754 return nautilus_file_get_boolean_metadata
755 (file, NAUTILUS_METADATA_KEY_ICON_VIEW_AUTO_LAYOUT, TRUE);
756 }
757
758 static void
759 nautilus_canvas_view_set_directory_auto_layout (NautilusCanvasView *canvas_view,
760 NautilusFile *file,
761 gboolean auto_layout)
762 {
763 if (!nautilus_canvas_view_supports_auto_layout (canvas_view) ||
764 !nautilus_canvas_view_supports_manual_layout (canvas_view)) {
765 return;
766 }
767
768 nautilus_file_set_boolean_metadata
769 (file, NAUTILUS_METADATA_KEY_ICON_VIEW_AUTO_LAYOUT,
770 TRUE,
771 auto_layout);
772 }
773
774 static gboolean
775 set_sort_reversed (NautilusCanvasView *canvas_view,
776 gboolean new_value,
777 gboolean set_metadata)
778 {
779 if (canvas_view->details->sort_reversed == new_value) {
780 return FALSE;
781 }
782 canvas_view->details->sort_reversed = new_value;
783
784 if (set_metadata) {
785 /* Store the new sort setting. */
786 nautilus_canvas_view_set_directory_sort_reversed (canvas_view, nautilus_view_get_directory_as_file (NAUTILUS_VIEW (canvas_view)), new_value);
787 }
788
789 /* Update the layout menus to match the new sort-order setting. */
790 update_layout_menus (canvas_view);
791
792 return TRUE;
793 }
794
795 static const SortCriterion *
796 get_sort_criterion_by_metadata_text (const char *metadata_text)
797 {
798 guint i;
799
800 /* Figure out what the new sort setting should be. */
801 for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++) {
802 if (g_strcmp0 (sort_criteria[i].metadata_text, metadata_text) == 0) {
803 return &sort_criteria[i];
804 }
805 }
806 return NULL;
807 }
808
809 static const SortCriterion *
810 get_sort_criterion_by_sort_type (NautilusFileSortType sort_type)
811 {
812 guint i;
813
814 /* Figure out what the new sort setting should be. */
815 for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++) {
816 if (sort_type == sort_criteria[i].sort_type) {
817 return &sort_criteria[i];
818 }
819 }
820
821 return &sort_criteria[0];
822 }
823
824 #define DEFAULT_ZOOM_LEVEL(canvas_view) default_zoom_level
825
826 static NautilusZoomLevel
827 get_default_zoom_level (NautilusCanvasView *canvas_view)
828 {
829 NautilusZoomLevel default_zoom_level;
830
831 default_zoom_level = g_settings_get_enum (nautilus_icon_view_preferences,
832 NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL);
833
834 return CLAMP (DEFAULT_ZOOM_LEVEL(canvas_view), NAUTILUS_ZOOM_LEVEL_SMALLEST, NAUTILUS_ZOOM_LEVEL_LARGEST);
835 }
836
837 static void
838 nautilus_canvas_view_begin_loading (NautilusView *view)
839 {
840 NautilusCanvasView *canvas_view;
841 GtkWidget *canvas_container;
842 NautilusFile *file;
843 char *sort_name, *uri;
844
845 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
846
847 canvas_view = NAUTILUS_CANVAS_VIEW (view);
848 file = nautilus_view_get_directory_as_file (view);
849 uri = nautilus_file_get_uri (file);
850 canvas_container = GTK_WIDGET (get_canvas_container (canvas_view));
851
852 nautilus_canvas_container_begin_loading (NAUTILUS_CANVAS_CONTAINER (canvas_container));
853
854 nautilus_canvas_container_set_allow_moves (NAUTILUS_CANVAS_CONTAINER (canvas_container),
855 !eel_uri_is_search (uri));
856
857 g_free (uri);
858
859 /* Set the sort mode.
860 * It's OK not to resort the icons because the
861 * container doesn't have any icons at this point.
862 */
863 sort_name = nautilus_canvas_view_get_directory_sort_by (canvas_view, file);
864 set_sort_criterion (canvas_view, get_sort_criterion_by_metadata_text (sort_name), FALSE);
865 g_free (sort_name);
866
867 /* Set the sort direction from the metadata. */
868 set_sort_reversed (canvas_view, nautilus_canvas_view_get_directory_sort_reversed (canvas_view, file), FALSE);
869
870 nautilus_canvas_container_set_keep_aligned
871 (get_canvas_container (canvas_view),
872 nautilus_canvas_view_get_directory_keep_aligned (canvas_view, file));
873
874 /* We must set auto-layout last, because it invokes the layout_changed
875 * callback, which works incorrectly if the other layout criteria are
876 * not already set up properly (see bug 6500, e.g.)
877 */
878 nautilus_canvas_container_set_auto_layout
879 (get_canvas_container (canvas_view),
880 nautilus_canvas_view_get_directory_auto_layout (canvas_view, file));
881
882 /* e.g. keep aligned may have changed */
883 update_layout_menus (canvas_view);
884 }
885
886 static void
887 canvas_view_notify_clipboard_info (NautilusClipboardMonitor *monitor,
888 NautilusClipboardInfo *info,
889 NautilusCanvasView *canvas_view)
890 {
891 GList *icon_data;
892
893 icon_data = NULL;
894 if (info && info->cut) {
895 icon_data = info->files;
896 }
897
898 nautilus_canvas_container_set_highlighted_for_clipboard (
899 get_canvas_container (canvas_view), icon_data);
900 }
901
902 static void
903 nautilus_canvas_view_end_loading (NautilusView *view,
904 gboolean all_files_seen)
905 {
906 NautilusCanvasView *canvas_view;
907 GtkWidget *canvas_container;
908 NautilusClipboardMonitor *monitor;
909 NautilusClipboardInfo *info;
910
911 canvas_view = NAUTILUS_CANVAS_VIEW (view);
912
913 canvas_container = GTK_WIDGET (get_canvas_container (canvas_view));
914 nautilus_canvas_container_end_loading (NAUTILUS_CANVAS_CONTAINER (canvas_container), all_files_seen);
915
916 monitor = nautilus_clipboard_monitor_get ();
917 info = nautilus_clipboard_monitor_get_clipboard_info (monitor);
918
919 canvas_view_notify_clipboard_info (monitor, info, canvas_view);
920 }
921
922 static NautilusZoomLevel
923 nautilus_canvas_view_get_zoom_level (NautilusView *view)
924 {
925 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NAUTILUS_ZOOM_LEVEL_STANDARD);
926
927 return nautilus_canvas_container_get_zoom_level (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)));
928 }
929
930 static void
931 nautilus_canvas_view_set_zoom_level (NautilusCanvasView *view,
932 NautilusZoomLevel new_level,
933 gboolean always_emit)
934 {
935 NautilusCanvasContainer *canvas_container;
936
937 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
938 g_return_if_fail (new_level >= NAUTILUS_ZOOM_LEVEL_SMALLEST &&
939 new_level <= NAUTILUS_ZOOM_LEVEL_LARGEST);
940
941 canvas_container = get_canvas_container (view);
942 if (nautilus_canvas_container_get_zoom_level (canvas_container) == new_level) {
943 if (always_emit) {
944 g_signal_emit_by_name (view, "zoom_level_changed");
945 }
946 return;
947 }
948
949 nautilus_canvas_container_set_zoom_level (canvas_container, new_level);
950
951 g_signal_emit_by_name (view, "zoom_level_changed");
952
953 if (nautilus_view_get_active (NAUTILUS_VIEW (view))) {
954 nautilus_view_update_menus (NAUTILUS_VIEW (view));
955 }
956 }
957
958 static void
959 nautilus_canvas_view_bump_zoom_level (NautilusView *view, int zoom_increment)
960 {
961 NautilusZoomLevel new_level;
962
963 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
964
965 new_level = nautilus_canvas_view_get_zoom_level (view) + zoom_increment;
966
967 if (new_level >= NAUTILUS_ZOOM_LEVEL_SMALLEST &&
968 new_level <= NAUTILUS_ZOOM_LEVEL_LARGEST) {
969 nautilus_view_zoom_to_level (view, new_level);
970 }
971 }
972
973 static void
974 nautilus_canvas_view_zoom_to_level (NautilusView *view,
975 NautilusZoomLevel zoom_level)
976 {
977 NautilusCanvasView *canvas_view;
978
979 g_assert (NAUTILUS_IS_CANVAS_VIEW (view));
980
981 canvas_view = NAUTILUS_CANVAS_VIEW (view);
982 nautilus_canvas_view_set_zoom_level (canvas_view, zoom_level, FALSE);
983 }
984
985 static void
986 nautilus_canvas_view_restore_default_zoom_level (NautilusView *view)
987 {
988 NautilusCanvasView *canvas_view;
989
990 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
991
992 canvas_view = NAUTILUS_CANVAS_VIEW (view);
993 nautilus_view_zoom_to_level
994 (view, get_default_zoom_level (canvas_view));
995 }
996
997 static gboolean
998 nautilus_canvas_view_can_zoom_in (NautilusView *view)
999 {
1000 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), FALSE);
1001
1002 return nautilus_canvas_view_get_zoom_level (view)
1003 < NAUTILUS_ZOOM_LEVEL_LARGEST;
1004 }
1005
1006 static gboolean
1007 nautilus_canvas_view_can_zoom_out (NautilusView *view)
1008 {
1009 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), FALSE);
1010
1011 return nautilus_canvas_view_get_zoom_level (view)
1012 > NAUTILUS_ZOOM_LEVEL_SMALLEST;
1013 }
1014
1015 static gboolean
1016 nautilus_canvas_view_is_empty (NautilusView *view)
1017 {
1018 g_assert (NAUTILUS_IS_CANVAS_VIEW (view));
1019
1020 return nautilus_canvas_container_is_empty
1021 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)));
1022 }
1023
1024 static GList *
1025 nautilus_canvas_view_get_selection (NautilusView *view)
1026 {
1027 GList *list;
1028
1029 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NULL);
1030
1031 list = nautilus_canvas_container_get_selection
1032 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)));
1033 nautilus_file_list_ref (list);
1034 return list;
1035 }
1036
1037 static void
1038 set_sort_criterion_by_sort_type (NautilusCanvasView *canvas_view,
1039 NautilusFileSortType sort_type)
1040 {
1041 const SortCriterion *sort;
1042
1043 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1044
1045 sort = get_sort_criterion_by_sort_type (sort_type);
1046 g_return_if_fail (sort != NULL);
1047
1048 if (sort == canvas_view->details->sort
1049 && nautilus_canvas_view_using_auto_layout (canvas_view)) {
1050 return;
1051 }
1052
1053 set_sort_criterion (canvas_view, sort, TRUE);
1054 nautilus_canvas_container_sort (get_canvas_container (canvas_view));
1055 nautilus_canvas_view_reveal_selection (NAUTILUS_VIEW (canvas_view));
1056 }
1057
1058
1059 static void
1060 action_reversed_order_callback (GtkAction *action,
1061 gpointer user_data)
1062 {
1063 NautilusCanvasView *canvas_view;
1064
1065 canvas_view = NAUTILUS_CANVAS_VIEW (user_data);
1066
1067 if (set_sort_reversed (canvas_view,
1068 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)),
1069 TRUE)) {
1070 nautilus_canvas_container_sort (get_canvas_container (canvas_view));
1071 nautilus_canvas_view_reveal_selection (NAUTILUS_VIEW (canvas_view));
1072 }
1073 }
1074
1075 static void
1076 action_keep_aligned_callback (GtkAction *action,
1077 gpointer user_data)
1078 {
1079 NautilusCanvasView *canvas_view;
1080 NautilusFile *file;
1081 gboolean keep_aligned;
1082
1083 canvas_view = NAUTILUS_CANVAS_VIEW (user_data);
1084
1085 keep_aligned = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1086
1087 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (canvas_view));
1088 nautilus_canvas_view_set_directory_keep_aligned (canvas_view,
1089 file,
1090 keep_aligned);
1091
1092 nautilus_canvas_container_set_keep_aligned (get_canvas_container (canvas_view),
1093 keep_aligned);
1094 }
1095
1096 static void
1097 switch_to_manual_layout (NautilusCanvasView *canvas_view)
1098 {
1099 if (!nautilus_canvas_view_using_auto_layout (canvas_view)) {
1100 return;
1101 }
1102
1103 canvas_view->details->sort = &sort_criteria[0];
1104
1105 nautilus_canvas_container_set_auto_layout
1106 (get_canvas_container (canvas_view), FALSE);
1107 }
1108
1109 static void
1110 layout_changed_callback (NautilusCanvasContainer *container,
1111 NautilusCanvasView *canvas_view)
1112 {
1113 NautilusFile *file;
1114
1115 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1116 g_assert (container == get_canvas_container (canvas_view));
1117
1118 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (canvas_view));
1119
1120 if (file != NULL) {
1121 nautilus_canvas_view_set_directory_auto_layout
1122 (canvas_view,
1123 file,
1124 nautilus_canvas_view_using_auto_layout (canvas_view));
1125 }
1126
1127 update_layout_menus (canvas_view);
1128 }
1129
1130 static gboolean
1131 nautilus_canvas_view_can_rename_file (NautilusView *view, NautilusFile *file)
1132 {
1133 if (!(nautilus_canvas_view_get_zoom_level (view) > NAUTILUS_ZOOM_LEVEL_SMALLEST)) {
1134 return FALSE;
1135 }
1136
1137 return NAUTILUS_VIEW_CLASS(nautilus_canvas_view_parent_class)->can_rename_file (view, file);
1138 }
1139
1140 static void
1141 nautilus_canvas_view_start_renaming_file (NautilusView *view,
1142 NautilusFile *file,
1143 gboolean select_all)
1144 {
1145 /* call parent class to make sure the right canvas is selected */
1146 NAUTILUS_VIEW_CLASS(nautilus_canvas_view_parent_class)->start_renaming_file (view, file, select_all);
1147
1148 /* start renaming */
1149 nautilus_canvas_container_start_renaming_selected_item
1150 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)), select_all);
1151 }
1152
1153 static const GtkToggleActionEntry canvas_view_toggle_entries[] = {
1154 /* name, stock id */ { "Reversed Order", NULL,
1155 /* label, accelerator */ N_("Re_versed Order"), NULL,
1156 /* tooltip */ N_("Display icons in the opposite order"),
1157 G_CALLBACK (action_reversed_order_callback),
1158 0 },
1159 /* name, stock id */ { "Keep Aligned", NULL,
1160 /* label, accelerator */ N_("_Keep Aligned"), NULL,
1161 /* tooltip */ N_("Keep icons lined up on a grid"),
1162 G_CALLBACK (action_keep_aligned_callback),
1163 0 },
1164 };
1165
1166 static const GtkRadioActionEntry arrange_radio_entries[] = {
1167 { NAUTILUS_ACTION_MANUAL_LAYOUT, NULL,
1168 N_("_Manually"), NULL,
1169 N_("Leave icons wherever they are dropped"),
1170 NAUTILUS_FILE_SORT_NONE },
1171 { "Sort by Name", NULL,
1172 N_("By _Name"), NULL,
1173 N_("Keep icons sorted by name in rows"),
1174 NAUTILUS_FILE_SORT_BY_DISPLAY_NAME },
1175 { "Sort by Size", NULL,
1176 N_("By _Size"), NULL,
1177 N_("Keep icons sorted by size in rows"),
1178 NAUTILUS_FILE_SORT_BY_SIZE },
1179 { "Sort by Type", NULL,
1180 N_("By _Type"), NULL,
1181 N_("Keep icons sorted by type in rows"),
1182 NAUTILUS_FILE_SORT_BY_TYPE },
1183 { "Sort by Modification Date", NULL,
1184 N_("By Modification _Date"), NULL,
1185 N_("Keep icons sorted by modification date in rows"),
1186 NAUTILUS_FILE_SORT_BY_MTIME },
1187 { NAUTILUS_ACTION_SORT_TRASH_TIME, NULL,
1188 N_("By T_rash Time"), NULL,
1189 N_("Keep icons sorted by trash time in rows"),
1190 NAUTILUS_FILE_SORT_BY_TRASHED_TIME },
1191 { NAUTILUS_ACTION_SORT_SEARCH_RELEVANCE, NULL,
1192 N_("By Search Relevance"), NULL,
1193 N_("Keep icons sorted by search relevance in rows"),
1194 NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE },
1195 };
1196
1197 static void
1198 nautilus_canvas_view_merge_menus (NautilusView *view)
1199 {
1200 NautilusCanvasView *canvas_view;
1201 GtkUIManager *ui_manager;
1202 GtkActionGroup *action_group;
1203
1204 g_assert (NAUTILUS_IS_CANVAS_VIEW (view));
1205
1206 NAUTILUS_VIEW_CLASS (nautilus_canvas_view_parent_class)->merge_menus (view);
1207
1208 canvas_view = NAUTILUS_CANVAS_VIEW (view);
1209
1210 ui_manager = nautilus_view_get_ui_manager (NAUTILUS_VIEW (canvas_view));
1211
1212 action_group = gtk_action_group_new ("CanvasViewActions");
1213 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1214 canvas_view->details->canvas_action_group = action_group;
1215 gtk_action_group_add_toggle_actions (action_group,
1216 canvas_view_toggle_entries, G_N_ELEMENTS (canvas_view_toggle_entries),
1217 canvas_view);
1218 gtk_action_group_add_radio_actions (action_group,
1219 arrange_radio_entries,
1220 G_N_ELEMENTS (arrange_radio_entries),
1221 -1,
1222 G_CALLBACK (action_sort_radio_callback),
1223 canvas_view);
1224
1225 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1226 g_object_unref (action_group); /* owned by ui manager */
1227
1228 canvas_view->details->canvas_merge_id =
1229 gtk_ui_manager_add_ui_from_resource (ui_manager, "/org/gnome/nautilus/nautilus-canvas-view-ui.xml", NULL);
1230
1231 update_layout_menus (canvas_view);
1232 }
1233
1234 static void
1235 nautilus_canvas_view_unmerge_menus (NautilusView *view)
1236 {
1237 NautilusCanvasView *canvas_view;
1238 GtkUIManager *ui_manager;
1239
1240 canvas_view = NAUTILUS_CANVAS_VIEW (view);
1241
1242 NAUTILUS_VIEW_CLASS (nautilus_canvas_view_parent_class)->unmerge_menus (view);
1243
1244 ui_manager = nautilus_view_get_ui_manager (view);
1245 if (ui_manager != NULL) {
1246 nautilus_ui_unmerge_ui (ui_manager,
1247 &canvas_view->details->canvas_merge_id,
1248 &canvas_view->details->canvas_action_group);
1249 }
1250 }
1251
1252 static void
1253 nautilus_canvas_view_update_menus (NautilusView *view)
1254 {
1255 NautilusCanvasView *canvas_view;
1256 GtkAction *action;
1257 gboolean editable;
1258
1259 canvas_view = NAUTILUS_CANVAS_VIEW (view);
1260
1261 NAUTILUS_VIEW_CLASS (nautilus_canvas_view_parent_class)->update_menus(view);
1262
1263 editable = nautilus_view_is_editable (view);
1264 action = gtk_action_group_get_action (canvas_view->details->canvas_action_group,
1265 NAUTILUS_ACTION_MANUAL_LAYOUT);
1266 gtk_action_set_sensitive (action, editable);
1267 }
1268
1269 static void
1270 nautilus_canvas_view_reset_to_defaults (NautilusView *view)
1271 {
1272 NautilusCanvasContainer *canvas_container;
1273 NautilusCanvasView *canvas_view;
1274
1275 canvas_view = NAUTILUS_CANVAS_VIEW (view);
1276 canvas_container = get_canvas_container (canvas_view);
1277
1278 clear_sort_criterion (canvas_view);
1279 nautilus_canvas_container_set_keep_aligned
1280 (canvas_container, get_default_directory_keep_aligned ());
1281
1282 nautilus_canvas_container_sort (canvas_container);
1283
1284 update_layout_menus (canvas_view);
1285
1286 nautilus_canvas_view_restore_default_zoom_level (view);
1287 }
1288
1289 static void
1290 nautilus_canvas_view_select_all (NautilusView *view)
1291 {
1292 NautilusCanvasContainer *canvas_container;
1293
1294 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
1295
1296 canvas_container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view));
1297 nautilus_canvas_container_select_all (canvas_container);
1298 }
1299
1300 static void
1301 nautilus_canvas_view_select_first (NautilusView *view)
1302 {
1303 NautilusCanvasContainer *canvas_container;
1304
1305 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
1306
1307 canvas_container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view));
1308 nautilus_canvas_container_select_first (canvas_container);
1309 }
1310
1311 static void
1312 nautilus_canvas_view_reveal_selection (NautilusView *view)
1313 {
1314 GList *selection;
1315
1316 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
1317
1318 selection = nautilus_view_get_selection (view);
1319
1320 /* Make sure at least one of the selected items is scrolled into view */
1321 if (selection != NULL) {
1322 nautilus_canvas_container_reveal
1323 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)),
1324 selection->data);
1325 }
1326
1327 nautilus_file_list_free (selection);
1328 }
1329
1330 static GArray *
1331 nautilus_canvas_view_get_selected_icon_locations (NautilusView *view)
1332 {
1333 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NULL);
1334
1335 return nautilus_canvas_container_get_selected_icon_locations
1336 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)));
1337 }
1338
1339
1340 static void
1341 nautilus_canvas_view_set_selection (NautilusView *view, GList *selection)
1342 {
1343 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
1344
1345 nautilus_canvas_container_set_selection
1346 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)), selection);
1347 }
1348
1349 static void
1350 nautilus_canvas_view_invert_selection (NautilusView *view)
1351 {
1352 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
1353
1354 nautilus_canvas_container_invert_selection
1355 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)));
1356 }
1357
1358 static gboolean
1359 nautilus_canvas_view_using_manual_layout (NautilusView *view)
1360 {
1361 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), FALSE);
1362
1363 return !nautilus_canvas_view_using_auto_layout (NAUTILUS_CANVAS_VIEW (view));
1364 }
1365
1366 static void
1367 nautilus_canvas_view_widget_to_file_operation_position (NautilusView *view,
1368 GdkPoint *position)
1369 {
1370 g_assert (NAUTILUS_IS_CANVAS_VIEW (view));
1371
1372 nautilus_canvas_container_widget_to_file_operation_position
1373 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)), position);
1374 }
1375
1376 static void
1377 canvas_container_activate_callback (NautilusCanvasContainer *container,
1378 GList *file_list,
1379 NautilusCanvasView *canvas_view)
1380 {
1381 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1382 g_assert (container == get_canvas_container (canvas_view));
1383
1384 nautilus_view_activate_files (NAUTILUS_VIEW (canvas_view),
1385 file_list,
1386 0, TRUE);
1387 }
1388
1389 static void
1390 canvas_container_activate_previewer_callback (NautilusCanvasContainer *container,
1391 GList *file_list,
1392 GArray *locations,
1393 NautilusCanvasView *canvas_view)
1394 {
1395 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1396 g_assert (container == get_canvas_container (canvas_view));
1397
1398 nautilus_view_preview_files (NAUTILUS_VIEW (canvas_view),
1399 file_list, locations);
1400 }
1401
1402 /* this is called in one of these cases:
1403 * - we activate with enter holding shift
1404 * - we activate with space holding shift
1405 * - we double click an canvas holding shift
1406 * - we middle click an canvas
1407 *
1408 * If we don't open in new windows by default, the behavior should be
1409 * - middle click, shift + activate -> open in new tab
1410 * - shift + double click -> open in new window
1411 *
1412 * If we open in new windows by default, the behaviour should be
1413 * - middle click, or shift + activate, or shift + double-click -> close parent
1414 */
1415 static void
1416 canvas_container_activate_alternate_callback (NautilusCanvasContainer *container,
1417 GList *file_list,
1418 NautilusCanvasView *canvas_view)
1419 {
1420 GdkEvent *event;
1421 GdkEventButton *button_event;
1422 GdkEventKey *key_event;
1423 gboolean open_in_tab, open_in_window, close_behind;
1424 NautilusWindowOpenFlags flags;
1425
1426 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1427 g_assert (container == get_canvas_container (canvas_view));
1428
1429 flags = 0;
1430 event = gtk_get_current_event ();
1431 open_in_tab = FALSE;
1432 open_in_window = FALSE;
1433 close_behind = FALSE;
1434
1435 if (event->type == GDK_BUTTON_PRESS ||
1436 event->type == GDK_BUTTON_RELEASE ||
1437 event->type == GDK_2BUTTON_PRESS ||
1438 event->type == GDK_3BUTTON_PRESS) {
1439 button_event = (GdkEventButton *) event;
1440 open_in_window = ((button_event->state & GDK_SHIFT_MASK) != 0);
1441 open_in_tab = !open_in_window;
1442 } else if (event->type == GDK_KEY_PRESS ||
1443 event->type == GDK_KEY_RELEASE) {
1444 key_event = (GdkEventKey *) event;
1445 open_in_tab = ((key_event->state & GDK_SHIFT_MASK) != 0);
1446 }
1447
1448 if (open_in_tab) {
1449 flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB;
1450 }
1451
1452 if (open_in_window) {
1453 flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
1454 }
1455
1456 if (close_behind) {
1457 flags |= NAUTILUS_WINDOW_OPEN_FLAG_CLOSE_BEHIND;
1458 }
1459
1460 DEBUG ("Activate alternate, open in tab %d, close behind %d, new window %d\n",
1461 open_in_tab, close_behind, open_in_window);
1462
1463 nautilus_view_activate_files (NAUTILUS_VIEW (canvas_view),
1464 file_list,
1465 flags,
1466 TRUE);
1467 }
1468
1469 static void
1470 band_select_started_callback (NautilusCanvasContainer *container,
1471 NautilusCanvasView *canvas_view)
1472 {
1473 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1474 g_assert (container == get_canvas_container (canvas_view));
1475
1476 nautilus_view_start_batching_selection_changes (NAUTILUS_VIEW (canvas_view));
1477 }
1478
1479 static void
1480 band_select_ended_callback (NautilusCanvasContainer *container,
1481 NautilusCanvasView *canvas_view)
1482 {
1483 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1484 g_assert (container == get_canvas_container (canvas_view));
1485
1486 nautilus_view_stop_batching_selection_changes (NAUTILUS_VIEW (canvas_view));
1487 }
1488
1489 int
1490 nautilus_canvas_view_compare_files (NautilusCanvasView *canvas_view,
1491 NautilusFile *a,
1492 NautilusFile *b)
1493 {
1494 return nautilus_file_compare_for_sort
1495 (a, b, canvas_view->details->sort->sort_type,
1496 /* Use type-unsafe cast for performance */
1497 nautilus_view_should_sort_directories_first ((NautilusView *)canvas_view),
1498 canvas_view->details->sort_reversed);
1499 }
1500
1501 static int
1502 compare_files (NautilusView *canvas_view,
1503 NautilusFile *a,
1504 NautilusFile *b)
1505 {
1506 return nautilus_canvas_view_compare_files ((NautilusCanvasView *)canvas_view, a, b);
1507 }
1508
1509
1510 void
1511 nautilus_canvas_view_filter_by_screen (NautilusCanvasView *canvas_view,
1512 gboolean filter)
1513 {
1514 canvas_view->details->filter_by_screen = filter;
1515 canvas_view->details->num_screens = gdk_display_get_n_screens (gtk_widget_get_display (GTK_WIDGET (canvas_view)));
1516 }
1517
1518 static void
1519 nautilus_canvas_view_screen_changed (GtkWidget *widget,
1520 GdkScreen *previous_screen)
1521 {
1522 NautilusView *view;
1523 GList *files, *l;
1524 NautilusFile *file;
1525 NautilusDirectory *directory;
1526 NautilusCanvasContainer *canvas_container;
1527
1528 if (GTK_WIDGET_CLASS (nautilus_canvas_view_parent_class)->screen_changed) {
1529 GTK_WIDGET_CLASS (nautilus_canvas_view_parent_class)->screen_changed (widget, previous_screen);
1530 }
1531
1532 view = NAUTILUS_VIEW (widget);
1533 if (NAUTILUS_CANVAS_VIEW (view)->details->filter_by_screen) {
1534 canvas_container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view));
1535
1536 directory = nautilus_view_get_model (view);
1537 files = nautilus_directory_get_file_list (directory);
1538
1539 for (l = files; l != NULL; l = l->next) {
1540 file = l->data;
1541
1542 if (!should_show_file_on_screen (view, file)) {
1543 nautilus_canvas_view_remove_file (view, file, directory);
1544 } else {
1545 if (nautilus_canvas_container_add (canvas_container,
1546 NAUTILUS_CANVAS_ICON_DATA (file))) {
1547 nautilus_file_ref (file);
1548 }
1549 }
1550 }
1551
1552 nautilus_file_list_unref (files);
1553 g_list_free (files);
1554 }
1555 }
1556
1557 static void
1558 selection_changed_callback (NautilusCanvasContainer *container,
1559 NautilusCanvasView *canvas_view)
1560 {
1561 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1562 g_assert (container == get_canvas_container (canvas_view));
1563
1564 nautilus_view_notify_selection_changed (NAUTILUS_VIEW (canvas_view));
1565 }
1566
1567 static void
1568 canvas_container_context_click_selection_callback (NautilusCanvasContainer *container,
1569 GdkEventButton *event,
1570 NautilusCanvasView *canvas_view)
1571 {
1572 g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
1573 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1574
1575 nautilus_view_pop_up_selection_context_menu
1576 (NAUTILUS_VIEW (canvas_view), event);
1577 }
1578
1579 static void
1580 canvas_container_context_click_background_callback (NautilusCanvasContainer *container,
1581 GdkEventButton *event,
1582 NautilusCanvasView *canvas_view)
1583 {
1584 g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
1585 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1586
1587 nautilus_view_pop_up_background_context_menu
1588 (NAUTILUS_VIEW (canvas_view), event);
1589 }
1590
1591 static gboolean
1592 nautilus_canvas_view_react_to_canvas_change_idle_callback (gpointer data)
1593 {
1594 NautilusCanvasView *canvas_view;
1595
1596 g_assert (NAUTILUS_IS_CANVAS_VIEW (data));
1597
1598 canvas_view = NAUTILUS_CANVAS_VIEW (data);
1599 canvas_view->details->react_to_canvas_change_idle_id = 0;
1600
1601 /* Rebuild the menus since some of them (e.g. Restore Stretched Icons)
1602 * may be different now.
1603 */
1604 nautilus_view_update_menus (NAUTILUS_VIEW (canvas_view));
1605
1606 /* Don't call this again (unless rescheduled) */
1607 return FALSE;
1608 }
1609
1610 static void
1611 icon_position_changed_callback (NautilusCanvasContainer *container,
1612 NautilusFile *file,
1613 const NautilusCanvasPosition *position,
1614 NautilusCanvasView *canvas_view)
1615 {
1616 char *position_string;
1617 char scale_string[G_ASCII_DTOSTR_BUF_SIZE];
1618
1619 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1620 g_assert (container == get_canvas_container (canvas_view));
1621 g_assert (NAUTILUS_IS_FILE (file));
1622
1623 /* Schedule updating menus for the next idle. Doing it directly here
1624 * noticeably slows down canvas stretching. The other work here to
1625 * store the canvas position and scale does not seem to noticeably
1626 * slow down canvas stretching. It would be trickier to move to an
1627 * idle call, because we'd have to keep track of potentially multiple
1628 * sets of file/geometry info.
1629 */
1630 if (nautilus_view_get_active (NAUTILUS_VIEW (canvas_view)) &&
1631 canvas_view->details->react_to_canvas_change_idle_id == 0) {
1632 canvas_view->details->react_to_canvas_change_idle_id
1633 = g_idle_add (nautilus_canvas_view_react_to_canvas_change_idle_callback,
1634 canvas_view);
1635 }
1636
1637 /* Store the new position of the canvas in the metadata. */
1638 if (!nautilus_canvas_view_using_auto_layout (canvas_view)) {
1639 position_string = g_strdup_printf
1640 ("%d,%d", position->x, position->y);
1641 nautilus_file_set_metadata
1642 (file, NAUTILUS_METADATA_KEY_ICON_POSITION,
1643 NULL, position_string);
1644 g_free (position_string);
1645 }
1646
1647
1648 g_ascii_dtostr (scale_string, sizeof (scale_string), position->scale);
1649 nautilus_file_set_metadata
1650 (file, NAUTILUS_METADATA_KEY_ICON_SCALE,
1651 "1.0", scale_string);
1652 }
1653
1654 /* Attempt to change the filename to the new text. Notify user if operation fails. */
1655 static void
1656 icon_rename_ended_cb (NautilusCanvasContainer *container,
1657 NautilusFile *file,
1658 const char *new_name,
1659 NautilusCanvasView *canvas_view)
1660 {
1661 g_assert (NAUTILUS_IS_FILE (file));
1662
1663 nautilus_view_set_is_renaming (NAUTILUS_VIEW (canvas_view), FALSE);
1664
1665 /* Don't allow a rename with an empty string. Revert to original
1666 * without notifying the user.
1667 */
1668 if ((new_name == NULL) || (new_name[0] == '\0')) {
1669 return;
1670 }
1671
1672 nautilus_rename_file (file, new_name, NULL, NULL);
1673 }
1674
1675 static void
1676 icon_rename_started_cb (NautilusCanvasContainer *container,
1677 GtkWidget *widget,
1678 gpointer callback_data)
1679 {
1680 NautilusView *directory_view;
1681
1682 directory_view = NAUTILUS_VIEW (callback_data);
1683 nautilus_clipboard_set_up_editable
1684 (GTK_EDITABLE (widget),
1685 nautilus_view_get_ui_manager (directory_view),
1686 FALSE);
1687 }
1688
1689 static char *
1690 get_icon_uri_callback (NautilusCanvasContainer *container,
1691 NautilusFile *file,
1692 NautilusCanvasView *canvas_view)
1693 {
1694 g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
1695 g_assert (NAUTILUS_IS_FILE (file));
1696 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1697
1698 return nautilus_file_get_uri (file);
1699 }
1700
1701 static char *
1702 get_icon_drop_target_uri_callback (NautilusCanvasContainer *container,
1703 NautilusFile *file,
1704 NautilusCanvasView *canvas_view)
1705 {
1706 g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), NULL);
1707 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
1708 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (canvas_view), NULL);
1709
1710 return nautilus_file_get_drop_target_uri (file);
1711 }
1712
1713 /* Preferences changed callbacks */
1714 static void
1715 nautilus_canvas_view_click_policy_changed (NautilusView *directory_view)
1716 {
1717 g_assert (NAUTILUS_IS_CANVAS_VIEW (directory_view));
1718
1719 nautilus_canvas_view_update_click_mode (NAUTILUS_CANVAS_VIEW (directory_view));
1720 }
1721
1722 static void
1723 image_display_policy_changed_callback (gpointer callback_data)
1724 {
1725 NautilusCanvasView *canvas_view;
1726
1727 canvas_view = NAUTILUS_CANVAS_VIEW (callback_data);
1728
1729 nautilus_canvas_container_request_update_all (get_canvas_container (canvas_view));
1730 }
1731
1732 static void
1733 text_attribute_names_changed_callback (gpointer callback_data)
1734 {
1735 NautilusCanvasView *canvas_view;
1736
1737 canvas_view = NAUTILUS_CANVAS_VIEW (callback_data);
1738
1739 nautilus_canvas_container_request_update_all (get_canvas_container (canvas_view));
1740 }
1741
1742 static void
1743 default_sort_order_changed_callback (gpointer callback_data)
1744 {
1745 NautilusCanvasView *canvas_view;
1746 NautilusFile *file;
1747 char *sort_name;
1748 NautilusCanvasContainer *canvas_container;
1749
1750 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (callback_data));
1751
1752 canvas_view = NAUTILUS_CANVAS_VIEW (callback_data);
1753
1754 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (canvas_view));
1755 sort_name = nautilus_canvas_view_get_directory_sort_by (canvas_view, file);
1756 set_sort_criterion (canvas_view, get_sort_criterion_by_metadata_text (sort_name), FALSE);
1757 g_free (sort_name);
1758
1759 canvas_container = get_canvas_container (canvas_view);
1760 g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (canvas_container));
1761
1762 nautilus_canvas_container_request_update_all (canvas_container);
1763 }
1764
1765 static void
1766 default_sort_in_reverse_order_changed_callback (gpointer callback_data)
1767 {
1768 NautilusCanvasView *canvas_view;
1769 NautilusFile *file;
1770 NautilusCanvasContainer *canvas_container;
1771
1772 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (callback_data));
1773
1774 canvas_view = NAUTILUS_CANVAS_VIEW (callback_data);
1775
1776 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (canvas_view));
1777 set_sort_reversed (canvas_view, nautilus_canvas_view_get_directory_sort_reversed (canvas_view, file), FALSE);
1778 canvas_container = get_canvas_container (canvas_view);
1779 g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (canvas_container));
1780
1781 nautilus_canvas_container_request_update_all (canvas_container);
1782 }
1783
1784 static void
1785 nautilus_canvas_view_sort_directories_first_changed (NautilusView *directory_view)
1786 {
1787 NautilusCanvasView *canvas_view;
1788
1789 canvas_view = NAUTILUS_CANVAS_VIEW (directory_view);
1790
1791 if (nautilus_canvas_view_using_auto_layout (canvas_view)) {
1792 nautilus_canvas_container_sort
1793 (get_canvas_container (canvas_view));
1794 }
1795 }
1796
1797 static gboolean
1798 canvas_view_can_accept_item (NautilusCanvasContainer *container,
1799 NautilusFile *target_item,
1800 const char *item_uri,
1801 NautilusView *view)
1802 {
1803 return nautilus_drag_can_accept_item (target_item, item_uri);
1804 }
1805
1806 static char *
1807 canvas_view_get_container_uri (NautilusCanvasContainer *container,
1808 NautilusView *view)
1809 {
1810 return nautilus_view_get_uri (view);
1811 }
1812
1813 static void
1814 canvas_view_move_copy_items (NautilusCanvasContainer *container,
1815 const GList *item_uris,
1816 GArray *relative_item_points,
1817 const char *target_dir,
1818 int copy_action,
1819 int x, int y,
1820 NautilusView *view)
1821 {
1822 nautilus_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
1823 item_uris,
1824 nautilus_view_get_copied_files_atom (view));
1825 nautilus_view_move_copy_items (view, item_uris, relative_item_points, target_dir,
1826 copy_action, x, y);
1827 }
1828
1829 static void
1830 nautilus_canvas_view_update_click_mode (NautilusCanvasView *canvas_view)
1831 {
1832 NautilusCanvasContainer *canvas_container;
1833 int click_mode;
1834
1835 canvas_container = get_canvas_container (canvas_view);
1836 g_assert (canvas_container != NULL);
1837
1838 click_mode = g_settings_get_enum (nautilus_preferences, NAUTILUS_PREFERENCES_CLICK_POLICY);
1839
1840 nautilus_canvas_container_set_single_click_mode (canvas_container,
1841 click_mode == NAUTILUS_CLICK_POLICY_SINGLE);
1842 }
1843
1844 static gboolean
1845 get_stored_layout_timestamp (NautilusCanvasContainer *container,
1846 NautilusCanvasIconData *icon_data,
1847 time_t *timestamp,
1848 NautilusCanvasView *view)
1849 {
1850 NautilusFile *file;
1851 NautilusDirectory *directory;
1852
1853 if (icon_data == NULL) {
1854 directory = nautilus_view_get_model (NAUTILUS_VIEW (view));
1855 if (directory == NULL) {
1856 return FALSE;
1857 }
1858
1859 file = nautilus_directory_get_corresponding_file (directory);
1860 *timestamp = nautilus_file_get_time_metadata (file,
1861 NAUTILUS_METADATA_KEY_ICON_VIEW_LAYOUT_TIMESTAMP);
1862 nautilus_file_unref (file);
1863 } else {
1864 *timestamp = nautilus_file_get_time_metadata (NAUTILUS_FILE (icon_data),
1865 NAUTILUS_METADATA_KEY_ICON_POSITION_TIMESTAMP);
1866 }
1867
1868 return TRUE;
1869 }
1870
1871 static gboolean
1872 store_layout_timestamp (NautilusCanvasContainer *container,
1873 NautilusCanvasIconData *icon_data,
1874 const time_t *timestamp,
1875 NautilusCanvasView *view)
1876 {
1877 NautilusFile *file;
1878 NautilusDirectory *directory;
1879
1880 if (icon_data == NULL) {
1881 directory = nautilus_view_get_model (NAUTILUS_VIEW (view));
1882 if (directory == NULL) {
1883 return FALSE;
1884 }
1885
1886 file = nautilus_directory_get_corresponding_file (directory);
1887 nautilus_file_set_time_metadata (file,
1888 NAUTILUS_METADATA_KEY_ICON_VIEW_LAYOUT_TIMESTAMP,
1889 (time_t) *timestamp);
1890 nautilus_file_unref (file);
1891 } else {
1892 nautilus_file_set_time_metadata (NAUTILUS_FILE (icon_data),
1893 NAUTILUS_METADATA_KEY_ICON_POSITION_TIMESTAMP,
1894 (time_t) *timestamp);
1895 }
1896
1897 return TRUE;
1898 }
1899
1900 static NautilusCanvasContainer *
1901 create_canvas_container (NautilusCanvasView *canvas_view)
1902 {
1903 NautilusCanvasContainer *canvas_container;
1904
1905 canvas_container = nautilus_canvas_view_container_new (canvas_view);
1906 canvas_view->details->canvas_container = GTK_WIDGET (canvas_container);
1907 g_object_add_weak_pointer (G_OBJECT (canvas_container),
1908 (gpointer *) &canvas_view->details->canvas_container);
1909
1910 gtk_widget_set_can_focus (GTK_WIDGET (canvas_container), TRUE);
1911
1912 g_signal_connect_object (canvas_container, "activate",
1913 G_CALLBACK (canvas_container_activate_callback), canvas_view, 0);
1914 g_signal_connect_object (canvas_container, "activate_alternate",
1915 G_CALLBACK (canvas_container_activate_alternate_callback), canvas_view, 0);
1916 g_signal_connect_object (canvas_container, "activate_previewer",
1917 G_CALLBACK (canvas_container_activate_previewer_callback), canvas_view, 0);
1918 g_signal_connect_object (canvas_container, "band_select_started",
1919 G_CALLBACK (band_select_started_callback), canvas_view, 0);
1920 g_signal_connect_object (canvas_container, "band_select_ended",
1921 G_CALLBACK (band_select_ended_callback), canvas_view, 0);
1922 g_signal_connect_object (canvas_container, "context_click_selection",
1923 G_CALLBACK (canvas_container_context_click_selection_callback), canvas_view, 0);
1924 g_signal_connect_object (canvas_container, "context_click_background",
1925 G_CALLBACK (canvas_container_context_click_background_callback), canvas_view, 0);
1926 g_signal_connect_object (canvas_container, "icon_position_changed",
1927 G_CALLBACK (icon_position_changed_callback), canvas_view, 0);
1928 g_signal_connect_object (canvas_container, "selection_changed",
1929 G_CALLBACK (selection_changed_callback), canvas_view, 0);
1930 /* FIXME: many of these should move into fm-canvas-container as virtual methods */
1931 g_signal_connect_object (canvas_container, "get_icon_uri",
1932 G_CALLBACK (get_icon_uri_callback), canvas_view, 0);
1933 g_signal_connect_object (canvas_container, "get_icon_drop_target_uri",
1934 G_CALLBACK (get_icon_drop_target_uri_callback), canvas_view, 0);
1935 g_signal_connect_object (canvas_container, "move_copy_items",
1936 G_CALLBACK (canvas_view_move_copy_items), canvas_view, 0);
1937 g_signal_connect_object (canvas_container, "get_container_uri",
1938 G_CALLBACK (canvas_view_get_container_uri), canvas_view, 0);
1939 g_signal_connect_object (canvas_container, "can_accept_item",
1940 G_CALLBACK (canvas_view_can_accept_item), canvas_view, 0);
1941 g_signal_connect_object (canvas_container, "get_stored_icon_position",
1942 G_CALLBACK (get_stored_icon_position_callback), canvas_view, 0);
1943 g_signal_connect_object (canvas_container, "layout_changed",
1944 G_CALLBACK (layout_changed_callback), canvas_view, 0);
1945 g_signal_connect_object (canvas_container, "icon_rename_started",
1946 G_CALLBACK (icon_rename_started_cb), canvas_view, 0);
1947 g_signal_connect_object (canvas_container, "icon_rename_ended",
1948 G_CALLBACK (icon_rename_ended_cb), canvas_view, 0);
1949 g_signal_connect_object (canvas_container, "icon_stretch_started",
1950 G_CALLBACK (nautilus_view_update_menus), canvas_view,
1951 G_CONNECT_SWAPPED);
1952 g_signal_connect_object (canvas_container, "icon_stretch_ended",
1953 G_CALLBACK (nautilus_view_update_menus), canvas_view,
1954 G_CONNECT_SWAPPED);
1955
1956 g_signal_connect_object (canvas_container, "get_stored_layout_timestamp",
1957 G_CALLBACK (get_stored_layout_timestamp), canvas_view, 0);
1958 g_signal_connect_object (canvas_container, "store_layout_timestamp",
1959 G_CALLBACK (store_layout_timestamp), canvas_view, 0);
1960
1961 gtk_container_add (GTK_CONTAINER (canvas_view),
1962 GTK_WIDGET (canvas_container));
1963
1964 nautilus_canvas_view_update_click_mode (canvas_view);
1965 nautilus_canvas_container_set_zoom_level (canvas_container,
1966 get_default_zoom_level (canvas_view));
1967
1968 gtk_widget_show (GTK_WIDGET (canvas_container));
1969
1970 return canvas_container;
1971 }
1972
1973 /* Handles an URL received from Mozilla */
1974 static void
1975 canvas_view_handle_netscape_url (NautilusCanvasContainer *container, const char *encoded_url,
1976 const char *target_uri,
1977 GdkDragAction action, int x, int y, NautilusCanvasView *view)
1978 {
1979 nautilus_view_handle_netscape_url_drop (NAUTILUS_VIEW (view),
1980 encoded_url, target_uri, action, x, y);
1981 }
1982
1983 static void
1984 canvas_view_handle_uri_list (NautilusCanvasContainer *container, const char *item_uris,
1985 const char *target_uri,
1986 GdkDragAction action, int x, int y, NautilusCanvasView *view)
1987 {
1988 nautilus_view_handle_uri_list_drop (NAUTILUS_VIEW (view),
1989 item_uris, target_uri, action, x, y);
1990 }
1991
1992 static void
1993 canvas_view_handle_text (NautilusCanvasContainer *container, const char *text,
1994 const char *target_uri,
1995 GdkDragAction action, int x, int y, NautilusCanvasView *view)
1996 {
1997 nautilus_view_handle_text_drop (NAUTILUS_VIEW (view),
1998 text, target_uri, action, x, y);
1999 }
2000
2001 static void
2002 canvas_view_handle_raw (NautilusCanvasContainer *container, const char *raw_data,
2003 int length, const char *target_uri, const char *direct_save_uri,
2004 GdkDragAction action, int x, int y, NautilusCanvasView *view)
2005 {
2006 nautilus_view_handle_raw_drop (NAUTILUS_VIEW (view),
2007 raw_data, length, target_uri, direct_save_uri, action, x, y);
2008 }
2009
2010 static char *
2011 canvas_view_get_first_visible_file (NautilusView *view)
2012 {
2013 NautilusFile *file;
2014 NautilusCanvasView *canvas_view;
2015
2016 canvas_view = NAUTILUS_CANVAS_VIEW (view);
2017
2018 file = NAUTILUS_FILE (nautilus_canvas_container_get_first_visible_icon (get_canvas_container (canvas_view)));
2019
2020 if (file) {
2021 return nautilus_file_get_uri (file);
2022 }
2023
2024 return NULL;
2025 }
2026
2027 static void
2028 canvas_view_scroll_to_file (NautilusView *view,
2029 const char *uri)
2030 {
2031 NautilusFile *file;
2032 NautilusCanvasView *canvas_view;
2033
2034 canvas_view = NAUTILUS_CANVAS_VIEW (view);
2035
2036 if (uri != NULL) {
2037 /* Only if existing, since we don't want to add the file to
2038 the directory if it has been removed since then */
2039 file = nautilus_file_get_existing_by_uri (uri);
2040 if (file != NULL) {
2041 nautilus_canvas_container_scroll_to_canvas (get_canvas_container (canvas_view),
2042 NAUTILUS_CANVAS_ICON_DATA (file));
2043 nautilus_file_unref (file);
2044 }
2045 }
2046 }
2047
2048 static const char *
2049 nautilus_canvas_view_get_id (NautilusView *view)
2050 {
2051 return NAUTILUS_CANVAS_VIEW_ID;
2052 }
2053
2054 static void
2055 nautilus_canvas_view_set_property (GObject *object,
2056 guint prop_id,
2057 const GValue *value,
2058 GParamSpec *pspec)
2059 {
2060 NautilusCanvasView *canvas_view;
2061
2062 canvas_view = NAUTILUS_CANVAS_VIEW (object);
2063
2064 switch (prop_id) {
2065 case PROP_SUPPORTS_AUTO_LAYOUT:
2066 canvas_view->details->supports_auto_layout = g_value_get_boolean (value);
2067 break;
2068 case PROP_SUPPORTS_MANUAL_LAYOUT:
2069 canvas_view->details->supports_manual_layout = g_value_get_boolean (value);
2070 break;
2071 case PROP_SUPPORTS_SCALING:
2072 canvas_view->details->supports_scaling = g_value_get_boolean (value);
2073 break;
2074 case PROP_SUPPORTS_KEEP_ALIGNED:
2075 canvas_view->details->supports_keep_aligned = g_value_get_boolean (value);
2076 break;
2077 default:
2078 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2079 break;
2080 }
2081 }
2082
2083 static void
2084 nautilus_canvas_view_finalize (GObject *object)
2085 {
2086 NautilusCanvasView *canvas_view;
2087
2088 canvas_view = NAUTILUS_CANVAS_VIEW (object);
2089
2090 g_free (canvas_view->details);
2091
2092 g_signal_handlers_disconnect_by_func (nautilus_preferences,
2093 default_sort_order_changed_callback,
2094 canvas_view);
2095 g_signal_handlers_disconnect_by_func (nautilus_preferences,
2096 default_sort_in_reverse_order_changed_callback,
2097 canvas_view);
2098 g_signal_handlers_disconnect_by_func (nautilus_preferences,
2099 image_display_policy_changed_callback,
2100 canvas_view);
2101
2102 g_signal_handlers_disconnect_by_func (nautilus_icon_view_preferences,
2103 text_attribute_names_changed_callback,
2104 canvas_view);
2105
2106 G_OBJECT_CLASS (nautilus_canvas_view_parent_class)->finalize (object);
2107 }
2108
2109 static void
2110 nautilus_canvas_view_class_init (NautilusCanvasViewClass *klass)
2111 {
2112 NautilusViewClass *nautilus_view_class;
2113 GObjectClass *oclass;
2114
2115 nautilus_view_class = NAUTILUS_VIEW_CLASS (klass);
2116 oclass = G_OBJECT_CLASS (klass);
2117
2118 oclass->set_property = nautilus_canvas_view_set_property;
2119 oclass->finalize = nautilus_canvas_view_finalize;
2120
2121 GTK_WIDGET_CLASS (klass)->destroy = nautilus_canvas_view_destroy;
2122 GTK_WIDGET_CLASS (klass)->screen_changed = nautilus_canvas_view_screen_changed;
2123
2124 nautilus_view_class->add_file = nautilus_canvas_view_add_file;
2125 nautilus_view_class->begin_loading = nautilus_canvas_view_begin_loading;
2126 nautilus_view_class->bump_zoom_level = nautilus_canvas_view_bump_zoom_level;
2127 nautilus_view_class->can_rename_file = nautilus_canvas_view_can_rename_file;
2128 nautilus_view_class->can_zoom_in = nautilus_canvas_view_can_zoom_in;
2129 nautilus_view_class->can_zoom_out = nautilus_canvas_view_can_zoom_out;
2130 nautilus_view_class->clear = nautilus_canvas_view_clear;
2131 nautilus_view_class->end_loading = nautilus_canvas_view_end_loading;
2132 nautilus_view_class->file_changed = nautilus_canvas_view_file_changed;
2133 nautilus_view_class->get_selected_icon_locations = nautilus_canvas_view_get_selected_icon_locations;
2134 nautilus_view_class->get_selection = nautilus_canvas_view_get_selection;
2135 nautilus_view_class->get_selection_for_file_transfer = nautilus_canvas_view_get_selection;
2136 nautilus_view_class->is_empty = nautilus_canvas_view_is_empty;
2137 nautilus_view_class->remove_file = nautilus_canvas_view_remove_file;
2138 nautilus_view_class->reset_to_defaults = nautilus_canvas_view_reset_to_defaults;
2139 nautilus_view_class->restore_default_zoom_level = nautilus_canvas_view_restore_default_zoom_level;
2140 nautilus_view_class->reveal_selection = nautilus_canvas_view_reveal_selection;
2141 nautilus_view_class->select_all = nautilus_canvas_view_select_all;
2142 nautilus_view_class->select_first = nautilus_canvas_view_select_first;
2143 nautilus_view_class->set_selection = nautilus_canvas_view_set_selection;
2144 nautilus_view_class->invert_selection = nautilus_canvas_view_invert_selection;
2145 nautilus_view_class->compare_files = compare_files;
2146 nautilus_view_class->zoom_to_level = nautilus_canvas_view_zoom_to_level;
2147 nautilus_view_class->get_zoom_level = nautilus_canvas_view_get_zoom_level;
2148 nautilus_view_class->click_policy_changed = nautilus_canvas_view_click_policy_changed;
2149 nautilus_view_class->merge_menus = nautilus_canvas_view_merge_menus;
2150 nautilus_view_class->unmerge_menus = nautilus_canvas_view_unmerge_menus;
2151 nautilus_view_class->sort_directories_first_changed = nautilus_canvas_view_sort_directories_first_changed;
2152 nautilus_view_class->start_renaming_file = nautilus_canvas_view_start_renaming_file;
2153 nautilus_view_class->update_menus = nautilus_canvas_view_update_menus;
2154 nautilus_view_class->using_manual_layout = nautilus_canvas_view_using_manual_layout;
2155 nautilus_view_class->widget_to_file_operation_position = nautilus_canvas_view_widget_to_file_operation_position;
2156 nautilus_view_class->get_view_id = nautilus_canvas_view_get_id;
2157 nautilus_view_class->get_first_visible_file = canvas_view_get_first_visible_file;
2158 nautilus_view_class->scroll_to_file = canvas_view_scroll_to_file;
2159
2160 properties[PROP_SUPPORTS_AUTO_LAYOUT] =
2161 g_param_spec_boolean ("supports-auto-layout",
2162 "Supports auto layout",
2163 "Whether this view supports auto layout",
2164 TRUE,
2165 G_PARAM_WRITABLE |
2166 G_PARAM_CONSTRUCT_ONLY);
2167 properties[PROP_SUPPORTS_MANUAL_LAYOUT] =
2168 g_param_spec_boolean ("supports-manual-layout",
2169 "Supports manual layout",
2170 "Whether this view supports manual layout",
2171 FALSE,
2172 G_PARAM_WRITABLE |
2173 G_PARAM_CONSTRUCT_ONLY);
2174 properties[PROP_SUPPORTS_SCALING] =
2175 g_param_spec_boolean ("supports-scaling",
2176 "Supports scaling",
2177 "Whether this view supports scaling",
2178 FALSE,
2179 G_PARAM_WRITABLE |
2180 G_PARAM_CONSTRUCT_ONLY);
2181 properties[PROP_SUPPORTS_KEEP_ALIGNED] =
2182 g_param_spec_boolean ("supports-keep-aligned",
2183 "Supports keep aligned",
2184 "Whether this view supports keep aligned",
2185 FALSE,
2186 G_PARAM_WRITABLE |
2187 G_PARAM_CONSTRUCT_ONLY);
2188
2189 g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
2190 }
2191
2192 static void
2193 nautilus_canvas_view_init (NautilusCanvasView *canvas_view)
2194 {
2195 NautilusCanvasContainer *canvas_container;
2196
2197 g_return_if_fail (gtk_bin_get_child (GTK_BIN (canvas_view)) == NULL);
2198
2199 canvas_view->details = g_new0 (NautilusCanvasViewDetails, 1);
2200 canvas_view->details->sort = &sort_criteria[0];
2201 canvas_view->details->filter_by_screen = FALSE;
2202
2203 canvas_container = create_canvas_container (canvas_view);
2204
2205 /* Set our default layout mode */
2206 nautilus_canvas_container_set_layout_mode (canvas_container,
2207 gtk_widget_get_direction (GTK_WIDGET(canvas_container)) == GTK_TEXT_DIR_RTL ?
2208 NAUTILUS_CANVAS_LAYOUT_R_L_T_B :
2209 NAUTILUS_CANVAS_LAYOUT_L_R_T_B);
2210
2211 g_signal_connect_swapped (nautilus_preferences,
2212 "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER,
2213 G_CALLBACK (default_sort_order_changed_callback),
2214 canvas_view);
2215 g_signal_connect_swapped (nautilus_preferences,
2216 "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER,
2217 G_CALLBACK (default_sort_in_reverse_order_changed_callback),
2218 canvas_view);
2219 g_signal_connect_swapped (nautilus_preferences,
2220 "changed::" NAUTILUS_PREFERENCES_SHOW_FILE_THUMBNAILS,
2221 G_CALLBACK (image_display_policy_changed_callback),
2222 canvas_view);
2223
2224 g_signal_connect_swapped (nautilus_icon_view_preferences,
2225 "changed::" NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS,
2226 G_CALLBACK (text_attribute_names_changed_callback),
2227 canvas_view);
2228
2229 g_signal_connect_object (get_canvas_container (canvas_view), "handle_netscape_url",
2230 G_CALLBACK (canvas_view_handle_netscape_url), canvas_view, 0);
2231 g_signal_connect_object (get_canvas_container (canvas_view), "handle_uri_list",
2232 G_CALLBACK (canvas_view_handle_uri_list), canvas_view, 0);
2233 g_signal_connect_object (get_canvas_container (canvas_view), "handle_text",
2234 G_CALLBACK (canvas_view_handle_text), canvas_view, 0);
2235 g_signal_connect_object (get_canvas_container (canvas_view), "handle_raw",
2236 G_CALLBACK (canvas_view_handle_raw), canvas_view, 0);
2237
2238 canvas_view->details->clipboard_handler_id =
2239 g_signal_connect (nautilus_clipboard_monitor_get (),
2240 "clipboard_info",
2241 G_CALLBACK (canvas_view_notify_clipboard_info), canvas_view);
2242 }
2243
2244 static NautilusView *
2245 nautilus_canvas_view_create (NautilusWindowSlot *slot)
2246 {
2247 NautilusCanvasView *view;
2248
2249 view = g_object_new (NAUTILUS_TYPE_CANVAS_VIEW,
2250 "window-slot", slot,
2251 NULL);
2252 return NAUTILUS_VIEW (view);
2253 }
2254
2255 static gboolean
2256 nautilus_canvas_view_supports_uri (const char *uri,
2257 GFileType file_type,
2258 const char *mime_type)
2259 {
2260 if (file_type == G_FILE_TYPE_DIRECTORY) {
2261 return TRUE;
2262 }
2263 if (strcmp (mime_type, NAUTILUS_SAVED_SEARCH_MIMETYPE) == 0){
2264 return TRUE;
2265 }
2266 if (g_str_has_prefix (uri, "trash:")) {
2267 return TRUE;
2268 }
2269 if (g_str_has_prefix (uri, EEL_SEARCH_URI)) {
2270 return TRUE;
2271 }
2272
2273 return FALSE;
2274 }
2275
2276 #define TRANSLATE_VIEW_INFO(view_info) \
2277 view_info.view_combo_label = _(view_info.view_combo_label); \
2278 view_info.view_menu_label_with_mnemonic = _(view_info.view_menu_label_with_mnemonic); \
2279 view_info.error_label = _(view_info.error_label); \
2280 view_info.startup_error_label = _(view_info.startup_error_label); \
2281 view_info.display_location_label = _(view_info.display_location_label); \
2282
2283
2284 static NautilusViewInfo nautilus_canvas_view = {
2285 NAUTILUS_CANVAS_VIEW_ID,
2286 /* translators: this is used in the view selection dropdown
2287 * of navigation windows and in the preferences dialog */
2288 N_("Icon View"),
2289 /* translators: this is used in the view menu */
2290 N_("_Icons"),
2291 N_("The icon view encountered an error."),
2292 N_("The icon view encountered an error while starting up."),
2293 N_("Display this location with the icon view."),
2294 nautilus_canvas_view_create,
2295 nautilus_canvas_view_supports_uri
2296 };
2297
2298 void
2299 nautilus_canvas_view_register (void)
2300 {
2301 TRANSLATE_VIEW_INFO (nautilus_canvas_view)
2302 nautilus_view_factory_register (&nautilus_canvas_view);
2303 }