1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3
/* fm-list-view.c - implementation of list view of directory.
5
Copyright (C) 2000 Eazel, Inc.
6
Copyright (C) 2001, 2002 Anders Carlsson <andersca@gnu.org>
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.
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.
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.
23
Authors: John Sullivan <sullivan@eazel.com>
24
Anders Carlsson <andersca@gnu.org>
25
David Emory Watson <dwatson@cs.ucr.edu>
29
#include "nautilus-list-view.h"
31
#include "nautilus-list-model.h"
32
#include "nautilus-error-reporting.h"
33
#include "nautilus-view-dnd.h"
36
#include <eel/eel-vfs-extensions.h>
37
#include <eel/eel-gdk-extensions.h>
38
#include <eel/eel-glib-extensions.h>
40
#include <gdk/gdkkeysyms.h>
42
#include <glib/gi18n.h>
43
#include <glib-object.h>
44
#include <libnautilus-extension/nautilus-column-provider.h>
45
#include <libnautilus-private/nautilus-clipboard-monitor.h>
46
#include <libnautilus-private/nautilus-column-chooser.h>
47
#include <libnautilus-private/nautilus-column-utilities.h>
48
#include <libnautilus-private/nautilus-dnd.h>
49
#include <libnautilus-private/nautilus-file-dnd.h>
50
#include <libnautilus-private/nautilus-file-utilities.h>
51
#include <libnautilus-private/nautilus-ui-utilities.h>
52
#include <libnautilus-private/nautilus-global-preferences.h>
53
#include <libnautilus-private/nautilus-metadata.h>
54
#include <libnautilus-private/nautilus-module.h>
55
#include <libnautilus-private/nautilus-tree-view-drag-dest.h>
56
#include <libnautilus-private/nautilus-clipboard.h>
58
#define DEBUG_FLAG NAUTILUS_DEBUG_LIST_VIEW
59
#include <libnautilus-private/nautilus-debug.h>
61
struct NautilusListViewDetails {
62
GtkTreeView *tree_view;
63
NautilusListModel *model;
64
GtkActionGroup *list_action_group;
67
GtkTreeViewColumn *file_name_column;
68
int file_name_column_num;
70
GtkCellRendererPixbuf *pixbuf_cell;
71
GtkCellRendererText *file_name_cell;
73
GtkCellEditable *editable_widget;
75
NautilusZoomLevel zoom_level;
77
NautilusTreeViewDragDest *drag_dest;
79
GtkTreePath *double_click_path[2]; /* Both clicks in a double click need to be on the same row */
81
GtkTreePath *new_selection_path; /* Path of the new selection after removing a file */
83
GtkTreePath *hover_path;
89
gboolean drag_started;
90
gboolean ignore_button_release;
91
gboolean row_selected_on_button_down;
96
GtkWidget *column_editor;
100
NautilusFile *renaming_file;
101
gboolean rename_done;
102
guint renaming_file_activate_timeout;
104
gulong clipboard_handler_id;
106
GQuark last_sort_attr;
109
struct SelectionForeachData {
111
GtkTreeSelection *selection;
115
* The row height should be large enough to not clip emblems.
116
* Computing this would be costly, so we just choose a number
117
* that works well with the set of emblems we've designed.
119
#define LIST_VIEW_MINIMUM_ROW_HEIGHT 28
121
/* We wait two seconds after row is collapsed to unload the subdirectory */
122
#define COLLAPSE_TO_UNLOAD_DELAY 2
124
/* Wait for the rename to end when activating a file being renamed */
125
#define WAIT_FOR_RENAME_ON_ACTIVATE 200
127
static GdkCursor * hand_cursor = NULL;
129
static GtkTargetList * source_target_list = NULL;
131
static GList *nautilus_list_view_get_selection (NautilusView *view);
132
static GList *nautilus_list_view_get_selection_for_file_transfer (NautilusView *view);
133
static void nautilus_list_view_set_zoom_level (NautilusListView *view,
134
NautilusZoomLevel new_level,
135
gboolean always_set_level);
136
static void nautilus_list_view_scroll_to_file (NautilusListView *view,
138
static void nautilus_list_view_rename_callback (NautilusFile *file,
139
GFile *result_location,
141
gpointer callback_data);
143
static void apply_columns_settings (NautilusListView *list_view,
145
char **visible_columns);
146
static char **get_visible_columns (NautilusListView *list_view);
147
static char **get_default_visible_columns (NautilusListView *list_view);
148
static char **get_column_order (NautilusListView *list_view);
149
static char **get_default_column_order (NautilusListView *list_view);
152
G_DEFINE_TYPE (NautilusListView, nautilus_list_view, NAUTILUS_TYPE_VIEW);
154
static const char * default_search_visible_columns[] = {
155
"name", "size", "type", "where", NULL
158
static const char * default_search_columns_order[] = {
159
"name", "size", "type", "where", NULL
162
static const char * default_trash_visible_columns[] = {
163
"name", "size", "type", "trashed_on", "trash_orig_path", NULL
166
static const char * default_trash_columns_order[] = {
167
"name", "size", "type", "trashed_on", "trash_orig_path", NULL
171
get_default_sort_order (NautilusFile *file, gboolean *reversed)
173
NautilusFileSortType default_sort_order;
174
gboolean default_sort_reversed;
176
const char *attributes[] = {
177
"name", /* is really "manually" which doesn't apply to lists */
187
retval = nautilus_file_get_default_sort_attribute (file, reversed);
189
if (retval == NULL) {
190
default_sort_order = g_settings_get_enum (nautilus_preferences,
191
NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER);
192
default_sort_reversed = g_settings_get_boolean (nautilus_preferences,
193
NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER);
195
retval = attributes[default_sort_order];
196
*reversed = default_sort_reversed;
203
list_selection_changed_callback (GtkTreeSelection *selection, gpointer user_data)
207
view = NAUTILUS_VIEW (user_data);
209
nautilus_view_notify_selection_changed (view);
212
/* Move these to eel? */
215
tree_selection_foreach_set_boolean (GtkTreeModel *model,
218
gpointer callback_data)
220
* (gboolean *) callback_data = TRUE;
224
tree_selection_not_empty (GtkTreeSelection *selection)
229
gtk_tree_selection_selected_foreach (selection,
230
tree_selection_foreach_set_boolean,
236
tree_view_has_selection (GtkTreeView *view)
238
return tree_selection_not_empty (gtk_tree_view_get_selection (view));
242
preview_selected_items (NautilusListView *view)
246
file_list = nautilus_list_view_get_selection (NAUTILUS_VIEW (view));
248
if (file_list != NULL) {
249
nautilus_view_preview_files (NAUTILUS_VIEW (view),
251
nautilus_file_list_free (file_list);
256
activate_selected_items (NautilusListView *view)
260
file_list = nautilus_list_view_get_selection (NAUTILUS_VIEW (view));
263
if (view->details->renaming_file) {
264
/* We're currently renaming a file, wait until the rename is
265
finished, or the activation uri will be wrong */
266
if (view->details->renaming_file_activate_timeout == 0) {
267
view->details->renaming_file_activate_timeout =
268
g_timeout_add (WAIT_FOR_RENAME_ON_ACTIVATE, (GSourceFunc) activate_selected_items, view);
273
if (view->details->renaming_file_activate_timeout != 0) {
274
g_source_remove (view->details->renaming_file_activate_timeout);
275
view->details->renaming_file_activate_timeout = 0;
278
nautilus_view_activate_files (NAUTILUS_VIEW (view),
281
nautilus_file_list_free (file_list);
286
activate_selected_items_alternate (NautilusListView *view,
288
gboolean open_in_tab)
291
NautilusWindowOpenFlags flags;
296
flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB;
298
flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
302
nautilus_file_ref (file);
303
file_list = g_list_prepend (NULL, file);
305
file_list = nautilus_list_view_get_selection (NAUTILUS_VIEW (view));
307
nautilus_view_activate_files (NAUTILUS_VIEW (view),
311
nautilus_file_list_free (file_list);
316
button_event_modifies_selection (GdkEventButton *event)
318
return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
322
get_click_policy (void)
324
return g_settings_get_enum (nautilus_preferences,
325
NAUTILUS_PREFERENCES_CLICK_POLICY);
329
nautilus_list_view_did_not_drag (NautilusListView *view,
330
GdkEventButton *event)
332
GtkTreeView *tree_view;
333
GtkTreeSelection *selection;
336
tree_view = view->details->tree_view;
337
selection = gtk_tree_view_get_selection (tree_view);
339
if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y,
340
&path, NULL, NULL, NULL)) {
341
if ((event->button == 1 || event->button == 2)
342
&& ((event->state & GDK_CONTROL_MASK) != 0 ||
343
(event->state & GDK_SHIFT_MASK) == 0)
344
&& view->details->row_selected_on_button_down) {
345
if (!button_event_modifies_selection (event)) {
346
gtk_tree_selection_unselect_all (selection);
347
gtk_tree_selection_select_path (selection, path);
349
gtk_tree_selection_unselect_path (selection, path);
353
if ((get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE)
354
&& !button_event_modifies_selection(event)) {
355
if (event->button == 1) {
356
activate_selected_items (view);
357
} else if (event->button == 2) {
358
activate_selected_items_alternate (view, NULL, TRUE);
361
gtk_tree_path_free (path);
367
drag_data_get_callback (GtkWidget *widget,
368
GdkDragContext *context,
369
GtkSelectionData *selection_data,
373
GtkTreeView *tree_view;
375
GList *selection_cache;
377
tree_view = GTK_TREE_VIEW (widget);
379
model = gtk_tree_view_get_model (tree_view);
385
selection_cache = g_object_get_data (G_OBJECT (context), "drag-info");
386
if (selection_cache == NULL) {
390
nautilus_drag_drag_data_get_from_cache (selection_cache, context, selection_data, info, time);
394
stop_drag_check (NautilusListView *view)
396
view->details->drag_button = 0;
399
static cairo_surface_t *
400
get_drag_surface (NautilusListView *view)
405
cairo_surface_t *ret;
406
GdkRectangle cell_area;
410
if (gtk_tree_view_get_path_at_pos (view->details->tree_view,
411
view->details->drag_x,
412
view->details->drag_y,
413
&path, NULL, NULL, NULL)) {
414
model = gtk_tree_view_get_model (view->details->tree_view);
415
gtk_tree_model_get_iter (model, &iter, path);
416
gtk_tree_model_get (model, &iter,
417
nautilus_list_model_get_column_id_from_zoom_level (view->details->zoom_level),
421
gtk_tree_view_get_cell_area (view->details->tree_view,
423
view->details->file_name_column,
426
gtk_tree_path_free (path);
432
/* iteration glue struct */
434
NautilusListView *view;
435
NautilusDragEachSelectedItemDataGet iteratee;
436
gpointer iteratee_data;
437
} ListGetDataBinderContext;
440
item_get_data_binder (GtkTreeModel *model,
445
ListGetDataBinderContext *context = data;
447
GtkTreeView *treeview;
448
GtkTreeViewColumn *column;
449
GdkRectangle cell_area;
450
int drag_begin_y = 0;
453
treeview = nautilus_list_model_get_drag_view (context->view->details->model,
456
column = gtk_tree_view_get_column (treeview, 0);
458
file = nautilus_list_model_file_for_path (NAUTILUS_LIST_MODEL (model), path);
463
gtk_tree_view_get_cell_area (treeview,
468
uri = nautilus_file_get_activation_uri (file);
469
nautilus_file_unref (file);
471
/* pass the uri, mouse-relative x/y and icon width/height */
472
context->iteratee (uri,
474
cell_area.y - drag_begin_y,
477
context->iteratee_data);
483
each_item_get_data_binder (NautilusDragEachSelectedItemDataGet iteratee,
484
gpointer iterator_context,
487
NautilusListView *view = NAUTILUS_LIST_VIEW (iterator_context);
488
ListGetDataBinderContext context;
489
GtkTreeSelection *selection;
492
context.iteratee = iteratee;
493
context.iteratee_data = data;
495
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->details->tree_view));
496
gtk_tree_selection_selected_foreach (selection, item_get_data_binder, &context);
501
drag_begin_callback (GtkWidget *widget,
502
GdkDragContext *context,
503
NautilusListView *view)
505
GList *selection_cache;
506
cairo_surface_t *surface;
508
surface = get_drag_surface (view);
510
gtk_drag_set_icon_surface (context, surface);
511
cairo_surface_destroy (surface);
513
gtk_drag_set_icon_default (context);
516
stop_drag_check (view);
517
view->details->drag_started = TRUE;
519
selection_cache = nautilus_drag_create_selection_cache (view,
520
each_item_get_data_binder);
522
g_object_set_data_full (G_OBJECT (context),
525
(GDestroyNotify)nautilus_drag_destroy_selection_list);
529
motion_notify_callback (GtkWidget *widget,
530
GdkEventMotion *event,
531
gpointer callback_data)
533
NautilusListView *view;
535
view = NAUTILUS_LIST_VIEW (callback_data);
537
if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget))) {
541
if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE) {
542
GtkTreePath *old_hover_path;
544
old_hover_path = view->details->hover_path;
545
gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
547
&view->details->hover_path,
550
if ((old_hover_path != NULL) != (view->details->hover_path != NULL)) {
551
if (view->details->hover_path != NULL) {
552
gdk_window_set_cursor (gtk_widget_get_window (widget), hand_cursor);
554
gdk_window_set_cursor (gtk_widget_get_window (widget), NULL);
558
if (old_hover_path != NULL) {
559
gtk_tree_path_free (old_hover_path);
563
if (view->details->drag_button != 0) {
564
if (!source_target_list) {
565
source_target_list = nautilus_list_model_get_drag_target_list ();
568
if (gtk_drag_check_threshold (widget,
569
view->details->drag_x,
570
view->details->drag_y,
576
GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK,
577
view->details->drag_button,
587
leave_notify_callback (GtkWidget *widget,
588
GdkEventCrossing *event,
589
gpointer callback_data)
591
NautilusListView *view;
593
view = NAUTILUS_LIST_VIEW (callback_data);
595
if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE &&
596
view->details->hover_path != NULL) {
597
gtk_tree_path_free (view->details->hover_path);
598
view->details->hover_path = NULL;
605
enter_notify_callback (GtkWidget *widget,
606
GdkEventCrossing *event,
607
gpointer callback_data)
609
NautilusListView *view;
611
view = NAUTILUS_LIST_VIEW (callback_data);
613
if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE) {
614
if (view->details->hover_path != NULL) {
615
gtk_tree_path_free (view->details->hover_path);
618
gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
620
&view->details->hover_path,
623
if (view->details->hover_path != NULL) {
624
gdk_window_set_cursor (gtk_widget_get_window (widget), hand_cursor);
632
do_popup_menu (GtkWidget *widget, NautilusListView *view, GdkEventButton *event)
634
if (tree_view_has_selection (GTK_TREE_VIEW (widget))) {
635
nautilus_view_pop_up_selection_context_menu (NAUTILUS_VIEW (view), event);
637
nautilus_view_pop_up_background_context_menu (NAUTILUS_VIEW (view), event);
642
row_activated_callback (GtkTreeView *treeview, GtkTreePath *path,
643
GtkTreeViewColumn *column, NautilusListView *view)
645
activate_selected_items (view);
649
button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer callback_data)
651
NautilusListView *view;
652
GtkTreeView *tree_view;
654
GtkTreeSelection *selection;
655
GtkWidgetClass *tree_view_class;
657
static gint64 last_click_time = 0;
658
static int click_count = 0;
659
int double_click_time;
660
gboolean call_parent, on_expander, show_expanders;
661
gboolean is_simple_click, path_selected;
664
view = NAUTILUS_LIST_VIEW (callback_data);
665
tree_view = GTK_TREE_VIEW (widget);
666
tree_view_class = GTK_WIDGET_GET_CLASS (tree_view);
667
selection = gtk_tree_view_get_selection (tree_view);
669
/* Don't handle extra mouse buttons here */
670
if (event->button > 5) {
674
if (event->window != gtk_tree_view_get_bin_window (tree_view)) {
678
nautilus_list_model_set_drag_view
679
(NAUTILUS_LIST_MODEL (gtk_tree_view_get_model (tree_view)),
683
g_object_get (G_OBJECT (gtk_widget_get_settings (widget)),
684
"gtk-double-click-time", &double_click_time,
687
/* Determine click count */
688
current_time = g_get_monotonic_time ();
689
if (current_time - last_click_time < double_click_time * 1000) {
695
/* Stash time for next compare */
696
last_click_time = current_time;
698
/* Ignore double click if we are in single click mode */
699
if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE && click_count >= 2) {
703
view->details->ignore_button_release = FALSE;
704
is_simple_click = ((event->button == 1 || event->button == 2) && (event->type == GDK_BUTTON_PRESS));
706
/* No item at this position */
707
if (!gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y,
708
&path, NULL, NULL, NULL)) {
709
if (is_simple_click) {
710
g_clear_pointer (&view->details->double_click_path[1], gtk_tree_path_free);
711
view->details->double_click_path[1] = view->details->double_click_path[0];
712
view->details->double_click_path[0] = NULL;
715
/* Deselect if people click outside any row. It's OK to
716
let default code run; it won't reselect anything. */
717
gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (tree_view));
718
tree_view_class->button_press_event (widget, event);
720
if (event->button == 3) {
721
do_popup_menu (widget, view, event);
729
path_selected = gtk_tree_selection_path_is_selected (selection, path);
730
show_expanders = g_settings_get_boolean (nautilus_list_view_preferences,
731
NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE);
733
if (show_expanders) {
734
int expander_size, horizontal_separator;
735
gtk_widget_style_get (widget,
736
"expander-size", &expander_size,
737
"horizontal-separator", &horizontal_separator,
739
/* TODO we should not hardcode this extra padding. It is
740
* EXPANDER_EXTRA_PADDING from GtkTreeView.
743
on_expander = (event->x <= horizontal_separator / 2 +
744
gtk_tree_path_get_depth (path) * expander_size);
747
/* Keep track of path of last click so double clicks only happen
748
* on the same item */
749
if (is_simple_click) {
750
g_clear_pointer (&view->details->double_click_path[1], gtk_tree_path_free);
751
view->details->double_click_path[1] = view->details->double_click_path[0];
752
view->details->double_click_path[0] = gtk_tree_path_copy (path);
755
if (event->type == GDK_2BUTTON_PRESS) {
756
/* Double clicking does not trigger a D&D action. */
757
view->details->drag_button = 0;
759
/* NOTE: Activation can actually destroy the view if we're switching */
761
view->details->double_click_path[1] &&
762
gtk_tree_path_compare (view->details->double_click_path[0], view->details->double_click_path[1]) == 0) {
763
if ((event->button == 1) && button_event_modifies_selection (event)) {
764
file = nautilus_list_model_file_for_path (view->details->model, path);
766
activate_selected_items_alternate (view, file, TRUE);
767
nautilus_file_unref (file);
770
if ((event->button == 1 || event->button == 3)) {
771
activate_selected_items (view);
772
} else if (event->button == 2) {
773
activate_selected_items_alternate (view, NULL, TRUE);
777
tree_view_class->button_press_event (widget, event);
780
/* We're going to filter out some situations where
781
* we can't let the default code run because all
782
* but one row would be would be deselected. We don't
783
* want that; we want the right click menu or single
784
* click to apply to everything that's currently selected.
786
if (event->button == 3 && path_selected) {
790
if ((event->button == 1 || event->button == 2) &&
791
((event->state & GDK_CONTROL_MASK) != 0 || (event->state & GDK_SHIFT_MASK) == 0)) {
792
view->details->row_selected_on_button_down = path_selected;
795
call_parent = on_expander;
796
view->details->ignore_button_release = on_expander;
797
} else if ((event->state & GDK_CONTROL_MASK) != 0) {
798
GList *selected_rows, *l;
801
if ((event->state & GDK_SHIFT_MASK) != 0) {
803
gtk_tree_view_get_cursor (tree_view, &cursor, NULL);
804
if (cursor != NULL) {
805
gtk_tree_selection_select_range (selection, cursor, path);
807
gtk_tree_selection_select_path (selection, path);
810
gtk_tree_selection_select_path (selection, path);
812
selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
814
/* This unselects everything */
815
gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
817
/* So select it again */
818
for (l = selected_rows; l != NULL; l = l->next) {
819
gtk_tree_selection_select_path (selection, l->data);
821
g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
823
view->details->ignore_button_release = on_expander;
828
g_signal_handlers_block_by_func (tree_view, row_activated_callback, view);
829
tree_view_class->button_press_event (widget, event);
830
g_signal_handlers_unblock_by_func (tree_view, row_activated_callback, view);
831
} else if (path_selected) {
832
gtk_widget_grab_focus (widget);
835
if (is_simple_click && !on_expander) {
836
view->details->drag_started = FALSE;
837
view->details->drag_button = event->button;
838
view->details->drag_x = event->x;
839
view->details->drag_y = event->y;
842
if (event->button == 3) {
843
do_popup_menu (widget, view, event);
847
gtk_tree_path_free (path);
849
/* We chained to the default handler in this method, so never
850
* let the default handler run */
855
button_release_callback (GtkWidget *widget,
856
GdkEventButton *event,
857
gpointer callback_data)
859
NautilusListView *view;
861
view = NAUTILUS_LIST_VIEW (callback_data);
863
if (event->button == view->details->drag_button) {
864
stop_drag_check (view);
865
if (!view->details->drag_started &&
866
!view->details->ignore_button_release) {
867
nautilus_list_view_did_not_drag (view, event);
874
popup_menu_callback (GtkWidget *widget, gpointer callback_data)
876
NautilusListView *view;
878
view = NAUTILUS_LIST_VIEW (callback_data);
880
do_popup_menu (widget, view, NULL);
886
subdirectory_done_loading_callback (NautilusDirectory *directory, NautilusListView *view)
888
nautilus_list_model_subdirectory_done_loading (view->details->model, directory);
892
row_expanded_callback (GtkTreeView *treeview,
895
gpointer callback_data)
897
NautilusListView *view;
898
NautilusDirectory *directory;
901
view = NAUTILUS_LIST_VIEW (callback_data);
903
if (!nautilus_list_model_load_subdirectory (view->details->model, path, &directory)) {
907
uri = nautilus_directory_get_uri (directory);
908
DEBUG ("Row expaded callback for uri %s", uri);
911
nautilus_view_add_subdirectory (NAUTILUS_VIEW (view), directory);
913
if (nautilus_directory_are_all_files_seen (directory)) {
914
nautilus_list_model_subdirectory_done_loading (view->details->model,
917
g_signal_connect_object (directory, "done-loading",
918
G_CALLBACK (subdirectory_done_loading_callback),
922
nautilus_directory_unref (directory);
927
NautilusDirectory *directory;
928
NautilusListView *view;
932
unload_delay_data_free (UnloadDelayData *unload_data)
934
if (unload_data->view != NULL) {
935
g_object_remove_weak_pointer (G_OBJECT (unload_data->view),
936
(gpointer *) &unload_data->view);
939
nautilus_directory_unref (unload_data->directory);
940
nautilus_file_unref (unload_data->file);
942
g_slice_free (UnloadDelayData, unload_data);
945
static UnloadDelayData *
946
unload_delay_data_new (NautilusFile *file,
947
NautilusDirectory *parent_directory,
948
NautilusListView *view)
950
UnloadDelayData *unload_data;
952
unload_data = g_slice_new0 (UnloadDelayData);
953
unload_data->view = view;
954
unload_data->file = nautilus_file_ref (file);
955
unload_data->directory = nautilus_directory_ref (parent_directory);
957
g_object_add_weak_pointer (G_OBJECT (unload_data->view),
958
(gpointer *) &unload_data->view);
964
unload_file_timeout (gpointer data)
966
UnloadDelayData *unload_data = data;
968
NautilusListModel *model;
971
if (unload_data->view == NULL) {
975
model = unload_data->view->details->model;
976
if (nautilus_list_model_get_tree_iter_from_file (model,
978
unload_data->directory,
980
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
981
if (!gtk_tree_view_row_expanded (unload_data->view->details->tree_view,
983
nautilus_list_model_unload_subdirectory (model, &iter);
985
gtk_tree_path_free (path);
989
unload_delay_data_free (unload_data);
994
row_collapsed_callback (GtkTreeView *treeview,
997
gpointer callback_data)
999
NautilusListView *view;
1001
NautilusDirectory *directory;
1003
UnloadDelayData *unload_data;
1004
GtkTreeModel *model;
1007
view = NAUTILUS_LIST_VIEW (callback_data);
1008
model = GTK_TREE_MODEL (view->details->model);
1010
gtk_tree_model_get (model, iter,
1011
NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
1014
uri = nautilus_file_get_uri (file);
1015
DEBUG ("Row collapsed callback for uri %s", uri);
1019
if (gtk_tree_model_iter_parent (model, &parent, iter)) {
1020
gtk_tree_model_get (model, &parent,
1021
NAUTILUS_LIST_MODEL_SUBDIRECTORY_COLUMN, &directory,
1025
unload_data = unload_delay_data_new (file, directory, view);
1026
g_timeout_add_seconds (COLLAPSE_TO_UNLOAD_DELAY,
1027
unload_file_timeout,
1030
nautilus_file_unref (file);
1031
nautilus_directory_unref (directory);
1035
subdirectory_unloaded_callback (NautilusListModel *model,
1036
NautilusDirectory *directory,
1037
gpointer callback_data)
1039
NautilusListView *view;
1041
g_return_if_fail (NAUTILUS_IS_LIST_MODEL (model));
1042
g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
1044
view = NAUTILUS_LIST_VIEW(callback_data);
1046
g_signal_handlers_disconnect_by_func (directory,
1047
G_CALLBACK (subdirectory_done_loading_callback),
1049
nautilus_view_remove_subdirectory (NAUTILUS_VIEW (view), directory);
1053
key_press_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_data)
1056
GdkEventButton button_event = { 0 };
1058
GtkTreeView *tree_view;
1061
tree_view = GTK_TREE_VIEW (widget);
1063
view = NAUTILUS_VIEW (callback_data);
1066
switch (event->keyval) {
1068
if (event->state & GDK_CONTROL_MASK) {
1069
nautilus_view_pop_up_background_context_menu (view, &button_event);
1074
gtk_tree_view_get_cursor (tree_view, &path, NULL);
1076
gtk_tree_view_expand_row (tree_view, path, FALSE);
1077
gtk_tree_path_free (path);
1082
gtk_tree_view_get_cursor (tree_view, &path, NULL);
1084
if (!gtk_tree_view_collapse_row (tree_view, path)) {
1085
/* if the row is already collapsed or doesn't have any children,
1086
* jump to the parent row instead.
1088
if ((gtk_tree_path_get_depth (path) > 1) && gtk_tree_path_up (path)) {
1089
gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
1093
gtk_tree_path_free (path);
1098
if (event->state & GDK_CONTROL_MASK) {
1102
if (!gtk_widget_has_focus (GTK_WIDGET (NAUTILUS_LIST_VIEW (view)->details->tree_view))) {
1106
if ((event->state & GDK_SHIFT_MASK) != 0) {
1107
activate_selected_items_alternate (NAUTILUS_LIST_VIEW (view), NULL, TRUE);
1109
preview_selected_items (NAUTILUS_LIST_VIEW (view));
1113
case GDK_KEY_Return:
1114
case GDK_KEY_KP_Enter:
1115
if ((event->state & GDK_SHIFT_MASK) != 0) {
1116
activate_selected_items_alternate (NAUTILUS_LIST_VIEW (view), NULL, TRUE);
1118
activate_selected_items (NAUTILUS_LIST_VIEW (view));
1123
/* Eat Control + v to not enable type ahead */
1124
if ((event->state & GDK_CONTROL_MASK) != 0) {
1137
test_expand_row_callback (GtkTreeView *tree_view,
1142
return !g_settings_get_boolean (nautilus_list_view_preferences,
1143
NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE);
1147
nautilus_list_view_reveal_selection (NautilusView *view)
1151
g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
1153
selection = nautilus_view_get_selection (view);
1155
/* Make sure at least one of the selected items is scrolled into view */
1156
if (selection != NULL) {
1157
NautilusListView *list_view;
1162
list_view = NAUTILUS_LIST_VIEW (view);
1163
file = selection->data;
1164
if (nautilus_list_model_get_first_iter_for_file (list_view->details->model, file, &iter)) {
1165
path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), &iter);
1167
gtk_tree_view_scroll_to_cell (list_view->details->tree_view, path, NULL, FALSE, 0.0, 0.0);
1169
gtk_tree_path_free (path);
1173
nautilus_file_list_free (selection);
1177
sort_criterion_changes_due_to_user (GtkTreeView *tree_view)
1180
GtkTreeViewColumn *column;
1181
GSignalInvocationHint *ihint;
1186
columns = gtk_tree_view_get_columns (tree_view);
1187
for (p = columns; p != NULL; p = p->next) {
1189
ihint = g_signal_get_invocation_hint (column);
1190
if (ihint != NULL) {
1195
g_list_free (columns);
1201
sort_column_changed_callback (GtkTreeSortable *sortable,
1202
NautilusListView *view)
1205
gint sort_column_id, default_sort_column_id;
1206
GtkSortType reversed;
1207
GQuark sort_attr, default_sort_attr;
1208
char *reversed_attr, *default_reversed_attr;
1209
gboolean default_sort_reversed;
1211
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (view));
1213
gtk_tree_sortable_get_sort_column_id (sortable, &sort_column_id, &reversed);
1214
sort_attr = nautilus_list_model_get_attribute_from_sort_column_id (view->details->model, sort_column_id);
1216
default_sort_column_id = nautilus_list_model_get_sort_column_id_from_attribute (view->details->model,
1217
g_quark_from_string (get_default_sort_order (file, &default_sort_reversed)));
1218
default_sort_attr = nautilus_list_model_get_attribute_from_sort_column_id (view->details->model, default_sort_column_id);
1219
nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN,
1220
g_quark_to_string (default_sort_attr), g_quark_to_string (sort_attr));
1222
default_reversed_attr = (default_sort_reversed ? "true" : "false");
1224
if (view->details->last_sort_attr != sort_attr &&
1225
sort_criterion_changes_due_to_user (view->details->tree_view)) {
1226
/* at this point, the sort order is always GTK_SORT_ASCENDING, if the sort column ID
1227
* switched. Invert the sort order, if it's the default criterion with a reversed preference,
1228
* or if it makes sense for the attribute (i.e. date). */
1229
if (sort_attr == default_sort_attr) {
1230
/* use value from preferences */
1231
reversed = g_settings_get_boolean (nautilus_preferences,
1232
NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER);
1234
reversed = nautilus_file_is_date_sort_attribute_q (sort_attr);
1238
g_signal_handlers_block_by_func (sortable, sort_column_changed_callback, view);
1239
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view->details->model),
1241
GTK_SORT_DESCENDING);
1242
g_signal_handlers_unblock_by_func (sortable, sort_column_changed_callback, view);
1247
reversed_attr = (reversed ? "true" : "false");
1248
nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED,
1249
default_reversed_attr, reversed_attr);
1251
/* Make sure selected item(s) is visible after sort */
1252
nautilus_list_view_reveal_selection (NAUTILUS_VIEW (view));
1254
view->details->last_sort_attr = sort_attr;
1258
editable_focus_out_cb (GtkWidget *widget,
1262
NautilusListView *view = user_data;
1264
view->details->editable_widget = NULL;
1266
nautilus_view_set_is_renaming (NAUTILUS_VIEW (view), FALSE);
1267
nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
1271
cell_renderer_editing_started_cb (GtkCellRenderer *renderer,
1272
GtkCellEditable *editable,
1273
const gchar *path_str,
1274
NautilusListView *list_view)
1278
entry = GTK_ENTRY (editable);
1279
list_view->details->editable_widget = editable;
1281
/* Free a previously allocated original_name */
1282
g_free (list_view->details->original_name);
1284
list_view->details->original_name = g_strdup (gtk_entry_get_text (entry));
1286
g_signal_connect (entry, "focus-out-event",
1287
G_CALLBACK (editable_focus_out_cb), list_view);
1289
nautilus_clipboard_set_up_editable
1290
(GTK_EDITABLE (entry),
1291
nautilus_view_get_ui_manager (NAUTILUS_VIEW (list_view)),
1296
cell_renderer_editing_canceled (GtkCellRendererText *cell,
1297
NautilusListView *view)
1299
view->details->editable_widget = NULL;
1301
nautilus_view_set_is_renaming (NAUTILUS_VIEW (view), FALSE);
1302
nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
1306
cell_renderer_edited (GtkCellRendererText *cell,
1307
const char *path_str,
1308
const char *new_text,
1309
NautilusListView *view)
1315
view->details->editable_widget = NULL;
1316
nautilus_view_set_is_renaming (NAUTILUS_VIEW (view), FALSE);
1318
/* Don't allow a rename with an empty string. Revert to original
1319
* without notifying the user.
1321
if (new_text[0] == '\0') {
1322
g_object_set (G_OBJECT (view->details->file_name_cell),
1325
nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
1329
path = gtk_tree_path_new_from_string (path_str);
1331
gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->model),
1334
gtk_tree_path_free (path);
1336
gtk_tree_model_get (GTK_TREE_MODEL (view->details->model),
1338
NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
1341
/* Only rename if name actually changed */
1342
if (strcmp (new_text, view->details->original_name) != 0) {
1343
view->details->renaming_file = nautilus_file_ref (file);
1344
view->details->rename_done = FALSE;
1345
nautilus_rename_file (file, new_text, nautilus_list_view_rename_callback, g_object_ref (view));
1346
g_free (view->details->original_name);
1347
view->details->original_name = g_strdup (new_text);
1350
nautilus_file_unref (file);
1352
/*We're done editing - make the filename-cells readonly again.*/
1353
g_object_set (G_OBJECT (view->details->file_name_cell),
1357
nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
1361
get_root_uri_callback (NautilusTreeViewDragDest *dest,
1364
NautilusListView *view;
1366
view = NAUTILUS_LIST_VIEW (user_data);
1368
return nautilus_view_get_uri (NAUTILUS_VIEW (view));
1371
static NautilusFile *
1372
get_file_for_path_callback (NautilusTreeViewDragDest *dest,
1376
NautilusListView *view;
1378
view = NAUTILUS_LIST_VIEW (user_data);
1380
return nautilus_list_model_file_for_path (view->details->model, path);
1383
/* Handles an URL received from Mozilla */
1385
list_view_handle_netscape_url (NautilusTreeViewDragDest *dest, const char *encoded_url,
1386
const char *target_uri, GdkDragAction action, int x, int y, NautilusListView *view)
1388
nautilus_view_handle_netscape_url_drop (NAUTILUS_VIEW (view),
1389
encoded_url, target_uri, action, x, y);
1393
list_view_handle_uri_list (NautilusTreeViewDragDest *dest, const char *item_uris,
1394
const char *target_uri,
1395
GdkDragAction action, int x, int y, NautilusListView *view)
1397
nautilus_view_handle_uri_list_drop (NAUTILUS_VIEW (view),
1398
item_uris, target_uri, action, x, y);
1402
list_view_handle_text (NautilusTreeViewDragDest *dest, const char *text,
1403
const char *target_uri,
1404
GdkDragAction action, int x, int y, NautilusListView *view)
1406
nautilus_view_handle_text_drop (NAUTILUS_VIEW (view),
1407
text, target_uri, action, x, y);
1411
list_view_handle_raw (NautilusTreeViewDragDest *dest, const char *raw_data,
1412
int length, const char *target_uri, const char *direct_save_uri,
1413
GdkDragAction action, int x, int y, NautilusListView *view)
1415
nautilus_view_handle_raw_drop (NAUTILUS_VIEW (view),
1416
raw_data, length, target_uri, direct_save_uri,
1421
list_view_handle_hover (NautilusTreeViewDragDest *dest,
1422
const char *target_uri,
1423
NautilusListView *view)
1425
nautilus_view_handle_hover (NAUTILUS_VIEW (view), target_uri);
1429
move_copy_items_callback (NautilusTreeViewDragDest *dest,
1430
const GList *item_uris,
1431
const char *target_uri,
1438
NautilusView *view = user_data;
1440
nautilus_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
1442
nautilus_view_get_copied_files_atom (view));
1443
nautilus_view_move_copy_items (view,
1452
column_header_menu_toggled (GtkCheckMenuItem *menu_item,
1453
NautilusListView *list_view)
1456
char **visible_columns;
1457
char **column_order;
1463
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
1464
visible_columns = get_visible_columns (list_view);
1465
column_order = get_column_order (list_view);
1466
column = g_object_get_data (G_OBJECT (menu_item), "column-name");
1468
for (i = 0; visible_columns[i] != NULL; ++i) {
1469
list = g_list_prepend (list, visible_columns[i]);
1472
if (gtk_check_menu_item_get_active (menu_item)) {
1473
list = g_list_prepend (list, g_strdup (column));
1475
l = g_list_find_custom (list, column, (GCompareFunc) g_strcmp0);
1476
list = g_list_delete_link (list, l);
1479
list = g_list_reverse (list);
1480
nautilus_file_set_metadata_list (file,
1481
NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS,
1484
g_free (visible_columns);
1486
visible_columns = g_new0 (char *, g_list_length (list) + 1);
1487
for (i = 0, l = list; l != NULL; ++i, l = l->next) {
1488
visible_columns[i] = l->data;
1491
/* set view values ourselves, as new metadata could not have been
1494
apply_columns_settings (list_view, column_order, visible_columns);
1497
g_strfreev (column_order);
1498
g_strfreev (visible_columns);
1502
column_header_menu_use_default (GtkMenuItem *menu_item,
1503
NautilusListView *list_view)
1506
char **default_columns;
1507
char **default_order;
1509
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
1511
nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, NULL);
1512
nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, NULL);
1514
default_columns = get_default_visible_columns (list_view);
1515
default_order = get_default_column_order (list_view);
1517
/* set view values ourselves, as new metadata could not have been
1520
apply_columns_settings (list_view, default_order, default_columns);
1522
g_strfreev (default_columns);
1523
g_strfreev (default_order);
1527
column_header_clicked (GtkWidget *column_button,
1528
GdkEventButton *event,
1529
NautilusListView *list_view)
1532
char **visible_columns;
1533
char **column_order;
1535
GHashTable *visible_columns_hash;
1539
GtkWidget *menu_item;
1541
if (event->button != GDK_BUTTON_SECONDARY) {
1545
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
1547
visible_columns = get_visible_columns (list_view);
1548
column_order = get_column_order (list_view);
1550
all_columns = nautilus_get_columns_for_file (file);
1551
all_columns = nautilus_sort_columns (all_columns, column_order);
1553
/* hash table to lookup if a given column should be visible */
1554
visible_columns_hash = g_hash_table_new_full (g_str_hash,
1556
(GDestroyNotify) g_free,
1557
(GDestroyNotify) g_free);
1558
/* always show name column */
1559
g_hash_table_insert (visible_columns_hash, g_strdup ("name"), g_strdup ("name"));
1560
if (visible_columns != NULL) {
1561
for (i = 0; visible_columns[i] != NULL; ++i) {
1562
g_hash_table_insert (visible_columns_hash,
1563
g_ascii_strdown (visible_columns[i], -1),
1564
g_ascii_strdown (visible_columns[i], -1));
1568
menu = gtk_menu_new ();
1570
for (l = all_columns; l != NULL; l = l->next) {
1575
g_object_get (G_OBJECT (l->data),
1579
lowercase = g_ascii_strdown (name, -1);
1581
menu_item = gtk_check_menu_item_new_with_label (label);
1582
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
1584
g_object_set_data_full (G_OBJECT (menu_item),
1585
"column-name", name, g_free);
1587
/* name is always visible */
1588
if (strcmp (lowercase, "name") == 0) {
1589
gtk_widget_set_sensitive (menu_item, FALSE);
1592
if (g_hash_table_lookup (visible_columns_hash, lowercase) != NULL) {
1593
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
1597
g_signal_connect (menu_item,
1599
G_CALLBACK (column_header_menu_toggled),
1606
menu_item = gtk_separator_menu_item_new ();
1607
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
1609
menu_item = gtk_menu_item_new_with_label (_("Use Default"));
1610
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
1612
g_signal_connect (menu_item,
1614
G_CALLBACK (column_header_menu_use_default),
1617
gtk_widget_show_all (menu);
1618
gtk_menu_popup_for_device (GTK_MENU (menu),
1619
gdk_event_get_device ((GdkEvent *) event),
1620
NULL, NULL, NULL, NULL, NULL,
1621
event->button, event->time);
1623
g_hash_table_destroy (visible_columns_hash);
1624
nautilus_column_list_free (all_columns);
1625
g_strfreev (column_order);
1626
g_strfreev (visible_columns);
1632
apply_columns_settings (NautilusListView *list_view,
1633
char **column_order,
1634
char **visible_columns)
1638
GList *old_view_columns, *view_columns;
1639
GHashTable *visible_columns_hash;
1640
GtkTreeViewColumn *prev_view_column;
1644
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
1646
/* prepare ordered list of view columns using column_order and visible_columns */
1647
view_columns = NULL;
1649
all_columns = nautilus_get_columns_for_file (file);
1650
all_columns = nautilus_sort_columns (all_columns, column_order);
1652
/* hash table to lookup if a given column should be visible */
1653
visible_columns_hash = g_hash_table_new_full (g_str_hash,
1655
(GDestroyNotify) g_free,
1656
(GDestroyNotify) g_free);
1657
/* always show name column */
1658
g_hash_table_insert (visible_columns_hash, g_strdup ("name"), g_strdup ("name"));
1659
if (visible_columns != NULL) {
1660
for (i = 0; visible_columns[i] != NULL; ++i) {
1661
g_hash_table_insert (visible_columns_hash,
1662
g_ascii_strdown (visible_columns[i], -1),
1663
g_ascii_strdown (visible_columns[i], -1));
1667
for (l = all_columns; l != NULL; l = l->next) {
1671
g_object_get (G_OBJECT (l->data), "name", &name, NULL);
1672
lowercase = g_ascii_strdown (name, -1);
1674
if (g_hash_table_lookup (visible_columns_hash, lowercase) != NULL) {
1675
GtkTreeViewColumn *view_column;
1677
view_column = g_hash_table_lookup (list_view->details->columns, name);
1678
if (view_column != NULL) {
1679
view_columns = g_list_prepend (view_columns, view_column);
1687
g_hash_table_destroy (visible_columns_hash);
1688
nautilus_column_list_free (all_columns);
1690
view_columns = g_list_reverse (view_columns);
1692
/* hide columns that are not present in the configuration */
1693
old_view_columns = gtk_tree_view_get_columns (list_view->details->tree_view);
1694
for (l = old_view_columns; l != NULL; l = l->next) {
1695
if (g_list_find (view_columns, l->data) == NULL) {
1696
gtk_tree_view_column_set_visible (l->data, FALSE);
1699
g_list_free (old_view_columns);
1701
/* show new columns from the configuration */
1702
for (l = view_columns; l != NULL; l = l->next) {
1703
gtk_tree_view_column_set_visible (l->data, TRUE);
1706
/* place columns in the correct order */
1707
prev_view_column = NULL;
1708
for (l = view_columns; l != NULL; l = l->next) {
1709
gtk_tree_view_move_column_after (list_view->details->tree_view, l->data, prev_view_column);
1710
prev_view_column = l->data;
1712
g_list_free (view_columns);
1716
filename_cell_data_func (GtkTreeViewColumn *column,
1717
GtkCellRenderer *renderer,
1718
GtkTreeModel *model,
1720
NautilusListView *view)
1724
PangoUnderline underline;
1726
gtk_tree_model_get (model, iter,
1727
view->details->file_name_column_num, &text,
1730
if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE) {
1731
path = gtk_tree_model_get_path (model, iter);
1733
if (view->details->hover_path == NULL ||
1734
gtk_tree_path_compare (path, view->details->hover_path)) {
1735
underline = PANGO_UNDERLINE_NONE;
1737
underline = PANGO_UNDERLINE_SINGLE;
1740
gtk_tree_path_free (path);
1742
underline = PANGO_UNDERLINE_NONE;
1745
g_object_set (G_OBJECT (renderer),
1747
"underline", underline,
1753
location_cell_data_func (GtkTreeViewColumn *column,
1754
GtkCellRenderer *renderer,
1755
GtkTreeModel *model,
1757
NautilusListView *view,
1758
gboolean show_trash_orig)
1760
NautilusDirectory *directory;
1761
GFile *home_location;
1763
GFile *dir_location;
1764
GFile *base_location;
1765
gchar *where = NULL;
1767
directory = nautilus_view_get_model (NAUTILUS_VIEW (view));
1769
home_location = g_file_new_for_path (g_get_home_dir ());
1771
gtk_tree_model_get (model, iter,
1772
NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
1775
/* The file might be NULL if we just toggled an expander
1776
* and we're still loading the subdirectory.
1782
if (show_trash_orig && nautilus_file_is_in_trash (file)) {
1783
NautilusFile *orig_file;
1785
orig_file = nautilus_file_get_trash_original_file (file);
1787
if (orig_file != NULL) {
1788
nautilus_file_unref (file);
1793
if (!nautilus_file_is_in_recent (file)) {
1794
dir_location = nautilus_file_get_parent_location (file);
1796
GFile *activation_location;
1798
activation_location = nautilus_file_get_activation_location (file);
1799
dir_location = g_file_get_parent (activation_location);
1801
g_object_unref (activation_location);
1804
if (!NAUTILUS_IS_SEARCH_DIRECTORY (directory)) {
1805
base_location = g_object_ref (home_location);
1807
NautilusQuery *query;
1811
query = nautilus_search_directory_get_query (NAUTILUS_SEARCH_DIRECTORY (directory));
1812
base_uri = nautilus_query_get_location (query);
1813
base = nautilus_file_get_by_uri (base_uri);
1815
if (!nautilus_file_is_in_recent (base)) {
1816
base_location = nautilus_file_get_location (base);
1818
base_location = g_object_ref (home_location);
1821
nautilus_file_unref (base);
1823
g_object_unref (query);
1826
if (g_file_equal (home_location, dir_location)) {
1827
where = g_strdup (_("Home"));
1828
} else if (g_file_equal (base_location, dir_location)) {
1829
/* Only occurs when search result is
1830
* a direct child of the base location
1832
where = g_strdup ("");
1833
} else if (g_file_has_prefix (dir_location, base_location)) {
1834
gchar *relative_path;
1836
relative_path = g_file_get_relative_path (base_location,
1838
where = g_filename_display_name (relative_path);
1840
g_free (relative_path);
1843
if (where != NULL) {
1844
g_object_set (G_OBJECT (renderer),
1851
g_object_unref (base_location);
1852
g_object_unref (dir_location);
1853
nautilus_file_unref (file);
1854
g_object_unref (home_location);
1859
where_cell_data_func (GtkTreeViewColumn *column,
1860
GtkCellRenderer *renderer,
1861
GtkTreeModel *model,
1863
NautilusListView *view)
1865
location_cell_data_func (column, renderer, model, iter, view, FALSE);
1869
trash_orig_path_cell_data_func (GtkTreeViewColumn *column,
1870
GtkCellRenderer *renderer,
1871
GtkTreeModel *model,
1873
NautilusListView *view)
1875
location_cell_data_func (column, renderer, model, iter, view, TRUE);
1880
set_up_pixbuf_size (NautilusListView *view)
1884
/* Make all rows the same size. */
1885
icon_size = nautilus_get_icon_size_for_zoom_level (view->details->zoom_level);
1886
gtk_cell_renderer_set_fixed_size (GTK_CELL_RENDERER (view->details->pixbuf_cell),
1890
/* FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=641518 */
1891
gtk_tree_view_columns_autosize (view->details->tree_view);
1895
get_icon_scale_callback (NautilusListModel *model,
1896
NautilusListView *view)
1898
return gtk_widget_get_scale_factor (GTK_WIDGET (view->details->tree_view));
1902
create_and_set_up_tree_view (NautilusListView *view)
1904
GtkCellRenderer *cell;
1905
GtkTreeViewColumn *column;
1906
GtkBindingSet *binding_set;
1908
GList *nautilus_columns;
1910
gchar **default_column_order, **default_visible_columns;
1912
view->details->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
1913
view->details->columns = g_hash_table_new_full (g_str_hash,
1915
(GDestroyNotify) g_free,
1917
gtk_tree_view_set_enable_search (view->details->tree_view, FALSE);
1919
/* Don't handle backspace key. It's used to open the parent folder. */
1920
binding_set = gtk_binding_set_by_class (GTK_WIDGET_GET_CLASS (view->details->tree_view));
1921
gtk_binding_entry_remove (binding_set, GDK_KEY_BackSpace, 0);
1923
view->details->drag_dest =
1924
nautilus_tree_view_drag_dest_new (view->details->tree_view);
1926
g_signal_connect_object (view->details->drag_dest,
1928
G_CALLBACK (get_root_uri_callback),
1930
g_signal_connect_object (view->details->drag_dest,
1931
"get-file-for-path",
1932
G_CALLBACK (get_file_for_path_callback),
1934
g_signal_connect_object (view->details->drag_dest,
1936
G_CALLBACK (move_copy_items_callback),
1938
g_signal_connect_object (view->details->drag_dest, "handle-netscape-url",
1939
G_CALLBACK (list_view_handle_netscape_url), view, 0);
1940
g_signal_connect_object (view->details->drag_dest, "handle-uri-list",
1941
G_CALLBACK (list_view_handle_uri_list), view, 0);
1942
g_signal_connect_object (view->details->drag_dest, "handle-text",
1943
G_CALLBACK (list_view_handle_text), view, 0);
1944
g_signal_connect_object (view->details->drag_dest, "handle-raw",
1945
G_CALLBACK (list_view_handle_raw), view, 0);
1946
g_signal_connect_object (view->details->drag_dest, "handle-hover",
1947
G_CALLBACK (list_view_handle_hover), view, 0);
1949
g_signal_connect_object (gtk_tree_view_get_selection (view->details->tree_view),
1951
G_CALLBACK (list_selection_changed_callback), view, 0);
1953
g_signal_connect_object (view->details->tree_view, "drag-begin",
1954
G_CALLBACK (drag_begin_callback), view, 0);
1955
g_signal_connect_object (view->details->tree_view, "drag-data-get",
1956
G_CALLBACK (drag_data_get_callback), view, 0);
1957
g_signal_connect_object (view->details->tree_view, "motion-notify-event",
1958
G_CALLBACK (motion_notify_callback), view, 0);
1959
g_signal_connect_object (view->details->tree_view, "enter-notify-event",
1960
G_CALLBACK (enter_notify_callback), view, 0);
1961
g_signal_connect_object (view->details->tree_view, "leave-notify-event",
1962
G_CALLBACK (leave_notify_callback), view, 0);
1963
g_signal_connect_object (view->details->tree_view, "button-press-event",
1964
G_CALLBACK (button_press_callback), view, 0);
1965
g_signal_connect_object (view->details->tree_view, "button-release-event",
1966
G_CALLBACK (button_release_callback), view, 0);
1967
g_signal_connect_object (view->details->tree_view, "key-press-event",
1968
G_CALLBACK (key_press_callback), view, 0);
1969
g_signal_connect_object (view->details->tree_view, "test-expand-row",
1970
G_CALLBACK (test_expand_row_callback), view, 0);
1971
g_signal_connect_object (view->details->tree_view, "popup-menu",
1972
G_CALLBACK (popup_menu_callback), view, 0);
1973
g_signal_connect_object (view->details->tree_view, "row-expanded",
1974
G_CALLBACK (row_expanded_callback), view, 0);
1975
g_signal_connect_object (view->details->tree_view, "row-collapsed",
1976
G_CALLBACK (row_collapsed_callback), view, 0);
1977
g_signal_connect_object (view->details->tree_view, "row-activated",
1978
G_CALLBACK (row_activated_callback), view, 0);
1980
view->details->model = g_object_new (NAUTILUS_TYPE_LIST_MODEL, NULL);
1981
gtk_tree_view_set_model (view->details->tree_view, GTK_TREE_MODEL (view->details->model));
1982
/* Need the model for the dnd drop icon "accept" change */
1983
nautilus_list_model_set_drag_view (NAUTILUS_LIST_MODEL (view->details->model),
1984
view->details->tree_view, 0, 0);
1986
g_signal_connect_object (view->details->model, "sort-column-changed",
1987
G_CALLBACK (sort_column_changed_callback), view, 0);
1989
g_signal_connect_object (view->details->model, "subdirectory-unloaded",
1990
G_CALLBACK (subdirectory_unloaded_callback), view, 0);
1992
g_signal_connect_object (view->details->model, "get-icon-scale",
1993
G_CALLBACK (get_icon_scale_callback), view, 0);
1995
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (view->details->tree_view), GTK_SELECTION_MULTIPLE);
1996
gtk_tree_view_set_rules_hint (view->details->tree_view, TRUE);
1998
g_settings_bind (nautilus_list_view_preferences, NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE,
1999
view->details->tree_view, "show-expanders",
2000
G_SETTINGS_BIND_DEFAULT);
2002
nautilus_columns = nautilus_get_all_columns ();
2004
for (l = nautilus_columns; l != NULL; l = l->next) {
2005
NautilusColumn *nautilus_column;
2010
GtkSortType sort_order;
2012
nautilus_column = NAUTILUS_COLUMN (l->data);
2014
g_object_get (nautilus_column,
2018
"default-sort-order", &sort_order,
2021
column_num = nautilus_list_model_add_column (view->details->model,
2024
/* Created the name column specially, because it
2025
* has the icon in it.*/
2026
if (!strcmp (name, "name")) {
2027
/* Create the file name column */
2028
view->details->file_name_column = gtk_tree_view_column_new ();
2029
gtk_tree_view_append_column (view->details->tree_view,
2030
view->details->file_name_column);
2031
view->details->file_name_column_num = column_num;
2033
g_hash_table_insert (view->details->columns,
2035
view->details->file_name_column);
2037
g_signal_connect (gtk_tree_view_column_get_button (view->details->file_name_column),
2038
"button-press-event",
2039
G_CALLBACK (column_header_clicked),
2042
gtk_tree_view_set_search_column (view->details->tree_view, column_num);
2044
gtk_tree_view_column_set_sort_column_id (view->details->file_name_column, column_num);
2045
gtk_tree_view_column_set_title (view->details->file_name_column, _("Name"));
2046
gtk_tree_view_column_set_resizable (view->details->file_name_column, TRUE);
2047
gtk_tree_view_column_set_expand (view->details->file_name_column, TRUE);
2049
/* Initial padding */
2050
cell = gtk_cell_renderer_text_new ();
2051
gtk_tree_view_column_pack_start (view->details->file_name_column, cell, FALSE);
2052
g_object_set (cell, "xpad", 6, NULL);
2053
g_settings_bind (nautilus_list_view_preferences, NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE,
2055
G_SETTINGS_BIND_INVERT_BOOLEAN | G_SETTINGS_BIND_GET);
2058
cell = gtk_cell_renderer_pixbuf_new ();
2059
view->details->pixbuf_cell = (GtkCellRendererPixbuf *)cell;
2060
set_up_pixbuf_size (view);
2062
gtk_tree_view_column_pack_start (view->details->file_name_column, cell, FALSE);
2063
gtk_tree_view_column_set_attributes (view->details->file_name_column,
2065
"surface", nautilus_list_model_get_column_id_from_zoom_level (view->details->zoom_level),
2068
cell = gtk_cell_renderer_text_new ();
2069
view->details->file_name_cell = (GtkCellRendererText *)cell;
2071
"ellipsize", PANGO_ELLIPSIZE_END,
2072
"single-paragraph-mode", TRUE,
2076
g_signal_connect (cell, "edited", G_CALLBACK (cell_renderer_edited), view);
2077
g_signal_connect (cell, "editing-canceled", G_CALLBACK (cell_renderer_editing_canceled), view);
2078
g_signal_connect (cell, "editing-started", G_CALLBACK (cell_renderer_editing_started_cb), view);
2080
gtk_tree_view_column_pack_start (view->details->file_name_column, cell, TRUE);
2081
gtk_tree_view_column_set_cell_data_func (view->details->file_name_column, cell,
2082
(GtkTreeCellDataFunc) filename_cell_data_func,
2085
cell = gtk_cell_renderer_text_new ();
2090
view->details->cells = g_list_append (view->details->cells,
2092
column = gtk_tree_view_column_new_with_attributes (label,
2096
gtk_tree_view_append_column (view->details->tree_view, column);
2097
gtk_tree_view_column_set_sort_column_id (column, column_num);
2098
g_hash_table_insert (view->details->columns,
2102
g_signal_connect (gtk_tree_view_column_get_button (column),
2103
"button-press-event",
2104
G_CALLBACK (column_header_clicked),
2107
gtk_tree_view_column_set_resizable (column, TRUE);
2108
gtk_tree_view_column_set_sort_order (column, sort_order);
2110
if (!strcmp (name, "where")) {
2111
gtk_tree_view_column_set_cell_data_func (column, cell,
2112
(GtkTreeCellDataFunc) where_cell_data_func,
2114
} else if (!strcmp (name, "trash_orig_path")) {
2115
gtk_tree_view_column_set_cell_data_func (column, cell,
2116
(GtkTreeCellDataFunc) trash_orig_path_cell_data_func,
2123
nautilus_column_list_free (nautilus_columns);
2125
default_visible_columns = g_settings_get_strv (nautilus_list_view_preferences,
2126
NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
2127
default_column_order = g_settings_get_strv (nautilus_list_view_preferences,
2128
NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER);
2130
/* Apply the default column order and visible columns, to get it
2131
* right most of the time. The metadata will be checked when a
2132
* folder is loaded */
2133
apply_columns_settings (view,
2134
default_column_order,
2135
default_visible_columns);
2137
gtk_widget_show (GTK_WIDGET (view->details->tree_view));
2138
gtk_container_add (GTK_CONTAINER (view), GTK_WIDGET (view->details->tree_view));
2140
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (view->details->tree_view));
2141
atk_object_set_name (atk_obj, _("List View"));
2143
g_strfreev (default_visible_columns);
2144
g_strfreev (default_column_order);
2148
nautilus_list_view_add_file (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
2150
NautilusListModel *model;
2152
model = NAUTILUS_LIST_VIEW (view)->details->model;
2153
nautilus_list_model_add_file (model, file, directory);
2157
get_default_visible_columns (NautilusListView *list_view)
2160
NautilusDirectory *directory;
2162
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
2164
if (nautilus_file_is_in_trash (file)) {
2165
return g_strdupv ((gchar **) default_trash_visible_columns);
2168
directory = nautilus_view_get_model (NAUTILUS_VIEW (list_view));
2169
if (NAUTILUS_IS_SEARCH_DIRECTORY (directory)) {
2170
return g_strdupv ((gchar **) default_search_visible_columns);
2173
return g_settings_get_strv (nautilus_list_view_preferences,
2174
NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
2178
get_visible_columns (NautilusListView *list_view)
2181
GList *visible_columns;
2183
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
2185
visible_columns = nautilus_file_get_metadata_list
2187
NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS);
2189
if (visible_columns) {
2193
res = g_ptr_array_new ();
2194
for (l = visible_columns; l != NULL; l = l->next) {
2195
g_ptr_array_add (res, l->data);
2197
g_ptr_array_add (res, NULL);
2199
g_list_free (visible_columns);
2201
return (char **) g_ptr_array_free (res, FALSE);
2204
return get_default_visible_columns (list_view);
2208
get_default_column_order (NautilusListView *list_view)
2211
NautilusDirectory *directory;
2213
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
2215
if (nautilus_file_is_in_trash (file)) {
2216
return g_strdupv ((gchar **) default_trash_columns_order);
2219
directory = nautilus_view_get_model (NAUTILUS_VIEW (list_view));
2220
if (NAUTILUS_IS_SEARCH_DIRECTORY (directory)) {
2221
return g_strdupv ((gchar **) default_search_columns_order);
2224
return g_settings_get_strv (nautilus_list_view_preferences,
2225
NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER);
2229
get_column_order (NautilusListView *list_view)
2232
GList *column_order;
2234
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
2236
column_order = nautilus_file_get_metadata_list
2238
NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER);
2244
res = g_ptr_array_new ();
2245
for (l = column_order; l != NULL; l = l->next) {
2246
g_ptr_array_add (res, l->data);
2248
g_ptr_array_add (res, NULL);
2250
g_list_free (column_order);
2252
return (char **) g_ptr_array_free (res, FALSE);
2255
return get_default_column_order (list_view);
2259
set_columns_settings_from_metadata_and_preferences (NautilusListView *list_view)
2261
char **column_order;
2262
char **visible_columns;
2264
column_order = get_column_order (list_view);
2265
visible_columns = get_visible_columns (list_view);
2267
apply_columns_settings (list_view, column_order, visible_columns);
2269
g_strfreev (column_order);
2270
g_strfreev (visible_columns);
2274
set_sort_order_from_metadata_and_preferences (NautilusListView *list_view)
2276
char *sort_attribute;
2279
gboolean sort_reversed, default_sort_reversed;
2280
const gchar *default_sort_order;
2282
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
2283
sort_attribute = nautilus_file_get_metadata (file,
2284
NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN,
2286
sort_column_id = nautilus_list_model_get_sort_column_id_from_attribute (list_view->details->model,
2287
g_quark_from_string (sort_attribute));
2288
g_free (sort_attribute);
2290
default_sort_order = get_default_sort_order (file, &default_sort_reversed);
2292
if (sort_column_id == -1) {
2294
nautilus_list_model_get_sort_column_id_from_attribute (list_view->details->model,
2295
g_quark_from_string (default_sort_order));
2298
sort_reversed = nautilus_file_get_boolean_metadata (file,
2299
NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED,
2300
default_sort_reversed);
2302
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_view->details->model),
2304
sort_reversed ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING);
2307
static NautilusZoomLevel
2308
get_default_zoom_level (void) {
2309
NautilusZoomLevel default_zoom_level;
2311
default_zoom_level = g_settings_get_enum (nautilus_list_view_preferences,
2312
NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL);
2314
if (default_zoom_level < NAUTILUS_ZOOM_LEVEL_SMALLEST
2315
|| NAUTILUS_ZOOM_LEVEL_LARGEST < default_zoom_level) {
2316
default_zoom_level = NAUTILUS_ZOOM_LEVEL_SMALL;
2319
return default_zoom_level;
2323
nautilus_list_view_begin_loading (NautilusView *view)
2325
NautilusListView *list_view;
2327
list_view = NAUTILUS_LIST_VIEW (view);
2329
set_sort_order_from_metadata_and_preferences (list_view);
2330
set_columns_settings_from_metadata_and_preferences (list_view);
2334
stop_cell_editing (NautilusListView *list_view)
2336
GtkTreeViewColumn *column;
2338
/* Stop an ongoing rename to commit the name changes when the user
2339
* changes directories without exiting cell edit mode. It also prevents
2340
* the edited handler from being called on the cleared list model.
2342
column = list_view->details->file_name_column;
2343
if (column != NULL && list_view->details->editable_widget != NULL &&
2344
GTK_IS_CELL_EDITABLE (list_view->details->editable_widget)) {
2345
gtk_cell_editable_editing_done (list_view->details->editable_widget);
2348
g_clear_object (&list_view->details->renaming_file);
2352
nautilus_list_view_clear (NautilusView *view)
2354
NautilusListView *list_view;
2356
list_view = NAUTILUS_LIST_VIEW (view);
2358
if (list_view->details->model != NULL) {
2359
stop_cell_editing (list_view);
2360
nautilus_list_model_clear (list_view->details->model);
2365
nautilus_list_view_rename_callback (NautilusFile *file,
2366
GFile *result_location,
2368
gpointer callback_data)
2370
NautilusListView *view;
2372
view = NAUTILUS_LIST_VIEW (callback_data);
2374
if (view->details->renaming_file) {
2375
view->details->rename_done = TRUE;
2377
if (error != NULL) {
2378
/* If the rename failed (or was cancelled), kill renaming_file.
2379
* We won't get a change event for the rename, so otherwise
2380
* it would stay around forever.
2382
nautilus_file_unref (view->details->renaming_file);
2383
view->details->renaming_file = NULL;
2387
g_object_unref (view);
2392
nautilus_list_view_file_changed (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
2394
NautilusListView *listview;
2396
GtkTreePath *file_path;
2398
listview = NAUTILUS_LIST_VIEW (view);
2400
nautilus_list_model_file_changed (listview->details->model, file, directory);
2402
if (listview->details->renaming_file != NULL &&
2403
file == listview->details->renaming_file &&
2404
listview->details->rename_done) {
2405
/* This is (probably) the result of the rename operation, and
2406
* the tree-view changes above could have resorted the list, so
2407
* scroll to the new position
2409
if (nautilus_list_model_get_tree_iter_from_file (listview->details->model, file, directory, &iter)) {
2410
file_path = gtk_tree_model_get_path (GTK_TREE_MODEL (listview->details->model), &iter);
2411
gtk_tree_view_scroll_to_cell (listview->details->tree_view,
2414
gtk_tree_path_free (file_path);
2417
nautilus_file_unref (listview->details->renaming_file);
2418
listview->details->renaming_file = NULL;
2426
} HasCommonParentData;
2429
tree_selection_has_common_parent_foreach_func (GtkTreeModel *model,
2434
HasCommonParentData *data;
2435
GtkTreePath *parent_path;
2436
gboolean has_parent;
2438
data = (HasCommonParentData *) user_data;
2440
parent_path = gtk_tree_path_copy (path);
2441
gtk_tree_path_up (parent_path);
2443
has_parent = (gtk_tree_path_get_depth (parent_path) > 0) ? TRUE : FALSE;
2446
data->is_root = TRUE;
2449
if (data->is_common && !data->is_root) {
2450
if (data->path == NULL) {
2451
data->path = gtk_tree_path_copy (parent_path);
2452
} else if (gtk_tree_path_compare (data->path, parent_path) != 0) {
2453
data->is_common = FALSE;
2457
gtk_tree_path_free (parent_path);
2461
tree_selection_has_common_parent (GtkTreeSelection *selection,
2462
gboolean *is_common,
2465
HasCommonParentData data;
2467
g_assert (is_common != NULL);
2468
g_assert (is_root != NULL);
2471
data.is_common = *is_common = TRUE;
2472
data.is_root = *is_root = FALSE;
2474
gtk_tree_selection_selected_foreach (selection,
2475
tree_selection_has_common_parent_foreach_func,
2478
*is_common = data.is_common;
2479
*is_root = data.is_root;
2481
if (data.path != NULL) {
2482
gtk_tree_path_free (data.path);
2487
nautilus_list_view_get_backing_uri (NautilusView *view)
2489
NautilusListView *list_view;
2490
NautilusListModel *list_model;
2492
GtkTreeView *tree_view;
2493
GtkTreeSelection *selection;
2499
g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), NULL);
2501
list_view = NAUTILUS_LIST_VIEW (view);
2502
list_model = list_view->details->model;
2503
tree_view = list_view->details->tree_view;
2505
g_assert (list_model);
2507
/* We currently handle three common cases here:
2508
* (a) if the selection contains non-filesystem items (i.e., the
2509
* "(Empty)" label), we return the uri of the parent.
2510
* (b) if the selection consists of exactly one _expanded_ directory, we
2512
* (c) if the selection consists of either exactly one item which is not
2513
* an expanded directory) or multiple items in the same directory,
2514
* we return the URI of the common parent.
2519
selection = gtk_tree_view_get_selection (tree_view);
2520
length = gtk_tree_selection_count_selected_rows (selection);
2524
paths = gtk_tree_selection_get_selected_rows (selection, NULL);
2525
path = (GtkTreePath *) paths->data;
2527
file = nautilus_list_model_file_for_path (list_model, path);
2529
/* The selected item is a label, not a file */
2530
gtk_tree_path_up (path);
2531
file = nautilus_list_model_file_for_path (list_model, path);
2535
if (nautilus_file_is_directory (file) &&
2536
gtk_tree_view_row_expanded (tree_view, path)) {
2537
uri = nautilus_file_get_uri (file);
2539
nautilus_file_unref (file);
2542
gtk_tree_path_free (path);
2543
g_list_free (paths);
2546
if (uri == NULL && length > 0) {
2548
gboolean is_common, is_root;
2550
/* Check that all the selected items belong to the same
2551
* directory and that directory is not the root directory (which
2552
* is handled by NautilusView::get_backing_directory.) */
2554
tree_selection_has_common_parent (selection, &is_common, &is_root);
2556
if (is_common && !is_root) {
2557
paths = gtk_tree_selection_get_selected_rows (selection, NULL);
2558
path = (GtkTreePath *) paths->data;
2560
file = nautilus_list_model_file_for_path (list_model, path);
2561
g_assert (file != NULL);
2562
uri = nautilus_file_get_parent_uri (file);
2563
nautilus_file_unref (file);
2565
g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
2573
return NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->get_backing_uri (view);
2577
nautilus_list_view_get_selection_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
2584
gtk_tree_model_get (model, iter,
2585
NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
2589
(* list) = g_list_prepend ((* list), file);
2594
nautilus_list_view_get_selection (NautilusView *view)
2600
gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view),
2601
nautilus_list_view_get_selection_foreach_func, &list);
2603
return g_list_reverse (list);
2607
nautilus_list_view_get_selection_for_file_transfer_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
2610
struct SelectionForeachData *selection_data;
2611
GtkTreeIter parent, child;
2613
selection_data = data;
2615
gtk_tree_model_get (model, iter,
2616
NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
2620
/* If the parent folder is also selected, don't include this file in the
2621
* file operation, since that would copy it to the toplevel target instead
2622
* of keeping it as a child of the copied folder
2625
while (gtk_tree_model_iter_parent (model, &parent, &child)) {
2626
if (gtk_tree_selection_iter_is_selected (selection_data->selection,
2633
nautilus_file_ref (file);
2634
selection_data->list = g_list_prepend (selection_data->list, file);
2640
nautilus_list_view_get_selection_for_file_transfer (NautilusView *view)
2642
struct SelectionForeachData selection_data;
2644
selection_data.list = NULL;
2645
selection_data.selection = gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view);
2647
gtk_tree_selection_selected_foreach (selection_data.selection,
2648
nautilus_list_view_get_selection_for_file_transfer_foreach_func, &selection_data);
2650
return g_list_reverse (selection_data.list);
2654
nautilus_list_view_is_empty (NautilusView *view)
2656
return nautilus_list_model_is_empty (NAUTILUS_LIST_VIEW (view)->details->model);
2660
nautilus_list_view_end_file_changes (NautilusView *view)
2662
NautilusListView *list_view;
2664
list_view = NAUTILUS_LIST_VIEW (view);
2666
if (list_view->details->new_selection_path) {
2667
gtk_tree_view_set_cursor (list_view->details->tree_view,
2668
list_view->details->new_selection_path,
2670
gtk_tree_path_free (list_view->details->new_selection_path);
2671
list_view->details->new_selection_path = NULL;
2676
nautilus_list_view_remove_file (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
2679
GtkTreePath *file_path;
2681
GtkTreeIter temp_iter;
2682
GtkTreeRowReference* row_reference;
2683
NautilusListView *list_view;
2684
GtkTreeModel* tree_model;
2685
GtkTreeSelection *selection;
2688
row_reference = NULL;
2689
list_view = NAUTILUS_LIST_VIEW (view);
2690
tree_model = GTK_TREE_MODEL(list_view->details->model);
2692
if (nautilus_list_model_get_tree_iter_from_file (list_view->details->model, file, directory, &iter)) {
2693
selection = gtk_tree_view_get_selection (list_view->details->tree_view);
2694
file_path = gtk_tree_model_get_path (tree_model, &iter);
2696
if (gtk_tree_selection_path_is_selected (selection, file_path)) {
2697
/* get reference for next element in the list view. If the element to be deleted is the
2698
* last one, get reference to previous element. If there is only one element in view
2699
* no need to select anything.
2703
if (gtk_tree_model_iter_next (tree_model, &iter)) {
2704
path = gtk_tree_model_get_path (tree_model, &iter);
2705
row_reference = gtk_tree_row_reference_new (tree_model, path);
2707
path = gtk_tree_model_get_path (tree_model, &temp_iter);
2708
if (gtk_tree_path_prev (path)) {
2709
row_reference = gtk_tree_row_reference_new (tree_model, path);
2712
gtk_tree_path_free (path);
2715
gtk_tree_path_free (file_path);
2717
nautilus_list_model_remove_file (list_view->details->model, file, directory);
2719
if (gtk_tree_row_reference_valid (row_reference)) {
2720
if (list_view->details->new_selection_path) {
2721
gtk_tree_path_free (list_view->details->new_selection_path);
2723
list_view->details->new_selection_path = gtk_tree_row_reference_get_path (row_reference);
2726
if (row_reference) {
2727
gtk_tree_row_reference_free (row_reference);
2735
nautilus_list_view_set_selection (NautilusView *view, GList *selection)
2737
NautilusListView *list_view;
2738
GtkTreeSelection *tree_selection;
2742
GtkTreePath *path = NULL;
2744
list_view = NAUTILUS_LIST_VIEW (view);
2745
tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view);
2747
g_signal_handlers_block_by_func (tree_selection, list_selection_changed_callback, view);
2749
gtk_tree_selection_unselect_all (tree_selection);
2750
for (node = selection; node != NULL; node = node->next) {
2752
iters = nautilus_list_model_get_all_iters_for_file (list_view->details->model, file);
2754
for (l = iters; l != NULL; l = l->next) {
2755
gtk_tree_selection_select_iter (tree_selection,
2756
(GtkTreeIter *)l->data);
2758
path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), (GtkTreeIter *)l->data);
2760
g_list_free_full (iters, g_free);
2763
gtk_tree_view_set_cursor_on_cell (list_view->details->tree_view,
2765
list_view->details->file_name_column,
2766
GTK_CELL_RENDERER (list_view->details->file_name_cell),
2768
gtk_tree_path_free (path);
2770
g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
2771
nautilus_view_notify_selection_changed (view);
2775
nautilus_list_view_invert_selection (NautilusView *view)
2777
NautilusListView *list_view;
2778
GtkTreeSelection *tree_selection;
2782
GList *selection = NULL;
2784
list_view = NAUTILUS_LIST_VIEW (view);
2785
tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view);
2787
g_signal_handlers_block_by_func (tree_selection, list_selection_changed_callback, view);
2789
gtk_tree_selection_selected_foreach (tree_selection,
2790
nautilus_list_view_get_selection_foreach_func, &selection);
2792
gtk_tree_selection_select_all (tree_selection);
2794
for (node = selection; node != NULL; node = node->next) {
2796
iters = nautilus_list_model_get_all_iters_for_file (list_view->details->model, file);
2798
for (l = iters; l != NULL; l = l->next) {
2799
gtk_tree_selection_unselect_iter (tree_selection,
2800
(GtkTreeIter *)l->data);
2802
g_list_free_full (iters, g_free);
2805
g_list_free (selection);
2807
g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
2808
nautilus_view_notify_selection_changed (view);
2812
nautilus_list_view_select_all (NautilusView *view)
2814
gtk_tree_selection_select_all (gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view));
2818
nautilus_list_view_select_first (NautilusView *view)
2820
GtkTreeSelection *selection;
2823
if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (NAUTILUS_LIST_VIEW (view)->details->model), &iter)) {
2826
selection = gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view);
2827
gtk_tree_selection_select_iter (selection, &iter);
2831
column_editor_response_callback (GtkWidget *dialog,
2835
gtk_widget_destroy (GTK_WIDGET (dialog));
2839
column_chooser_changed_callback (NautilusColumnChooser *chooser,
2840
NautilusListView *view)
2843
char **visible_columns;
2844
char **column_order;
2848
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (view));
2850
nautilus_column_chooser_get_settings (chooser,
2855
for (i = 0; visible_columns[i] != NULL; ++i) {
2856
list = g_list_prepend (list, visible_columns[i]);
2858
list = g_list_reverse (list);
2859
nautilus_file_set_metadata_list (file,
2860
NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS,
2865
for (i = 0; column_order[i] != NULL; ++i) {
2866
list = g_list_prepend (list, column_order[i]);
2868
list = g_list_reverse (list);
2869
nautilus_file_set_metadata_list (file,
2870
NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER,
2874
apply_columns_settings (view, column_order, visible_columns);
2876
g_strfreev (visible_columns);
2877
g_strfreev (column_order);
2881
column_chooser_set_from_arrays (NautilusColumnChooser *chooser,
2882
NautilusListView *view,
2883
char **visible_columns,
2884
char **column_order)
2886
g_signal_handlers_block_by_func
2887
(chooser, G_CALLBACK (column_chooser_changed_callback), view);
2889
nautilus_column_chooser_set_settings (chooser,
2893
g_signal_handlers_unblock_by_func
2894
(chooser, G_CALLBACK (column_chooser_changed_callback), view);
2898
column_chooser_set_from_settings (NautilusColumnChooser *chooser,
2899
NautilusListView *view)
2901
char **visible_columns;
2902
char **column_order;
2904
visible_columns = get_visible_columns (view);
2905
column_order = get_column_order (view);
2907
column_chooser_set_from_arrays (chooser, view,
2908
visible_columns, column_order);
2910
g_strfreev (visible_columns);
2911
g_strfreev (column_order);
2915
column_chooser_use_default_callback (NautilusColumnChooser *chooser,
2916
NautilusListView *view)
2919
char **default_columns;
2920
char **default_order;
2922
file = nautilus_view_get_directory_as_file
2923
(NAUTILUS_VIEW (view));
2925
nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, NULL);
2926
nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, NULL);
2928
/* set view values ourselves, as new metadata could not have been
2931
default_columns = get_default_visible_columns (view);
2932
default_order = get_default_column_order (view);
2934
apply_columns_settings (view, default_order, default_columns);
2935
column_chooser_set_from_arrays (chooser, view,
2936
default_columns, default_order);
2938
g_strfreev (default_columns);
2939
g_strfreev (default_order);
2943
create_column_editor (NautilusListView *view)
2948
GtkWidget *column_chooser;
2949
GtkWidget *alignment;
2953
const char *label_text;
2955
file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (view));
2956
name = nautilus_file_get_display_name (file);
2957
str = g_strdup_printf (_("%s Visible Columns"), name);
2960
window = gtk_dialog_new_with_buttons (str,
2961
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
2962
GTK_DIALOG_DESTROY_WITH_PARENT,
2963
_("_Close"), GTK_RESPONSE_CLOSE,
2966
g_signal_connect (window, "response",
2967
G_CALLBACK (column_editor_response_callback), NULL);
2969
gtk_window_set_default_size (GTK_WINDOW (window), 300, 400);
2971
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
2972
gtk_container_set_border_width (GTK_CONTAINER (box), 12);
2973
gtk_widget_show (box);
2974
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))), box,
2977
label_text = _("Choose the order of information to appear in this folder:");
2978
str = g_strconcat ("<b>", label_text, "</b>", NULL);
2979
label = gtk_label_new (NULL);
2980
gtk_label_set_markup (GTK_LABEL (label), str);
2981
gtk_label_set_line_wrap (GTK_LABEL (label), FALSE);
2982
gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
2983
gtk_widget_show (label);
2984
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
2988
alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
2989
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
2991
gtk_widget_show (alignment);
2992
gtk_box_pack_start (GTK_BOX (box), alignment, TRUE, TRUE, 0);
2994
column_chooser = nautilus_column_chooser_new (file);
2995
gtk_widget_show (column_chooser);
2996
gtk_container_add (GTK_CONTAINER (alignment), column_chooser);
2998
g_signal_connect (column_chooser, "changed",
2999
G_CALLBACK (column_chooser_changed_callback),
3001
g_signal_connect (column_chooser, "use-default",
3002
G_CALLBACK (column_chooser_use_default_callback),
3005
column_chooser_set_from_settings
3006
(NAUTILUS_COLUMN_CHOOSER (column_chooser), view);
3012
action_visible_columns_callback (GtkAction *action,
3013
gpointer callback_data)
3015
NautilusListView *list_view;
3017
list_view = NAUTILUS_LIST_VIEW (callback_data);
3019
if (list_view->details->column_editor) {
3020
gtk_window_present (GTK_WINDOW (list_view->details->column_editor));
3022
list_view->details->column_editor = create_column_editor (list_view);
3023
g_object_add_weak_pointer (G_OBJECT (list_view->details->column_editor),
3024
(gpointer *) &list_view->details->column_editor);
3026
gtk_widget_show (list_view->details->column_editor);
3030
static const GtkActionEntry list_view_entries[] = {
3031
/* name, stock id */ { "Visible Columns", NULL,
3032
/* label, accelerator */ N_("Visible _Columns…"), NULL,
3033
/* tooltip */ N_("Select the columns visible in this folder"),
3034
G_CALLBACK (action_visible_columns_callback) },
3038
nautilus_list_view_merge_menus (NautilusView *view)
3040
NautilusListView *list_view;
3041
GtkUIManager *ui_manager;
3042
GtkActionGroup *action_group;
3044
list_view = NAUTILUS_LIST_VIEW (view);
3046
NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->merge_menus (view);
3048
ui_manager = nautilus_view_get_ui_manager (view);
3050
action_group = gtk_action_group_new ("ListViewActions");
3051
gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
3052
list_view->details->list_action_group = action_group;
3053
gtk_action_group_add_actions (action_group,
3054
list_view_entries, G_N_ELEMENTS (list_view_entries),
3057
gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
3058
g_object_unref (action_group); /* owned by ui manager */
3060
list_view->details->list_merge_id =
3061
gtk_ui_manager_add_ui_from_resource (ui_manager, "/org/gnome/nautilus/nautilus-list-view-ui.xml", NULL);
3063
list_view->details->menus_ready = TRUE;
3067
nautilus_list_view_unmerge_menus (NautilusView *view)
3069
NautilusListView *list_view;
3070
GtkUIManager *ui_manager;
3072
list_view = NAUTILUS_LIST_VIEW (view);
3074
NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->unmerge_menus (view);
3076
ui_manager = nautilus_view_get_ui_manager (view);
3077
if (ui_manager != NULL) {
3078
nautilus_ui_unmerge_ui (ui_manager,
3079
&list_view->details->list_merge_id,
3080
&list_view->details->list_action_group);
3085
nautilus_list_view_update_menus (NautilusView *view)
3087
NautilusListView *list_view;
3089
list_view = NAUTILUS_LIST_VIEW (view);
3091
/* don't update if the menus aren't ready */
3092
if (!list_view->details->menus_ready) {
3096
NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->update_menus (view);
3099
/* Reset sort criteria and zoom level to match defaults */
3101
nautilus_list_view_reset_to_defaults (NautilusView *view)
3104
const gchar *default_sort_order;
3105
gboolean default_sort_reversed;
3106
char **default_columns;
3107
char **default_order;
3109
file = nautilus_view_get_directory_as_file (view);
3111
nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN, NULL, NULL);
3112
nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED, NULL, NULL);
3113
nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, NULL);
3114
nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, NULL);
3116
default_sort_order = get_default_sort_order (file, &default_sort_reversed);
3118
gtk_tree_sortable_set_sort_column_id
3119
(GTK_TREE_SORTABLE (NAUTILUS_LIST_VIEW (view)->details->model),
3120
nautilus_list_model_get_sort_column_id_from_attribute (NAUTILUS_LIST_VIEW (view)->details->model,
3121
g_quark_from_string (default_sort_order)),
3122
default_sort_reversed ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING);
3124
nautilus_list_view_set_zoom_level (NAUTILUS_LIST_VIEW (view), get_default_zoom_level (), FALSE);
3126
default_columns = get_default_visible_columns (NAUTILUS_LIST_VIEW (view));
3127
default_order = get_default_column_order (NAUTILUS_LIST_VIEW (view));
3129
apply_columns_settings (NAUTILUS_LIST_VIEW (view), default_order, default_columns);
3131
g_strfreev (default_columns);
3132
g_strfreev (default_order);
3136
nautilus_list_view_set_zoom_level (NautilusListView *view,
3137
NautilusZoomLevel new_level,
3138
gboolean always_emit)
3142
g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
3143
g_return_if_fail (new_level >= NAUTILUS_ZOOM_LEVEL_SMALLEST &&
3144
new_level <= NAUTILUS_ZOOM_LEVEL_LARGEST);
3146
if (view->details->zoom_level == new_level) {
3148
g_signal_emit_by_name (NAUTILUS_VIEW(view), "zoom-level-changed");
3153
view->details->zoom_level = new_level;
3154
g_signal_emit_by_name (NAUTILUS_VIEW(view), "zoom-level-changed");
3156
/* Select correctly scaled icons. */
3157
column = nautilus_list_model_get_column_id_from_zoom_level (new_level);
3158
gtk_tree_view_column_set_attributes (view->details->file_name_column,
3159
GTK_CELL_RENDERER (view->details->pixbuf_cell),
3163
nautilus_view_update_menus (NAUTILUS_VIEW (view));
3165
set_up_pixbuf_size (view);
3169
nautilus_list_view_bump_zoom_level (NautilusView *view, int zoom_increment)
3171
NautilusListView *list_view;
3174
g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
3176
list_view = NAUTILUS_LIST_VIEW (view);
3177
new_level = list_view->details->zoom_level + zoom_increment;
3179
if (new_level >= NAUTILUS_ZOOM_LEVEL_SMALLEST &&
3180
new_level <= NAUTILUS_ZOOM_LEVEL_LARGEST) {
3181
nautilus_list_view_set_zoom_level (list_view, new_level, FALSE);
3185
static NautilusZoomLevel
3186
nautilus_list_view_get_zoom_level (NautilusView *view)
3188
NautilusListView *list_view;
3190
g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), NAUTILUS_ZOOM_LEVEL_STANDARD);
3192
list_view = NAUTILUS_LIST_VIEW (view);
3194
return list_view->details->zoom_level;
3198
nautilus_list_view_zoom_to_level (NautilusView *view,
3199
NautilusZoomLevel zoom_level)
3201
NautilusListView *list_view;
3203
g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
3205
list_view = NAUTILUS_LIST_VIEW (view);
3207
nautilus_list_view_set_zoom_level (list_view, zoom_level, FALSE);
3211
nautilus_list_view_restore_default_zoom_level (NautilusView *view)
3213
NautilusListView *list_view;
3215
g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
3217
list_view = NAUTILUS_LIST_VIEW (view);
3219
nautilus_list_view_set_zoom_level (list_view, get_default_zoom_level (), FALSE);
3223
nautilus_list_view_can_zoom_in (NautilusView *view)
3225
g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), FALSE);
3227
return NAUTILUS_LIST_VIEW (view)->details->zoom_level < NAUTILUS_ZOOM_LEVEL_LARGEST;
3231
nautilus_list_view_can_zoom_out (NautilusView *view)
3233
g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), FALSE);
3235
return NAUTILUS_LIST_VIEW (view)->details->zoom_level > NAUTILUS_ZOOM_LEVEL_SMALLEST;
3239
nautilus_list_view_start_renaming_file (NautilusView *view,
3241
gboolean select_all)
3243
NautilusListView *list_view;
3247
list_view = NAUTILUS_LIST_VIEW (view);
3249
/* Select all if we are in renaming mode already */
3250
if (list_view->details->file_name_column && list_view->details->editable_widget) {
3251
gtk_editable_select_region (GTK_EDITABLE (list_view->details->editable_widget),
3257
if (!nautilus_list_model_get_first_iter_for_file (list_view->details->model, file, &iter)) {
3261
/* call parent class to make sure the right icon is selected */
3262
NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->start_renaming_file (view, file, select_all);
3264
/* Freeze updates to the view to prevent losing rename focus when the tree view updates */
3265
nautilus_view_freeze_updates (NAUTILUS_VIEW (view));
3267
path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), &iter);
3269
/* Make filename-cells editable. */
3270
g_object_set (G_OBJECT (list_view->details->file_name_cell),
3274
gtk_tree_view_scroll_to_cell (list_view->details->tree_view,
3276
list_view->details->file_name_column,
3278
gtk_tree_view_set_cursor_on_cell (list_view->details->tree_view,
3280
list_view->details->file_name_column,
3281
GTK_CELL_RENDERER (list_view->details->file_name_cell),
3284
/* set cursor also triggers editing-started, where we save the editable widget */
3285
if (list_view->details->editable_widget != NULL) {
3286
int start_offset = 0;
3287
int end_offset = -1;
3290
eel_filename_get_rename_region (list_view->details->original_name,
3291
&start_offset, &end_offset);
3294
gtk_editable_select_region (GTK_EDITABLE (list_view->details->editable_widget),
3295
start_offset, end_offset);
3298
gtk_tree_path_free (path);
3302
nautilus_list_view_click_policy_changed (NautilusView *directory_view)
3305
GdkDisplay *display;
3306
NautilusListView *view;
3310
view = NAUTILUS_LIST_VIEW (directory_view);
3312
/* ensure that we unset the hand cursor and refresh underlined rows */
3313
if (get_click_policy () == NAUTILUS_CLICK_POLICY_DOUBLE) {
3314
if (view->details->hover_path != NULL) {
3315
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->model),
3316
&iter, view->details->hover_path)) {
3317
gtk_tree_model_row_changed (GTK_TREE_MODEL (view->details->model),
3318
view->details->hover_path, &iter);
3321
gtk_tree_path_free (view->details->hover_path);
3322
view->details->hover_path = NULL;
3325
tree = view->details->tree_view;
3326
if (gtk_widget_get_realized (GTK_WIDGET (tree))) {
3327
win = gtk_widget_get_window (GTK_WIDGET (tree));
3328
gdk_window_set_cursor (win, NULL);
3330
display = gtk_widget_get_display (GTK_WIDGET (view));
3331
if (display != NULL) {
3332
gdk_display_flush (display);
3336
g_clear_object (&hand_cursor);
3337
} else if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE) {
3338
if (hand_cursor == NULL) {
3339
hand_cursor = gdk_cursor_new(GDK_HAND2);
3345
default_sort_order_changed_callback (gpointer callback_data)
3347
NautilusListView *list_view;
3349
list_view = NAUTILUS_LIST_VIEW (callback_data);
3351
set_sort_order_from_metadata_and_preferences (list_view);
3355
default_visible_columns_changed_callback (gpointer callback_data)
3357
NautilusListView *list_view;
3359
list_view = NAUTILUS_LIST_VIEW (callback_data);
3361
set_columns_settings_from_metadata_and_preferences (list_view);
3365
default_column_order_changed_callback (gpointer callback_data)
3367
NautilusListView *list_view;
3369
list_view = NAUTILUS_LIST_VIEW (callback_data);
3371
set_columns_settings_from_metadata_and_preferences (list_view);
3375
nautilus_list_view_sort_directories_first_changed (NautilusView *view)
3377
NautilusListView *list_view;
3379
list_view = NAUTILUS_LIST_VIEW (view);
3381
nautilus_list_model_set_should_sort_directories_first (list_view->details->model,
3382
nautilus_view_should_sort_directories_first (view));
3386
nautilus_list_view_compare_files (NautilusView *view, NautilusFile *file1, NautilusFile *file2)
3388
NautilusListView *list_view;
3390
list_view = NAUTILUS_LIST_VIEW (view);
3391
return nautilus_list_model_compare_func (list_view->details->model, file1, file2);
3395
nautilus_list_view_using_manual_layout (NautilusView *view)
3397
g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), FALSE);
3403
nautilus_list_view_dispose (GObject *object)
3405
NautilusListView *list_view;
3407
list_view = NAUTILUS_LIST_VIEW (object);
3409
if (list_view->details->model) {
3410
stop_cell_editing (list_view);
3411
g_object_unref (list_view->details->model);
3412
list_view->details->model = NULL;
3415
if (list_view->details->drag_dest) {
3416
g_object_unref (list_view->details->drag_dest);
3417
list_view->details->drag_dest = NULL;
3420
if (list_view->details->renaming_file_activate_timeout != 0) {
3421
g_source_remove (list_view->details->renaming_file_activate_timeout);
3422
list_view->details->renaming_file_activate_timeout = 0;
3425
if (list_view->details->clipboard_handler_id != 0) {
3426
g_signal_handler_disconnect (nautilus_clipboard_monitor_get (),
3427
list_view->details->clipboard_handler_id);
3428
list_view->details->clipboard_handler_id = 0;
3431
G_OBJECT_CLASS (nautilus_list_view_parent_class)->dispose (object);
3435
nautilus_list_view_finalize (GObject *object)
3437
NautilusListView *list_view;
3439
list_view = NAUTILUS_LIST_VIEW (object);
3441
g_free (list_view->details->original_name);
3442
list_view->details->original_name = NULL;
3444
if (list_view->details->double_click_path[0]) {
3445
gtk_tree_path_free (list_view->details->double_click_path[0]);
3447
if (list_view->details->double_click_path[1]) {
3448
gtk_tree_path_free (list_view->details->double_click_path[1]);
3450
if (list_view->details->new_selection_path) {
3451
gtk_tree_path_free (list_view->details->new_selection_path);
3454
g_list_free (list_view->details->cells);
3455
g_hash_table_destroy (list_view->details->columns);
3457
if (list_view->details->hover_path != NULL) {
3458
gtk_tree_path_free (list_view->details->hover_path);
3461
if (list_view->details->column_editor != NULL) {
3462
gtk_widget_destroy (list_view->details->column_editor);
3465
g_free (list_view->details);
3467
g_signal_handlers_disconnect_by_func (nautilus_preferences,
3468
default_sort_order_changed_callback,
3470
g_signal_handlers_disconnect_by_func (nautilus_list_view_preferences,
3471
default_visible_columns_changed_callback,
3473
g_signal_handlers_disconnect_by_func (nautilus_list_view_preferences,
3474
default_column_order_changed_callback,
3477
G_OBJECT_CLASS (nautilus_list_view_parent_class)->finalize (object);
3481
nautilus_list_view_get_first_visible_file (NautilusView *view)
3486
NautilusListView *list_view;
3488
list_view = NAUTILUS_LIST_VIEW (view);
3490
if (gtk_tree_view_get_path_at_pos (list_view->details->tree_view,
3492
&path, NULL, NULL, NULL)) {
3493
gtk_tree_model_get_iter (GTK_TREE_MODEL (list_view->details->model),
3496
gtk_tree_path_free (path);
3498
gtk_tree_model_get (GTK_TREE_MODEL (list_view->details->model),
3500
NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
3505
uri = nautilus_file_get_uri (file);
3507
nautilus_file_unref (file);
3517
nautilus_list_view_scroll_to_file (NautilusListView *view,
3523
if (!nautilus_list_model_get_first_iter_for_file (view->details->model, file, &iter)) {
3527
path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->details->model), &iter);
3529
gtk_tree_view_scroll_to_cell (view->details->tree_view,
3533
gtk_tree_path_free (path);
3537
list_view_scroll_to_file (NautilusView *view,
3543
/* Only if existing, since we don't want to add the file to
3544
the directory if it has been removed since then */
3545
file = nautilus_file_get_existing_by_uri (uri);
3547
nautilus_list_view_scroll_to_file (NAUTILUS_LIST_VIEW (view), file);
3548
nautilus_file_unref (file);
3554
list_view_notify_clipboard_info (NautilusClipboardMonitor *monitor,
3555
NautilusClipboardInfo *info,
3556
NautilusListView *view)
3558
/* this could be called as a result of _end_loading() being
3559
* called after _dispose(), where the model is cleared.
3561
if (view->details->model == NULL) {
3565
if (info != NULL && info->cut) {
3566
nautilus_list_model_set_highlight_for_files (view->details->model, info->files);
3568
nautilus_list_model_set_highlight_for_files (view->details->model, NULL);
3573
nautilus_list_view_end_loading (NautilusView *view,
3574
gboolean all_files_seen)
3576
NautilusClipboardMonitor *monitor;
3577
NautilusClipboardInfo *info;
3579
monitor = nautilus_clipboard_monitor_get ();
3580
info = nautilus_clipboard_monitor_get_clipboard_info (monitor);
3582
list_view_notify_clipboard_info (monitor, info, NAUTILUS_LIST_VIEW (view));
3586
nautilus_list_view_get_id (NautilusView *view)
3588
return NAUTILUS_LIST_VIEW_ID;
3592
nautilus_list_view_class_init (NautilusListViewClass *class)
3594
NautilusViewClass *nautilus_view_class;
3596
nautilus_view_class = NAUTILUS_VIEW_CLASS (class);
3598
G_OBJECT_CLASS (class)->dispose = nautilus_list_view_dispose;
3599
G_OBJECT_CLASS (class)->finalize = nautilus_list_view_finalize;
3601
nautilus_view_class->add_file = nautilus_list_view_add_file;
3602
nautilus_view_class->begin_loading = nautilus_list_view_begin_loading;
3603
nautilus_view_class->end_loading = nautilus_list_view_end_loading;
3604
nautilus_view_class->bump_zoom_level = nautilus_list_view_bump_zoom_level;
3605
nautilus_view_class->can_zoom_in = nautilus_list_view_can_zoom_in;
3606
nautilus_view_class->can_zoom_out = nautilus_list_view_can_zoom_out;
3607
nautilus_view_class->click_policy_changed = nautilus_list_view_click_policy_changed;
3608
nautilus_view_class->clear = nautilus_list_view_clear;
3609
nautilus_view_class->file_changed = nautilus_list_view_file_changed;
3610
nautilus_view_class->get_backing_uri = nautilus_list_view_get_backing_uri;
3611
nautilus_view_class->get_selection = nautilus_list_view_get_selection;
3612
nautilus_view_class->get_selection_for_file_transfer = nautilus_list_view_get_selection_for_file_transfer;
3613
nautilus_view_class->is_empty = nautilus_list_view_is_empty;
3614
nautilus_view_class->remove_file = nautilus_list_view_remove_file;
3615
nautilus_view_class->merge_menus = nautilus_list_view_merge_menus;
3616
nautilus_view_class->unmerge_menus = nautilus_list_view_unmerge_menus;
3617
nautilus_view_class->update_menus = nautilus_list_view_update_menus;
3618
nautilus_view_class->reset_to_defaults = nautilus_list_view_reset_to_defaults;
3619
nautilus_view_class->restore_default_zoom_level = nautilus_list_view_restore_default_zoom_level;
3620
nautilus_view_class->reveal_selection = nautilus_list_view_reveal_selection;
3621
nautilus_view_class->select_all = nautilus_list_view_select_all;
3622
nautilus_view_class->select_first = nautilus_list_view_select_first;
3623
nautilus_view_class->set_selection = nautilus_list_view_set_selection;
3624
nautilus_view_class->invert_selection = nautilus_list_view_invert_selection;
3625
nautilus_view_class->compare_files = nautilus_list_view_compare_files;
3626
nautilus_view_class->sort_directories_first_changed = nautilus_list_view_sort_directories_first_changed;
3627
nautilus_view_class->start_renaming_file = nautilus_list_view_start_renaming_file;
3628
nautilus_view_class->get_zoom_level = nautilus_list_view_get_zoom_level;
3629
nautilus_view_class->zoom_to_level = nautilus_list_view_zoom_to_level;
3630
nautilus_view_class->end_file_changes = nautilus_list_view_end_file_changes;
3631
nautilus_view_class->using_manual_layout = nautilus_list_view_using_manual_layout;
3632
nautilus_view_class->get_view_id = nautilus_list_view_get_id;
3633
nautilus_view_class->get_first_visible_file = nautilus_list_view_get_first_visible_file;
3634
nautilus_view_class->scroll_to_file = list_view_scroll_to_file;
3638
nautilus_list_view_init (NautilusListView *list_view)
3640
list_view->details = g_new0 (NautilusListViewDetails, 1);
3642
/* ensure that the zoom level is always set before settings up the tree view columns */
3643
list_view->details->zoom_level = get_default_zoom_level ();
3645
create_and_set_up_tree_view (list_view);
3647
g_signal_connect_swapped (nautilus_preferences,
3648
"changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER,
3649
G_CALLBACK (default_sort_order_changed_callback),
3651
g_signal_connect_swapped (nautilus_preferences,
3652
"changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER,
3653
G_CALLBACK (default_sort_order_changed_callback),
3655
g_signal_connect_swapped (nautilus_list_view_preferences,
3656
"changed::" NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS,
3657
G_CALLBACK (default_visible_columns_changed_callback),
3659
g_signal_connect_swapped (nautilus_list_view_preferences,
3660
"changed::" NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER,
3661
G_CALLBACK (default_column_order_changed_callback),
3664
nautilus_list_view_click_policy_changed (NAUTILUS_VIEW (list_view));
3666
nautilus_list_view_sort_directories_first_changed (NAUTILUS_VIEW (list_view));
3667
nautilus_list_view_set_zoom_level (list_view, get_default_zoom_level (), TRUE);
3669
list_view->details->hover_path = NULL;
3670
list_view->details->clipboard_handler_id =
3671
g_signal_connect (nautilus_clipboard_monitor_get (),
3673
G_CALLBACK (list_view_notify_clipboard_info), list_view);
3677
nautilus_list_view_new (NautilusWindowSlot *slot)
3679
return g_object_new (NAUTILUS_TYPE_LIST_VIEW,
3680
"window-slot", slot,
3685
nautilus_list_view_get_tree_view (NautilusListView *list_view)
3687
return list_view->details->tree_view;