Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
nautilus-list-view.c:1918:4 | clang-analyzer | Value stored to 'file' is never read |
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* fm-list-view.c - implementation of list view of directory.
4
5 Copyright (C) 2000 Eazel, Inc.
6 Copyright (C) 2001, 2002 Anders Carlsson <andersca@gnu.org>
7
8 The Gnome Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library 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 The Gnome Library 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 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public
19 License along with the Gnome Library; see the file COPYING.LIB. If not,
20 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
22
23 Authors: John Sullivan <sullivan@eazel.com>
24 Anders Carlsson <andersca@gnu.org>
25 David Emory Watson <dwatson@cs.ucr.edu>
26 */
27
28 #include <config.h>
29 #include "nautilus-list-view.h"
30
31 #include "nautilus-list-model.h"
32 #include "nautilus-error-reporting.h"
33 #include "nautilus-view-dnd.h"
34 #include "nautilus-view-factory.h"
35
36 #include <string.h>
37 #include <eel/eel-vfs-extensions.h>
38 #include <eel/eel-gdk-extensions.h>
39 #include <eel/eel-glib-extensions.h>
40 #include <gdk/gdk.h>
41 #include <gdk/gdkkeysyms.h>
42 #include <gtk/gtk.h>
43 #include <libegg/eggtreemultidnd.h>
44 #include <glib/gi18n.h>
45 #include <glib-object.h>
46 #include <libnautilus-extension/nautilus-column-provider.h>
47 #include <libnautilus-private/nautilus-clipboard-monitor.h>
48 #include <libnautilus-private/nautilus-column-chooser.h>
49 #include <libnautilus-private/nautilus-column-utilities.h>
50 #include <libnautilus-private/nautilus-dnd.h>
51 #include <libnautilus-private/nautilus-file-dnd.h>
52 #include <libnautilus-private/nautilus-file-utilities.h>
53 #include <libnautilus-private/nautilus-ui-utilities.h>
54 #include <libnautilus-private/nautilus-global-preferences.h>
55 #include <libnautilus-private/nautilus-metadata.h>
56 #include <libnautilus-private/nautilus-module.h>
57 #include <libnautilus-private/nautilus-tree-view-drag-dest.h>
58 #include <libnautilus-private/nautilus-clipboard.h>
59
60 #define DEBUG_FLAG NAUTILUS_DEBUG_LIST_VIEW
61 #include <libnautilus-private/nautilus-debug.h>
62
63 struct NautilusListViewDetails {
64 GtkTreeView *tree_view;
65 NautilusListModel *model;
66 GtkActionGroup *list_action_group;
67 guint list_merge_id;
68
69 GtkTreeViewColumn *file_name_column;
70 int file_name_column_num;
71
72 GtkCellRendererPixbuf *pixbuf_cell;
73 GtkCellRendererText *file_name_cell;
74 GList *cells;
75 GtkCellEditable *editable_widget;
76
77 NautilusZoomLevel zoom_level;
78
79 NautilusTreeViewDragDest *drag_dest;
80
81 GtkTreePath *double_click_path[2]; /* Both clicks in a double click need to be on the same row */
82
83 GtkTreePath *new_selection_path; /* Path of the new selection after removing a file */
84
85 GtkTreePath *hover_path;
86
87 guint drag_button;
88 int drag_x;
89 int drag_y;
90
91 gboolean drag_started;
92 gboolean row_selected_on_button_down;
93 gboolean menus_ready;
94 gboolean active;
95
96 GHashTable *columns;
97 GtkWidget *column_editor;
98
99 char *original_name;
100
101 NautilusFile *renaming_file;
102 gboolean rename_done;
103 guint renaming_file_activate_timeout;
104
105 gulong clipboard_handler_id;
106
107 GQuark last_sort_attr;
108 };
109
110 struct SelectionForeachData {
111 GList *list;
112 GtkTreeSelection *selection;
113 };
114
115 /*
116 * The row height should be large enough to not clip emblems.
117 * Computing this would be costly, so we just choose a number
118 * that works well with the set of emblems we've designed.
119 */
120 #define LIST_VIEW_MINIMUM_ROW_HEIGHT 28
121
122 /* Wait for the rename to end when activating a file being renamed */
123 #define WAIT_FOR_RENAME_ON_ACTIVATE 200
124
125 static GdkCursor * hand_cursor = NULL;
126
127 static GtkTargetList * source_target_list = NULL;
128
129 static GList *nautilus_list_view_get_selection (NautilusView *view);
130 static GList *nautilus_list_view_get_selection_for_file_transfer (NautilusView *view);
131 static void nautilus_list_view_set_zoom_level (NautilusListView *view,
132 NautilusZoomLevel new_level,
133 gboolean always_set_level);
134 static void nautilus_list_view_scroll_to_file (NautilusListView *view,
135 NautilusFile *file);
136 static void nautilus_list_view_rename_callback (NautilusFile *file,
137 GFile *result_location,
138 GError *error,
139 gpointer callback_data);
140
141
142 G_DEFINE_TYPE (NautilusListView, nautilus_list_view, NAUTILUS_TYPE_VIEW);
143
144 static const char * default_trash_visible_columns[] = {
145 "name", "size", "type", "trashed_on", "trash_orig_path", NULL
146 };
147
148 static const char * default_trash_columns_order[] = {
149 "name", "size", "type", "trashed_on", "trash_orig_path", NULL
150 };
151
152 static const gchar*
153 get_default_sort_order (NautilusFile *file, gboolean *reversed)
154 {
155 NautilusFileSortType default_sort_order;
156 gboolean default_sort_reversed;
157 const gchar *retval;
158 const char *attributes[] = {
159 "name", /* is really "manually" which doesn't apply to lists */
160 "name",
161 "size",
162 "type",
163 "date_modified",
164 "date_accessed",
165 "trashed_on",
166 NULL
167 };
168
169 retval = nautilus_file_get_default_sort_attribute (file, reversed);
170
171 if (retval == NULL) {
172 default_sort_order = g_settings_get_enum (nautilus_preferences,
173 NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER);
174 default_sort_reversed = g_settings_get_boolean (nautilus_preferences,
175 NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER);
176
177 retval = attributes[default_sort_order];
178 *reversed = default_sort_reversed;
179 }
180
181 return retval;
182 }
183
184 static void
185 list_selection_changed_callback (GtkTreeSelection *selection, gpointer user_data)
186 {
187 NautilusView *view;
188
189 view = NAUTILUS_VIEW (user_data);
190
191 nautilus_view_notify_selection_changed (view);
192 }
193
194 /* Move these to eel? */
195
196 static void
197 tree_selection_foreach_set_boolean (GtkTreeModel *model,
198 GtkTreePath *path,
199 GtkTreeIter *iter,
200 gpointer callback_data)
201 {
202 * (gboolean *) callback_data = TRUE;
203 }
204
205 static gboolean
206 tree_selection_not_empty (GtkTreeSelection *selection)
207 {
208 gboolean not_empty;
209
210 not_empty = FALSE;
211 gtk_tree_selection_selected_foreach (selection,
212 tree_selection_foreach_set_boolean,
213 ¬_empty);
214 return not_empty;
215 }
216
217 static gboolean
218 tree_view_has_selection (GtkTreeView *view)
219 {
220 return tree_selection_not_empty (gtk_tree_view_get_selection (view));
221 }
222
223 static void
224 preview_selected_items (NautilusListView *view)
225 {
226 GList *file_list;
227
228 file_list = nautilus_list_view_get_selection (NAUTILUS_VIEW (view));
229
230 if (file_list != NULL) {
231 nautilus_view_preview_files (NAUTILUS_VIEW (view),
232 file_list, NULL);
233 nautilus_file_list_free (file_list);
234 }
235 }
236
237 static void
238 activate_selected_items (NautilusListView *view)
239 {
240 GList *file_list;
241
242 file_list = nautilus_list_view_get_selection (NAUTILUS_VIEW (view));
243
244
245 if (view->details->renaming_file) {
246 /* We're currently renaming a file, wait until the rename is
247 finished, or the activation uri will be wrong */
248 if (view->details->renaming_file_activate_timeout == 0) {
249 view->details->renaming_file_activate_timeout =
250 g_timeout_add (WAIT_FOR_RENAME_ON_ACTIVATE, (GSourceFunc) activate_selected_items, view);
251 }
252 return;
253 }
254
255 if (view->details->renaming_file_activate_timeout != 0) {
256 g_source_remove (view->details->renaming_file_activate_timeout);
257 view->details->renaming_file_activate_timeout = 0;
258 }
259
260 nautilus_view_activate_files (NAUTILUS_VIEW (view),
261 file_list,
262 0, TRUE);
263 nautilus_file_list_free (file_list);
264
265 }
266
267 static void
268 activate_selected_items_alternate (NautilusListView *view,
269 NautilusFile *file,
270 gboolean open_in_tab)
271 {
272 GList *file_list;
273 NautilusWindowOpenFlags flags;
274
275 flags = 0;
276
277 if (open_in_tab) {
278 flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB;
279 } else {
280 flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
281 }
282
283 if (file != NULL) {
284 nautilus_file_ref (file);
285 file_list = g_list_prepend (NULL, file);
286 } else {
287 file_list = nautilus_list_view_get_selection (NAUTILUS_VIEW (view));
288 }
289 nautilus_view_activate_files (NAUTILUS_VIEW (view),
290 file_list,
291 flags,
292 TRUE);
293 nautilus_file_list_free (file_list);
294
295 }
296
297 static gboolean
298 button_event_modifies_selection (GdkEventButton *event)
299 {
300 return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
301 }
302
303 static int
304 get_click_policy (void)
305 {
306 return g_settings_get_enum (nautilus_preferences,
307 NAUTILUS_PREFERENCES_CLICK_POLICY);
308 }
309
310 static void
311 nautilus_list_view_did_not_drag (NautilusListView *view,
312 GdkEventButton *event)
313 {
314 GtkTreeView *tree_view;
315 GtkTreeSelection *selection;
316 GtkTreePath *path;
317
318 tree_view = view->details->tree_view;
319 selection = gtk_tree_view_get_selection (tree_view);
320
321 if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y,
322 &path, NULL, NULL, NULL)) {
323 if ((event->button == 1 || event->button == 2)
324 && ((event->state & GDK_CONTROL_MASK) != 0 ||
325 (event->state & GDK_SHIFT_MASK) == 0)
326 && view->details->row_selected_on_button_down) {
327 if (!button_event_modifies_selection (event)) {
328 gtk_tree_selection_unselect_all (selection);
329 gtk_tree_selection_select_path (selection, path);
330 } else {
331 gtk_tree_selection_unselect_path (selection, path);
332 }
333 }
334
335 if ((get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE)
336 && !button_event_modifies_selection(event)) {
337 if (event->button == 1) {
338 activate_selected_items (view);
339 } else if (event->button == 2) {
340 activate_selected_items_alternate (view, NULL, TRUE);
341 }
342 }
343 gtk_tree_path_free (path);
344 }
345
346 }
347
348 static void
349 drag_data_get_callback (GtkWidget *widget,
350 GdkDragContext *context,
351 GtkSelectionData *selection_data,
352 guint info,
353 guint time)
354 {
355 GtkTreeView *tree_view;
356 GtkTreeModel *model;
357 GList *ref_list;
358
359 tree_view = GTK_TREE_VIEW (widget);
360
361 model = gtk_tree_view_get_model (tree_view);
362
363 if (model == NULL) {
364 return;
365 }
366
367 ref_list = g_object_get_data (G_OBJECT (context), "drag-info");
368
369 if (ref_list == NULL) {
370 return;
371 }
372
373 if (EGG_IS_TREE_MULTI_DRAG_SOURCE (model)) {
374 egg_tree_multi_drag_source_drag_data_get (EGG_TREE_MULTI_DRAG_SOURCE (model),
375 ref_list,
376 selection_data);
377 }
378 }
379
380 static void
381 filtered_selection_foreach (GtkTreeModel *model,
382 GtkTreePath *path,
383 GtkTreeIter *iter,
384 gpointer data)
385 {
386 struct SelectionForeachData *selection_data;
387 GtkTreeIter parent;
388 GtkTreeIter child;
389
390 selection_data = data;
391
392 /* If the parent folder is also selected, don't include this file in the
393 * file operation, since that would copy it to the toplevel target instead
394 * of keeping it as a child of the copied folder
395 */
396 child = *iter;
397 while (gtk_tree_model_iter_parent (model, &parent, &child)) {
398 if (gtk_tree_selection_iter_is_selected (selection_data->selection,
399 &parent)) {
400 return;
401 }
402 child = parent;
403 }
404
405 selection_data->list = g_list_prepend (selection_data->list,
406 gtk_tree_row_reference_new (model, path));
407 }
408
409 static GList *
410 get_filtered_selection_refs (GtkTreeView *tree_view)
411 {
412 struct SelectionForeachData selection_data;
413
414 selection_data.list = NULL;
415 selection_data.selection = gtk_tree_view_get_selection (tree_view);
416
417 gtk_tree_selection_selected_foreach (selection_data.selection,
418 filtered_selection_foreach,
419 &selection_data);
420 return g_list_reverse (selection_data.list);
421 }
422
423 static void
424 ref_list_free (GList *ref_list)
425 {
426 g_list_foreach (ref_list, (GFunc) gtk_tree_row_reference_free, NULL);
427 g_list_free (ref_list);
428 }
429
430 static void
431 stop_drag_check (NautilusListView *view)
432 {
433 view->details->drag_button = 0;
434 }
435
436 static GdkPixbuf *
437 get_drag_pixbuf (NautilusListView *view)
438 {
439 GtkTreeModel *model;
440 GtkTreePath *path;
441 GtkTreeIter iter;
442 GdkPixbuf *ret;
443 GdkRectangle cell_area;
444
445 ret = NULL;
446
447 if (gtk_tree_view_get_path_at_pos (view->details->tree_view,
448 view->details->drag_x,
449 view->details->drag_y,
450 &path, NULL, NULL, NULL)) {
451 model = gtk_tree_view_get_model (view->details->tree_view);
452 gtk_tree_model_get_iter (model, &iter, path);
453 gtk_tree_model_get (model, &iter,
454 nautilus_list_model_get_column_id_from_zoom_level (view->details->zoom_level),
455 &ret,
456 -1);
457
458 gtk_tree_view_get_cell_area (view->details->tree_view,
459 path,
460 view->details->file_name_column,
461 &cell_area);
462
463 gtk_tree_path_free (path);
464 }
465
466 return ret;
467 }
468
469 static void
470 drag_begin_callback (GtkWidget *widget,
471 GdkDragContext *context,
472 NautilusListView *view)
473 {
474 GList *ref_list;
475 GdkPixbuf *pixbuf;
476
477 pixbuf = get_drag_pixbuf (view);
478 if (pixbuf) {
479 gtk_drag_set_icon_pixbuf (context,
480 pixbuf,
481 0, 0);
482 g_object_unref (pixbuf);
483 } else {
484 gtk_drag_set_icon_default (context);
485 }
486
487 stop_drag_check (view);
488 view->details->drag_started = TRUE;
489
490 ref_list = get_filtered_selection_refs (GTK_TREE_VIEW (widget));
491 g_object_set_data_full (G_OBJECT (context),
492 "drag-info",
493 ref_list,
494 (GDestroyNotify)ref_list_free);
495 }
496
497 static gboolean
498 motion_notify_callback (GtkWidget *widget,
499 GdkEventMotion *event,
500 gpointer callback_data)
501 {
502 NautilusListView *view;
503
504 view = NAUTILUS_LIST_VIEW (callback_data);
505
506 if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget))) {
507 return FALSE;
508 }
509
510 if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE) {
511 GtkTreePath *old_hover_path;
512
513 old_hover_path = view->details->hover_path;
514 gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
515 event->x, event->y,
516 &view->details->hover_path,
517 NULL, NULL, NULL);
518
519 if ((old_hover_path != NULL) != (view->details->hover_path != NULL)) {
520 if (view->details->hover_path != NULL) {
521 gdk_window_set_cursor (gtk_widget_get_window (widget), hand_cursor);
522 } else {
523 gdk_window_set_cursor (gtk_widget_get_window (widget), NULL);
524 }
525 }
526
527 if (old_hover_path != NULL) {
528 gtk_tree_path_free (old_hover_path);
529 }
530 }
531
532 if (view->details->drag_button != 0) {
533 if (!source_target_list) {
534 source_target_list = nautilus_list_model_get_drag_target_list ();
535 }
536
537 if (gtk_drag_check_threshold (widget,
538 view->details->drag_x,
539 view->details->drag_y,
540 event->x,
541 event->y)) {
542 gtk_drag_begin
543 (widget,
544 source_target_list,
545 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK,
546 view->details->drag_button,
547 (GdkEvent*)event);
548 }
549 return TRUE;
550 }
551
552 return FALSE;
553 }
554
555 static gboolean
556 leave_notify_callback (GtkWidget *widget,
557 GdkEventCrossing *event,
558 gpointer callback_data)
559 {
560 NautilusListView *view;
561
562 view = NAUTILUS_LIST_VIEW (callback_data);
563
564 if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE &&
565 view->details->hover_path != NULL) {
566 gtk_tree_path_free (view->details->hover_path);
567 view->details->hover_path = NULL;
568 }
569
570 return FALSE;
571 }
572
573 static gboolean
574 enter_notify_callback (GtkWidget *widget,
575 GdkEventCrossing *event,
576 gpointer callback_data)
577 {
578 NautilusListView *view;
579
580 view = NAUTILUS_LIST_VIEW (callback_data);
581
582 if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE) {
583 if (view->details->hover_path != NULL) {
584 gtk_tree_path_free (view->details->hover_path);
585 }
586
587 gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
588 event->x, event->y,
589 &view->details->hover_path,
590 NULL, NULL, NULL);
591
592 if (view->details->hover_path != NULL) {
593 gdk_window_set_cursor (gtk_widget_get_window (widget), hand_cursor);
594 }
595 }
596
597 return FALSE;
598 }
599
600 static void
601 do_popup_menu (GtkWidget *widget, NautilusListView *view, GdkEventButton *event)
602 {
603 if (tree_view_has_selection (GTK_TREE_VIEW (widget))) {
604 nautilus_view_pop_up_selection_context_menu (NAUTILUS_VIEW (view), event);
605 } else {
606 nautilus_view_pop_up_background_context_menu (NAUTILUS_VIEW (view), event);
607 }
608 }
609
610 static void
611 row_activated_callback (GtkTreeView *treeview, GtkTreePath *path,
612 GtkTreeViewColumn *column, NautilusListView *view)
613 {
614 activate_selected_items (view);
615 }
616
617 static gboolean
618 button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer callback_data)
619 {
620 NautilusListView *view;
621 GtkTreeView *tree_view;
622 GtkTreePath *path;
623 gboolean call_parent;
624 GtkTreeSelection *selection;
625 GtkWidgetClass *tree_view_class;
626 gint64 current_time;
627 static gint64 last_click_time = 0;
628 static int click_count = 0;
629 int double_click_time;
630
631 view = NAUTILUS_LIST_VIEW (callback_data);
632 tree_view = GTK_TREE_VIEW (widget);
633 tree_view_class = GTK_WIDGET_GET_CLASS (tree_view);
634 selection = gtk_tree_view_get_selection (tree_view);
635
636 /* Don't handle extra mouse buttons here */
637 if (event->button > 5) {
638 return FALSE;
639 }
640
641 if (event->window != gtk_tree_view_get_bin_window (tree_view)) {
642 return FALSE;
643 }
644
645 nautilus_list_model_set_drag_view
646 (NAUTILUS_LIST_MODEL (gtk_tree_view_get_model (tree_view)),
647 tree_view,
648 event->x, event->y);
649
650 g_object_get (G_OBJECT (gtk_widget_get_settings (widget)),
651 "gtk-double-click-time", &double_click_time,
652 NULL);
653
654 /* Determine click count */
655 current_time = g_get_monotonic_time ();
656 if (current_time - last_click_time < double_click_time * 1000) {
657 click_count++;
658 } else {
659 click_count = 0;
660 }
661
662 /* Stash time for next compare */
663 last_click_time = current_time;
664
665 /* Ignore double click if we are in single click mode */
666 if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE && click_count >= 2) {
667 return TRUE;
668 }
669
670 call_parent = TRUE;
671 if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y,
672 &path, NULL, NULL, NULL)) {
673 /* Keep track of path of last click so double clicks only happen
674 * on the same item */
675 if ((event->button == 1 || event->button == 2) &&
676 event->type == GDK_BUTTON_PRESS) {
677 if (view->details->double_click_path[1]) {
678 gtk_tree_path_free (view->details->double_click_path[1]);
679 }
680 view->details->double_click_path[1] = view->details->double_click_path[0];
681 view->details->double_click_path[0] = gtk_tree_path_copy (path);
682 }
683 if (event->type == GDK_2BUTTON_PRESS) {
684 /* Double clicking does not trigger a D&D action. */
685 view->details->drag_button = 0;
686 if (view->details->double_click_path[1] &&
687 gtk_tree_path_compare (view->details->double_click_path[0], view->details->double_click_path[1]) == 0) {
688 /* NOTE: Activation can actually destroy the view if we're switching */
689 if (!button_event_modifies_selection (event)) {
690 if ((event->button == 1 || event->button == 3)) {
691 activate_selected_items (view);
692 } else if (event->button == 2) {
693 activate_selected_items_alternate (view, NULL, TRUE);
694 }
695 } else if (event->button == 1 &&
696 (event->state & GDK_SHIFT_MASK) != 0) {
697 NautilusFile *file;
698 file = nautilus_list_model_file_for_path (view->details->model, path);
699 if (file != NULL) {
700 activate_selected_items_alternate (view, file, TRUE);
701 nautilus_file_unref (file);
702 }
703 }
704 } else {
705 tree_view_class->button_press_event (widget, event);
706 }
707 } else {
708
709 /* We're going to filter out some situations where
710 * we can't let the default code run because all
711 * but one row would be would be deselected. We don't
712 * want that; we want the right click menu or single
713 * click to apply to everything that's currently selected. */
714
715 if (event->button == 3 && gtk_tree_selection_path_is_selected (selection, path)) {
716 call_parent = FALSE;
717 }
718
719 if ((event->button == 1 || event->button == 2) &&
720 ((event->state & GDK_CONTROL_MASK) != 0 ||
721 (event->state & GDK_SHIFT_MASK) == 0)) {
722 view->details->row_selected_on_button_down = gtk_tree_selection_path_is_selected (selection, path);
723 if (view->details->row_selected_on_button_down) {
724 call_parent = FALSE;
725 } else if ((event->state & GDK_CONTROL_MASK) != 0) {
726 GList *selected_rows;
727 GList *l;
728
729 call_parent = FALSE;
730 if ((event->state & GDK_SHIFT_MASK) != 0) {
731 GtkTreePath *cursor;
732 gtk_tree_view_get_cursor (tree_view, &cursor, NULL);
733 if (cursor != NULL) {
734 gtk_tree_selection_select_range (selection, cursor, path);
735 } else {
736 gtk_tree_selection_select_path (selection, path);
737 }
738 } else {
739 gtk_tree_selection_select_path (selection, path);
740 }
741 selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
742
743 /* This unselects everything */
744 gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
745
746 /* So select it again */
747 l = selected_rows;
748 while (l != NULL) {
749 GtkTreePath *p = l->data;
750 l = l->next;
751 gtk_tree_selection_select_path (selection, p);
752 gtk_tree_path_free (p);
753 }
754 g_list_free (selected_rows);
755 }
756 }
757
758 if (call_parent) {
759 g_signal_handlers_block_by_func (tree_view,
760 row_activated_callback,
761 view);
762
763 tree_view_class->button_press_event (widget, event);
764
765 g_signal_handlers_unblock_by_func (tree_view,
766 row_activated_callback,
767 view);
768 } else if (gtk_tree_selection_path_is_selected (selection, path)) {
769 gtk_widget_grab_focus (widget);
770 }
771
772 if ((event->button == 1 || event->button == 2) &&
773 event->type == GDK_BUTTON_PRESS) {
774 view->details->drag_started = FALSE;
775 view->details->drag_button = event->button;
776 view->details->drag_x = event->x;
777 view->details->drag_y = event->y;
778 }
779
780 if (event->button == 3) {
781 do_popup_menu (widget, view, event);
782 }
783 }
784
785 gtk_tree_path_free (path);
786 } else {
787 if ((event->button == 1 || event->button == 2) &&
788 event->type == GDK_BUTTON_PRESS) {
789 if (view->details->double_click_path[1]) {
790 gtk_tree_path_free (view->details->double_click_path[1]);
791 }
792 view->details->double_click_path[1] = view->details->double_click_path[0];
793 view->details->double_click_path[0] = NULL;
794 }
795 /* Deselect if people click outside any row. It's OK to
796 let default code run; it won't reselect anything. */
797 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (tree_view));
798 tree_view_class->button_press_event (widget, event);
799
800 if (event->button == 3) {
801 do_popup_menu (widget, view, event);
802 }
803 }
804
805 /* We chained to the default handler in this method, so never
806 * let the default handler run */
807 return TRUE;
808 }
809
810 static gboolean
811 button_release_callback (GtkWidget *widget,
812 GdkEventButton *event,
813 gpointer callback_data)
814 {
815 NautilusListView *view;
816
817 view = NAUTILUS_LIST_VIEW (callback_data);
818
819 if (event->button == view->details->drag_button) {
820 stop_drag_check (view);
821 if (!view->details->drag_started) {
822 nautilus_list_view_did_not_drag (view, event);
823 }
824 }
825 return FALSE;
826 }
827
828 static gboolean
829 popup_menu_callback (GtkWidget *widget, gpointer callback_data)
830 {
831 NautilusListView *view;
832
833 view = NAUTILUS_LIST_VIEW (callback_data);
834
835 do_popup_menu (widget, view, NULL);
836
837 return TRUE;
838 }
839
840 static void
841 subdirectory_done_loading_callback (NautilusDirectory *directory, NautilusListView *view)
842 {
843 nautilus_list_model_subdirectory_done_loading (view->details->model, directory);
844 }
845
846 struct UnloadDelayData {
847 NautilusFile *file;
848 NautilusDirectory *directory;
849 NautilusListView *view;
850 };
851
852 static void
853 subdirectory_unloaded_callback (NautilusListModel *model,
854 NautilusDirectory *directory,
855 gpointer callback_data)
856 {
857 NautilusListView *view;
858
859 g_return_if_fail (NAUTILUS_IS_LIST_MODEL (model));
860 g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
861
862 view = NAUTILUS_LIST_VIEW(callback_data);
863
864 g_signal_handlers_disconnect_by_func (directory,
865 G_CALLBACK (subdirectory_done_loading_callback),
866 view);
867 nautilus_view_remove_subdirectory (NAUTILUS_VIEW (view), directory);
868 }
869
870 static gboolean
871 key_press_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_data)
872 {
873 NautilusView *view;
874 GdkEventButton button_event = { 0 };
875 gboolean handled;
876
877 view = NAUTILUS_VIEW (callback_data);
878 handled = FALSE;
879
880 switch (event->keyval) {
881 case GDK_KEY_F10:
882 if (event->state & GDK_CONTROL_MASK) {
883 nautilus_view_pop_up_background_context_menu (view, &button_event);
884 handled = TRUE;
885 }
886 break;
887 case GDK_KEY_space:
888 if (event->state & GDK_CONTROL_MASK) {
889 handled = FALSE;
890 break;
891 }
892 if (!gtk_widget_has_focus (GTK_WIDGET (NAUTILUS_LIST_VIEW (view)->details->tree_view))) {
893 handled = FALSE;
894 break;
895 }
896 if ((event->state & GDK_SHIFT_MASK) != 0) {
897 activate_selected_items_alternate (NAUTILUS_LIST_VIEW (view), NULL, TRUE);
898 } else {
899 preview_selected_items (NAUTILUS_LIST_VIEW (view));
900 }
901 handled = TRUE;
902 break;
903 case GDK_KEY_Return:
904 case GDK_KEY_KP_Enter:
905 if ((event->state & GDK_SHIFT_MASK) != 0) {
906 activate_selected_items_alternate (NAUTILUS_LIST_VIEW (view), NULL, TRUE);
907 } else {
908 activate_selected_items (NAUTILUS_LIST_VIEW (view));
909 }
910 handled = TRUE;
911 break;
912 case GDK_KEY_v:
913 /* Eat Control + v to not enable type ahead */
914 if ((event->state & GDK_CONTROL_MASK) != 0) {
915 handled = TRUE;
916 }
917 break;
918
919 default:
920 handled = FALSE;
921 }
922
923 return handled;
924 }
925
926 static void
927 nautilus_list_view_reveal_selection (NautilusView *view)
928 {
929 GList *selection;
930
931 g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
932
933 selection = nautilus_view_get_selection (view);
934
935 /* Make sure at least one of the selected items is scrolled into view */
936 if (selection != NULL) {
937 NautilusListView *list_view;
938 NautilusFile *file;
939 GtkTreeIter iter;
940 GtkTreePath *path;
941
942 list_view = NAUTILUS_LIST_VIEW (view);
943 file = selection->data;
944 if (nautilus_list_model_get_first_iter_for_file (list_view->details->model, file, &iter)) {
945 path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), &iter);
946
947 gtk_tree_view_scroll_to_cell (list_view->details->tree_view, path, NULL, FALSE, 0.0, 0.0);
948
949 gtk_tree_path_free (path);
950 }
951 }
952
953 nautilus_file_list_free (selection);
954 }
955
956 static gboolean
957 sort_criterion_changes_due_to_user (GtkTreeView *tree_view)
958 {
959 GList *columns, *p;
960 GtkTreeViewColumn *column;
961 GSignalInvocationHint *ihint;
962 gboolean ret;
963
964 ret = FALSE;
965
966 columns = gtk_tree_view_get_columns (tree_view);
967 for (p = columns; p != NULL; p = p->next) {
968 column = p->data;
969 ihint = g_signal_get_invocation_hint (column);
970 if (ihint != NULL) {
971 ret = TRUE;
972 break;
973 }
974 }
975 g_list_free (columns);
976
977 return ret;
978 }
979
980 static void
981 sort_column_changed_callback (GtkTreeSortable *sortable,
982 NautilusListView *view)
983 {
984 NautilusFile *file;
985 gint sort_column_id, default_sort_column_id;
986 GtkSortType reversed;
987 GQuark sort_attr, default_sort_attr;
988 char *reversed_attr, *default_reversed_attr;
989 gboolean default_sort_reversed;
990
991 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (view));
992
993 gtk_tree_sortable_get_sort_column_id (sortable, &sort_column_id, &reversed);
994 sort_attr = nautilus_list_model_get_attribute_from_sort_column_id (view->details->model, sort_column_id);
995
996 default_sort_column_id = nautilus_list_model_get_sort_column_id_from_attribute (view->details->model,
997 g_quark_from_string (get_default_sort_order (file, &default_sort_reversed)));
998 default_sort_attr = nautilus_list_model_get_attribute_from_sort_column_id (view->details->model, default_sort_column_id);
999 nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN,
1000 g_quark_to_string (default_sort_attr), g_quark_to_string (sort_attr));
1001
1002 default_reversed_attr = (default_sort_reversed ? "true" : "false");
1003
1004 if (view->details->last_sort_attr != sort_attr &&
1005 sort_criterion_changes_due_to_user (view->details->tree_view)) {
1006 /* at this point, the sort order is always GTK_SORT_ASCENDING, if the sort column ID
1007 * switched. Invert the sort order, if it's the default criterion with a reversed preference,
1008 * or if it makes sense for the attribute (i.e. date). */
1009 if (sort_attr == default_sort_attr) {
1010 /* use value from preferences */
1011 reversed = g_settings_get_boolean (nautilus_preferences,
1012 NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER);
1013 } else {
1014 reversed = nautilus_file_is_date_sort_attribute_q (sort_attr);
1015 }
1016
1017 if (reversed) {
1018 g_signal_handlers_block_by_func (sortable, sort_column_changed_callback, view);
1019 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view->details->model),
1020 sort_column_id,
1021 GTK_SORT_DESCENDING);
1022 g_signal_handlers_unblock_by_func (sortable, sort_column_changed_callback, view);
1023 }
1024 }
1025
1026
1027 reversed_attr = (reversed ? "true" : "false");
1028 nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED,
1029 default_reversed_attr, reversed_attr);
1030
1031 /* Make sure selected item(s) is visible after sort */
1032 nautilus_list_view_reveal_selection (NAUTILUS_VIEW (view));
1033
1034 view->details->last_sort_attr = sort_attr;
1035 }
1036
1037 static void
1038 editable_focus_out_cb (GtkWidget *widget,
1039 GdkEvent *event,
1040 gpointer user_data)
1041 {
1042 NautilusListView *view = user_data;
1043
1044 view->details->editable_widget = NULL;
1045
1046 nautilus_view_set_is_renaming (NAUTILUS_VIEW (view), FALSE);
1047 nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
1048 }
1049
1050 static void
1051 cell_renderer_editing_started_cb (GtkCellRenderer *renderer,
1052 GtkCellEditable *editable,
1053 const gchar *path_str,
1054 NautilusListView *list_view)
1055 {
1056 GtkEntry *entry;
1057
1058 entry = GTK_ENTRY (editable);
1059 list_view->details->editable_widget = editable;
1060
1061 /* Free a previously allocated original_name */
1062 g_free (list_view->details->original_name);
1063
1064 list_view->details->original_name = g_strdup (gtk_entry_get_text (entry));
1065
1066 g_signal_connect (entry, "focus-out-event",
1067 G_CALLBACK (editable_focus_out_cb), list_view);
1068
1069 nautilus_clipboard_set_up_editable
1070 (GTK_EDITABLE (entry),
1071 nautilus_view_get_ui_manager (NAUTILUS_VIEW (list_view)),
1072 FALSE);
1073 }
1074
1075 static void
1076 cell_renderer_editing_canceled (GtkCellRendererText *cell,
1077 NautilusListView *view)
1078 {
1079 view->details->editable_widget = NULL;
1080
1081 nautilus_view_set_is_renaming (NAUTILUS_VIEW (view), FALSE);
1082 nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
1083 }
1084
1085 static void
1086 cell_renderer_edited (GtkCellRendererText *cell,
1087 const char *path_str,
1088 const char *new_text,
1089 NautilusListView *view)
1090 {
1091 GtkTreePath *path;
1092 NautilusFile *file;
1093 GtkTreeIter iter;
1094
1095 view->details->editable_widget = NULL;
1096 nautilus_view_set_is_renaming (NAUTILUS_VIEW (view), FALSE);
1097
1098 /* Don't allow a rename with an empty string. Revert to original
1099 * without notifying the user.
1100 */
1101 if (new_text[0] == '\0') {
1102 g_object_set (G_OBJECT (view->details->file_name_cell),
1103 "editable", FALSE,
1104 NULL);
1105 nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
1106 return;
1107 }
1108
1109 path = gtk_tree_path_new_from_string (path_str);
1110
1111 gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->model),
1112 &iter, path);
1113
1114 gtk_tree_path_free (path);
1115
1116 gtk_tree_model_get (GTK_TREE_MODEL (view->details->model),
1117 &iter,
1118 NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
1119 -1);
1120
1121 /* Only rename if name actually changed */
1122 if (strcmp (new_text, view->details->original_name) != 0) {
1123 view->details->renaming_file = nautilus_file_ref (file);
1124 view->details->rename_done = FALSE;
1125 nautilus_rename_file (file, new_text, nautilus_list_view_rename_callback, g_object_ref (view));
1126 g_free (view->details->original_name);
1127 view->details->original_name = g_strdup (new_text);
1128 }
1129
1130 nautilus_file_unref (file);
1131
1132 /*We're done editing - make the filename-cells readonly again.*/
1133 g_object_set (G_OBJECT (view->details->file_name_cell),
1134 "editable", FALSE,
1135 NULL);
1136
1137 nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
1138 }
1139
1140 static char *
1141 get_root_uri_callback (NautilusTreeViewDragDest *dest,
1142 gpointer user_data)
1143 {
1144 NautilusListView *view;
1145
1146 view = NAUTILUS_LIST_VIEW (user_data);
1147
1148 return nautilus_view_get_uri (NAUTILUS_VIEW (view));
1149 }
1150
1151 static NautilusFile *
1152 get_file_for_path_callback (NautilusTreeViewDragDest *dest,
1153 GtkTreePath *path,
1154 gpointer user_data)
1155 {
1156 NautilusListView *view;
1157
1158 view = NAUTILUS_LIST_VIEW (user_data);
1159
1160 return nautilus_list_model_file_for_path (view->details->model, path);
1161 }
1162
1163 /* Handles an URL received from Mozilla */
1164 static void
1165 list_view_handle_netscape_url (NautilusTreeViewDragDest *dest, const char *encoded_url,
1166 const char *target_uri, GdkDragAction action, int x, int y, NautilusListView *view)
1167 {
1168 nautilus_view_handle_netscape_url_drop (NAUTILUS_VIEW (view),
1169 encoded_url, target_uri, action, x, y);
1170 }
1171
1172 static void
1173 list_view_handle_uri_list (NautilusTreeViewDragDest *dest, const char *item_uris,
1174 const char *target_uri,
1175 GdkDragAction action, int x, int y, NautilusListView *view)
1176 {
1177 nautilus_view_handle_uri_list_drop (NAUTILUS_VIEW (view),
1178 item_uris, target_uri, action, x, y);
1179 }
1180
1181 static void
1182 list_view_handle_text (NautilusTreeViewDragDest *dest, const char *text,
1183 const char *target_uri,
1184 GdkDragAction action, int x, int y, NautilusListView *view)
1185 {
1186 nautilus_view_handle_text_drop (NAUTILUS_VIEW (view),
1187 text, target_uri, action, x, y);
1188 }
1189
1190 static void
1191 list_view_handle_raw (NautilusTreeViewDragDest *dest, const char *raw_data,
1192 int length, const char *target_uri, const char *direct_save_uri,
1193 GdkDragAction action, int x, int y, NautilusListView *view)
1194 {
1195 nautilus_view_handle_raw_drop (NAUTILUS_VIEW (view),
1196 raw_data, length, target_uri, direct_save_uri,
1197 action, x, y);
1198 }
1199
1200 static void
1201 move_copy_items_callback (NautilusTreeViewDragDest *dest,
1202 const GList *item_uris,
1203 const char *target_uri,
1204 guint action,
1205 int x,
1206 int y,
1207 gpointer user_data)
1208
1209 {
1210 NautilusView *view = user_data;
1211
1212 nautilus_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
1213 item_uris,
1214 nautilus_view_get_copied_files_atom (view));
1215 nautilus_view_move_copy_items (view,
1216 item_uris,
1217 NULL,
1218 target_uri,
1219 action,
1220 x, y);
1221 }
1222
1223 static void
1224 apply_columns_settings (NautilusListView *list_view,
1225 char **column_order,
1226 char **visible_columns)
1227 {
1228 GList *all_columns;
1229 NautilusFile *file;
1230 GList *old_view_columns, *view_columns;
1231 GHashTable *visible_columns_hash;
1232 GtkTreeViewColumn *prev_view_column;
1233 GList *l;
1234 int i;
1235
1236 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
1237
1238 /* prepare ordered list of view columns using column_order and visible_columns */
1239 view_columns = NULL;
1240
1241 all_columns = nautilus_get_columns_for_file (file);
1242 all_columns = nautilus_sort_columns (all_columns, column_order);
1243
1244 /* hash table to lookup if a given column should be visible */
1245 visible_columns_hash = g_hash_table_new_full (g_str_hash,
1246 g_str_equal,
1247 (GDestroyNotify) g_free,
1248 (GDestroyNotify) g_free);
1249 /* always show name column */
1250 g_hash_table_insert (visible_columns_hash, g_strdup ("name"), g_strdup ("name"));
1251 if (visible_columns != NULL) {
1252 for (i = 0; visible_columns[i] != NULL; ++i) {
1253 g_hash_table_insert (visible_columns_hash,
1254 g_ascii_strdown (visible_columns[i], -1),
1255 g_ascii_strdown (visible_columns[i], -1));
1256 }
1257 }
1258
1259 for (l = all_columns; l != NULL; l = l->next) {
1260 char *name;
1261 char *lowercase;
1262
1263 g_object_get (G_OBJECT (l->data), "name", &name, NULL);
1264 lowercase = g_ascii_strdown (name, -1);
1265
1266 if (g_hash_table_lookup (visible_columns_hash, lowercase) != NULL) {
1267 GtkTreeViewColumn *view_column;
1268
1269 view_column = g_hash_table_lookup (list_view->details->columns, name);
1270 if (view_column != NULL) {
1271 view_columns = g_list_prepend (view_columns, view_column);
1272 }
1273 }
1274
1275 g_free (name);
1276 g_free (lowercase);
1277 }
1278
1279 g_hash_table_destroy (visible_columns_hash);
1280 nautilus_column_list_free (all_columns);
1281
1282 view_columns = g_list_reverse (view_columns);
1283
1284 /* remove columns that are not present in the configuration */
1285 old_view_columns = gtk_tree_view_get_columns (list_view->details->tree_view);
1286 for (l = old_view_columns; l != NULL; l = l->next) {
1287 if (g_list_find (view_columns, l->data) == NULL) {
1288 gtk_tree_view_remove_column (list_view->details->tree_view, l->data);
1289 }
1290 }
1291 g_list_free (old_view_columns);
1292
1293 /* append new columns from the configuration */
1294 old_view_columns = gtk_tree_view_get_columns (list_view->details->tree_view);
1295 for (l = view_columns; l != NULL; l = l->next) {
1296 if (g_list_find (old_view_columns, l->data) == NULL) {
1297 gtk_tree_view_append_column (list_view->details->tree_view, l->data);
1298 }
1299 }
1300 g_list_free (old_view_columns);
1301
1302 /* place columns in the correct order */
1303 prev_view_column = NULL;
1304 for (l = view_columns; l != NULL; l = l->next) {
1305 gtk_tree_view_move_column_after (list_view->details->tree_view, l->data, prev_view_column);
1306 prev_view_column = l->data;
1307 }
1308 g_list_free (view_columns);
1309 }
1310
1311 static void
1312 filename_cell_data_func (GtkTreeViewColumn *column,
1313 GtkCellRenderer *renderer,
1314 GtkTreeModel *model,
1315 GtkTreeIter *iter,
1316 NautilusListView *view)
1317 {
1318 char *text;
1319 GtkTreePath *path;
1320 PangoUnderline underline;
1321
1322 gtk_tree_model_get (model, iter,
1323 view->details->file_name_column_num, &text,
1324 -1);
1325
1326 if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE) {
1327 path = gtk_tree_model_get_path (model, iter);
1328
1329 if (view->details->hover_path == NULL ||
1330 gtk_tree_path_compare (path, view->details->hover_path)) {
1331 underline = PANGO_UNDERLINE_NONE;
1332 } else {
1333 underline = PANGO_UNDERLINE_SINGLE;
1334 }
1335
1336 gtk_tree_path_free (path);
1337 } else {
1338 underline = PANGO_UNDERLINE_NONE;
1339 }
1340
1341 g_object_set (G_OBJECT (renderer),
1342 "text", text,
1343 "underline", underline,
1344 NULL);
1345 g_free (text);
1346 }
1347
1348 static void
1349 set_up_pixbuf_size (NautilusListView *view)
1350 {
1351 int icon_size;
1352
1353 /* Make all rows the same size. */
1354 icon_size = nautilus_get_icon_size_for_zoom_level (view->details->zoom_level);
1355 gtk_cell_renderer_set_fixed_size (GTK_CELL_RENDERER (view->details->pixbuf_cell),
1356 -1, icon_size);
1357
1358
1359 /* FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=641518 */
1360 gtk_tree_view_columns_autosize (view->details->tree_view);
1361 }
1362
1363 static void
1364 create_and_set_up_tree_view (NautilusListView *view)
1365 {
1366 GtkCellRenderer *cell;
1367 GtkTreeViewColumn *column;
1368 AtkObject *atk_obj;
1369 GList *nautilus_columns;
1370 GList *l;
1371 gchar **default_column_order, **default_visible_columns;
1372
1373 view->details->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
1374 view->details->columns = g_hash_table_new_full (g_str_hash,
1375 g_str_equal,
1376 (GDestroyNotify)g_free,
1377 (GDestroyNotify) g_object_unref);
1378 gtk_tree_view_set_enable_search (view->details->tree_view, FALSE);
1379
1380 view->details->drag_dest =
1381 nautilus_tree_view_drag_dest_new (view->details->tree_view);
1382
1383 g_signal_connect_object (view->details->drag_dest,
1384 "get_root_uri",
1385 G_CALLBACK (get_root_uri_callback),
1386 view, 0);
1387 g_signal_connect_object (view->details->drag_dest,
1388 "get_file_for_path",
1389 G_CALLBACK (get_file_for_path_callback),
1390 view, 0);
1391 g_signal_connect_object (view->details->drag_dest,
1392 "move_copy_items",
1393 G_CALLBACK (move_copy_items_callback),
1394 view, 0);
1395 g_signal_connect_object (view->details->drag_dest, "handle_netscape_url",
1396 G_CALLBACK (list_view_handle_netscape_url), view, 0);
1397 g_signal_connect_object (view->details->drag_dest, "handle_uri_list",
1398 G_CALLBACK (list_view_handle_uri_list), view, 0);
1399 g_signal_connect_object (view->details->drag_dest, "handle_text",
1400 G_CALLBACK (list_view_handle_text), view, 0);
1401 g_signal_connect_object (view->details->drag_dest, "handle_raw",
1402 G_CALLBACK (list_view_handle_raw), view, 0);
1403
1404 g_signal_connect_object (gtk_tree_view_get_selection (view->details->tree_view),
1405 "changed",
1406 G_CALLBACK (list_selection_changed_callback), view, 0);
1407
1408 g_signal_connect_object (view->details->tree_view, "drag_begin",
1409 G_CALLBACK (drag_begin_callback), view, 0);
1410 g_signal_connect_object (view->details->tree_view, "drag_data_get",
1411 G_CALLBACK (drag_data_get_callback), view, 0);
1412 g_signal_connect_object (view->details->tree_view, "motion_notify_event",
1413 G_CALLBACK (motion_notify_callback), view, 0);
1414 g_signal_connect_object (view->details->tree_view, "enter_notify_event",
1415 G_CALLBACK (enter_notify_callback), view, 0);
1416 g_signal_connect_object (view->details->tree_view, "leave_notify_event",
1417 G_CALLBACK (leave_notify_callback), view, 0);
1418 g_signal_connect_object (view->details->tree_view, "button_press_event",
1419 G_CALLBACK (button_press_callback), view, 0);
1420 g_signal_connect_object (view->details->tree_view, "button_release_event",
1421 G_CALLBACK (button_release_callback), view, 0);
1422 g_signal_connect_object (view->details->tree_view, "key_press_event",
1423 G_CALLBACK (key_press_callback), view, 0);
1424 g_signal_connect_object (view->details->tree_view, "popup_menu",
1425 G_CALLBACK (popup_menu_callback), view, 0);
1426 g_signal_connect_object (view->details->tree_view, "row-activated",
1427 G_CALLBACK (row_activated_callback), view, 0);
1428
1429 view->details->model = g_object_new (NAUTILUS_TYPE_LIST_MODEL, NULL);
1430 gtk_tree_view_set_model (view->details->tree_view, GTK_TREE_MODEL (view->details->model));
1431 /* Need the model for the dnd drop icon "accept" change */
1432 nautilus_list_model_set_drag_view (NAUTILUS_LIST_MODEL (view->details->model),
1433 view->details->tree_view, 0, 0);
1434
1435 g_signal_connect_object (view->details->model, "sort_column_changed",
1436 G_CALLBACK (sort_column_changed_callback), view, 0);
1437
1438 g_signal_connect_object (view->details->model, "subdirectory_unloaded",
1439 G_CALLBACK (subdirectory_unloaded_callback), view, 0);
1440
1441 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (view->details->tree_view), GTK_SELECTION_MULTIPLE);
1442 gtk_tree_view_set_rules_hint (view->details->tree_view, TRUE);
1443
1444 nautilus_columns = nautilus_get_all_columns ();
1445
1446 for (l = nautilus_columns; l != NULL; l = l->next) {
1447 NautilusColumn *nautilus_column;
1448 int column_num;
1449 char *name;
1450 char *label;
1451 float xalign;
1452 GtkSortType sort_order;
1453
1454 nautilus_column = NAUTILUS_COLUMN (l->data);
1455
1456 g_object_get (nautilus_column,
1457 "name", &name,
1458 "label", &label,
1459 "xalign", &xalign,
1460 "default-sort-order", &sort_order,
1461 NULL);
1462
1463 column_num = nautilus_list_model_add_column (view->details->model,
1464 nautilus_column);
1465
1466 /* Created the name column specially, because it
1467 * has the icon in it.*/
1468 if (!strcmp (name, "name")) {
1469 /* Create the file name column */
1470 cell = gtk_cell_renderer_pixbuf_new ();
1471 view->details->pixbuf_cell = (GtkCellRendererPixbuf *)cell;
1472 set_up_pixbuf_size (view);
1473
1474 view->details->file_name_column = gtk_tree_view_column_new ();
1475 g_object_ref_sink (view->details->file_name_column);
1476 view->details->file_name_column_num = column_num;
1477
1478 g_hash_table_insert (view->details->columns,
1479 g_strdup ("name"),
1480 view->details->file_name_column);
1481
1482 gtk_tree_view_set_search_column (view->details->tree_view, column_num);
1483
1484 gtk_tree_view_column_set_sort_column_id (view->details->file_name_column, column_num);
1485 gtk_tree_view_column_set_title (view->details->file_name_column, _("Name"));
1486 gtk_tree_view_column_set_resizable (view->details->file_name_column, TRUE);
1487 gtk_tree_view_column_set_expand (view->details->file_name_column, TRUE);
1488
1489 gtk_tree_view_column_pack_start (view->details->file_name_column, cell, FALSE);
1490 gtk_tree_view_column_set_attributes (view->details->file_name_column,
1491 cell,
1492 "pixbuf", nautilus_list_model_get_column_id_from_zoom_level (view->details->zoom_level),
1493 NULL);
1494
1495 cell = gtk_cell_renderer_text_new ();
1496 view->details->file_name_cell = (GtkCellRendererText *)cell;
1497 g_object_set (cell,
1498 "ellipsize", PANGO_ELLIPSIZE_END,
1499 "single-paragraph-mode", TRUE,
1500 "xpad", 5,
1501 NULL);
1502
1503 g_signal_connect (cell, "edited", G_CALLBACK (cell_renderer_edited), view);
1504 g_signal_connect (cell, "editing-canceled", G_CALLBACK (cell_renderer_editing_canceled), view);
1505 g_signal_connect (cell, "editing-started", G_CALLBACK (cell_renderer_editing_started_cb), view);
1506
1507 gtk_tree_view_column_pack_start (view->details->file_name_column, cell, TRUE);
1508 gtk_tree_view_column_set_cell_data_func (view->details->file_name_column, cell,
1509 (GtkTreeCellDataFunc) filename_cell_data_func,
1510 view, NULL);
1511 } else {
1512 cell = gtk_cell_renderer_text_new ();
1513 g_object_set (cell,
1514 "xalign", xalign,
1515 "xpad", 5,
1516 NULL);
1517 view->details->cells = g_list_append (view->details->cells,
1518 cell);
1519 column = gtk_tree_view_column_new_with_attributes (label,
1520 cell,
1521 "text", column_num,
1522 NULL);
1523 g_object_ref_sink (column);
1524 gtk_tree_view_column_set_sort_column_id (column, column_num);
1525 g_hash_table_insert (view->details->columns,
1526 g_strdup (name),
1527 column);
1528
1529 gtk_tree_view_column_set_resizable (column, TRUE);
1530 gtk_tree_view_column_set_visible (column, TRUE);
1531 gtk_tree_view_column_set_sort_order (column, sort_order);
1532 }
1533 g_free (name);
1534 g_free (label);
1535 }
1536 nautilus_column_list_free (nautilus_columns);
1537
1538 default_visible_columns = g_settings_get_strv (nautilus_list_view_preferences,
1539 NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
1540 default_column_order = g_settings_get_strv (nautilus_list_view_preferences,
1541 NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER);
1542
1543 /* Apply the default column order and visible columns, to get it
1544 * right most of the time. The metadata will be checked when a
1545 * folder is loaded */
1546 apply_columns_settings (view,
1547 default_column_order,
1548 default_visible_columns);
1549
1550 gtk_widget_show (GTK_WIDGET (view->details->tree_view));
1551 gtk_container_add (GTK_CONTAINER (view), GTK_WIDGET (view->details->tree_view));
1552
1553 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (view->details->tree_view));
1554 atk_object_set_name (atk_obj, _("List View"));
1555
1556 g_strfreev (default_visible_columns);
1557 g_strfreev (default_column_order);
1558 }
1559
1560 static void
1561 nautilus_list_view_add_file (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
1562 {
1563 NautilusListModel *model;
1564
1565 model = NAUTILUS_LIST_VIEW (view)->details->model;
1566 nautilus_list_model_add_file (model, file, directory);
1567 }
1568
1569 static char **
1570 get_visible_columns (NautilusListView *list_view)
1571 {
1572 NautilusFile *file;
1573 GList *visible_columns;
1574 char **ret;
1575
1576 ret = NULL;
1577
1578 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
1579
1580 visible_columns = nautilus_file_get_metadata_list
1581 (file,
1582 NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS);
1583
1584 if (visible_columns) {
1585 GPtrArray *res;
1586 GList *l;
1587
1588 res = g_ptr_array_new ();
1589 for (l = visible_columns; l != NULL; l = l->next) {
1590 g_ptr_array_add (res, l->data);
1591 }
1592 g_ptr_array_add (res, NULL);
1593
1594 ret = (char **) g_ptr_array_free (res, FALSE);
1595 g_list_free (visible_columns);
1596 }
1597
1598 if (ret != NULL) {
1599 return ret;
1600 }
1601
1602 return nautilus_file_is_in_trash (file) ?
1603 g_strdupv ((gchar **) default_trash_visible_columns) :
1604 g_settings_get_strv (nautilus_list_view_preferences,
1605 NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
1606 }
1607
1608 static char **
1609 get_column_order (NautilusListView *list_view)
1610 {
1611 NautilusFile *file;
1612 GList *column_order;
1613 char **ret;
1614
1615 ret = NULL;
1616
1617 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
1618
1619 column_order = nautilus_file_get_metadata_list
1620 (file,
1621 NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER);
1622
1623 if (column_order) {
1624 GPtrArray *res;
1625 GList *l;
1626
1627 res = g_ptr_array_new ();
1628 for (l = column_order; l != NULL; l = l->next) {
1629 g_ptr_array_add (res, l->data);
1630 }
1631 g_ptr_array_add (res, NULL);
1632
1633 ret = (char **) g_ptr_array_free (res, FALSE);
1634 g_list_free (column_order);
1635 }
1636
1637 if (ret != NULL) {
1638 return ret;
1639 }
1640
1641 return nautilus_file_is_in_trash (file) ?
1642 g_strdupv ((gchar **) default_trash_columns_order) :
1643 g_settings_get_strv (nautilus_list_view_preferences,
1644 NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER);
1645 }
1646
1647 static void
1648 set_columns_settings_from_metadata_and_preferences (NautilusListView *list_view)
1649 {
1650 char **column_order;
1651 char **visible_columns;
1652
1653 column_order = get_column_order (list_view);
1654 visible_columns = get_visible_columns (list_view);
1655
1656 apply_columns_settings (list_view, column_order, visible_columns);
1657
1658 g_strfreev (column_order);
1659 g_strfreev (visible_columns);
1660 }
1661
1662 static void
1663 set_sort_order_from_metadata_and_preferences (NautilusListView *list_view)
1664 {
1665 char *sort_attribute;
1666 int sort_column_id;
1667 NautilusFile *file;
1668 gboolean sort_reversed, default_sort_reversed;
1669 const gchar *default_sort_order;
1670
1671 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
1672 sort_attribute = nautilus_file_get_metadata (file,
1673 NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN,
1674 NULL);
1675 sort_column_id = nautilus_list_model_get_sort_column_id_from_attribute (list_view->details->model,
1676 g_quark_from_string (sort_attribute));
1677 g_free (sort_attribute);
1678
1679 default_sort_order = get_default_sort_order (file, &default_sort_reversed);
1680
1681 if (sort_column_id == -1) {
1682 sort_column_id =
1683 nautilus_list_model_get_sort_column_id_from_attribute (list_view->details->model,
1684 g_quark_from_string (default_sort_order));
1685 }
1686
1687 sort_reversed = nautilus_file_get_boolean_metadata (file,
1688 NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED,
1689 default_sort_reversed);
1690
1691 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_view->details->model),
1692 sort_column_id,
1693 sort_reversed ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING);
1694 }
1695
1696 static NautilusZoomLevel
1697 get_default_zoom_level (void) {
1698 NautilusZoomLevel default_zoom_level;
1699
1700 default_zoom_level = g_settings_get_enum (nautilus_list_view_preferences,
1701 NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL);
1702
1703 if (default_zoom_level < NAUTILUS_ZOOM_LEVEL_SMALLEST
1704 || NAUTILUS_ZOOM_LEVEL_LARGEST < default_zoom_level) {
1705 default_zoom_level = NAUTILUS_ZOOM_LEVEL_SMALL;
1706 }
1707
1708 return default_zoom_level;
1709 }
1710
1711 static void
1712 nautilus_list_view_begin_loading (NautilusView *view)
1713 {
1714 NautilusListView *list_view;
1715
1716 list_view = NAUTILUS_LIST_VIEW (view);
1717
1718 set_sort_order_from_metadata_and_preferences (list_view);
1719 set_columns_settings_from_metadata_and_preferences (list_view);
1720 }
1721
1722 static void
1723 stop_cell_editing (NautilusListView *list_view)
1724 {
1725 GtkTreeViewColumn *column;
1726
1727 /* Stop an ongoing rename to commit the name changes when the user
1728 * changes directories without exiting cell edit mode. It also prevents
1729 * the edited handler from being called on the cleared list model.
1730 */
1731 column = list_view->details->file_name_column;
1732 if (column != NULL && list_view->details->editable_widget != NULL &&
1733 GTK_IS_CELL_EDITABLE (list_view->details->editable_widget)) {
1734 gtk_cell_editable_editing_done (list_view->details->editable_widget);
1735 }
1736
1737 g_clear_object (&list_view->details->renaming_file);
1738 }
1739
1740 static void
1741 nautilus_list_view_clear (NautilusView *view)
1742 {
1743 NautilusListView *list_view;
1744
1745 list_view = NAUTILUS_LIST_VIEW (view);
1746
1747 if (list_view->details->model != NULL) {
1748 stop_cell_editing (list_view);
1749 nautilus_list_model_clear (list_view->details->model);
1750 }
1751 }
1752
1753 static void
1754 nautilus_list_view_rename_callback (NautilusFile *file,
1755 GFile *result_location,
1756 GError *error,
1757 gpointer callback_data)
1758 {
1759 NautilusListView *view;
1760
1761 view = NAUTILUS_LIST_VIEW (callback_data);
1762
1763 if (view->details->renaming_file) {
1764 view->details->rename_done = TRUE;
1765
1766 if (error != NULL) {
1767 /* If the rename failed (or was cancelled), kill renaming_file.
1768 * We won't get a change event for the rename, so otherwise
1769 * it would stay around forever.
1770 */
1771 nautilus_file_unref (view->details->renaming_file);
1772 view->details->renaming_file = NULL;
1773 }
1774 }
1775
1776 g_object_unref (view);
1777 }
1778
1779
1780 static void
1781 nautilus_list_view_file_changed (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
1782 {
1783 NautilusListView *listview;
1784 GtkTreeIter iter;
1785 GtkTreePath *file_path;
1786
1787 listview = NAUTILUS_LIST_VIEW (view);
1788
1789 nautilus_list_model_file_changed (listview->details->model, file, directory);
1790
1791 if (listview->details->renaming_file != NULL &&
1792 file == listview->details->renaming_file &&
1793 listview->details->rename_done) {
1794 /* This is (probably) the result of the rename operation, and
1795 * the tree-view changes above could have resorted the list, so
1796 * scroll to the new position
1797 */
1798 if (nautilus_list_model_get_tree_iter_from_file (listview->details->model, file, directory, &iter)) {
1799 file_path = gtk_tree_model_get_path (GTK_TREE_MODEL (listview->details->model), &iter);
1800 gtk_tree_view_scroll_to_cell (listview->details->tree_view,
1801 file_path, NULL,
1802 FALSE, 0.0, 0.0);
1803 gtk_tree_path_free (file_path);
1804 }
1805
1806 nautilus_file_unref (listview->details->renaming_file);
1807 listview->details->renaming_file = NULL;
1808 }
1809 }
1810
1811 typedef struct {
1812 GtkTreePath *path;
1813 gboolean is_common;
1814 gboolean is_root;
1815 } HasCommonParentData;
1816
1817 static void
1818 tree_selection_has_common_parent_foreach_func (GtkTreeModel *model,
1819 GtkTreePath *path,
1820 GtkTreeIter *iter,
1821 gpointer user_data)
1822 {
1823 HasCommonParentData *data;
1824 GtkTreePath *parent_path;
1825 gboolean has_parent;
1826
1827 data = (HasCommonParentData *) user_data;
1828
1829 parent_path = gtk_tree_path_copy (path);
1830 gtk_tree_path_up (parent_path);
1831
1832 has_parent = (gtk_tree_path_get_depth (parent_path) > 0) ? TRUE : FALSE;
1833
1834 if (!has_parent) {
1835 data->is_root = TRUE;
1836 }
1837
1838 if (data->is_common && !data->is_root) {
1839 if (data->path == NULL) {
1840 data->path = gtk_tree_path_copy (parent_path);
1841 } else if (gtk_tree_path_compare (data->path, parent_path) != 0) {
1842 data->is_common = FALSE;
1843 }
1844 }
1845
1846 gtk_tree_path_free (parent_path);
1847 }
1848
1849 static void
1850 tree_selection_has_common_parent (GtkTreeSelection *selection,
1851 gboolean *is_common,
1852 gboolean *is_root)
1853 {
1854 HasCommonParentData data;
1855
1856 g_assert (is_common != NULL);
1857 g_assert (is_root != NULL);
1858
1859 data.path = NULL;
1860 data.is_common = *is_common = TRUE;
1861 data.is_root = *is_root = FALSE;
1862
1863 gtk_tree_selection_selected_foreach (selection,
1864 tree_selection_has_common_parent_foreach_func,
1865 &data);
1866
1867 *is_common = data.is_common;
1868 *is_root = data.is_root;
1869
1870 if (data.path != NULL) {
1871 gtk_tree_path_free (data.path);
1872 }
1873 }
1874
1875 static char *
1876 nautilus_list_view_get_backing_uri (NautilusView *view)
1877 {
1878 NautilusListView *list_view;
1879 NautilusListModel *list_model;
1880 NautilusFile *file;
1881 GtkTreeView *tree_view;
1882 GtkTreeSelection *selection;
1883 GtkTreePath *path;
1884 GList *paths;
1885 guint length;
1886 char *uri;
1887
1888 g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), NULL);
1889
1890 list_view = NAUTILUS_LIST_VIEW (view);
1891 list_model = list_view->details->model;
1892 tree_view = list_view->details->tree_view;
1893
1894 g_assert (list_model);
1895
1896 /* We currently handle two common cases here:
1897 * (a) if the selection contains non-filesystem items (i.e., the
1898 * "(Empty)" label), we return the uri of the parent.
1899 * (b) if the selection consists of either exactly one item or
1900 * multiple items in the same directory, we return the URI
1901 * of the common parent.
1902 */
1903
1904 uri = NULL;
1905
1906 selection = gtk_tree_view_get_selection (tree_view);
1907 length = gtk_tree_selection_count_selected_rows (selection);
1908
1909 if (length == 1) {
1910
1911 paths = gtk_tree_selection_get_selected_rows (selection, NULL);
1912 path = (GtkTreePath *) paths->data;
1913
1914 file = nautilus_list_model_file_for_path (list_model, path);
1915 if (file == NULL) {
1916 /* The selected item is a label, not a file */
1917 gtk_tree_path_up (path);
1918 file = nautilus_list_model_file_for_path (list_model, path);
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
1919 }
1920
1921 gtk_tree_path_free (path);
1922 g_list_free (paths);
1923 }
1924
1925 if (uri == NULL && length > 0) {
1926
1927 gboolean is_common, is_root;
1928
1929 /* Check that all the selected items belong to the same
1930 * directory and that directory is not the root directory (which
1931 * is handled by NautilusView::get_backing_directory.) */
1932
1933 tree_selection_has_common_parent (selection, &is_common, &is_root);
1934
1935 if (is_common && !is_root) {
1936
1937 paths = gtk_tree_selection_get_selected_rows (selection, NULL);
1938 path = (GtkTreePath *) paths->data;
1939
1940 file = nautilus_list_model_file_for_path (list_model, path);
1941 g_assert (file != NULL);
1942 uri = nautilus_file_get_parent_uri (file);
1943 nautilus_file_unref (file);
1944
1945 g_list_foreach (paths, (GFunc) gtk_tree_path_free, NULL);
1946 g_list_free (paths);
1947 }
1948 }
1949
1950 if (uri != NULL) {
1951 return uri;
1952 }
1953
1954 return NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->get_backing_uri (view);
1955 }
1956
1957 static void
1958 nautilus_list_view_get_selection_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1959 {
1960 GList **list;
1961 NautilusFile *file;
1962
1963 list = data;
1964
1965 gtk_tree_model_get (model, iter,
1966 NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
1967 -1);
1968
1969 if (file != NULL) {
1970 (* list) = g_list_prepend ((* list), file);
1971 }
1972 }
1973
1974 static GList *
1975 nautilus_list_view_get_selection (NautilusView *view)
1976 {
1977 GList *list;
1978
1979 list = NULL;
1980
1981 gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view),
1982 nautilus_list_view_get_selection_foreach_func, &list);
1983
1984 return g_list_reverse (list);
1985 }
1986
1987 static void
1988 nautilus_list_view_get_selection_for_file_transfer_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1989 {
1990 NautilusFile *file;
1991 struct SelectionForeachData *selection_data;
1992 GtkTreeIter parent, child;
1993
1994 selection_data = data;
1995
1996 gtk_tree_model_get (model, iter,
1997 NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
1998 -1);
1999
2000 if (file != NULL) {
2001 /* If the parent folder is also selected, don't include this file in the
2002 * file operation, since that would copy it to the toplevel target instead
2003 * of keeping it as a child of the copied folder
2004 */
2005 child = *iter;
2006 while (gtk_tree_model_iter_parent (model, &parent, &child)) {
2007 if (gtk_tree_selection_iter_is_selected (selection_data->selection,
2008 &parent)) {
2009 return;
2010 }
2011 child = parent;
2012 }
2013
2014 nautilus_file_ref (file);
2015 selection_data->list = g_list_prepend (selection_data->list, file);
2016 }
2017 }
2018
2019
2020 static GList *
2021 nautilus_list_view_get_selection_for_file_transfer (NautilusView *view)
2022 {
2023 struct SelectionForeachData selection_data;
2024
2025 selection_data.list = NULL;
2026 selection_data.selection = gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view);
2027
2028 gtk_tree_selection_selected_foreach (selection_data.selection,
2029 nautilus_list_view_get_selection_for_file_transfer_foreach_func, &selection_data);
2030
2031 return g_list_reverse (selection_data.list);
2032 }
2033
2034 static gboolean
2035 nautilus_list_view_is_empty (NautilusView *view)
2036 {
2037 return nautilus_list_model_is_empty (NAUTILUS_LIST_VIEW (view)->details->model);
2038 }
2039
2040 static void
2041 nautilus_list_view_end_file_changes (NautilusView *view)
2042 {
2043 NautilusListView *list_view;
2044
2045 list_view = NAUTILUS_LIST_VIEW (view);
2046
2047 if (list_view->details->new_selection_path) {
2048 gtk_tree_view_set_cursor (list_view->details->tree_view,
2049 list_view->details->new_selection_path,
2050 NULL, FALSE);
2051 gtk_tree_path_free (list_view->details->new_selection_path);
2052 list_view->details->new_selection_path = NULL;
2053 }
2054 }
2055
2056 static void
2057 nautilus_list_view_remove_file (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
2058 {
2059 GtkTreePath *path;
2060 GtkTreePath *file_path;
2061 GtkTreeIter iter;
2062 GtkTreeIter temp_iter;
2063 GtkTreeRowReference* row_reference;
2064 NautilusListView *list_view;
2065 GtkTreeModel* tree_model;
2066 GtkTreeSelection *selection;
2067
2068 path = NULL;
2069 row_reference = NULL;
2070 list_view = NAUTILUS_LIST_VIEW (view);
2071 tree_model = GTK_TREE_MODEL(list_view->details->model);
2072
2073 if (nautilus_list_model_get_tree_iter_from_file (list_view->details->model, file, directory, &iter)) {
2074 selection = gtk_tree_view_get_selection (list_view->details->tree_view);
2075 file_path = gtk_tree_model_get_path (tree_model, &iter);
2076
2077 if (gtk_tree_selection_path_is_selected (selection, file_path)) {
2078 /* get reference for next element in the list view. If the element to be deleted is the
2079 * last one, get reference to previous element. If there is only one element in view
2080 * no need to select anything.
2081 */
2082 temp_iter = iter;
2083
2084 if (gtk_tree_model_iter_next (tree_model, &iter)) {
2085 path = gtk_tree_model_get_path (tree_model, &iter);
2086 row_reference = gtk_tree_row_reference_new (tree_model, path);
2087 } else {
2088 path = gtk_tree_model_get_path (tree_model, &temp_iter);
2089 if (gtk_tree_path_prev (path)) {
2090 row_reference = gtk_tree_row_reference_new (tree_model, path);
2091 }
2092 }
2093 gtk_tree_path_free (path);
2094 }
2095
2096 gtk_tree_path_free (file_path);
2097
2098 nautilus_list_model_remove_file (list_view->details->model, file, directory);
2099
2100 if (gtk_tree_row_reference_valid (row_reference)) {
2101 if (list_view->details->new_selection_path) {
2102 gtk_tree_path_free (list_view->details->new_selection_path);
2103 }
2104 list_view->details->new_selection_path = gtk_tree_row_reference_get_path (row_reference);
2105 }
2106
2107 if (row_reference) {
2108 gtk_tree_row_reference_free (row_reference);
2109 }
2110 }
2111
2112
2113 }
2114
2115 static void
2116 nautilus_list_view_set_selection (NautilusView *view, GList *selection)
2117 {
2118 NautilusListView *list_view;
2119 GtkTreeSelection *tree_selection;
2120 GList *node;
2121 GList *iters, *l;
2122 NautilusFile *file;
2123
2124 list_view = NAUTILUS_LIST_VIEW (view);
2125 tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view);
2126
2127 g_signal_handlers_block_by_func (tree_selection, list_selection_changed_callback, view);
2128
2129 gtk_tree_selection_unselect_all (tree_selection);
2130 for (node = selection; node != NULL; node = node->next) {
2131 file = node->data;
2132 iters = nautilus_list_model_get_all_iters_for_file (list_view->details->model, file);
2133
2134 for (l = iters; l != NULL; l = l->next) {
2135 gtk_tree_selection_select_iter (tree_selection,
2136 (GtkTreeIter *)l->data);
2137 }
2138 g_list_free_full (iters, g_free);
2139 }
2140
2141 g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
2142 nautilus_view_notify_selection_changed (view);
2143 }
2144
2145 static void
2146 nautilus_list_view_invert_selection (NautilusView *view)
2147 {
2148 NautilusListView *list_view;
2149 GtkTreeSelection *tree_selection;
2150 GList *node;
2151 GList *iters, *l;
2152 NautilusFile *file;
2153 GList *selection = NULL;
2154
2155 list_view = NAUTILUS_LIST_VIEW (view);
2156 tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view);
2157
2158 g_signal_handlers_block_by_func (tree_selection, list_selection_changed_callback, view);
2159
2160 gtk_tree_selection_selected_foreach (tree_selection,
2161 nautilus_list_view_get_selection_foreach_func, &selection);
2162
2163 gtk_tree_selection_select_all (tree_selection);
2164
2165 for (node = selection; node != NULL; node = node->next) {
2166 file = node->data;
2167 iters = nautilus_list_model_get_all_iters_for_file (list_view->details->model, file);
2168
2169 for (l = iters; l != NULL; l = l->next) {
2170 gtk_tree_selection_unselect_iter (tree_selection,
2171 (GtkTreeIter *)l->data);
2172 }
2173 g_list_free_full (iters, g_free);
2174 }
2175
2176 g_list_free (selection);
2177
2178 g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
2179 nautilus_view_notify_selection_changed (view);
2180 }
2181
2182 static void
2183 nautilus_list_view_select_all (NautilusView *view)
2184 {
2185 gtk_tree_selection_select_all (gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view));
2186 }
2187
2188 static void
2189 nautilus_list_view_select_first (NautilusView *view)
2190 {
2191 GtkTreeSelection *selection;
2192 GtkTreeIter iter;
2193
2194 if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (NAUTILUS_LIST_VIEW (view)->details->model), &iter)) {
2195 return;
2196 }
2197 selection = gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view);
2198 gtk_tree_selection_select_iter (selection, &iter);
2199 }
2200
2201 static void
2202 column_editor_response_callback (GtkWidget *dialog,
2203 int response_id,
2204 gpointer user_data)
2205 {
2206 gtk_widget_destroy (GTK_WIDGET (dialog));
2207 }
2208
2209 static void
2210 column_chooser_changed_callback (NautilusColumnChooser *chooser,
2211 NautilusListView *view)
2212 {
2213 NautilusFile *file;
2214 char **visible_columns;
2215 char **column_order;
2216 GList *list;
2217 int i;
2218
2219 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (view));
2220
2221 nautilus_column_chooser_get_settings (chooser,
2222 &visible_columns,
2223 &column_order);
2224
2225 list = NULL;
2226 for (i = 0; visible_columns[i] != NULL; ++i) {
2227 list = g_list_prepend (list, visible_columns[i]);
2228 }
2229 list = g_list_reverse (list);
2230 nautilus_file_set_metadata_list (file,
2231 NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS,
2232 list);
2233 g_list_free (list);
2234
2235 list = NULL;
2236 for (i = 0; column_order[i] != NULL; ++i) {
2237 list = g_list_prepend (list, column_order[i]);
2238 }
2239 list = g_list_reverse (list);
2240 nautilus_file_set_metadata_list (file,
2241 NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER,
2242 list);
2243 g_list_free (list);
2244
2245 apply_columns_settings (view, column_order, visible_columns);
2246
2247 g_strfreev (visible_columns);
2248 g_strfreev (column_order);
2249 }
2250
2251 static void
2252 column_chooser_set_from_arrays (NautilusColumnChooser *chooser,
2253 NautilusListView *view,
2254 char **visible_columns,
2255 char **column_order)
2256 {
2257 g_signal_handlers_block_by_func
2258 (chooser, G_CALLBACK (column_chooser_changed_callback), view);
2259
2260 nautilus_column_chooser_set_settings (chooser,
2261 visible_columns,
2262 column_order);
2263
2264 g_signal_handlers_unblock_by_func
2265 (chooser, G_CALLBACK (column_chooser_changed_callback), view);
2266 }
2267
2268 static void
2269 column_chooser_set_from_settings (NautilusColumnChooser *chooser,
2270 NautilusListView *view)
2271 {
2272 char **visible_columns;
2273 char **column_order;
2274
2275 visible_columns = get_visible_columns (view);
2276 column_order = get_column_order (view);
2277
2278 column_chooser_set_from_arrays (chooser, view,
2279 visible_columns, column_order);
2280
2281 g_strfreev (visible_columns);
2282 g_strfreev (column_order);
2283 }
2284
2285 static void
2286 column_chooser_use_default_callback (NautilusColumnChooser *chooser,
2287 NautilusListView *view)
2288 {
2289 NautilusFile *file;
2290 char **default_columns;
2291 char **default_order;
2292
2293 file = nautilus_view_get_directory_as_file
2294 (NAUTILUS_VIEW (view));
2295
2296 nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, NULL);
2297 nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, NULL);
2298
2299 /* set view values ourselves, as new metadata could not have been
2300 * updated yet.
2301 */
2302 default_columns = nautilus_file_is_in_trash (file) ?
2303 g_strdupv ((gchar **) default_trash_visible_columns) :
2304 g_settings_get_strv (nautilus_list_view_preferences,
2305 NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
2306
2307 default_order = nautilus_file_is_in_trash (file) ?
2308 g_strdupv ((gchar **) default_trash_columns_order) :
2309 g_settings_get_strv (nautilus_list_view_preferences,
2310 NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER);
2311
2312 apply_columns_settings (view, default_order, default_columns);
2313 column_chooser_set_from_arrays (chooser, view,
2314 default_columns, default_order);
2315
2316 g_strfreev (default_columns);
2317 g_strfreev (default_order);
2318 }
2319
2320 static GtkWidget *
2321 create_column_editor (NautilusListView *view)
2322 {
2323 GtkWidget *window;
2324 GtkWidget *label;
2325 GtkWidget *box;
2326 GtkWidget *column_chooser;
2327 GtkWidget *alignment;
2328 NautilusFile *file;
2329 char *str;
2330 char *name;
2331 const char *label_text;
2332
2333 file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (view));
2334 name = nautilus_file_get_display_name (file);
2335 str = g_strdup_printf (_("%s Visible Columns"), name);
2336 g_free (name);
2337
2338 window = gtk_dialog_new_with_buttons (str,
2339 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
2340 GTK_DIALOG_DESTROY_WITH_PARENT,
2341 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
2342 NULL);
2343 g_free (str);
2344 g_signal_connect (window, "response",
2345 G_CALLBACK (column_editor_response_callback), NULL);
2346
2347 gtk_window_set_default_size (GTK_WINDOW (window), 300, 400);
2348
2349 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
2350 gtk_container_set_border_width (GTK_CONTAINER (box), 12);
2351 gtk_widget_show (box);
2352 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))), box,
2353 TRUE, TRUE, 0);
2354
2355 label_text = _("Choose the order of information to appear in this folder:");
2356 str = g_strconcat ("<b>", label_text, "</b>", NULL);
2357 label = gtk_label_new (NULL);
2358 gtk_label_set_markup (GTK_LABEL (label), str);
2359 gtk_label_set_line_wrap (GTK_LABEL (label), FALSE);
2360 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
2361 gtk_widget_show (label);
2362 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
2363
2364 g_free (str);
2365
2366 alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
2367 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
2368 0, 0, 12, 0);
2369 gtk_widget_show (alignment);
2370 gtk_box_pack_start (GTK_BOX (box), alignment, TRUE, TRUE, 0);
2371
2372 column_chooser = nautilus_column_chooser_new (file);
2373 gtk_widget_show (column_chooser);
2374 gtk_container_add (GTK_CONTAINER (alignment), column_chooser);
2375
2376 g_signal_connect (column_chooser, "changed",
2377 G_CALLBACK (column_chooser_changed_callback),
2378 view);
2379 g_signal_connect (column_chooser, "use_default",
2380 G_CALLBACK (column_chooser_use_default_callback),
2381 view);
2382
2383 column_chooser_set_from_settings
2384 (NAUTILUS_COLUMN_CHOOSER (column_chooser), view);
2385
2386 return window;
2387 }
2388
2389 static void
2390 action_visible_columns_callback (GtkAction *action,
2391 gpointer callback_data)
2392 {
2393 NautilusListView *list_view;
2394
2395 list_view = NAUTILUS_LIST_VIEW (callback_data);
2396
2397 if (list_view->details->column_editor) {
2398 gtk_window_present (GTK_WINDOW (list_view->details->column_editor));
2399 } else {
2400 list_view->details->column_editor = create_column_editor (list_view);
2401 g_object_add_weak_pointer (G_OBJECT (list_view->details->column_editor),
2402 (gpointer *) &list_view->details->column_editor);
2403
2404 gtk_widget_show (list_view->details->column_editor);
2405 }
2406 }
2407
2408 static const GtkActionEntry list_view_entries[] = {
2409 /* name, stock id */ { "Visible Columns", NULL,
2410 /* label, accelerator */ N_("Visible _Columns..."), NULL,
2411 /* tooltip */ N_("Select the columns visible in this folder"),
2412 G_CALLBACK (action_visible_columns_callback) },
2413 };
2414
2415 static void
2416 nautilus_list_view_merge_menus (NautilusView *view)
2417 {
2418 NautilusListView *list_view;
2419 GtkUIManager *ui_manager;
2420 GtkActionGroup *action_group;
2421
2422 list_view = NAUTILUS_LIST_VIEW (view);
2423
2424 NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->merge_menus (view);
2425
2426 ui_manager = nautilus_view_get_ui_manager (view);
2427
2428 action_group = gtk_action_group_new ("ListViewActions");
2429 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
2430 list_view->details->list_action_group = action_group;
2431 gtk_action_group_add_actions (action_group,
2432 list_view_entries, G_N_ELEMENTS (list_view_entries),
2433 list_view);
2434
2435 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
2436 g_object_unref (action_group); /* owned by ui manager */
2437
2438 list_view->details->list_merge_id =
2439 gtk_ui_manager_add_ui_from_resource (ui_manager, "/org/gnome/nautilus/nautilus-list-view-ui.xml", NULL);
2440
2441 list_view->details->menus_ready = TRUE;
2442 }
2443
2444 static void
2445 nautilus_list_view_unmerge_menus (NautilusView *view)
2446 {
2447 NautilusListView *list_view;
2448 GtkUIManager *ui_manager;
2449
2450 list_view = NAUTILUS_LIST_VIEW (view);
2451
2452 NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->unmerge_menus (view);
2453
2454 ui_manager = nautilus_view_get_ui_manager (view);
2455 if (ui_manager != NULL) {
2456 nautilus_ui_unmerge_ui (ui_manager,
2457 &list_view->details->list_merge_id,
2458 &list_view->details->list_action_group);
2459 }
2460 }
2461
2462 static void
2463 nautilus_list_view_update_menus (NautilusView *view)
2464 {
2465 NautilusListView *list_view;
2466
2467 list_view = NAUTILUS_LIST_VIEW (view);
2468
2469 /* don't update if the menus aren't ready */
2470 if (!list_view->details->menus_ready) {
2471 return;
2472 }
2473
2474 NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->update_menus (view);
2475 }
2476
2477 /* Reset sort criteria and zoom level to match defaults */
2478 static void
2479 nautilus_list_view_reset_to_defaults (NautilusView *view)
2480 {
2481 NautilusFile *file;
2482 const gchar *default_sort_order;
2483 gboolean default_sort_reversed;
2484
2485 file = nautilus_view_get_directory_as_file (view);
2486
2487 nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN, NULL, NULL);
2488 nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED, NULL, NULL);
2489 nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, NULL);
2490 nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, NULL);
2491
2492 default_sort_order = get_default_sort_order (file, &default_sort_reversed);
2493
2494 gtk_tree_sortable_set_sort_column_id
2495 (GTK_TREE_SORTABLE (NAUTILUS_LIST_VIEW (view)->details->model),
2496 nautilus_list_model_get_sort_column_id_from_attribute (NAUTILUS_LIST_VIEW (view)->details->model,
2497 g_quark_from_string (default_sort_order)),
2498 default_sort_reversed ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING);
2499
2500 nautilus_list_view_set_zoom_level (NAUTILUS_LIST_VIEW (view), get_default_zoom_level (), FALSE);
2501 set_columns_settings_from_metadata_and_preferences (NAUTILUS_LIST_VIEW (view));
2502 }
2503
2504 static void
2505 nautilus_list_view_set_zoom_level (NautilusListView *view,
2506 NautilusZoomLevel new_level,
2507 gboolean always_emit)
2508 {
2509 int column;
2510
2511 g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
2512 g_return_if_fail (new_level >= NAUTILUS_ZOOM_LEVEL_SMALLEST &&
2513 new_level <= NAUTILUS_ZOOM_LEVEL_LARGEST);
2514
2515 if (view->details->zoom_level == new_level) {
2516 if (always_emit) {
2517 g_signal_emit_by_name (NAUTILUS_VIEW(view), "zoom_level_changed");
2518 }
2519 return;
2520 }
2521
2522 view->details->zoom_level = new_level;
2523 g_signal_emit_by_name (NAUTILUS_VIEW(view), "zoom_level_changed");
2524
2525 /* Select correctly scaled icons. */
2526 column = nautilus_list_model_get_column_id_from_zoom_level (new_level);
2527 gtk_tree_view_column_set_attributes (view->details->file_name_column,
2528 GTK_CELL_RENDERER (view->details->pixbuf_cell),
2529 "pixbuf", column,
2530 NULL);
2531
2532 nautilus_view_update_menus (NAUTILUS_VIEW (view));
2533
2534 set_up_pixbuf_size (view);
2535 }
2536
2537 static void
2538 nautilus_list_view_bump_zoom_level (NautilusView *view, int zoom_increment)
2539 {
2540 NautilusListView *list_view;
2541 gint new_level;
2542
2543 g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
2544
2545 list_view = NAUTILUS_LIST_VIEW (view);
2546 new_level = list_view->details->zoom_level + zoom_increment;
2547
2548 if (new_level >= NAUTILUS_ZOOM_LEVEL_SMALLEST &&
2549 new_level <= NAUTILUS_ZOOM_LEVEL_LARGEST) {
2550 nautilus_list_view_set_zoom_level (list_view, new_level, FALSE);
2551 }
2552 }
2553
2554 static NautilusZoomLevel
2555 nautilus_list_view_get_zoom_level (NautilusView *view)
2556 {
2557 NautilusListView *list_view;
2558
2559 g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), NAUTILUS_ZOOM_LEVEL_STANDARD);
2560
2561 list_view = NAUTILUS_LIST_VIEW (view);
2562
2563 return list_view->details->zoom_level;
2564 }
2565
2566 static void
2567 nautilus_list_view_zoom_to_level (NautilusView *view,
2568 NautilusZoomLevel zoom_level)
2569 {
2570 NautilusListView *list_view;
2571
2572 g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
2573
2574 list_view = NAUTILUS_LIST_VIEW (view);
2575
2576 nautilus_list_view_set_zoom_level (list_view, zoom_level, FALSE);
2577 }
2578
2579 static void
2580 nautilus_list_view_restore_default_zoom_level (NautilusView *view)
2581 {
2582 NautilusListView *list_view;
2583
2584 g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
2585
2586 list_view = NAUTILUS_LIST_VIEW (view);
2587
2588 nautilus_list_view_set_zoom_level (list_view, get_default_zoom_level (), FALSE);
2589 }
2590
2591 static gboolean
2592 nautilus_list_view_can_zoom_in (NautilusView *view)
2593 {
2594 g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), FALSE);
2595
2596 return NAUTILUS_LIST_VIEW (view)->details->zoom_level < NAUTILUS_ZOOM_LEVEL_LARGEST;
2597 }
2598
2599 static gboolean
2600 nautilus_list_view_can_zoom_out (NautilusView *view)
2601 {
2602 g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), FALSE);
2603
2604 return NAUTILUS_LIST_VIEW (view)->details->zoom_level > NAUTILUS_ZOOM_LEVEL_SMALLEST;
2605 }
2606
2607 static void
2608 nautilus_list_view_start_renaming_file (NautilusView *view,
2609 NautilusFile *file,
2610 gboolean select_all)
2611 {
2612 NautilusListView *list_view;
2613 GtkTreeIter iter;
2614 GtkTreePath *path;
2615
2616 list_view = NAUTILUS_LIST_VIEW (view);
2617
2618 /* Select all if we are in renaming mode already */
2619 if (list_view->details->file_name_column && list_view->details->editable_widget) {
2620 gtk_editable_select_region (GTK_EDITABLE (list_view->details->editable_widget),
2621 0,
2622 -1);
2623 return;
2624 }
2625
2626 if (!nautilus_list_model_get_first_iter_for_file (list_view->details->model, file, &iter)) {
2627 return;
2628 }
2629
2630 /* call parent class to make sure the right icon is selected */
2631 NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->start_renaming_file (view, file, select_all);
2632
2633 /* Freeze updates to the view to prevent losing rename focus when the tree view updates */
2634 nautilus_view_freeze_updates (NAUTILUS_VIEW (view));
2635
2636 path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), &iter);
2637
2638 /* Make filename-cells editable. */
2639 g_object_set (G_OBJECT (list_view->details->file_name_cell),
2640 "editable", TRUE,
2641 NULL);
2642
2643 gtk_tree_view_scroll_to_cell (list_view->details->tree_view,
2644 NULL,
2645 list_view->details->file_name_column,
2646 TRUE, 0.0, 0.0);
2647 gtk_tree_view_set_cursor_on_cell (list_view->details->tree_view,
2648 path,
2649 list_view->details->file_name_column,
2650 GTK_CELL_RENDERER (list_view->details->file_name_cell),
2651 TRUE);
2652
2653 /* set cursor also triggers editing-started, where we save the editable widget */
2654 if (list_view->details->editable_widget != NULL) {
2655 int start_offset = 0;
2656 int end_offset = -1;
2657
2658 if (!select_all) {
2659 eel_filename_get_rename_region (list_view->details->original_name,
2660 &start_offset, &end_offset);
2661 }
2662
2663 gtk_editable_select_region (GTK_EDITABLE (list_view->details->editable_widget),
2664 start_offset, end_offset);
2665 }
2666
2667 gtk_tree_path_free (path);
2668 }
2669
2670 static void
2671 nautilus_list_view_click_policy_changed (NautilusView *directory_view)
2672 {
2673 GdkWindow *win;
2674 GdkDisplay *display;
2675 NautilusListView *view;
2676 GtkTreeIter iter;
2677 GtkTreeView *tree;
2678
2679 view = NAUTILUS_LIST_VIEW (directory_view);
2680
2681 /* ensure that we unset the hand cursor and refresh underlined rows */
2682 if (get_click_policy () == NAUTILUS_CLICK_POLICY_DOUBLE) {
2683 if (view->details->hover_path != NULL) {
2684 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->model),
2685 &iter, view->details->hover_path)) {
2686 gtk_tree_model_row_changed (GTK_TREE_MODEL (view->details->model),
2687 view->details->hover_path, &iter);
2688 }
2689
2690 gtk_tree_path_free (view->details->hover_path);
2691 view->details->hover_path = NULL;
2692 }
2693
2694 tree = view->details->tree_view;
2695 if (gtk_widget_get_realized (GTK_WIDGET (tree))) {
2696 win = gtk_widget_get_window (GTK_WIDGET (tree));
2697 gdk_window_set_cursor (win, NULL);
2698
2699 display = gtk_widget_get_display (GTK_WIDGET (view));
2700 if (display != NULL) {
2701 gdk_display_flush (display);
2702 }
2703 }
2704
2705 g_clear_object (&hand_cursor);
2706 } else if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE) {
2707 if (hand_cursor == NULL) {
2708 hand_cursor = gdk_cursor_new(GDK_HAND2);
2709 }
2710 }
2711 }
2712
2713 static void
2714 default_sort_order_changed_callback (gpointer callback_data)
2715 {
2716 NautilusListView *list_view;
2717
2718 list_view = NAUTILUS_LIST_VIEW (callback_data);
2719
2720 set_sort_order_from_metadata_and_preferences (list_view);
2721 }
2722
2723 static void
2724 default_visible_columns_changed_callback (gpointer callback_data)
2725 {
2726 NautilusListView *list_view;
2727
2728 list_view = NAUTILUS_LIST_VIEW (callback_data);
2729
2730 set_columns_settings_from_metadata_and_preferences (list_view);
2731 }
2732
2733 static void
2734 default_column_order_changed_callback (gpointer callback_data)
2735 {
2736 NautilusListView *list_view;
2737
2738 list_view = NAUTILUS_LIST_VIEW (callback_data);
2739
2740 set_columns_settings_from_metadata_and_preferences (list_view);
2741 }
2742
2743 static void
2744 nautilus_list_view_sort_directories_first_changed (NautilusView *view)
2745 {
2746 NautilusListView *list_view;
2747
2748 list_view = NAUTILUS_LIST_VIEW (view);
2749
2750 nautilus_list_model_set_should_sort_directories_first (list_view->details->model,
2751 nautilus_view_should_sort_directories_first (view));
2752 }
2753
2754 static int
2755 nautilus_list_view_compare_files (NautilusView *view, NautilusFile *file1, NautilusFile *file2)
2756 {
2757 NautilusListView *list_view;
2758
2759 list_view = NAUTILUS_LIST_VIEW (view);
2760 return nautilus_list_model_compare_func (list_view->details->model, file1, file2);
2761 }
2762
2763 static gboolean
2764 nautilus_list_view_using_manual_layout (NautilusView *view)
2765 {
2766 g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), FALSE);
2767
2768 return FALSE;
2769 }
2770
2771 static void
2772 nautilus_list_view_dispose (GObject *object)
2773 {
2774 NautilusListView *list_view;
2775
2776 list_view = NAUTILUS_LIST_VIEW (object);
2777
2778 if (list_view->details->model) {
2779 stop_cell_editing (list_view);
2780 g_object_unref (list_view->details->model);
2781 list_view->details->model = NULL;
2782 }
2783
2784 if (list_view->details->drag_dest) {
2785 g_object_unref (list_view->details->drag_dest);
2786 list_view->details->drag_dest = NULL;
2787 }
2788
2789 if (list_view->details->renaming_file_activate_timeout != 0) {
2790 g_source_remove (list_view->details->renaming_file_activate_timeout);
2791 list_view->details->renaming_file_activate_timeout = 0;
2792 }
2793
2794 if (list_view->details->clipboard_handler_id != 0) {
2795 g_signal_handler_disconnect (nautilus_clipboard_monitor_get (),
2796 list_view->details->clipboard_handler_id);
2797 list_view->details->clipboard_handler_id = 0;
2798 }
2799
2800 G_OBJECT_CLASS (nautilus_list_view_parent_class)->dispose (object);
2801 }
2802
2803 static void
2804 nautilus_list_view_finalize (GObject *object)
2805 {
2806 NautilusListView *list_view;
2807
2808 list_view = NAUTILUS_LIST_VIEW (object);
2809
2810 g_free (list_view->details->original_name);
2811 list_view->details->original_name = NULL;
2812
2813 if (list_view->details->double_click_path[0]) {
2814 gtk_tree_path_free (list_view->details->double_click_path[0]);
2815 }
2816 if (list_view->details->double_click_path[1]) {
2817 gtk_tree_path_free (list_view->details->double_click_path[1]);
2818 }
2819 if (list_view->details->new_selection_path) {
2820 gtk_tree_path_free (list_view->details->new_selection_path);
2821 }
2822
2823 g_list_free (list_view->details->cells);
2824 g_hash_table_destroy (list_view->details->columns);
2825
2826 if (list_view->details->hover_path != NULL) {
2827 gtk_tree_path_free (list_view->details->hover_path);
2828 }
2829
2830 if (list_view->details->column_editor != NULL) {
2831 gtk_widget_destroy (list_view->details->column_editor);
2832 }
2833
2834 g_free (list_view->details);
2835
2836 g_signal_handlers_disconnect_by_func (nautilus_preferences,
2837 default_sort_order_changed_callback,
2838 list_view);
2839 g_signal_handlers_disconnect_by_func (nautilus_list_view_preferences,
2840 default_visible_columns_changed_callback,
2841 list_view);
2842 g_signal_handlers_disconnect_by_func (nautilus_list_view_preferences,
2843 default_column_order_changed_callback,
2844 list_view);
2845
2846 G_OBJECT_CLASS (nautilus_list_view_parent_class)->finalize (object);
2847 }
2848
2849 static char *
2850 nautilus_list_view_get_first_visible_file (NautilusView *view)
2851 {
2852 NautilusFile *file;
2853 GtkTreePath *path;
2854 GtkTreeIter iter;
2855 NautilusListView *list_view;
2856
2857 list_view = NAUTILUS_LIST_VIEW (view);
2858
2859 if (gtk_tree_view_get_path_at_pos (list_view->details->tree_view,
2860 0, 0,
2861 &path, NULL, NULL, NULL)) {
2862 gtk_tree_model_get_iter (GTK_TREE_MODEL (list_view->details->model),
2863 &iter, path);
2864
2865 gtk_tree_path_free (path);
2866
2867 gtk_tree_model_get (GTK_TREE_MODEL (list_view->details->model),
2868 &iter,
2869 NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
2870 -1);
2871 if (file) {
2872 char *uri;
2873
2874 uri = nautilus_file_get_uri (file);
2875
2876 nautilus_file_unref (file);
2877
2878 return uri;
2879 }
2880 }
2881
2882 return NULL;
2883 }
2884
2885 static void
2886 nautilus_list_view_scroll_to_file (NautilusListView *view,
2887 NautilusFile *file)
2888 {
2889 GtkTreePath *path;
2890 GtkTreeIter iter;
2891
2892 if (!nautilus_list_model_get_first_iter_for_file (view->details->model, file, &iter)) {
2893 return;
2894 }
2895
2896 path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->details->model), &iter);
2897
2898 gtk_tree_view_scroll_to_cell (view->details->tree_view,
2899 path, NULL,
2900 TRUE, 0.0, 0.0);
2901
2902 gtk_tree_path_free (path);
2903 }
2904
2905 static void
2906 list_view_scroll_to_file (NautilusView *view,
2907 const char *uri)
2908 {
2909 NautilusFile *file;
2910
2911 if (uri != NULL) {
2912 /* Only if existing, since we don't want to add the file to
2913 the directory if it has been removed since then */
2914 file = nautilus_file_get_existing_by_uri (uri);
2915 if (file != NULL) {
2916 nautilus_list_view_scroll_to_file (NAUTILUS_LIST_VIEW (view), file);
2917 nautilus_file_unref (file);
2918 }
2919 }
2920 }
2921
2922 static void
2923 list_view_notify_clipboard_info (NautilusClipboardMonitor *monitor,
2924 NautilusClipboardInfo *info,
2925 NautilusListView *view)
2926 {
2927 /* this could be called as a result of _end_loading() being
2928 * called after _dispose(), where the model is cleared.
2929 */
2930 if (view->details->model == NULL) {
2931 return;
2932 }
2933
2934 if (info != NULL && info->cut) {
2935 nautilus_list_model_set_highlight_for_files (view->details->model, info->files);
2936 } else {
2937 nautilus_list_model_set_highlight_for_files (view->details->model, NULL);
2938 }
2939 }
2940
2941 static void
2942 nautilus_list_view_end_loading (NautilusView *view,
2943 gboolean all_files_seen)
2944 {
2945 NautilusClipboardMonitor *monitor;
2946 NautilusClipboardInfo *info;
2947
2948 monitor = nautilus_clipboard_monitor_get ();
2949 info = nautilus_clipboard_monitor_get_clipboard_info (monitor);
2950
2951 list_view_notify_clipboard_info (monitor, info, NAUTILUS_LIST_VIEW (view));
2952 }
2953
2954 static const char *
2955 nautilus_list_view_get_id (NautilusView *view)
2956 {
2957 return NAUTILUS_LIST_VIEW_ID;
2958 }
2959
2960 static void
2961 nautilus_list_view_class_init (NautilusListViewClass *class)
2962 {
2963 NautilusViewClass *nautilus_view_class;
2964
2965 nautilus_view_class = NAUTILUS_VIEW_CLASS (class);
2966
2967 G_OBJECT_CLASS (class)->dispose = nautilus_list_view_dispose;
2968 G_OBJECT_CLASS (class)->finalize = nautilus_list_view_finalize;
2969
2970 nautilus_view_class->add_file = nautilus_list_view_add_file;
2971 nautilus_view_class->begin_loading = nautilus_list_view_begin_loading;
2972 nautilus_view_class->end_loading = nautilus_list_view_end_loading;
2973 nautilus_view_class->bump_zoom_level = nautilus_list_view_bump_zoom_level;
2974 nautilus_view_class->can_zoom_in = nautilus_list_view_can_zoom_in;
2975 nautilus_view_class->can_zoom_out = nautilus_list_view_can_zoom_out;
2976 nautilus_view_class->click_policy_changed = nautilus_list_view_click_policy_changed;
2977 nautilus_view_class->clear = nautilus_list_view_clear;
2978 nautilus_view_class->file_changed = nautilus_list_view_file_changed;
2979 nautilus_view_class->get_backing_uri = nautilus_list_view_get_backing_uri;
2980 nautilus_view_class->get_selection = nautilus_list_view_get_selection;
2981 nautilus_view_class->get_selection_for_file_transfer = nautilus_list_view_get_selection_for_file_transfer;
2982 nautilus_view_class->is_empty = nautilus_list_view_is_empty;
2983 nautilus_view_class->remove_file = nautilus_list_view_remove_file;
2984 nautilus_view_class->merge_menus = nautilus_list_view_merge_menus;
2985 nautilus_view_class->unmerge_menus = nautilus_list_view_unmerge_menus;
2986 nautilus_view_class->update_menus = nautilus_list_view_update_menus;
2987 nautilus_view_class->reset_to_defaults = nautilus_list_view_reset_to_defaults;
2988 nautilus_view_class->restore_default_zoom_level = nautilus_list_view_restore_default_zoom_level;
2989 nautilus_view_class->reveal_selection = nautilus_list_view_reveal_selection;
2990 nautilus_view_class->select_all = nautilus_list_view_select_all;
2991 nautilus_view_class->select_first = nautilus_list_view_select_first;
2992 nautilus_view_class->set_selection = nautilus_list_view_set_selection;
2993 nautilus_view_class->invert_selection = nautilus_list_view_invert_selection;
2994 nautilus_view_class->compare_files = nautilus_list_view_compare_files;
2995 nautilus_view_class->sort_directories_first_changed = nautilus_list_view_sort_directories_first_changed;
2996 nautilus_view_class->start_renaming_file = nautilus_list_view_start_renaming_file;
2997 nautilus_view_class->get_zoom_level = nautilus_list_view_get_zoom_level;
2998 nautilus_view_class->zoom_to_level = nautilus_list_view_zoom_to_level;
2999 nautilus_view_class->end_file_changes = nautilus_list_view_end_file_changes;
3000 nautilus_view_class->using_manual_layout = nautilus_list_view_using_manual_layout;
3001 nautilus_view_class->get_view_id = nautilus_list_view_get_id;
3002 nautilus_view_class->get_first_visible_file = nautilus_list_view_get_first_visible_file;
3003 nautilus_view_class->scroll_to_file = list_view_scroll_to_file;
3004 }
3005
3006 static void
3007 nautilus_list_view_init (NautilusListView *list_view)
3008 {
3009 list_view->details = g_new0 (NautilusListViewDetails, 1);
3010
3011 /* ensure that the zoom level is always set before settings up the tree view columns */
3012 list_view->details->zoom_level = get_default_zoom_level ();
3013
3014 create_and_set_up_tree_view (list_view);
3015
3016 g_signal_connect_swapped (nautilus_preferences,
3017 "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER,
3018 G_CALLBACK (default_sort_order_changed_callback),
3019 list_view);
3020 g_signal_connect_swapped (nautilus_preferences,
3021 "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER,
3022 G_CALLBACK (default_sort_order_changed_callback),
3023 list_view);
3024 g_signal_connect_swapped (nautilus_list_view_preferences,
3025 "changed::" NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS,
3026 G_CALLBACK (default_visible_columns_changed_callback),
3027 list_view);
3028 g_signal_connect_swapped (nautilus_list_view_preferences,
3029 "changed::" NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER,
3030 G_CALLBACK (default_column_order_changed_callback),
3031 list_view);
3032
3033 nautilus_list_view_click_policy_changed (NAUTILUS_VIEW (list_view));
3034
3035 nautilus_list_view_sort_directories_first_changed (NAUTILUS_VIEW (list_view));
3036 nautilus_list_view_set_zoom_level (list_view, get_default_zoom_level (), TRUE);
3037
3038 list_view->details->hover_path = NULL;
3039 list_view->details->clipboard_handler_id =
3040 g_signal_connect (nautilus_clipboard_monitor_get (),
3041 "clipboard_info",
3042 G_CALLBACK (list_view_notify_clipboard_info), list_view);
3043 }
3044
3045 static NautilusView *
3046 nautilus_list_view_create (NautilusWindowSlot *slot)
3047 {
3048 NautilusListView *view;
3049
3050 view = g_object_new (NAUTILUS_TYPE_LIST_VIEW,
3051 "window-slot", slot,
3052 NULL);
3053 return NAUTILUS_VIEW (view);
3054 }
3055
3056 static gboolean
3057 nautilus_list_view_supports_uri (const char *uri,
3058 GFileType file_type,
3059 const char *mime_type)
3060 {
3061 if (file_type == G_FILE_TYPE_DIRECTORY) {
3062 return TRUE;
3063 }
3064 if (strcmp (mime_type, NAUTILUS_SAVED_SEARCH_MIMETYPE) == 0){
3065 return TRUE;
3066 }
3067 if (g_str_has_prefix (uri, "trash:")) {
3068 return TRUE;
3069 }
3070 if (g_str_has_prefix (uri, EEL_SEARCH_URI)) {
3071 return TRUE;
3072 }
3073
3074 return FALSE;
3075 }
3076
3077 static NautilusViewInfo nautilus_list_view = {
3078 NAUTILUS_LIST_VIEW_ID,
3079 /* translators: this is used in the view selection dropdown
3080 * of navigation windows and in the preferences dialog */
3081 N_("List View"),
3082 /* translators: this is used in the view menu */
3083 N_("_List"),
3084 N_("The list view encountered an error."),
3085 N_("The list view encountered an error while starting up."),
3086 N_("Display this location with the list view."),
3087 nautilus_list_view_create,
3088 nautilus_list_view_supports_uri
3089 };
3090
3091 void
3092 nautilus_list_view_register (void)
3093 {
3094 nautilus_list_view.view_combo_label = _(nautilus_list_view.view_combo_label);
3095 nautilus_list_view.view_menu_label_with_mnemonic = _(nautilus_list_view.view_menu_label_with_mnemonic);
3096 nautilus_list_view.error_label = _(nautilus_list_view.error_label);
3097 nautilus_list_view.startup_error_label = _(nautilus_list_view.startup_error_label);
3098 nautilus_list_view.display_location_label = _(nautilus_list_view.display_location_label);
3099
3100 nautilus_view_factory_register (&nautilus_list_view);
3101 }
3102
3103 GtkTreeView*
3104 nautilus_list_view_get_tree_view (NautilusListView *list_view)
3105 {
3106 return list_view->details->tree_view;
3107 }