~ubuntu-branches/ubuntu/vivid/nautilus/vivid

« back to all changes in this revision

Viewing changes to .pc/git_name_column.patch/src/nautilus-list-view.c

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher, Lars Uebernickel
  • Date: 2014-10-20 09:05:18 UTC
  • Revision ID: package-import@ubuntu.com-20141020090518-ykbdbqn3cb98gyh5
Tags: 1:3.10.1-0ubuntu15
* debian/patches/git_name_column.patch:
  - "nautilus-list-view: Avoid unreadable names" (lp: #1243806)

[ Lars Uebernickel ]
* debian/patches/properties_window_set_max_width_for_value_labels.patch:
  - avoid very wide properties window (GNOME: #732117)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 
2
 
 
3
/* fm-list-view.c - implementation of list view of directory.
 
4
 
 
5
   Copyright (C) 2000 Eazel, Inc.
 
6
   Copyright (C) 2001, 2002 Anders Carlsson <andersca@gnu.org>
 
7
   
 
8
   The Gnome Library is free software; you can redistribute it and/or
 
9
   modify it under the terms of the GNU Library General Public License as
 
10
   published by the Free Software Foundation; either version 2 of the
 
11
   License, or (at your option) any later version.
 
12
 
 
13
   The Gnome Library is distributed in the hope that it will be useful,
 
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
   Library General Public License for more details.
 
17
 
 
18
   You should have received a copy of the GNU Library General Public
 
19
   License along with the Gnome Library; see the file COPYING.LIB.  If not,
 
20
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
21
   Boston, MA 02111-1307, USA.
 
22
 
 
23
   Authors: John Sullivan <sullivan@eazel.com>
 
24
            Anders Carlsson <andersca@gnu.org>
 
25
            David Emory Watson <dwatson@cs.ucr.edu>
 
26
*/
 
27
 
 
28
#include <config.h>
 
29
#include "nautilus-list-view.h"
 
30
 
 
31
#include "nautilus-list-model.h"
 
32
#include "nautilus-error-reporting.h"
 
33
#include "nautilus-view-dnd.h"
 
34
 
 
35
#include <string.h>
 
36
#include <eel/eel-vfs-extensions.h>
 
37
#include <eel/eel-gdk-extensions.h>
 
38
#include <eel/eel-glib-extensions.h>
 
39
#include <gdk/gdk.h>
 
40
#include <gdk/gdkkeysyms.h>
 
41
#include <gtk/gtk.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>
 
57
 
 
58
#define DEBUG_FLAG NAUTILUS_DEBUG_LIST_VIEW
 
59
#include <libnautilus-private/nautilus-debug.h>
 
60
 
 
61
struct NautilusListViewDetails {
 
62
        GtkTreeView *tree_view;
 
63
        NautilusListModel *model;
 
64
        GtkActionGroup *list_action_group;
 
65
        guint list_merge_id;
 
66
 
 
67
        GtkTreeViewColumn   *file_name_column;
 
68
        int file_name_column_num;
 
69
 
 
70
        GtkCellRendererPixbuf *pixbuf_cell;
 
71
        GtkCellRendererText   *file_name_cell;
 
72
        GList *cells;
 
73
        GtkCellEditable *editable_widget;
 
74
 
 
75
        NautilusZoomLevel zoom_level;
 
76
 
 
77
        NautilusTreeViewDragDest *drag_dest;
 
78
 
 
79
        GtkTreePath *double_click_path[2]; /* Both clicks in a double click need to be on the same row */
 
80
 
 
81
        GtkTreePath *new_selection_path;   /* Path of the new selection after removing a file */
 
82
 
 
83
        GtkTreePath *hover_path;
 
84
 
 
85
        guint drag_button;
 
86
        int drag_x;
 
87
        int drag_y;
 
88
 
 
89
        gboolean drag_started;
 
90
        gboolean ignore_button_release;
 
91
        gboolean row_selected_on_button_down;
 
92
        gboolean menus_ready;
 
93
        gboolean active;
 
94
        
 
95
        GHashTable *columns;
 
96
        GtkWidget *column_editor;
 
97
 
 
98
        char *original_name;
 
99
        
 
100
        NautilusFile *renaming_file;
 
101
        gboolean rename_done;
 
102
        guint renaming_file_activate_timeout;
 
103
 
 
104
        gulong clipboard_handler_id;
 
105
 
 
106
        GQuark last_sort_attr;
 
107
};
 
108
 
 
109
struct SelectionForeachData {
 
110
        GList *list;
 
111
        GtkTreeSelection *selection;
 
112
};
 
113
 
 
114
/*
 
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.
 
118
 */
 
119
#define LIST_VIEW_MINIMUM_ROW_HEIGHT    28
 
120
 
 
121
/* We wait two seconds after row is collapsed to unload the subdirectory */
 
122
#define COLLAPSE_TO_UNLOAD_DELAY 2
 
123
 
 
124
/* Wait for the rename to end when activating a file being renamed */
 
125
#define WAIT_FOR_RENAME_ON_ACTIVATE 200
 
126
 
 
127
static GdkCursor *              hand_cursor = NULL;
 
128
 
 
129
static GtkTargetList *          source_target_list = NULL;
 
130
 
 
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,
 
137
                                                                  NautilusFile      *file);
 
138
static void   nautilus_list_view_rename_callback                 (NautilusFile      *file,
 
139
                                                                  GFile             *result_location,
 
140
                                                                  GError            *error,
 
141
                                                                  gpointer           callback_data);
 
142
 
 
143
static void   apply_columns_settings                             (NautilusListView *list_view,
 
144
                                                                  char **column_order,
 
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);
 
150
 
 
151
 
 
152
G_DEFINE_TYPE (NautilusListView, nautilus_list_view, NAUTILUS_TYPE_VIEW);
 
153
 
 
154
static const char * default_search_visible_columns[] = {
 
155
        "name", "size", "type", "where", NULL
 
156
};
 
157
 
 
158
static const char * default_search_columns_order[] = {
 
159
        "name", "size", "type", "where", NULL
 
160
};
 
161
 
 
162
static const char * default_trash_visible_columns[] = {
 
163
        "name", "size", "type", "trashed_on", "trash_orig_path", NULL
 
164
};
 
165
 
 
166
static const char * default_trash_columns_order[] = {
 
167
        "name", "size", "type", "trashed_on", "trash_orig_path", NULL
 
168
};
 
169
 
 
170
static const gchar*
 
171
get_default_sort_order (NautilusFile *file, gboolean *reversed)
 
172
{
 
173
        NautilusFileSortType default_sort_order;
 
174
        gboolean default_sort_reversed;
 
175
        const gchar *retval;
 
176
        const char *attributes[] = {
 
177
                "name", /* is really "manually" which doesn't apply to lists */
 
178
                "name",
 
179
                "size",
 
180
                "type",
 
181
                "date_modified",
 
182
                "date_accessed",
 
183
                "trashed_on",
 
184
                NULL
 
185
        };
 
186
 
 
187
        retval = nautilus_file_get_default_sort_attribute (file, reversed);
 
188
 
 
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);
 
194
 
 
195
                retval = attributes[default_sort_order];
 
196
                *reversed = default_sort_reversed;
 
197
        }
 
198
 
 
199
        return retval;
 
200
}
 
201
 
 
202
static void
 
203
list_selection_changed_callback (GtkTreeSelection *selection, gpointer user_data)
 
204
{
 
205
        NautilusView *view;
 
206
 
 
207
        view = NAUTILUS_VIEW (user_data);
 
208
 
 
209
        nautilus_view_notify_selection_changed (view);
 
210
}
 
211
 
 
212
/* Move these to eel? */
 
213
 
 
214
static void
 
215
tree_selection_foreach_set_boolean (GtkTreeModel *model,
 
216
                                    GtkTreePath *path,
 
217
                                    GtkTreeIter *iter,
 
218
                                    gpointer callback_data)
 
219
{
 
220
        * (gboolean *) callback_data = TRUE;
 
221
}
 
222
 
 
223
static gboolean
 
224
tree_selection_not_empty (GtkTreeSelection *selection)
 
225
{
 
226
        gboolean not_empty;
 
227
 
 
228
        not_empty = FALSE;
 
229
        gtk_tree_selection_selected_foreach (selection,
 
230
                                             tree_selection_foreach_set_boolean,
 
231
                                             &not_empty);
 
232
        return not_empty;
 
233
}
 
234
 
 
235
static gboolean
 
236
tree_view_has_selection (GtkTreeView *view)
 
237
{
 
238
        return tree_selection_not_empty (gtk_tree_view_get_selection (view));
 
239
}
 
240
 
 
241
static void
 
242
preview_selected_items (NautilusListView *view)
 
243
{
 
244
        GList *file_list;
 
245
        
 
246
        file_list = nautilus_list_view_get_selection (NAUTILUS_VIEW (view));
 
247
 
 
248
        if (file_list != NULL) {
 
249
                nautilus_view_preview_files (NAUTILUS_VIEW (view),
 
250
                                             file_list, NULL);
 
251
                nautilus_file_list_free (file_list);
 
252
        }
 
253
}
 
254
 
 
255
static void
 
256
activate_selected_items (NautilusListView *view)
 
257
{
 
258
        GList *file_list;
 
259
        
 
260
        file_list = nautilus_list_view_get_selection (NAUTILUS_VIEW (view));
 
261
 
 
262
        
 
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);
 
269
                }
 
270
                return;
 
271
        }
 
272
        
 
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;
 
276
        }
 
277
        
 
278
        nautilus_view_activate_files (NAUTILUS_VIEW (view),
 
279
                                      file_list,
 
280
                                      0, TRUE);
 
281
        nautilus_file_list_free (file_list);
 
282
 
 
283
}
 
284
 
 
285
static void
 
286
activate_selected_items_alternate (NautilusListView *view,
 
287
                                   NautilusFile *file,
 
288
                                   gboolean open_in_tab)
 
289
{
 
290
        GList *file_list;
 
291
        NautilusWindowOpenFlags flags;
 
292
 
 
293
        flags = 0;
 
294
 
 
295
        if (open_in_tab) {
 
296
                flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB;
 
297
        } else {
 
298
                flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
 
299
        }
 
300
 
 
301
        if (file != NULL) {
 
302
                nautilus_file_ref (file);
 
303
                file_list = g_list_prepend (NULL, file);
 
304
        } else {
 
305
                file_list = nautilus_list_view_get_selection (NAUTILUS_VIEW (view));
 
306
        }
 
307
        nautilus_view_activate_files (NAUTILUS_VIEW (view),
 
308
                                      file_list,
 
309
                                      flags,
 
310
                                      TRUE);
 
311
        nautilus_file_list_free (file_list);
 
312
 
 
313
}
 
314
 
 
315
static gboolean
 
316
button_event_modifies_selection (GdkEventButton *event)
 
317
{
 
318
        return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
 
319
}
 
320
 
 
321
static int
 
322
get_click_policy (void)
 
323
{
 
324
        return g_settings_get_enum (nautilus_preferences,
 
325
                                    NAUTILUS_PREFERENCES_CLICK_POLICY);
 
326
}
 
327
 
 
328
static void
 
329
nautilus_list_view_did_not_drag (NautilusListView *view,
 
330
                                 GdkEventButton *event)
 
331
{
 
332
        GtkTreeView *tree_view;
 
333
        GtkTreeSelection *selection;
 
334
        GtkTreePath *path;
 
335
        
 
336
        tree_view = view->details->tree_view;
 
337
        selection = gtk_tree_view_get_selection (tree_view);
 
338
 
 
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);
 
348
                        } else {
 
349
                                gtk_tree_selection_unselect_path (selection, path);
 
350
                        }
 
351
                }
 
352
 
 
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);
 
359
                        }
 
360
                }
 
361
                gtk_tree_path_free (path);
 
362
        }
 
363
        
 
364
}
 
365
 
 
366
static void 
 
367
drag_data_get_callback (GtkWidget *widget,
 
368
                        GdkDragContext *context,
 
369
                        GtkSelectionData *selection_data,
 
370
                        guint info,
 
371
                        guint time)
 
372
{
 
373
        GtkTreeView *tree_view;
 
374
        GtkTreeModel *model;
 
375
        GList *selection_cache;
 
376
 
 
377
        tree_view = GTK_TREE_VIEW (widget);
 
378
  
 
379
        model = gtk_tree_view_get_model (tree_view);
 
380
  
 
381
        if (model == NULL) {
 
382
                return;
 
383
        }
 
384
 
 
385
        selection_cache = g_object_get_data (G_OBJECT (context), "drag-info");
 
386
        if (selection_cache == NULL) {
 
387
                return;
 
388
        }
 
389
 
 
390
        nautilus_drag_drag_data_get_from_cache (selection_cache, context, selection_data, info, time);
 
391
}
 
392
 
 
393
static void
 
394
stop_drag_check (NautilusListView *view)
 
395
{               
 
396
        view->details->drag_button = 0;
 
397
}
 
398
 
 
399
static cairo_surface_t *
 
400
get_drag_surface (NautilusListView *view)
 
401
{
 
402
        GtkTreeModel *model;
 
403
        GtkTreePath *path;
 
404
        GtkTreeIter iter;
 
405
        cairo_surface_t *ret;
 
406
        GdkRectangle cell_area;
 
407
        
 
408
        ret = NULL;
 
409
        
 
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),
 
418
                                    &ret,
 
419
                                    -1);
 
420
 
 
421
                gtk_tree_view_get_cell_area (view->details->tree_view,
 
422
                                             path, 
 
423
                                             view->details->file_name_column, 
 
424
                                             &cell_area);
 
425
 
 
426
                gtk_tree_path_free (path);
 
427
        }
 
428
 
 
429
        return ret;
 
430
}
 
431
 
 
432
/* iteration glue struct */
 
433
typedef struct {
 
434
        NautilusListView *view;
 
435
        NautilusDragEachSelectedItemDataGet iteratee;
 
436
        gpointer iteratee_data;
 
437
} ListGetDataBinderContext;
 
438
 
 
439
static void
 
440
item_get_data_binder (GtkTreeModel *model,
 
441
                      GtkTreePath *path,
 
442
                      GtkTreeIter *iter,
 
443
                      gpointer data)
 
444
{
 
445
        ListGetDataBinderContext *context = data;
 
446
        NautilusFile *file;
 
447
        GtkTreeView *treeview;
 
448
        GtkTreeViewColumn *column;
 
449
        GdkRectangle cell_area;
 
450
        int drag_begin_y  = 0;
 
451
        char *uri;
 
452
 
 
453
        treeview = nautilus_list_model_get_drag_view (context->view->details->model,
 
454
                                                      NULL,
 
455
                                                      &drag_begin_y);
 
456
        column = gtk_tree_view_get_column (treeview, 0);
 
457
 
 
458
        file = nautilus_list_model_file_for_path (NAUTILUS_LIST_MODEL (model), path);
 
459
        if (file == NULL) {
 
460
                return;
 
461
        }
 
462
 
 
463
        gtk_tree_view_get_cell_area (treeview,
 
464
                                     path,
 
465
                                     column,
 
466
                                     &cell_area);
 
467
 
 
468
        uri = nautilus_file_get_activation_uri (file);
 
469
        nautilus_file_unref (file);
 
470
 
 
471
        /* pass the uri, mouse-relative x/y and icon width/height */
 
472
        context->iteratee (uri,
 
473
                           0,
 
474
                           cell_area.y - drag_begin_y,
 
475
                           cell_area.width,
 
476
                           cell_area.height,
 
477
                           context->iteratee_data);
 
478
 
 
479
        g_free (uri);
 
480
}
 
481
 
 
482
static void
 
483
each_item_get_data_binder (NautilusDragEachSelectedItemDataGet iteratee,
 
484
                           gpointer iterator_context,
 
485
                           gpointer data)
 
486
{
 
487
        NautilusListView *view = NAUTILUS_LIST_VIEW (iterator_context);
 
488
        ListGetDataBinderContext context;
 
489
        GtkTreeSelection *selection;
 
490
 
 
491
        context.view = view;
 
492
        context.iteratee = iteratee;
 
493
        context.iteratee_data = data;
 
494
 
 
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);
 
497
}
 
498
 
 
499
 
 
500
static void
 
501
drag_begin_callback (GtkWidget *widget,
 
502
                     GdkDragContext *context,
 
503
                     NautilusListView *view)
 
504
{
 
505
        GList *selection_cache;
 
506
        cairo_surface_t *surface;
 
507
 
 
508
        surface = get_drag_surface (view);
 
509
        if (surface) {
 
510
                gtk_drag_set_icon_surface (context, surface);
 
511
                cairo_surface_destroy (surface);
 
512
        } else {
 
513
                gtk_drag_set_icon_default (context);
 
514
        }
 
515
 
 
516
        stop_drag_check (view);
 
517
        view->details->drag_started = TRUE;
 
518
 
 
519
        selection_cache = nautilus_drag_create_selection_cache (view,
 
520
                                                                each_item_get_data_binder);
 
521
 
 
522
        g_object_set_data_full (G_OBJECT (context),
 
523
                                "drag-info",
 
524
                                selection_cache,
 
525
                                (GDestroyNotify)nautilus_drag_destroy_selection_list);
 
526
}
 
527
 
 
528
static gboolean
 
529
motion_notify_callback (GtkWidget *widget,
 
530
                        GdkEventMotion *event,
 
531
                        gpointer callback_data)
 
532
{
 
533
        NautilusListView *view;
 
534
        
 
535
        view = NAUTILUS_LIST_VIEW (callback_data);
 
536
 
 
537
        if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget))) {
 
538
                return FALSE;
 
539
        }
 
540
 
 
541
        if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE) {
 
542
                GtkTreePath *old_hover_path;
 
543
 
 
544
                old_hover_path = view->details->hover_path;
 
545
                gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
 
546
                                               event->x, event->y,
 
547
                                               &view->details->hover_path,
 
548
                                               NULL, NULL, NULL);
 
549
 
 
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);
 
553
                        } else {
 
554
                                gdk_window_set_cursor (gtk_widget_get_window (widget), NULL);
 
555
                        }
 
556
                }
 
557
 
 
558
                if (old_hover_path != NULL) {
 
559
                        gtk_tree_path_free (old_hover_path);
 
560
                }
 
561
        }
 
562
 
 
563
        if (view->details->drag_button != 0) {
 
564
                if (!source_target_list) {
 
565
                        source_target_list = nautilus_list_model_get_drag_target_list ();
 
566
                }
 
567
 
 
568
                if (gtk_drag_check_threshold (widget,
 
569
                                              view->details->drag_x,
 
570
                                              view->details->drag_y,
 
571
                                              event->x, 
 
572
                                              event->y)) {
 
573
                        gtk_drag_begin
 
574
                                (widget,
 
575
                                 source_target_list,
 
576
                                 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK,
 
577
                                 view->details->drag_button,
 
578
                                 (GdkEvent*)event);
 
579
                }                     
 
580
                return TRUE;
 
581
        }
 
582
        
 
583
        return FALSE;
 
584
}
 
585
 
 
586
static gboolean
 
587
leave_notify_callback (GtkWidget *widget,
 
588
                       GdkEventCrossing *event,
 
589
                       gpointer callback_data)
 
590
{
 
591
        NautilusListView *view;
 
592
 
 
593
        view = NAUTILUS_LIST_VIEW (callback_data);
 
594
 
 
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;
 
599
        }
 
600
 
 
601
        return FALSE;
 
602
}
 
603
 
 
604
static gboolean
 
605
enter_notify_callback (GtkWidget *widget,
 
606
                       GdkEventCrossing *event,
 
607
                       gpointer callback_data)
 
608
{
 
609
        NautilusListView *view;
 
610
 
 
611
        view = NAUTILUS_LIST_VIEW (callback_data);
 
612
 
 
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);
 
616
                }
 
617
 
 
618
                gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
 
619
                                               event->x, event->y,
 
620
                                               &view->details->hover_path,
 
621
                                               NULL, NULL, NULL);
 
622
 
 
623
                if (view->details->hover_path != NULL) {
 
624
                        gdk_window_set_cursor (gtk_widget_get_window (widget), hand_cursor);
 
625
                }
 
626
        }
 
627
 
 
628
        return FALSE;
 
629
}
 
630
 
 
631
static void
 
632
do_popup_menu (GtkWidget *widget, NautilusListView *view, GdkEventButton *event)
 
633
{
 
634
        if (tree_view_has_selection (GTK_TREE_VIEW (widget))) {
 
635
                nautilus_view_pop_up_selection_context_menu (NAUTILUS_VIEW (view), event);
 
636
        } else {
 
637
                nautilus_view_pop_up_background_context_menu (NAUTILUS_VIEW (view), event);
 
638
        }
 
639
}
 
640
 
 
641
static void
 
642
row_activated_callback (GtkTreeView *treeview, GtkTreePath *path, 
 
643
                        GtkTreeViewColumn *column, NautilusListView *view)
 
644
{
 
645
        activate_selected_items (view);
 
646
}
 
647
 
 
648
static gboolean
 
649
button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer callback_data)
 
650
{
 
651
        NautilusListView *view;
 
652
        GtkTreeView *tree_view;
 
653
        GtkTreePath *path;
 
654
        GtkTreeSelection *selection;
 
655
        GtkWidgetClass *tree_view_class;
 
656
        gint64 current_time;
 
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;
 
662
        NautilusFile *file;
 
663
 
 
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);
 
668
 
 
669
        /* Don't handle extra mouse buttons here */
 
670
        if (event->button > 5) {
 
671
                return FALSE;
 
672
        }
 
673
 
 
674
        if (event->window != gtk_tree_view_get_bin_window (tree_view)) {
 
675
                return FALSE;
 
676
        }
 
677
 
 
678
        nautilus_list_model_set_drag_view
 
679
                (NAUTILUS_LIST_MODEL (gtk_tree_view_get_model (tree_view)),
 
680
                 tree_view,
 
681
                 event->x, event->y);
 
682
 
 
683
        g_object_get (G_OBJECT (gtk_widget_get_settings (widget)),
 
684
                      "gtk-double-click-time", &double_click_time,
 
685
                      NULL);
 
686
 
 
687
        /* Determine click count */
 
688
        current_time = g_get_monotonic_time ();
 
689
        if (current_time - last_click_time < double_click_time * 1000) {
 
690
                click_count++;
 
691
        } else {
 
692
                click_count = 0;
 
693
        }
 
694
 
 
695
        /* Stash time for next compare */
 
696
        last_click_time = current_time;
 
697
 
 
698
        /* Ignore double click if we are in single click mode */
 
699
        if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE && click_count >= 2) {
 
700
                return TRUE;
 
701
        }
 
702
 
 
703
        view->details->ignore_button_release = FALSE;
 
704
        is_simple_click = ((event->button == 1 || event->button == 2) && (event->type == GDK_BUTTON_PRESS));
 
705
 
 
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;
 
713
                }
 
714
 
 
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);
 
719
 
 
720
                if (event->button == 3) {
 
721
                        do_popup_menu (widget, view, event);
 
722
                }
 
723
 
 
724
                return TRUE;
 
725
        }
 
726
 
 
727
        call_parent = TRUE;
 
728
        on_expander = FALSE;
 
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);
 
732
 
 
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,
 
738
                                      NULL);
 
739
                /* TODO we should not hardcode this extra padding. It is
 
740
                 * EXPANDER_EXTRA_PADDING from GtkTreeView.
 
741
                 */
 
742
                expander_size += 4;
 
743
                on_expander = (event->x <= horizontal_separator / 2 +
 
744
                               gtk_tree_path_get_depth (path) * expander_size);
 
745
        }
 
746
 
 
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);
 
753
        }
 
754
 
 
755
        if (event->type == GDK_2BUTTON_PRESS) {
 
756
                /* Double clicking does not trigger a D&D action. */
 
757
                view->details->drag_button = 0;
 
758
 
 
759
                /* NOTE: Activation can actually destroy the view if we're switching */
 
760
                if (!on_expander &&
 
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);
 
765
                                if (file != NULL) {
 
766
                                        activate_selected_items_alternate (view, file, TRUE);
 
767
                                        nautilus_file_unref (file);
 
768
                                }
 
769
                        } else {
 
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);
 
774
                                }
 
775
                        }
 
776
                } else {
 
777
                        tree_view_class->button_press_event (widget, event);
 
778
                }
 
779
        } else {
 
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.
 
785
                 */
 
786
                if (event->button == 3 && path_selected) {
 
787
                        call_parent = FALSE;
 
788
                }
 
789
 
 
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;
 
793
 
 
794
                        if (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;
 
799
 
 
800
                                call_parent = FALSE;
 
801
                                if ((event->state & GDK_SHIFT_MASK) != 0) {
 
802
                                        GtkTreePath *cursor;
 
803
                                        gtk_tree_view_get_cursor (tree_view, &cursor, NULL);
 
804
                                        if (cursor != NULL) {
 
805
                                                gtk_tree_selection_select_range (selection, cursor, path);
 
806
                                        } else {
 
807
                                                gtk_tree_selection_select_path (selection, path);
 
808
                                        }
 
809
                                } else {
 
810
                                        gtk_tree_selection_select_path (selection, path);
 
811
                                }
 
812
                                selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
 
813
 
 
814
                                /* This unselects everything */
 
815
                                gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
 
816
 
 
817
                                /* So select it again */
 
818
                                for (l = selected_rows; l != NULL; l = l->next) {
 
819
                                        gtk_tree_selection_select_path (selection, l->data);
 
820
                                }
 
821
                                g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
 
822
                        } else {
 
823
                                view->details->ignore_button_release = on_expander;
 
824
                        }
 
825
                }
 
826
                
 
827
                if (call_parent) {
 
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);
 
833
                }
 
834
 
 
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;
 
840
                }
 
841
 
 
842
                if (event->button == 3) {
 
843
                        do_popup_menu (widget, view, event);
 
844
                }
 
845
        }
 
846
 
 
847
        gtk_tree_path_free (path);
 
848
 
 
849
        /* We chained to the default handler in this method, so never
 
850
         * let the default handler run */ 
 
851
        return TRUE;
 
852
}
 
853
 
 
854
static gboolean
 
855
button_release_callback (GtkWidget *widget, 
 
856
                         GdkEventButton *event, 
 
857
                         gpointer callback_data)
 
858
{
 
859
        NautilusListView *view;
 
860
        
 
861
        view = NAUTILUS_LIST_VIEW (callback_data);
 
862
 
 
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);
 
868
                }
 
869
        }
 
870
        return FALSE;
 
871
}
 
872
 
 
873
static gboolean
 
874
popup_menu_callback (GtkWidget *widget, gpointer callback_data)
 
875
{
 
876
        NautilusListView *view;
 
877
 
 
878
        view = NAUTILUS_LIST_VIEW (callback_data);
 
879
 
 
880
        do_popup_menu (widget, view, NULL);
 
881
 
 
882
        return TRUE;
 
883
}
 
884
 
 
885
static void
 
886
subdirectory_done_loading_callback (NautilusDirectory *directory, NautilusListView *view)
 
887
{
 
888
        nautilus_list_model_subdirectory_done_loading (view->details->model, directory);
 
889
}
 
890
 
 
891
static void
 
892
row_expanded_callback (GtkTreeView *treeview,
 
893
                       GtkTreeIter *iter,
 
894
                       GtkTreePath *path,
 
895
                       gpointer callback_data)
 
896
{
 
897
        NautilusListView *view;
 
898
        NautilusDirectory *directory;
 
899
        char *uri;
 
900
 
 
901
        view = NAUTILUS_LIST_VIEW (callback_data);
 
902
 
 
903
        if (!nautilus_list_model_load_subdirectory (view->details->model, path, &directory)) {
 
904
                return;
 
905
        }
 
906
 
 
907
        uri = nautilus_directory_get_uri (directory);
 
908
        DEBUG ("Row expaded callback for uri %s", uri);
 
909
        g_free (uri);
 
910
 
 
911
        nautilus_view_add_subdirectory (NAUTILUS_VIEW (view), directory);
 
912
 
 
913
        if (nautilus_directory_are_all_files_seen (directory)) {
 
914
                nautilus_list_model_subdirectory_done_loading (view->details->model,
 
915
                                                               directory);
 
916
        } else {
 
917
                g_signal_connect_object (directory, "done-loading",
 
918
                                         G_CALLBACK (subdirectory_done_loading_callback),
 
919
                                         view, 0);
 
920
        }
 
921
 
 
922
        nautilus_directory_unref (directory);
 
923
}
 
924
 
 
925
typedef struct {
 
926
        NautilusFile *file;
 
927
        NautilusDirectory *directory;
 
928
        NautilusListView *view;
 
929
} UnloadDelayData;
 
930
 
 
931
static void
 
932
unload_delay_data_free (UnloadDelayData *unload_data)
 
933
{
 
934
        if (unload_data->view != NULL) {
 
935
                g_object_remove_weak_pointer (G_OBJECT (unload_data->view),
 
936
                                              (gpointer *) &unload_data->view);
 
937
        }
 
938
 
 
939
        nautilus_directory_unref (unload_data->directory);
 
940
        nautilus_file_unref (unload_data->file);
 
941
 
 
942
        g_slice_free (UnloadDelayData, unload_data);
 
943
}
 
944
 
 
945
static UnloadDelayData *
 
946
unload_delay_data_new (NautilusFile *file,
 
947
                       NautilusDirectory *parent_directory,
 
948
                       NautilusListView *view)
 
949
{
 
950
        UnloadDelayData *unload_data;
 
951
 
 
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);
 
956
 
 
957
        g_object_add_weak_pointer (G_OBJECT (unload_data->view),
 
958
                                   (gpointer *) &unload_data->view);
 
959
 
 
960
        return unload_data;
 
961
}
 
962
 
 
963
static gboolean
 
964
unload_file_timeout (gpointer data)
 
965
{
 
966
        UnloadDelayData *unload_data = data;
 
967
        GtkTreeIter iter;
 
968
        NautilusListModel *model;
 
969
        GtkTreePath *path;
 
970
 
 
971
        if (unload_data->view == NULL) {
 
972
                goto out;
 
973
        }
 
974
 
 
975
        model = unload_data->view->details->model;
 
976
        if (nautilus_list_model_get_tree_iter_from_file (model,
 
977
                                                         unload_data->file,
 
978
                                                         unload_data->directory,
 
979
                                                         &iter)) {
 
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,
 
982
                                                 path)) {
 
983
                        nautilus_list_model_unload_subdirectory (model, &iter);
 
984
                }
 
985
                gtk_tree_path_free (path);
 
986
        }
 
987
 
 
988
 out:
 
989
        unload_delay_data_free (unload_data);
 
990
        return FALSE;
 
991
}
 
992
 
 
993
static void
 
994
row_collapsed_callback (GtkTreeView *treeview,
 
995
                        GtkTreeIter *iter,
 
996
                        GtkTreePath *path,
 
997
                        gpointer callback_data)
 
998
{
 
999
        NautilusListView *view;
 
1000
        NautilusFile *file;
 
1001
        NautilusDirectory *directory;
 
1002
        GtkTreeIter parent;
 
1003
        UnloadDelayData *unload_data;
 
1004
        GtkTreeModel *model;
 
1005
        char *uri;
 
1006
 
 
1007
        view = NAUTILUS_LIST_VIEW (callback_data);
 
1008
        model = GTK_TREE_MODEL (view->details->model);
 
1009
 
 
1010
        gtk_tree_model_get (model, iter,
 
1011
                            NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
 
1012
                            -1);
 
1013
 
 
1014
        uri = nautilus_file_get_uri (file);
 
1015
        DEBUG ("Row collapsed callback for uri %s", uri);
 
1016
        g_free (uri);
 
1017
 
 
1018
        directory = NULL;
 
1019
        if (gtk_tree_model_iter_parent (model, &parent, iter)) {
 
1020
                gtk_tree_model_get (model, &parent,
 
1021
                                    NAUTILUS_LIST_MODEL_SUBDIRECTORY_COLUMN, &directory,
 
1022
                                    -1);
 
1023
        }
 
1024
 
 
1025
        unload_data = unload_delay_data_new (file, directory, view);
 
1026
        g_timeout_add_seconds (COLLAPSE_TO_UNLOAD_DELAY,
 
1027
                               unload_file_timeout,
 
1028
                               unload_data);
 
1029
 
 
1030
        nautilus_file_unref (file);
 
1031
        nautilus_directory_unref (directory);
 
1032
}
 
1033
 
 
1034
static void
 
1035
subdirectory_unloaded_callback (NautilusListModel *model,
 
1036
                                NautilusDirectory *directory,
 
1037
                                gpointer callback_data)
 
1038
{
 
1039
        NautilusListView *view;
 
1040
        
 
1041
        g_return_if_fail (NAUTILUS_IS_LIST_MODEL (model));
 
1042
        g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
 
1043
 
 
1044
        view = NAUTILUS_LIST_VIEW(callback_data);
 
1045
        
 
1046
        g_signal_handlers_disconnect_by_func (directory,
 
1047
                                              G_CALLBACK (subdirectory_done_loading_callback),
 
1048
                                              view);
 
1049
        nautilus_view_remove_subdirectory (NAUTILUS_VIEW (view), directory);
 
1050
}
 
1051
 
 
1052
static gboolean
 
1053
key_press_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_data)
 
1054
{
 
1055
        NautilusView *view;
 
1056
        GdkEventButton button_event = { 0 };
 
1057
        gboolean handled;
 
1058
        GtkTreeView *tree_view;
 
1059
        GtkTreePath *path;
 
1060
 
 
1061
        tree_view = GTK_TREE_VIEW (widget);
 
1062
 
 
1063
        view = NAUTILUS_VIEW (callback_data);
 
1064
        handled = FALSE;
 
1065
 
 
1066
        switch (event->keyval) {
 
1067
        case GDK_KEY_F10:
 
1068
                if (event->state & GDK_CONTROL_MASK) {
 
1069
                        nautilus_view_pop_up_background_context_menu (view, &button_event);
 
1070
                        handled = TRUE;
 
1071
                }
 
1072
                break;
 
1073
        case GDK_KEY_Right:
 
1074
                gtk_tree_view_get_cursor (tree_view, &path, NULL);
 
1075
                if (path) {
 
1076
                        gtk_tree_view_expand_row (tree_view, path, FALSE);
 
1077
                        gtk_tree_path_free (path);
 
1078
                }
 
1079
                handled = TRUE;
 
1080
                break;
 
1081
        case GDK_KEY_Left:
 
1082
                gtk_tree_view_get_cursor (tree_view, &path, NULL);
 
1083
                if (path) {
 
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.
 
1087
                                 */
 
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);
 
1090
                                }
 
1091
                        }
 
1092
 
 
1093
                        gtk_tree_path_free (path);
 
1094
                }
 
1095
                handled = TRUE;
 
1096
                break;
 
1097
        case GDK_KEY_space:
 
1098
                if (event->state & GDK_CONTROL_MASK) {
 
1099
                        handled = FALSE;
 
1100
                        break;
 
1101
                }
 
1102
                if (!gtk_widget_has_focus (GTK_WIDGET (NAUTILUS_LIST_VIEW (view)->details->tree_view))) {
 
1103
                        handled = FALSE;
 
1104
                        break;
 
1105
                }
 
1106
                if ((event->state & GDK_SHIFT_MASK) != 0) {
 
1107
                        activate_selected_items_alternate (NAUTILUS_LIST_VIEW (view), NULL, TRUE);
 
1108
                } else {
 
1109
                        preview_selected_items (NAUTILUS_LIST_VIEW (view));
 
1110
                }
 
1111
                handled = TRUE;
 
1112
                break;
 
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);
 
1117
                } else {
 
1118
                        activate_selected_items (NAUTILUS_LIST_VIEW (view));
 
1119
                }
 
1120
                handled = TRUE;
 
1121
                break;
 
1122
        case GDK_KEY_v:
 
1123
                /* Eat Control + v to not enable type ahead */
 
1124
                if ((event->state & GDK_CONTROL_MASK) != 0) {
 
1125
                        handled = TRUE;
 
1126
                }
 
1127
                break;
 
1128
 
 
1129
        default:
 
1130
                handled = FALSE;
 
1131
        }
 
1132
 
 
1133
        return handled;
 
1134
}
 
1135
 
 
1136
static gboolean
 
1137
test_expand_row_callback (GtkTreeView *tree_view,
 
1138
                          GtkTreeIter *iter,
 
1139
                          GtkTreePath *path,
 
1140
                          gboolean user_data)
 
1141
{
 
1142
        return !g_settings_get_boolean (nautilus_list_view_preferences,
 
1143
                                        NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE);
 
1144
}
 
1145
 
 
1146
static void
 
1147
nautilus_list_view_reveal_selection (NautilusView *view)
 
1148
{
 
1149
        GList *selection;
 
1150
 
 
1151
        g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
 
1152
 
 
1153
        selection = nautilus_view_get_selection (view);
 
1154
 
 
1155
        /* Make sure at least one of the selected items is scrolled into view */
 
1156
        if (selection != NULL) {
 
1157
                NautilusListView *list_view;
 
1158
                NautilusFile *file;
 
1159
                GtkTreeIter iter;
 
1160
                GtkTreePath *path;
 
1161
                
 
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);
 
1166
 
 
1167
                        gtk_tree_view_scroll_to_cell (list_view->details->tree_view, path, NULL, FALSE, 0.0, 0.0);
 
1168
                        
 
1169
                        gtk_tree_path_free (path);
 
1170
                }
 
1171
        }
 
1172
 
 
1173
        nautilus_file_list_free (selection);
 
1174
}
 
1175
 
 
1176
static gboolean
 
1177
sort_criterion_changes_due_to_user (GtkTreeView *tree_view)
 
1178
{
 
1179
        GList *columns, *p;
 
1180
        GtkTreeViewColumn *column;
 
1181
        GSignalInvocationHint *ihint;
 
1182
        gboolean ret;
 
1183
 
 
1184
        ret = FALSE;
 
1185
 
 
1186
        columns = gtk_tree_view_get_columns (tree_view);
 
1187
        for (p = columns; p != NULL; p = p->next) {
 
1188
                column = p->data;
 
1189
                ihint = g_signal_get_invocation_hint (column);
 
1190
                if (ihint != NULL) {
 
1191
                        ret = TRUE;
 
1192
                        break;
 
1193
                }
 
1194
        }
 
1195
        g_list_free (columns);
 
1196
 
 
1197
        return ret;
 
1198
}
 
1199
 
 
1200
static void
 
1201
sort_column_changed_callback (GtkTreeSortable *sortable, 
 
1202
                              NautilusListView *view)
 
1203
{
 
1204
        NautilusFile *file;
 
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;
 
1210
 
 
1211
        file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (view));
 
1212
 
 
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);
 
1215
 
 
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));
 
1221
 
 
1222
        default_reversed_attr = (default_sort_reversed ? "true" : "false");
 
1223
 
 
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);
 
1233
                } else {
 
1234
                        reversed = nautilus_file_is_date_sort_attribute_q (sort_attr);
 
1235
                }
 
1236
 
 
1237
                if (reversed) {
 
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),
 
1240
                                                              sort_column_id,
 
1241
                                                              GTK_SORT_DESCENDING);
 
1242
                        g_signal_handlers_unblock_by_func (sortable, sort_column_changed_callback, view);
 
1243
                }
 
1244
        }
 
1245
 
 
1246
 
 
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);
 
1250
 
 
1251
        /* Make sure selected item(s) is visible after sort */
 
1252
        nautilus_list_view_reveal_selection (NAUTILUS_VIEW (view));
 
1253
 
 
1254
        view->details->last_sort_attr = sort_attr;
 
1255
}
 
1256
 
 
1257
static void
 
1258
editable_focus_out_cb (GtkWidget *widget,
 
1259
                       GdkEvent *event,
 
1260
                       gpointer user_data)
 
1261
{
 
1262
        NautilusListView *view = user_data;
 
1263
 
 
1264
        view->details->editable_widget = NULL;
 
1265
 
 
1266
        nautilus_view_set_is_renaming (NAUTILUS_VIEW (view), FALSE);
 
1267
        nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
 
1268
}
 
1269
 
 
1270
static void
 
1271
cell_renderer_editing_started_cb (GtkCellRenderer *renderer,
 
1272
                                  GtkCellEditable *editable,
 
1273
                                  const gchar *path_str,
 
1274
                                  NautilusListView *list_view)
 
1275
{
 
1276
        GtkEntry *entry;
 
1277
 
 
1278
        entry = GTK_ENTRY (editable);
 
1279
        list_view->details->editable_widget = editable;
 
1280
 
 
1281
        /* Free a previously allocated original_name */
 
1282
        g_free (list_view->details->original_name);
 
1283
 
 
1284
        list_view->details->original_name = g_strdup (gtk_entry_get_text (entry));
 
1285
 
 
1286
        g_signal_connect (entry, "focus-out-event",
 
1287
                          G_CALLBACK (editable_focus_out_cb), list_view);
 
1288
 
 
1289
        nautilus_clipboard_set_up_editable
 
1290
                (GTK_EDITABLE (entry),
 
1291
                 nautilus_view_get_ui_manager (NAUTILUS_VIEW (list_view)),
 
1292
                 FALSE);
 
1293
}
 
1294
 
 
1295
static void
 
1296
cell_renderer_editing_canceled (GtkCellRendererText *cell,
 
1297
                                NautilusListView    *view)
 
1298
{
 
1299
        view->details->editable_widget = NULL;
 
1300
 
 
1301
        nautilus_view_set_is_renaming (NAUTILUS_VIEW (view), FALSE);
 
1302
        nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
 
1303
}
 
1304
 
 
1305
static void
 
1306
cell_renderer_edited (GtkCellRendererText *cell,
 
1307
                      const char          *path_str,
 
1308
                      const char          *new_text,
 
1309
                      NautilusListView    *view)
 
1310
{
 
1311
        GtkTreePath *path;
 
1312
        NautilusFile *file;
 
1313
        GtkTreeIter iter;
 
1314
 
 
1315
        view->details->editable_widget = NULL;
 
1316
        nautilus_view_set_is_renaming (NAUTILUS_VIEW (view), FALSE);
 
1317
 
 
1318
        /* Don't allow a rename with an empty string. Revert to original 
 
1319
         * without notifying the user.
 
1320
         */
 
1321
        if (new_text[0] == '\0') {
 
1322
                g_object_set (G_OBJECT (view->details->file_name_cell),
 
1323
                              "editable", FALSE,
 
1324
                              NULL);
 
1325
                nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
 
1326
                return;
 
1327
        }
 
1328
        
 
1329
        path = gtk_tree_path_new_from_string (path_str);
 
1330
 
 
1331
        gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->model),
 
1332
                                 &iter, path);
 
1333
 
 
1334
        gtk_tree_path_free (path);
 
1335
        
 
1336
        gtk_tree_model_get (GTK_TREE_MODEL (view->details->model),
 
1337
                            &iter,
 
1338
                            NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
 
1339
                            -1);
 
1340
 
 
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);
 
1348
        }
 
1349
        
 
1350
        nautilus_file_unref (file);
 
1351
 
 
1352
        /*We're done editing - make the filename-cells readonly again.*/
 
1353
        g_object_set (G_OBJECT (view->details->file_name_cell),
 
1354
                      "editable", FALSE,
 
1355
                      NULL);
 
1356
 
 
1357
        nautilus_view_unfreeze_updates (NAUTILUS_VIEW (view));
 
1358
}
 
1359
 
 
1360
static char *
 
1361
get_root_uri_callback (NautilusTreeViewDragDest *dest,
 
1362
                       gpointer user_data)
 
1363
{
 
1364
        NautilusListView *view;
 
1365
        
 
1366
        view = NAUTILUS_LIST_VIEW (user_data);
 
1367
 
 
1368
        return nautilus_view_get_uri (NAUTILUS_VIEW (view));
 
1369
}
 
1370
 
 
1371
static NautilusFile *
 
1372
get_file_for_path_callback (NautilusTreeViewDragDest *dest,
 
1373
                            GtkTreePath *path,
 
1374
                            gpointer user_data)
 
1375
{
 
1376
        NautilusListView *view;
 
1377
        
 
1378
        view = NAUTILUS_LIST_VIEW (user_data);
 
1379
 
 
1380
        return nautilus_list_model_file_for_path (view->details->model, path);
 
1381
}
 
1382
 
 
1383
/* Handles an URL received from Mozilla */
 
1384
static void
 
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)
 
1387
{
 
1388
        nautilus_view_handle_netscape_url_drop (NAUTILUS_VIEW (view),
 
1389
                                                encoded_url, target_uri, action, x, y);
 
1390
}
 
1391
 
 
1392
static void
 
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)
 
1396
{
 
1397
        nautilus_view_handle_uri_list_drop (NAUTILUS_VIEW (view),
 
1398
                                            item_uris, target_uri, action, x, y);
 
1399
}
 
1400
 
 
1401
static void
 
1402
list_view_handle_text (NautilusTreeViewDragDest *dest, const char *text,
 
1403
                       const char *target_uri,
 
1404
                       GdkDragAction action, int x, int y, NautilusListView *view)
 
1405
{
 
1406
        nautilus_view_handle_text_drop (NAUTILUS_VIEW (view),
 
1407
                                        text, target_uri, action, x, y);
 
1408
}
 
1409
 
 
1410
static void
 
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)
 
1414
{
 
1415
        nautilus_view_handle_raw_drop (NAUTILUS_VIEW (view),
 
1416
                                       raw_data, length, target_uri, direct_save_uri,
 
1417
                                       action, x, y);
 
1418
}
 
1419
 
 
1420
static void
 
1421
list_view_handle_hover (NautilusTreeViewDragDest *dest,
 
1422
                        const char *target_uri,
 
1423
                        NautilusListView *view)
 
1424
{
 
1425
        nautilus_view_handle_hover (NAUTILUS_VIEW (view), target_uri);
 
1426
}
 
1427
 
 
1428
static void
 
1429
move_copy_items_callback (NautilusTreeViewDragDest *dest,
 
1430
                          const GList *item_uris,
 
1431
                          const char *target_uri,
 
1432
                          guint action,
 
1433
                          int x, 
 
1434
                          int y,
 
1435
                          gpointer user_data)
 
1436
 
 
1437
{
 
1438
        NautilusView *view = user_data;
 
1439
 
 
1440
        nautilus_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
 
1441
                                                    item_uris,
 
1442
                                                    nautilus_view_get_copied_files_atom (view));
 
1443
        nautilus_view_move_copy_items (view,
 
1444
                                       item_uris,
 
1445
                                       NULL,
 
1446
                                       target_uri,
 
1447
                                       action,
 
1448
                                       x, y);
 
1449
}
 
1450
 
 
1451
static void
 
1452
column_header_menu_toggled (GtkCheckMenuItem *menu_item,
 
1453
                            NautilusListView *list_view)
 
1454
{
 
1455
        NautilusFile *file;
 
1456
        char **visible_columns;
 
1457
        char **column_order;
 
1458
        const char *column;
 
1459
        GList *list = NULL;
 
1460
        GList *l;
 
1461
        int i;
 
1462
 
 
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");
 
1467
 
 
1468
        for (i = 0; visible_columns[i] != NULL; ++i) {
 
1469
                list = g_list_prepend (list, visible_columns[i]);
 
1470
        }
 
1471
 
 
1472
        if (gtk_check_menu_item_get_active (menu_item)) {
 
1473
                list = g_list_prepend (list, g_strdup (column));
 
1474
        } else {
 
1475
                l = g_list_find_custom (list, column, (GCompareFunc) g_strcmp0);
 
1476
                list = g_list_delete_link (list, l);
 
1477
        }
 
1478
 
 
1479
        list = g_list_reverse (list);
 
1480
        nautilus_file_set_metadata_list (file,
 
1481
                                         NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS,
 
1482
                                         list);
 
1483
 
 
1484
        g_free (visible_columns);
 
1485
 
 
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;
 
1489
        }
 
1490
 
 
1491
        /* set view values ourselves, as new metadata could not have been
 
1492
         * updated yet.
 
1493
         */
 
1494
        apply_columns_settings (list_view, column_order, visible_columns);
 
1495
 
 
1496
        g_list_free (list);
 
1497
        g_strfreev (column_order);
 
1498
        g_strfreev (visible_columns);
 
1499
}
 
1500
 
 
1501
static void
 
1502
column_header_menu_use_default (GtkMenuItem *menu_item,
 
1503
                                NautilusListView *list_view)
 
1504
{
 
1505
        NautilusFile *file;
 
1506
        char **default_columns;
 
1507
        char **default_order;
 
1508
 
 
1509
        file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
 
1510
 
 
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);
 
1513
 
 
1514
        default_columns = get_default_visible_columns (list_view);
 
1515
        default_order = get_default_column_order (list_view);
 
1516
 
 
1517
        /* set view values ourselves, as new metadata could not have been
 
1518
         * updated yet.
 
1519
         */
 
1520
        apply_columns_settings (list_view, default_order, default_columns);
 
1521
 
 
1522
        g_strfreev (default_columns);
 
1523
        g_strfreev (default_order);
 
1524
}
 
1525
 
 
1526
static gboolean
 
1527
column_header_clicked (GtkWidget *column_button,
 
1528
                       GdkEventButton *event,
 
1529
                       NautilusListView *list_view)
 
1530
{
 
1531
        NautilusFile *file;
 
1532
        char **visible_columns;
 
1533
        char **column_order;
 
1534
        GList *all_columns;
 
1535
        GHashTable *visible_columns_hash;
 
1536
        int i;
 
1537
        GList *l;
 
1538
        GtkWidget *menu;
 
1539
        GtkWidget *menu_item;
 
1540
 
 
1541
        if (event->button != GDK_BUTTON_SECONDARY) {
 
1542
                return FALSE;
 
1543
        }
 
1544
 
 
1545
        file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
 
1546
 
 
1547
        visible_columns = get_visible_columns (list_view);
 
1548
        column_order = get_column_order (list_view);
 
1549
 
 
1550
        all_columns = nautilus_get_columns_for_file (file);
 
1551
        all_columns = nautilus_sort_columns (all_columns, column_order);
 
1552
 
 
1553
        /* hash table to lookup if a given column should be visible */
 
1554
        visible_columns_hash = g_hash_table_new_full (g_str_hash,
 
1555
                                                      g_str_equal,
 
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));
 
1565
                }
 
1566
        }
 
1567
 
 
1568
        menu = gtk_menu_new ();
 
1569
 
 
1570
        for (l = all_columns; l != NULL; l = l->next) {
 
1571
                char *name;
 
1572
                char *label;
 
1573
                char *lowercase;
 
1574
 
 
1575
                g_object_get (G_OBJECT (l->data),
 
1576
                              "name", &name,
 
1577
                              "label", &label,
 
1578
                              NULL);
 
1579
                lowercase = g_ascii_strdown (name, -1);
 
1580
 
 
1581
                menu_item = gtk_check_menu_item_new_with_label (label);
 
1582
                gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
 
1583
 
 
1584
                g_object_set_data_full (G_OBJECT (menu_item),
 
1585
                                        "column-name", name, g_free);
 
1586
 
 
1587
                /* name is always visible */
 
1588
                if (strcmp (lowercase, "name") == 0) {
 
1589
                        gtk_widget_set_sensitive (menu_item, FALSE);
 
1590
                }
 
1591
 
 
1592
                if (g_hash_table_lookup (visible_columns_hash, lowercase) != NULL) {
 
1593
                        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
 
1594
                                                        TRUE);
 
1595
                }
 
1596
 
 
1597
                g_signal_connect (menu_item,
 
1598
                                  "toggled",
 
1599
                                  G_CALLBACK (column_header_menu_toggled),
 
1600
                                  list_view);
 
1601
 
 
1602
                g_free (lowercase);
 
1603
                g_free (label);
 
1604
        }
 
1605
 
 
1606
        menu_item = gtk_separator_menu_item_new ();
 
1607
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
 
1608
 
 
1609
        menu_item = gtk_menu_item_new_with_label (_("Use Default"));
 
1610
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
 
1611
 
 
1612
        g_signal_connect (menu_item,
 
1613
                          "activate",
 
1614
                          G_CALLBACK (column_header_menu_use_default),
 
1615
                          list_view);
 
1616
 
 
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);
 
1622
 
 
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);
 
1627
 
 
1628
        return TRUE;
 
1629
}
 
1630
 
 
1631
static void
 
1632
apply_columns_settings (NautilusListView *list_view,
 
1633
                        char **column_order,
 
1634
                        char **visible_columns)
 
1635
{
 
1636
        GList *all_columns;
 
1637
        NautilusFile *file;
 
1638
        GList *old_view_columns, *view_columns;
 
1639
        GHashTable *visible_columns_hash;
 
1640
        GtkTreeViewColumn *prev_view_column;
 
1641
        GList *l;
 
1642
        int i;
 
1643
 
 
1644
        file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
 
1645
 
 
1646
        /* prepare ordered list of view columns using column_order and visible_columns */
 
1647
        view_columns = NULL;
 
1648
 
 
1649
        all_columns = nautilus_get_columns_for_file (file);
 
1650
        all_columns = nautilus_sort_columns (all_columns, column_order);
 
1651
 
 
1652
        /* hash table to lookup if a given column should be visible */
 
1653
        visible_columns_hash = g_hash_table_new_full (g_str_hash,
 
1654
                                                      g_str_equal,
 
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));
 
1664
                }
 
1665
        }
 
1666
 
 
1667
        for (l = all_columns; l != NULL; l = l->next) {
 
1668
                char *name;
 
1669
                char *lowercase;
 
1670
 
 
1671
                g_object_get (G_OBJECT (l->data), "name", &name, NULL);
 
1672
                lowercase = g_ascii_strdown (name, -1);
 
1673
 
 
1674
                if (g_hash_table_lookup (visible_columns_hash, lowercase) != NULL) {
 
1675
                        GtkTreeViewColumn *view_column;
 
1676
 
 
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);
 
1680
                        }
 
1681
                }
 
1682
 
 
1683
                g_free (name);
 
1684
                g_free (lowercase);
 
1685
        }
 
1686
 
 
1687
        g_hash_table_destroy (visible_columns_hash);
 
1688
        nautilus_column_list_free (all_columns);
 
1689
 
 
1690
        view_columns = g_list_reverse (view_columns);
 
1691
 
 
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);
 
1697
                }
 
1698
        }
 
1699
        g_list_free (old_view_columns);
 
1700
 
 
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);
 
1704
        }
 
1705
 
 
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;
 
1711
        }
 
1712
        g_list_free (view_columns);
 
1713
}
 
1714
 
 
1715
static void
 
1716
filename_cell_data_func (GtkTreeViewColumn *column,
 
1717
                         GtkCellRenderer   *renderer,
 
1718
                         GtkTreeModel      *model,
 
1719
                         GtkTreeIter       *iter,
 
1720
                         NautilusListView        *view)
 
1721
{
 
1722
        char *text;
 
1723
        GtkTreePath *path;
 
1724
        PangoUnderline underline;
 
1725
 
 
1726
        gtk_tree_model_get (model, iter,
 
1727
                            view->details->file_name_column_num, &text,
 
1728
                            -1);
 
1729
 
 
1730
        if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE) {
 
1731
                path = gtk_tree_model_get_path (model, iter);
 
1732
 
 
1733
                if (view->details->hover_path == NULL ||
 
1734
                    gtk_tree_path_compare (path, view->details->hover_path)) {
 
1735
                        underline = PANGO_UNDERLINE_NONE;
 
1736
                } else {
 
1737
                        underline = PANGO_UNDERLINE_SINGLE;
 
1738
                }
 
1739
 
 
1740
                gtk_tree_path_free (path);
 
1741
        } else {
 
1742
                underline = PANGO_UNDERLINE_NONE;
 
1743
        }
 
1744
 
 
1745
        g_object_set (G_OBJECT (renderer),
 
1746
                      "text", text,
 
1747
                      "underline", underline,
 
1748
                      NULL);
 
1749
        g_free (text);
 
1750
}
 
1751
 
 
1752
static void
 
1753
location_cell_data_func (GtkTreeViewColumn *column,
 
1754
                         GtkCellRenderer   *renderer,
 
1755
                         GtkTreeModel      *model,
 
1756
                         GtkTreeIter       *iter,
 
1757
                         NautilusListView  *view,
 
1758
                         gboolean           show_trash_orig)
 
1759
{
 
1760
        NautilusDirectory *directory;
 
1761
        GFile *home_location;
 
1762
        NautilusFile *file;
 
1763
        GFile *dir_location;
 
1764
        GFile *base_location;
 
1765
        gchar *where = NULL;
 
1766
 
 
1767
        directory = nautilus_view_get_model (NAUTILUS_VIEW (view));
 
1768
 
 
1769
        home_location = g_file_new_for_path (g_get_home_dir ());
 
1770
 
 
1771
        gtk_tree_model_get (model, iter,
 
1772
                            NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
 
1773
                            -1);
 
1774
 
 
1775
        /* The file might be NULL if we just toggled an expander
 
1776
         * and we're still loading the subdirectory.
 
1777
         */
 
1778
        if (file == NULL) {
 
1779
                return;
 
1780
        }
 
1781
 
 
1782
        if (show_trash_orig && nautilus_file_is_in_trash (file)) {
 
1783
                NautilusFile *orig_file;
 
1784
 
 
1785
                orig_file = nautilus_file_get_trash_original_file (file);
 
1786
 
 
1787
                if (orig_file != NULL) {
 
1788
                        nautilus_file_unref (file);
 
1789
                        file = orig_file;
 
1790
                }
 
1791
        }
 
1792
 
 
1793
        if (!nautilus_file_is_in_recent (file)) {
 
1794
                dir_location = nautilus_file_get_parent_location (file);
 
1795
        } else {
 
1796
                GFile *activation_location;
 
1797
 
 
1798
                activation_location = nautilus_file_get_activation_location (file);
 
1799
                dir_location = g_file_get_parent (activation_location);
 
1800
 
 
1801
                g_object_unref (activation_location);
 
1802
        }
 
1803
 
 
1804
        if (!NAUTILUS_IS_SEARCH_DIRECTORY (directory)) {
 
1805
                base_location = g_object_ref (home_location);
 
1806
        } else {
 
1807
                NautilusQuery *query;
 
1808
                gchar *base_uri;
 
1809
                NautilusFile *base;
 
1810
 
 
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);
 
1814
 
 
1815
                if (!nautilus_file_is_in_recent (base)) {
 
1816
                        base_location = nautilus_file_get_location (base);
 
1817
                } else {
 
1818
                        base_location = g_object_ref (home_location);
 
1819
                }
 
1820
 
 
1821
                nautilus_file_unref (base);
 
1822
                g_free (base_uri);
 
1823
                g_object_unref (query);
 
1824
        }
 
1825
 
 
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
 
1831
                 */
 
1832
                where = g_strdup ("");
 
1833
        } else if (g_file_has_prefix (dir_location, base_location)) {
 
1834
                gchar *relative_path;
 
1835
 
 
1836
                relative_path = g_file_get_relative_path (base_location,
 
1837
                                                          dir_location);
 
1838
                where = g_filename_display_name (relative_path);
 
1839
 
 
1840
                g_free (relative_path);
 
1841
        }
 
1842
 
 
1843
        if (where != NULL) {
 
1844
                g_object_set (G_OBJECT (renderer),
 
1845
                              "text", where,
 
1846
                              NULL);
 
1847
 
 
1848
                g_free (where);
 
1849
        }
 
1850
 
 
1851
        g_object_unref (base_location);
 
1852
        g_object_unref (dir_location);
 
1853
        nautilus_file_unref (file);
 
1854
        g_object_unref (home_location);
 
1855
}
 
1856
 
 
1857
 
 
1858
static void
 
1859
where_cell_data_func (GtkTreeViewColumn *column,
 
1860
                      GtkCellRenderer   *renderer,
 
1861
                      GtkTreeModel      *model,
 
1862
                      GtkTreeIter       *iter,
 
1863
                      NautilusListView  *view)
 
1864
{
 
1865
        location_cell_data_func (column, renderer, model, iter, view, FALSE);
 
1866
}
 
1867
 
 
1868
static void
 
1869
trash_orig_path_cell_data_func (GtkTreeViewColumn *column,
 
1870
                                GtkCellRenderer   *renderer,
 
1871
                                GtkTreeModel      *model,
 
1872
                                GtkTreeIter       *iter,
 
1873
                                NautilusListView  *view)
 
1874
{
 
1875
        location_cell_data_func (column, renderer, model, iter, view, TRUE);
 
1876
}
 
1877
 
 
1878
 
 
1879
static void
 
1880
set_up_pixbuf_size (NautilusListView *view)
 
1881
{
 
1882
        int icon_size;
 
1883
 
 
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),
 
1887
                                          -1, icon_size);
 
1888
 
 
1889
 
 
1890
        /* FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=641518 */
 
1891
        gtk_tree_view_columns_autosize (view->details->tree_view);
 
1892
}
 
1893
 
 
1894
static gint
 
1895
get_icon_scale_callback (NautilusListModel *model,
 
1896
                         NautilusListView  *view)
 
1897
{
 
1898
        return gtk_widget_get_scale_factor (GTK_WIDGET (view->details->tree_view));
 
1899
}
 
1900
 
 
1901
static void
 
1902
create_and_set_up_tree_view (NautilusListView *view)
 
1903
{
 
1904
        GtkCellRenderer *cell;
 
1905
        GtkTreeViewColumn *column;
 
1906
        GtkBindingSet *binding_set;
 
1907
        AtkObject *atk_obj;
 
1908
        GList *nautilus_columns;
 
1909
        GList *l;
 
1910
        gchar **default_column_order, **default_visible_columns;
 
1911
        
 
1912
        view->details->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
 
1913
        view->details->columns = g_hash_table_new_full (g_str_hash, 
 
1914
                                                        g_str_equal,
 
1915
                                                        (GDestroyNotify) g_free,
 
1916
                                                        NULL);
 
1917
        gtk_tree_view_set_enable_search (view->details->tree_view, FALSE);
 
1918
 
 
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);
 
1922
 
 
1923
        view->details->drag_dest = 
 
1924
                nautilus_tree_view_drag_dest_new (view->details->tree_view);
 
1925
 
 
1926
        g_signal_connect_object (view->details->drag_dest,
 
1927
                                 "get-root-uri",
 
1928
                                 G_CALLBACK (get_root_uri_callback),
 
1929
                                 view, 0);
 
1930
        g_signal_connect_object (view->details->drag_dest,
 
1931
                                 "get-file-for-path",
 
1932
                                 G_CALLBACK (get_file_for_path_callback),
 
1933
                                 view, 0);
 
1934
        g_signal_connect_object (view->details->drag_dest,
 
1935
                                 "move-copy-items",
 
1936
                                 G_CALLBACK (move_copy_items_callback),
 
1937
                                 view, 0);
 
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);
 
1948
 
 
1949
        g_signal_connect_object (gtk_tree_view_get_selection (view->details->tree_view),
 
1950
                                 "changed",
 
1951
                                 G_CALLBACK (list_selection_changed_callback), view, 0);
 
1952
 
 
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);
 
1979
        
 
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);
 
1985
 
 
1986
        g_signal_connect_object (view->details->model, "sort-column-changed",
 
1987
                                 G_CALLBACK (sort_column_changed_callback), view, 0);
 
1988
        
 
1989
        g_signal_connect_object (view->details->model, "subdirectory-unloaded",
 
1990
                                 G_CALLBACK (subdirectory_unloaded_callback), view, 0);
 
1991
 
 
1992
        g_signal_connect_object (view->details->model, "get-icon-scale",
 
1993
                                 G_CALLBACK (get_icon_scale_callback), view, 0);
 
1994
 
 
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);
 
1997
 
 
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);
 
2001
 
 
2002
        nautilus_columns = nautilus_get_all_columns ();
 
2003
 
 
2004
        for (l = nautilus_columns; l != NULL; l = l->next) {
 
2005
                NautilusColumn *nautilus_column;
 
2006
                int column_num;         
 
2007
                char *name;
 
2008
                char *label;
 
2009
                float xalign;
 
2010
                GtkSortType sort_order;
 
2011
 
 
2012
                nautilus_column = NAUTILUS_COLUMN (l->data);
 
2013
 
 
2014
                g_object_get (nautilus_column, 
 
2015
                              "name", &name, 
 
2016
                              "label", &label,
 
2017
                              "xalign", &xalign,
 
2018
                              "default-sort-order", &sort_order,
 
2019
                              NULL);
 
2020
 
 
2021
                column_num = nautilus_list_model_add_column (view->details->model,
 
2022
                                                       nautilus_column);
 
2023
 
 
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;
 
2032
                        
 
2033
                        g_hash_table_insert (view->details->columns,
 
2034
                                             g_strdup ("name"), 
 
2035
                                             view->details->file_name_column);
 
2036
 
 
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),
 
2040
                                          view);
 
2041
 
 
2042
                        gtk_tree_view_set_search_column (view->details->tree_view, column_num);
 
2043
 
 
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);
 
2048
 
 
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,
 
2054
                                         cell, "visible",
 
2055
                                         G_SETTINGS_BIND_INVERT_BOOLEAN | G_SETTINGS_BIND_GET);
 
2056
 
 
2057
                        /* File icon */
 
2058
                        cell = gtk_cell_renderer_pixbuf_new ();
 
2059
                        view->details->pixbuf_cell = (GtkCellRendererPixbuf *)cell;
 
2060
                        set_up_pixbuf_size (view);
 
2061
 
 
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,
 
2064
                                                             cell,
 
2065
                                                             "surface", nautilus_list_model_get_column_id_from_zoom_level (view->details->zoom_level),
 
2066
                                                             NULL);
 
2067
                        
 
2068
                        cell = gtk_cell_renderer_text_new ();
 
2069
                        view->details->file_name_cell = (GtkCellRendererText *)cell;
 
2070
                        g_object_set (cell,
 
2071
                                      "ellipsize", PANGO_ELLIPSIZE_END,
 
2072
                                      "single-paragraph-mode", TRUE,
 
2073
                                      "xpad", 5,
 
2074
                                      NULL);
 
2075
 
 
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);
 
2079
 
 
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,
 
2083
                                                                 view, NULL);
 
2084
                } else {
 
2085
                        cell = gtk_cell_renderer_text_new ();
 
2086
                        g_object_set (cell,
 
2087
                                      "xalign", xalign,
 
2088
                                      "xpad", 5,
 
2089
                                      NULL);
 
2090
                        view->details->cells = g_list_append (view->details->cells,
 
2091
                                                              cell);
 
2092
                        column = gtk_tree_view_column_new_with_attributes (label,
 
2093
                                                                           cell,
 
2094
                                                                           "text", column_num,
 
2095
                                                                           NULL);
 
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, 
 
2099
                                             g_strdup (name), 
 
2100
                                             column);
 
2101
 
 
2102
                        g_signal_connect (gtk_tree_view_column_get_button (column),
 
2103
                                          "button-press-event",
 
2104
                                          G_CALLBACK (column_header_clicked),
 
2105
                                          view);
 
2106
                        
 
2107
                        gtk_tree_view_column_set_resizable (column, TRUE);
 
2108
                        gtk_tree_view_column_set_sort_order (column, sort_order);
 
2109
 
 
2110
                        if (!strcmp (name, "where")) {
 
2111
                                gtk_tree_view_column_set_cell_data_func (column, cell,
 
2112
                                                                         (GtkTreeCellDataFunc) where_cell_data_func,
 
2113
                                                                         view, NULL);
 
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,
 
2117
                                                                         view, NULL);
 
2118
                        }
 
2119
                }
 
2120
                g_free (name);
 
2121
                g_free (label);
 
2122
        }
 
2123
        nautilus_column_list_free (nautilus_columns);
 
2124
 
 
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);
 
2129
 
 
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);
 
2136
 
 
2137
        gtk_widget_show (GTK_WIDGET (view->details->tree_view));
 
2138
        gtk_container_add (GTK_CONTAINER (view), GTK_WIDGET (view->details->tree_view));
 
2139
 
 
2140
        atk_obj = gtk_widget_get_accessible (GTK_WIDGET (view->details->tree_view));
 
2141
        atk_object_set_name (atk_obj, _("List View"));
 
2142
 
 
2143
        g_strfreev (default_visible_columns);
 
2144
        g_strfreev (default_column_order);
 
2145
}
 
2146
 
 
2147
static void
 
2148
nautilus_list_view_add_file (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
 
2149
{
 
2150
        NautilusListModel *model;
 
2151
 
 
2152
        model = NAUTILUS_LIST_VIEW (view)->details->model;
 
2153
        nautilus_list_model_add_file (model, file, directory);
 
2154
}
 
2155
 
 
2156
static char **
 
2157
get_default_visible_columns (NautilusListView *list_view)
 
2158
{
 
2159
        NautilusFile *file;
 
2160
        NautilusDirectory *directory;
 
2161
 
 
2162
        file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
 
2163
 
 
2164
        if (nautilus_file_is_in_trash (file)) {
 
2165
                return g_strdupv ((gchar **) default_trash_visible_columns);
 
2166
        }
 
2167
 
 
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);
 
2171
        }
 
2172
 
 
2173
        return g_settings_get_strv (nautilus_list_view_preferences,
 
2174
                                    NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
 
2175
}
 
2176
 
 
2177
static char **
 
2178
get_visible_columns (NautilusListView *list_view)
 
2179
{
 
2180
        NautilusFile *file;
 
2181
        GList *visible_columns;
 
2182
 
 
2183
        file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
 
2184
 
 
2185
        visible_columns = nautilus_file_get_metadata_list
 
2186
                (file,
 
2187
                 NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS);
 
2188
 
 
2189
        if (visible_columns) {
 
2190
                GPtrArray *res;
 
2191
                GList *l;
 
2192
 
 
2193
                res = g_ptr_array_new ();
 
2194
                for (l = visible_columns; l != NULL; l = l->next) {
 
2195
                        g_ptr_array_add (res, l->data);
 
2196
                }
 
2197
                g_ptr_array_add (res, NULL);
 
2198
 
 
2199
                g_list_free (visible_columns);
 
2200
 
 
2201
                return (char **) g_ptr_array_free (res, FALSE);
 
2202
        }
 
2203
 
 
2204
        return get_default_visible_columns (list_view);
 
2205
}
 
2206
 
 
2207
static char **
 
2208
get_default_column_order (NautilusListView *list_view)
 
2209
{
 
2210
        NautilusFile *file;
 
2211
        NautilusDirectory *directory;
 
2212
 
 
2213
        file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
 
2214
 
 
2215
        if (nautilus_file_is_in_trash (file)) {
 
2216
                return g_strdupv ((gchar **) default_trash_columns_order);
 
2217
        }
 
2218
 
 
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);
 
2222
        }
 
2223
 
 
2224
        return g_settings_get_strv (nautilus_list_view_preferences,
 
2225
                                    NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER);
 
2226
}
 
2227
 
 
2228
static char **
 
2229
get_column_order (NautilusListView *list_view)
 
2230
{
 
2231
        NautilusFile *file;
 
2232
        GList *column_order;
 
2233
 
 
2234
        file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (list_view));
 
2235
 
 
2236
        column_order = nautilus_file_get_metadata_list
 
2237
                (file,
 
2238
                 NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER);
 
2239
 
 
2240
        if (column_order) {
 
2241
                GPtrArray *res;
 
2242
                GList *l;
 
2243
 
 
2244
                res = g_ptr_array_new ();
 
2245
                for (l = column_order; l != NULL; l = l->next) {
 
2246
                        g_ptr_array_add (res, l->data);
 
2247
                }
 
2248
                g_ptr_array_add (res, NULL);
 
2249
 
 
2250
                g_list_free (column_order);
 
2251
 
 
2252
                return (char **) g_ptr_array_free (res, FALSE);
 
2253
        }
 
2254
 
 
2255
        return get_default_column_order (list_view);
 
2256
}
 
2257
 
 
2258
static void
 
2259
set_columns_settings_from_metadata_and_preferences (NautilusListView *list_view)
 
2260
{
 
2261
        char **column_order;
 
2262
        char **visible_columns;
 
2263
 
 
2264
        column_order = get_column_order (list_view);
 
2265
        visible_columns = get_visible_columns (list_view);
 
2266
 
 
2267
        apply_columns_settings (list_view, column_order, visible_columns);
 
2268
 
 
2269
        g_strfreev (column_order);
 
2270
        g_strfreev (visible_columns);
 
2271
}
 
2272
 
 
2273
static void
 
2274
set_sort_order_from_metadata_and_preferences (NautilusListView *list_view)
 
2275
{
 
2276
        char *sort_attribute;
 
2277
        int sort_column_id;
 
2278
        NautilusFile *file;
 
2279
        gboolean sort_reversed, default_sort_reversed;
 
2280
        const gchar *default_sort_order;
 
2281
        
 
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,
 
2285
                                                     NULL);
 
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);
 
2289
 
 
2290
        default_sort_order = get_default_sort_order (file, &default_sort_reversed);
 
2291
        
 
2292
        if (sort_column_id == -1) {
 
2293
                sort_column_id =
 
2294
                        nautilus_list_model_get_sort_column_id_from_attribute (list_view->details->model,
 
2295
                                                                         g_quark_from_string (default_sort_order));
 
2296
        }
 
2297
 
 
2298
        sort_reversed = nautilus_file_get_boolean_metadata (file,
 
2299
                                                            NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED,
 
2300
                                                            default_sort_reversed);
 
2301
 
 
2302
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_view->details->model),
 
2303
                                              sort_column_id,
 
2304
                                              sort_reversed ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING);                                              
 
2305
}
 
2306
 
 
2307
static NautilusZoomLevel
 
2308
get_default_zoom_level (void) {
 
2309
        NautilusZoomLevel default_zoom_level;
 
2310
 
 
2311
        default_zoom_level = g_settings_get_enum (nautilus_list_view_preferences,
 
2312
                                                  NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL);
 
2313
 
 
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;
 
2317
        }
 
2318
 
 
2319
        return default_zoom_level;
 
2320
}
 
2321
 
 
2322
static void
 
2323
nautilus_list_view_begin_loading (NautilusView *view)
 
2324
{
 
2325
        NautilusListView *list_view;
 
2326
 
 
2327
        list_view = NAUTILUS_LIST_VIEW (view);
 
2328
 
 
2329
        set_sort_order_from_metadata_and_preferences (list_view);
 
2330
        set_columns_settings_from_metadata_and_preferences (list_view);
 
2331
}
 
2332
 
 
2333
static void
 
2334
stop_cell_editing (NautilusListView *list_view)
 
2335
{
 
2336
        GtkTreeViewColumn *column;
 
2337
 
 
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.
 
2341
         */
 
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);
 
2346
        }
 
2347
 
 
2348
        g_clear_object (&list_view->details->renaming_file);
 
2349
}
 
2350
 
 
2351
static void
 
2352
nautilus_list_view_clear (NautilusView *view)
 
2353
{
 
2354
        NautilusListView *list_view;
 
2355
 
 
2356
        list_view = NAUTILUS_LIST_VIEW (view);
 
2357
 
 
2358
        if (list_view->details->model != NULL) {
 
2359
                stop_cell_editing (list_view);
 
2360
                nautilus_list_model_clear (list_view->details->model);
 
2361
        }
 
2362
}
 
2363
 
 
2364
static void
 
2365
nautilus_list_view_rename_callback (NautilusFile *file,
 
2366
                                    GFile *result_location,
 
2367
                                    GError *error,
 
2368
                                    gpointer callback_data)
 
2369
{
 
2370
        NautilusListView *view;
 
2371
        
 
2372
        view = NAUTILUS_LIST_VIEW (callback_data);
 
2373
 
 
2374
        if (view->details->renaming_file) {
 
2375
                view->details->rename_done = TRUE;
 
2376
                
 
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.
 
2381
                         */
 
2382
                        nautilus_file_unref (view->details->renaming_file);
 
2383
                        view->details->renaming_file = NULL;
 
2384
                }
 
2385
        }
 
2386
        
 
2387
        g_object_unref (view);
 
2388
}
 
2389
 
 
2390
 
 
2391
static void
 
2392
nautilus_list_view_file_changed (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
 
2393
{
 
2394
        NautilusListView *listview;
 
2395
        GtkTreeIter iter;
 
2396
        GtkTreePath *file_path;
 
2397
 
 
2398
        listview = NAUTILUS_LIST_VIEW (view);
 
2399
        
 
2400
        nautilus_list_model_file_changed (listview->details->model, file, directory);
 
2401
 
 
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
 
2408
                 */
 
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,
 
2412
                                                      file_path, NULL,
 
2413
                                                      FALSE, 0.0, 0.0);
 
2414
                        gtk_tree_path_free (file_path);
 
2415
                }
 
2416
                
 
2417
                nautilus_file_unref (listview->details->renaming_file);
 
2418
                listview->details->renaming_file = NULL;
 
2419
        }
 
2420
}
 
2421
 
 
2422
typedef struct {
 
2423
        GtkTreePath *path;
 
2424
        gboolean is_common;
 
2425
        gboolean is_root;
 
2426
} HasCommonParentData;
 
2427
 
 
2428
static void
 
2429
tree_selection_has_common_parent_foreach_func (GtkTreeModel *model,
 
2430
                                                GtkTreePath *path,
 
2431
                                                GtkTreeIter *iter,
 
2432
                                                gpointer user_data)
 
2433
{
 
2434
        HasCommonParentData *data;
 
2435
        GtkTreePath *parent_path;
 
2436
        gboolean has_parent;
 
2437
 
 
2438
        data = (HasCommonParentData *) user_data;
 
2439
 
 
2440
        parent_path = gtk_tree_path_copy (path);
 
2441
        gtk_tree_path_up (parent_path);
 
2442
 
 
2443
        has_parent = (gtk_tree_path_get_depth (parent_path) > 0) ? TRUE : FALSE;
 
2444
 
 
2445
        if (!has_parent) {
 
2446
                data->is_root = TRUE;
 
2447
        }
 
2448
 
 
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;
 
2454
                }
 
2455
        }
 
2456
 
 
2457
        gtk_tree_path_free (parent_path);
 
2458
}
 
2459
 
 
2460
static void
 
2461
tree_selection_has_common_parent (GtkTreeSelection *selection,
 
2462
                                  gboolean *is_common,
 
2463
                                  gboolean *is_root)
 
2464
{
 
2465
        HasCommonParentData data;
 
2466
 
 
2467
        g_assert (is_common != NULL);
 
2468
        g_assert (is_root != NULL);
 
2469
 
 
2470
        data.path = NULL;
 
2471
        data.is_common = *is_common = TRUE;
 
2472
        data.is_root = *is_root = FALSE;
 
2473
 
 
2474
        gtk_tree_selection_selected_foreach (selection,
 
2475
                                             tree_selection_has_common_parent_foreach_func,
 
2476
                                             &data);
 
2477
 
 
2478
        *is_common = data.is_common;
 
2479
        *is_root = data.is_root;
 
2480
 
 
2481
        if (data.path != NULL) {
 
2482
                gtk_tree_path_free (data.path);
 
2483
        }
 
2484
}
 
2485
 
 
2486
static char *
 
2487
nautilus_list_view_get_backing_uri (NautilusView *view)
 
2488
{
 
2489
        NautilusListView *list_view;
 
2490
        NautilusListModel *list_model;
 
2491
        NautilusFile *file;
 
2492
        GtkTreeView *tree_view;
 
2493
        GtkTreeSelection *selection;
 
2494
        GtkTreePath *path;
 
2495
        GList *paths;
 
2496
        guint length;
 
2497
        char *uri;
 
2498
 
 
2499
        g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), NULL);
 
2500
 
 
2501
        list_view = NAUTILUS_LIST_VIEW (view);
 
2502
        list_model = list_view->details->model;
 
2503
        tree_view = list_view->details->tree_view;
 
2504
 
 
2505
        g_assert (list_model);
 
2506
 
 
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
 
2511
         *     return its URI.
 
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.
 
2515
         */
 
2516
 
 
2517
        uri = NULL;
 
2518
 
 
2519
        selection = gtk_tree_view_get_selection (tree_view);
 
2520
        length = gtk_tree_selection_count_selected_rows (selection);
 
2521
 
 
2522
        if (length == 1) {
 
2523
 
 
2524
                paths = gtk_tree_selection_get_selected_rows (selection, NULL);
 
2525
                path = (GtkTreePath *) paths->data;
 
2526
 
 
2527
                file = nautilus_list_model_file_for_path (list_model, path);
 
2528
                if (file == NULL) {
 
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);
 
2532
                }
 
2533
 
 
2534
                if (file != NULL) {
 
2535
                        if (nautilus_file_is_directory (file) &&
 
2536
                            gtk_tree_view_row_expanded (tree_view, path)) {
 
2537
                                uri = nautilus_file_get_uri (file);
 
2538
                        }
 
2539
                        nautilus_file_unref (file);
 
2540
                }
 
2541
 
 
2542
                gtk_tree_path_free (path);
 
2543
                g_list_free (paths);
 
2544
        }
 
2545
 
 
2546
        if (uri == NULL && length > 0) {
 
2547
 
 
2548
                gboolean is_common, is_root;
 
2549
 
 
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.) */
 
2553
 
 
2554
                tree_selection_has_common_parent (selection, &is_common, &is_root);
 
2555
 
 
2556
                if (is_common && !is_root) {
 
2557
                        paths = gtk_tree_selection_get_selected_rows (selection, NULL);
 
2558
                        path = (GtkTreePath *) paths->data;
 
2559
 
 
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);
 
2564
 
 
2565
                        g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
 
2566
                }
 
2567
        }
 
2568
 
 
2569
        if (uri != NULL) {
 
2570
                return uri;
 
2571
        }
 
2572
 
 
2573
        return NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->get_backing_uri (view);
 
2574
}
 
2575
 
 
2576
static void
 
2577
nautilus_list_view_get_selection_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
 
2578
{
 
2579
        GList **list;
 
2580
        NautilusFile *file;
 
2581
        
 
2582
        list = data;
 
2583
 
 
2584
        gtk_tree_model_get (model, iter,
 
2585
                            NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
 
2586
                            -1);
 
2587
 
 
2588
        if (file != NULL) {
 
2589
                (* list) = g_list_prepend ((* list), file);
 
2590
        }
 
2591
}
 
2592
 
 
2593
static GList *
 
2594
nautilus_list_view_get_selection (NautilusView *view)
 
2595
{
 
2596
        GList *list;
 
2597
 
 
2598
        list = NULL;
 
2599
 
 
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);
 
2602
 
 
2603
        return g_list_reverse (list);
 
2604
}
 
2605
 
 
2606
static void
 
2607
nautilus_list_view_get_selection_for_file_transfer_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
 
2608
{
 
2609
        NautilusFile *file;
 
2610
        struct SelectionForeachData *selection_data;
 
2611
        GtkTreeIter parent, child;
 
2612
 
 
2613
        selection_data = data;
 
2614
 
 
2615
        gtk_tree_model_get (model, iter,
 
2616
                            NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
 
2617
                            -1);
 
2618
 
 
2619
        if (file != NULL) {
 
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
 
2623
                 */
 
2624
                child = *iter;
 
2625
                while (gtk_tree_model_iter_parent (model, &parent, &child)) {
 
2626
                        if (gtk_tree_selection_iter_is_selected (selection_data->selection,
 
2627
                                                                 &parent)) {
 
2628
                                return;
 
2629
                        }
 
2630
                        child = parent;
 
2631
                }
 
2632
                
 
2633
                nautilus_file_ref (file);
 
2634
                selection_data->list = g_list_prepend (selection_data->list, file);
 
2635
        }
 
2636
}
 
2637
 
 
2638
 
 
2639
static GList *
 
2640
nautilus_list_view_get_selection_for_file_transfer (NautilusView *view)
 
2641
{
 
2642
        struct SelectionForeachData selection_data;
 
2643
 
 
2644
        selection_data.list = NULL;
 
2645
        selection_data.selection = gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view);
 
2646
 
 
2647
        gtk_tree_selection_selected_foreach (selection_data.selection,
 
2648
                                             nautilus_list_view_get_selection_for_file_transfer_foreach_func, &selection_data);
 
2649
 
 
2650
        return g_list_reverse (selection_data.list);
 
2651
}
 
2652
 
 
2653
static gboolean
 
2654
nautilus_list_view_is_empty (NautilusView *view)
 
2655
{
 
2656
        return nautilus_list_model_is_empty (NAUTILUS_LIST_VIEW (view)->details->model);
 
2657
}
 
2658
 
 
2659
static void
 
2660
nautilus_list_view_end_file_changes (NautilusView *view)
 
2661
{
 
2662
        NautilusListView *list_view;
 
2663
 
 
2664
        list_view = NAUTILUS_LIST_VIEW (view);
 
2665
 
 
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,
 
2669
                                          NULL, FALSE);
 
2670
                gtk_tree_path_free (list_view->details->new_selection_path);
 
2671
                list_view->details->new_selection_path = NULL;
 
2672
        }
 
2673
}
 
2674
 
 
2675
static void
 
2676
nautilus_list_view_remove_file (NautilusView *view, NautilusFile *file, NautilusDirectory *directory)
 
2677
{
 
2678
        GtkTreePath *path;
 
2679
        GtkTreePath *file_path;
 
2680
        GtkTreeIter iter;
 
2681
        GtkTreeIter temp_iter;
 
2682
        GtkTreeRowReference* row_reference;
 
2683
        NautilusListView *list_view;
 
2684
        GtkTreeModel* tree_model; 
 
2685
        GtkTreeSelection *selection;
 
2686
 
 
2687
        path = NULL;
 
2688
        row_reference = NULL;
 
2689
        list_view = NAUTILUS_LIST_VIEW (view);
 
2690
        tree_model = GTK_TREE_MODEL(list_view->details->model);
 
2691
        
 
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);
 
2695
 
 
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.
 
2700
                         */
 
2701
                        temp_iter = iter;
 
2702
 
 
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);
 
2706
                        } else {
 
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);
 
2710
                                }
 
2711
                        }
 
2712
                        gtk_tree_path_free (path);
 
2713
                }
 
2714
       
 
2715
                gtk_tree_path_free (file_path);
 
2716
                
 
2717
                nautilus_list_model_remove_file (list_view->details->model, file, directory);
 
2718
 
 
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);
 
2722
                        }
 
2723
                        list_view->details->new_selection_path = gtk_tree_row_reference_get_path (row_reference);
 
2724
                }
 
2725
          
 
2726
                if (row_reference) {
 
2727
                        gtk_tree_row_reference_free (row_reference);
 
2728
                }
 
2729
        }   
 
2730
        
 
2731
        
 
2732
}
 
2733
 
 
2734
static void
 
2735
nautilus_list_view_set_selection (NautilusView *view, GList *selection)
 
2736
{
 
2737
        NautilusListView *list_view;
 
2738
        GtkTreeSelection *tree_selection;
 
2739
        GList *node;
 
2740
        GList *iters, *l;
 
2741
        NautilusFile *file;
 
2742
        GtkTreePath *path = NULL;
 
2743
        
 
2744
        list_view = NAUTILUS_LIST_VIEW (view);
 
2745
        tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view);
 
2746
 
 
2747
        g_signal_handlers_block_by_func (tree_selection, list_selection_changed_callback, view);
 
2748
 
 
2749
        gtk_tree_selection_unselect_all (tree_selection);
 
2750
        for (node = selection; node != NULL; node = node->next) {
 
2751
                file = node->data;
 
2752
                iters = nautilus_list_model_get_all_iters_for_file (list_view->details->model, file);
 
2753
 
 
2754
                for (l = iters; l != NULL; l = l->next) {
 
2755
                        gtk_tree_selection_select_iter (tree_selection,
 
2756
                                                        (GtkTreeIter *)l->data);
 
2757
                        if (!path)
 
2758
                                path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), (GtkTreeIter *)l->data);
 
2759
                }
 
2760
                g_list_free_full (iters, g_free);
 
2761
        }
 
2762
        if (path) {
 
2763
                gtk_tree_view_set_cursor_on_cell (list_view->details->tree_view,
 
2764
                          path,
 
2765
                          list_view->details->file_name_column,
 
2766
                        GTK_CELL_RENDERER (list_view->details->file_name_cell),
 
2767
                        TRUE);
 
2768
                gtk_tree_path_free (path);
 
2769
        }
 
2770
        g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
 
2771
        nautilus_view_notify_selection_changed (view);
 
2772
}
 
2773
 
 
2774
static void
 
2775
nautilus_list_view_invert_selection (NautilusView *view)
 
2776
{
 
2777
        NautilusListView *list_view;
 
2778
        GtkTreeSelection *tree_selection;
 
2779
        GList *node;
 
2780
        GList *iters, *l;
 
2781
        NautilusFile *file;
 
2782
        GList *selection = NULL;
 
2783
        
 
2784
        list_view = NAUTILUS_LIST_VIEW (view);
 
2785
        tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view);
 
2786
 
 
2787
        g_signal_handlers_block_by_func (tree_selection, list_selection_changed_callback, view);
 
2788
        
 
2789
        gtk_tree_selection_selected_foreach (tree_selection,
 
2790
                                             nautilus_list_view_get_selection_foreach_func, &selection);
 
2791
 
 
2792
        gtk_tree_selection_select_all (tree_selection);
 
2793
        
 
2794
        for (node = selection; node != NULL; node = node->next) {
 
2795
                file = node->data;
 
2796
                iters = nautilus_list_model_get_all_iters_for_file (list_view->details->model, file);
 
2797
 
 
2798
                for (l = iters; l != NULL; l = l->next) {
 
2799
                        gtk_tree_selection_unselect_iter (tree_selection,
 
2800
                                                          (GtkTreeIter *)l->data);
 
2801
                }
 
2802
                g_list_free_full (iters, g_free);
 
2803
        }
 
2804
 
 
2805
        g_list_free (selection);
 
2806
 
 
2807
        g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
 
2808
        nautilus_view_notify_selection_changed (view);
 
2809
}
 
2810
 
 
2811
static void
 
2812
nautilus_list_view_select_all (NautilusView *view)
 
2813
{
 
2814
        gtk_tree_selection_select_all (gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view));
 
2815
}
 
2816
 
 
2817
static void
 
2818
nautilus_list_view_select_first (NautilusView *view)
 
2819
{
 
2820
        GtkTreeSelection *selection;
 
2821
        GtkTreeIter iter;
 
2822
 
 
2823
        if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (NAUTILUS_LIST_VIEW (view)->details->model), &iter)) {
 
2824
                return;
 
2825
        }
 
2826
        selection = gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view);
 
2827
        gtk_tree_selection_select_iter (selection, &iter);
 
2828
}
 
2829
 
 
2830
static void
 
2831
column_editor_response_callback (GtkWidget *dialog, 
 
2832
                                 int response_id,
 
2833
                                 gpointer user_data)
 
2834
{
 
2835
        gtk_widget_destroy (GTK_WIDGET (dialog));
 
2836
}
 
2837
 
 
2838
static void
 
2839
column_chooser_changed_callback (NautilusColumnChooser *chooser,
 
2840
                                 NautilusListView *view)
 
2841
{
 
2842
        NautilusFile *file;
 
2843
        char **visible_columns;
 
2844
        char **column_order;
 
2845
        GList *list;
 
2846
        int i;
 
2847
 
 
2848
        file = nautilus_view_get_directory_as_file (NAUTILUS_VIEW (view));
 
2849
 
 
2850
        nautilus_column_chooser_get_settings (chooser,
 
2851
                                              &visible_columns,
 
2852
                                              &column_order);
 
2853
 
 
2854
        list = NULL;
 
2855
        for (i = 0; visible_columns[i] != NULL; ++i) {
 
2856
                list = g_list_prepend (list, visible_columns[i]);
 
2857
        }
 
2858
        list = g_list_reverse (list);
 
2859
        nautilus_file_set_metadata_list (file,
 
2860
                                         NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS,
 
2861
                                         list);
 
2862
        g_list_free (list);
 
2863
 
 
2864
        list = NULL;
 
2865
        for (i = 0; column_order[i] != NULL; ++i) {
 
2866
                list = g_list_prepend (list, column_order[i]);
 
2867
        }
 
2868
        list = g_list_reverse (list);
 
2869
        nautilus_file_set_metadata_list (file,
 
2870
                                         NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER,
 
2871
                                         list);
 
2872
        g_list_free (list);
 
2873
 
 
2874
        apply_columns_settings (view, column_order, visible_columns);
 
2875
 
 
2876
        g_strfreev (visible_columns);
 
2877
        g_strfreev (column_order);
 
2878
}
 
2879
 
 
2880
static void
 
2881
column_chooser_set_from_arrays (NautilusColumnChooser *chooser,
 
2882
                                NautilusListView *view,
 
2883
                                char **visible_columns,
 
2884
                                char **column_order)
 
2885
{
 
2886
        g_signal_handlers_block_by_func 
 
2887
                (chooser, G_CALLBACK (column_chooser_changed_callback), view);
 
2888
 
 
2889
        nautilus_column_chooser_set_settings (chooser,
 
2890
                                              visible_columns, 
 
2891
                                              column_order);
 
2892
 
 
2893
        g_signal_handlers_unblock_by_func 
 
2894
                (chooser, G_CALLBACK (column_chooser_changed_callback), view);
 
2895
}
 
2896
 
 
2897
static void
 
2898
column_chooser_set_from_settings (NautilusColumnChooser *chooser,
 
2899
                                  NautilusListView *view)
 
2900
{
 
2901
        char **visible_columns;
 
2902
        char **column_order;
 
2903
 
 
2904
        visible_columns = get_visible_columns (view);
 
2905
        column_order = get_column_order (view);
 
2906
 
 
2907
        column_chooser_set_from_arrays (chooser, view,
 
2908
                                        visible_columns, column_order);
 
2909
 
 
2910
        g_strfreev (visible_columns);
 
2911
        g_strfreev (column_order);
 
2912
}
 
2913
 
 
2914
static void
 
2915
column_chooser_use_default_callback (NautilusColumnChooser *chooser,
 
2916
                                     NautilusListView *view)
 
2917
{
 
2918
        NautilusFile *file;
 
2919
        char **default_columns;
 
2920
        char **default_order;
 
2921
 
 
2922
        file = nautilus_view_get_directory_as_file 
 
2923
                (NAUTILUS_VIEW (view));
 
2924
 
 
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);
 
2927
 
 
2928
        /* set view values ourselves, as new metadata could not have been
 
2929
         * updated yet.
 
2930
         */
 
2931
        default_columns = get_default_visible_columns (view);
 
2932
        default_order = get_default_column_order (view);
 
2933
 
 
2934
        apply_columns_settings (view, default_order, default_columns);
 
2935
        column_chooser_set_from_arrays (chooser, view,
 
2936
                                        default_columns, default_order);
 
2937
 
 
2938
        g_strfreev (default_columns);
 
2939
        g_strfreev (default_order);
 
2940
}
 
2941
 
 
2942
static GtkWidget *
 
2943
create_column_editor (NautilusListView *view)
 
2944
{
 
2945
        GtkWidget *window;
 
2946
        GtkWidget *label;
 
2947
        GtkWidget *box;
 
2948
        GtkWidget *column_chooser;
 
2949
        GtkWidget *alignment;
 
2950
        NautilusFile *file;
 
2951
        char *str;
 
2952
        char *name;
 
2953
        const char *label_text;
 
2954
        
 
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);
 
2958
        g_free (name);
 
2959
 
 
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,
 
2964
                                              NULL);
 
2965
        g_free (str);
 
2966
        g_signal_connect (window, "response", 
 
2967
                          G_CALLBACK (column_editor_response_callback), NULL);
 
2968
        
 
2969
        gtk_window_set_default_size (GTK_WINDOW (window), 300, 400);
 
2970
 
 
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,
 
2975
                            TRUE, TRUE, 0);
 
2976
 
 
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);
 
2985
 
 
2986
        g_free (str);
 
2987
 
 
2988
        alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
 
2989
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
 
2990
                                   0, 0, 12, 0);
 
2991
        gtk_widget_show (alignment);
 
2992
        gtk_box_pack_start (GTK_BOX (box), alignment, TRUE, TRUE, 0);
 
2993
 
 
2994
        column_chooser = nautilus_column_chooser_new (file);
 
2995
        gtk_widget_show (column_chooser);
 
2996
        gtk_container_add (GTK_CONTAINER (alignment), column_chooser);
 
2997
 
 
2998
        g_signal_connect (column_chooser, "changed",
 
2999
                          G_CALLBACK (column_chooser_changed_callback),
 
3000
                          view);
 
3001
        g_signal_connect (column_chooser, "use-default",
 
3002
                          G_CALLBACK (column_chooser_use_default_callback),
 
3003
                          view);
 
3004
 
 
3005
        column_chooser_set_from_settings 
 
3006
                (NAUTILUS_COLUMN_CHOOSER (column_chooser), view);
 
3007
 
 
3008
        return window;
 
3009
}
 
3010
 
 
3011
static void
 
3012
action_visible_columns_callback (GtkAction *action,
 
3013
                                 gpointer callback_data)
 
3014
{
 
3015
        NautilusListView *list_view;
 
3016
        
 
3017
        list_view = NAUTILUS_LIST_VIEW (callback_data);
 
3018
 
 
3019
        if (list_view->details->column_editor) {
 
3020
                gtk_window_present (GTK_WINDOW (list_view->details->column_editor));
 
3021
        } else {
 
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);
 
3025
                
 
3026
                gtk_widget_show (list_view->details->column_editor);
 
3027
        }
 
3028
}
 
3029
 
 
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) },
 
3035
};
 
3036
 
 
3037
static void
 
3038
nautilus_list_view_merge_menus (NautilusView *view)
 
3039
{
 
3040
        NautilusListView *list_view;
 
3041
        GtkUIManager *ui_manager;
 
3042
        GtkActionGroup *action_group;
 
3043
 
 
3044
        list_view = NAUTILUS_LIST_VIEW (view);
 
3045
 
 
3046
        NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->merge_menus (view);
 
3047
 
 
3048
        ui_manager = nautilus_view_get_ui_manager (view);
 
3049
 
 
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),
 
3055
                                      list_view);
 
3056
 
 
3057
        gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
 
3058
        g_object_unref (action_group); /* owned by ui manager */
 
3059
 
 
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);
 
3062
 
 
3063
        list_view->details->menus_ready = TRUE;
 
3064
}
 
3065
 
 
3066
static void
 
3067
nautilus_list_view_unmerge_menus (NautilusView *view)
 
3068
{
 
3069
        NautilusListView *list_view;
 
3070
        GtkUIManager *ui_manager;
 
3071
 
 
3072
        list_view = NAUTILUS_LIST_VIEW (view);
 
3073
 
 
3074
        NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->unmerge_menus (view);
 
3075
 
 
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);
 
3081
        }
 
3082
}
 
3083
 
 
3084
static void
 
3085
nautilus_list_view_update_menus (NautilusView *view)
 
3086
{
 
3087
        NautilusListView *list_view;
 
3088
 
 
3089
        list_view = NAUTILUS_LIST_VIEW (view);
 
3090
 
 
3091
        /* don't update if the menus aren't ready */
 
3092
        if (!list_view->details->menus_ready) {
 
3093
                return;
 
3094
        }
 
3095
 
 
3096
        NAUTILUS_VIEW_CLASS (nautilus_list_view_parent_class)->update_menus (view);
 
3097
}
 
3098
 
 
3099
/* Reset sort criteria and zoom level to match defaults */
 
3100
static void
 
3101
nautilus_list_view_reset_to_defaults (NautilusView *view)
 
3102
{
 
3103
        NautilusFile *file;
 
3104
        const gchar *default_sort_order;
 
3105
        gboolean default_sort_reversed;
 
3106
        char **default_columns;
 
3107
        char **default_order;
 
3108
 
 
3109
        file = nautilus_view_get_directory_as_file (view);
 
3110
 
 
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);
 
3115
 
 
3116
        default_sort_order = get_default_sort_order (file, &default_sort_reversed);
 
3117
 
 
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);
 
3123
 
 
3124
        nautilus_list_view_set_zoom_level (NAUTILUS_LIST_VIEW (view), get_default_zoom_level (), FALSE);
 
3125
 
 
3126
        default_columns = get_default_visible_columns (NAUTILUS_LIST_VIEW (view));
 
3127
        default_order = get_default_column_order (NAUTILUS_LIST_VIEW (view));
 
3128
 
 
3129
        apply_columns_settings (NAUTILUS_LIST_VIEW (view), default_order, default_columns);
 
3130
 
 
3131
        g_strfreev (default_columns);
 
3132
        g_strfreev (default_order);
 
3133
}
 
3134
 
 
3135
static void
 
3136
nautilus_list_view_set_zoom_level (NautilusListView *view,
 
3137
                                   NautilusZoomLevel new_level,
 
3138
                                   gboolean always_emit)
 
3139
{
 
3140
        int column;
 
3141
 
 
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);
 
3145
 
 
3146
        if (view->details->zoom_level == new_level) {
 
3147
                if (always_emit) {
 
3148
                        g_signal_emit_by_name (NAUTILUS_VIEW(view), "zoom-level-changed");
 
3149
                }
 
3150
                return;
 
3151
        }
 
3152
 
 
3153
        view->details->zoom_level = new_level;
 
3154
        g_signal_emit_by_name (NAUTILUS_VIEW(view), "zoom-level-changed");
 
3155
 
 
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),
 
3160
                                             "surface", column,
 
3161
                                             NULL);
 
3162
 
 
3163
        nautilus_view_update_menus (NAUTILUS_VIEW (view));
 
3164
 
 
3165
        set_up_pixbuf_size (view);
 
3166
}
 
3167
 
 
3168
static void
 
3169
nautilus_list_view_bump_zoom_level (NautilusView *view, int zoom_increment)
 
3170
{
 
3171
        NautilusListView *list_view;
 
3172
        gint new_level;
 
3173
 
 
3174
        g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
 
3175
 
 
3176
        list_view = NAUTILUS_LIST_VIEW (view);
 
3177
        new_level = list_view->details->zoom_level + zoom_increment;
 
3178
 
 
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);
 
3182
        }
 
3183
}
 
3184
 
 
3185
static NautilusZoomLevel
 
3186
nautilus_list_view_get_zoom_level (NautilusView *view)
 
3187
{
 
3188
        NautilusListView *list_view;
 
3189
 
 
3190
        g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), NAUTILUS_ZOOM_LEVEL_STANDARD);
 
3191
 
 
3192
        list_view = NAUTILUS_LIST_VIEW (view);
 
3193
 
 
3194
        return list_view->details->zoom_level;
 
3195
}
 
3196
 
 
3197
static void
 
3198
nautilus_list_view_zoom_to_level (NautilusView *view,
 
3199
                                  NautilusZoomLevel zoom_level)
 
3200
{
 
3201
        NautilusListView *list_view;
 
3202
 
 
3203
        g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
 
3204
 
 
3205
        list_view = NAUTILUS_LIST_VIEW (view);
 
3206
 
 
3207
        nautilus_list_view_set_zoom_level (list_view, zoom_level, FALSE);
 
3208
}
 
3209
 
 
3210
static void
 
3211
nautilus_list_view_restore_default_zoom_level (NautilusView *view)
 
3212
{
 
3213
        NautilusListView *list_view;
 
3214
 
 
3215
        g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
 
3216
 
 
3217
        list_view = NAUTILUS_LIST_VIEW (view);
 
3218
 
 
3219
        nautilus_list_view_set_zoom_level (list_view, get_default_zoom_level (), FALSE);
 
3220
}
 
3221
 
 
3222
static gboolean 
 
3223
nautilus_list_view_can_zoom_in (NautilusView *view) 
 
3224
{
 
3225
        g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), FALSE);
 
3226
 
 
3227
        return NAUTILUS_LIST_VIEW (view)->details->zoom_level   < NAUTILUS_ZOOM_LEVEL_LARGEST;
 
3228
}
 
3229
 
 
3230
static gboolean 
 
3231
nautilus_list_view_can_zoom_out (NautilusView *view) 
 
3232
{
 
3233
        g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), FALSE);
 
3234
 
 
3235
        return NAUTILUS_LIST_VIEW (view)->details->zoom_level > NAUTILUS_ZOOM_LEVEL_SMALLEST;
 
3236
}
 
3237
 
 
3238
static void
 
3239
nautilus_list_view_start_renaming_file (NautilusView *view,
 
3240
                                        NautilusFile *file,
 
3241
                                        gboolean select_all)
 
3242
{
 
3243
        NautilusListView *list_view;
 
3244
        GtkTreeIter iter;
 
3245
        GtkTreePath *path;
 
3246
        
 
3247
        list_view = NAUTILUS_LIST_VIEW (view);
 
3248
        
 
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),
 
3252
                                            0,
 
3253
                                            -1);
 
3254
                return;
 
3255
        }
 
3256
 
 
3257
        if (!nautilus_list_model_get_first_iter_for_file (list_view->details->model, file, &iter)) {
 
3258
                return;
 
3259
        }
 
3260
 
 
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);
 
3263
 
 
3264
        /* Freeze updates to the view to prevent losing rename focus when the tree view updates */
 
3265
        nautilus_view_freeze_updates (NAUTILUS_VIEW (view));
 
3266
 
 
3267
        path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), &iter);
 
3268
 
 
3269
        /* Make filename-cells editable. */
 
3270
        g_object_set (G_OBJECT (list_view->details->file_name_cell),
 
3271
                      "editable", TRUE,
 
3272
                      NULL);
 
3273
 
 
3274
        gtk_tree_view_scroll_to_cell (list_view->details->tree_view,
 
3275
                                      NULL,
 
3276
                                      list_view->details->file_name_column,
 
3277
                                      TRUE, 0.0, 0.0);
 
3278
        gtk_tree_view_set_cursor_on_cell (list_view->details->tree_view,
 
3279
                                          path,
 
3280
                                          list_view->details->file_name_column,
 
3281
                                          GTK_CELL_RENDERER (list_view->details->file_name_cell),
 
3282
                                          TRUE);
 
3283
 
 
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;
 
3288
 
 
3289
                if (!select_all) {
 
3290
                        eel_filename_get_rename_region (list_view->details->original_name,
 
3291
                                                        &start_offset, &end_offset);
 
3292
                }
 
3293
 
 
3294
                gtk_editable_select_region (GTK_EDITABLE (list_view->details->editable_widget),
 
3295
                                            start_offset, end_offset);
 
3296
        }
 
3297
 
 
3298
        gtk_tree_path_free (path);
 
3299
}
 
3300
 
 
3301
static void
 
3302
nautilus_list_view_click_policy_changed (NautilusView *directory_view)
 
3303
{
 
3304
        GdkWindow *win;
 
3305
        GdkDisplay *display;
 
3306
        NautilusListView *view;
 
3307
        GtkTreeIter iter;
 
3308
        GtkTreeView *tree;
 
3309
 
 
3310
        view = NAUTILUS_LIST_VIEW (directory_view);
 
3311
 
 
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);
 
3319
                        }
 
3320
 
 
3321
                        gtk_tree_path_free (view->details->hover_path);
 
3322
                        view->details->hover_path = NULL;
 
3323
                }
 
3324
 
 
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);
 
3329
                        
 
3330
                        display = gtk_widget_get_display (GTK_WIDGET (view));
 
3331
                        if (display != NULL) {
 
3332
                                gdk_display_flush (display);
 
3333
                        }
 
3334
                }
 
3335
 
 
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);
 
3340
                }
 
3341
        }
 
3342
}
 
3343
 
 
3344
static void
 
3345
default_sort_order_changed_callback (gpointer callback_data)
 
3346
{
 
3347
        NautilusListView *list_view;
 
3348
 
 
3349
        list_view = NAUTILUS_LIST_VIEW (callback_data);
 
3350
 
 
3351
        set_sort_order_from_metadata_and_preferences (list_view);
 
3352
}
 
3353
 
 
3354
static void
 
3355
default_visible_columns_changed_callback (gpointer callback_data)
 
3356
{
 
3357
        NautilusListView *list_view;
 
3358
        
 
3359
        list_view = NAUTILUS_LIST_VIEW (callback_data);
 
3360
 
 
3361
        set_columns_settings_from_metadata_and_preferences (list_view); 
 
3362
}
 
3363
 
 
3364
static void
 
3365
default_column_order_changed_callback (gpointer callback_data)
 
3366
{
 
3367
        NautilusListView *list_view;
 
3368
        
 
3369
        list_view = NAUTILUS_LIST_VIEW (callback_data);
 
3370
 
 
3371
        set_columns_settings_from_metadata_and_preferences (list_view);
 
3372
}
 
3373
 
 
3374
static void
 
3375
nautilus_list_view_sort_directories_first_changed (NautilusView *view)
 
3376
{
 
3377
        NautilusListView *list_view;
 
3378
 
 
3379
        list_view = NAUTILUS_LIST_VIEW (view);
 
3380
 
 
3381
        nautilus_list_model_set_should_sort_directories_first (list_view->details->model,
 
3382
                                                         nautilus_view_should_sort_directories_first (view));
 
3383
}
 
3384
 
 
3385
static int
 
3386
nautilus_list_view_compare_files (NautilusView *view, NautilusFile *file1, NautilusFile *file2)
 
3387
{
 
3388
        NautilusListView *list_view;
 
3389
 
 
3390
        list_view = NAUTILUS_LIST_VIEW (view);
 
3391
        return nautilus_list_model_compare_func (list_view->details->model, file1, file2);
 
3392
}
 
3393
 
 
3394
static gboolean
 
3395
nautilus_list_view_using_manual_layout (NautilusView *view)
 
3396
{
 
3397
        g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), FALSE);
 
3398
 
 
3399
        return FALSE;
 
3400
}
 
3401
 
 
3402
static void
 
3403
nautilus_list_view_dispose (GObject *object)
 
3404
{
 
3405
        NautilusListView *list_view;
 
3406
 
 
3407
        list_view = NAUTILUS_LIST_VIEW (object);
 
3408
 
 
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;
 
3413
        }
 
3414
 
 
3415
        if (list_view->details->drag_dest) {
 
3416
                g_object_unref (list_view->details->drag_dest);
 
3417
                list_view->details->drag_dest = NULL;
 
3418
        }
 
3419
 
 
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;
 
3423
        }
 
3424
 
 
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;
 
3429
        }
 
3430
 
 
3431
        G_OBJECT_CLASS (nautilus_list_view_parent_class)->dispose (object);
 
3432
}
 
3433
 
 
3434
static void
 
3435
nautilus_list_view_finalize (GObject *object)
 
3436
{
 
3437
        NautilusListView *list_view;
 
3438
 
 
3439
        list_view = NAUTILUS_LIST_VIEW (object);
 
3440
 
 
3441
        g_free (list_view->details->original_name);
 
3442
        list_view->details->original_name = NULL;
 
3443
        
 
3444
        if (list_view->details->double_click_path[0]) {
 
3445
                gtk_tree_path_free (list_view->details->double_click_path[0]);
 
3446
        }       
 
3447
        if (list_view->details->double_click_path[1]) {
 
3448
                gtk_tree_path_free (list_view->details->double_click_path[1]);
 
3449
        }
 
3450
        if (list_view->details->new_selection_path) {
 
3451
                gtk_tree_path_free (list_view->details->new_selection_path);
 
3452
        }
 
3453
        
 
3454
        g_list_free (list_view->details->cells);
 
3455
        g_hash_table_destroy (list_view->details->columns);
 
3456
 
 
3457
        if (list_view->details->hover_path != NULL) {
 
3458
                gtk_tree_path_free (list_view->details->hover_path);
 
3459
        }
 
3460
 
 
3461
        if (list_view->details->column_editor != NULL) {
 
3462
                gtk_widget_destroy (list_view->details->column_editor);
 
3463
        }
 
3464
 
 
3465
        g_free (list_view->details);
 
3466
 
 
3467
        g_signal_handlers_disconnect_by_func (nautilus_preferences,
 
3468
                                              default_sort_order_changed_callback,
 
3469
                                              list_view);
 
3470
        g_signal_handlers_disconnect_by_func (nautilus_list_view_preferences,
 
3471
                                              default_visible_columns_changed_callback,
 
3472
                                              list_view);
 
3473
        g_signal_handlers_disconnect_by_func (nautilus_list_view_preferences,
 
3474
                                              default_column_order_changed_callback,
 
3475
                                              list_view);
 
3476
 
 
3477
        G_OBJECT_CLASS (nautilus_list_view_parent_class)->finalize (object);
 
3478
}
 
3479
 
 
3480
static char *
 
3481
nautilus_list_view_get_first_visible_file (NautilusView *view)
 
3482
{
 
3483
        NautilusFile *file;
 
3484
        GtkTreePath *path;
 
3485
        GtkTreeIter iter;
 
3486
        NautilusListView *list_view;
 
3487
 
 
3488
        list_view = NAUTILUS_LIST_VIEW (view);
 
3489
 
 
3490
        if (gtk_tree_view_get_path_at_pos (list_view->details->tree_view,
 
3491
                                           0, 0,
 
3492
                                           &path, NULL, NULL, NULL)) {
 
3493
                gtk_tree_model_get_iter (GTK_TREE_MODEL (list_view->details->model),
 
3494
                                         &iter, path);
 
3495
 
 
3496
                gtk_tree_path_free (path);
 
3497
        
 
3498
                gtk_tree_model_get (GTK_TREE_MODEL (list_view->details->model),
 
3499
                                    &iter,
 
3500
                                    NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
 
3501
                                    -1);
 
3502
                if (file) {
 
3503
                        char *uri;
 
3504
                        
 
3505
                        uri = nautilus_file_get_uri (file);
 
3506
                        
 
3507
                        nautilus_file_unref (file);
 
3508
                        
 
3509
                        return uri;
 
3510
                }
 
3511
        }
 
3512
        
 
3513
        return NULL;
 
3514
}
 
3515
 
 
3516
static void
 
3517
nautilus_list_view_scroll_to_file (NautilusListView *view,
 
3518
                                   NautilusFile *file)
 
3519
{
 
3520
        GtkTreePath *path;
 
3521
        GtkTreeIter iter;
 
3522
        
 
3523
        if (!nautilus_list_model_get_first_iter_for_file (view->details->model, file, &iter)) {
 
3524
                return;
 
3525
        }
 
3526
                
 
3527
        path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->details->model), &iter);
 
3528
 
 
3529
        gtk_tree_view_scroll_to_cell (view->details->tree_view,
 
3530
                                      path, NULL,
 
3531
                                      TRUE, 0.0, 0.0);
 
3532
        
 
3533
        gtk_tree_path_free (path);
 
3534
}
 
3535
 
 
3536
static void
 
3537
list_view_scroll_to_file (NautilusView *view,
 
3538
                          const char *uri)
 
3539
{
 
3540
        NautilusFile *file;
 
3541
 
 
3542
        if (uri != NULL) {
 
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);
 
3546
                if (file != NULL) {
 
3547
                        nautilus_list_view_scroll_to_file (NAUTILUS_LIST_VIEW (view), file);
 
3548
                        nautilus_file_unref (file);
 
3549
                }
 
3550
        }
 
3551
}
 
3552
 
 
3553
static void
 
3554
list_view_notify_clipboard_info (NautilusClipboardMonitor *monitor,
 
3555
                                 NautilusClipboardInfo *info,
 
3556
                                 NautilusListView *view)
 
3557
{
 
3558
        /* this could be called as a result of _end_loading() being
 
3559
         * called after _dispose(), where the model is cleared.
 
3560
         */
 
3561
        if (view->details->model == NULL) {
 
3562
                return;
 
3563
        }
 
3564
 
 
3565
        if (info != NULL && info->cut) {
 
3566
                nautilus_list_model_set_highlight_for_files (view->details->model, info->files);
 
3567
        } else {
 
3568
                nautilus_list_model_set_highlight_for_files (view->details->model, NULL);
 
3569
        }
 
3570
}
 
3571
 
 
3572
static void
 
3573
nautilus_list_view_end_loading (NautilusView *view,
 
3574
                                gboolean all_files_seen)
 
3575
{
 
3576
        NautilusClipboardMonitor *monitor;
 
3577
        NautilusClipboardInfo *info;
 
3578
 
 
3579
        monitor = nautilus_clipboard_monitor_get ();
 
3580
        info = nautilus_clipboard_monitor_get_clipboard_info (monitor);
 
3581
 
 
3582
        list_view_notify_clipboard_info (monitor, info, NAUTILUS_LIST_VIEW (view));
 
3583
}
 
3584
 
 
3585
static const char *
 
3586
nautilus_list_view_get_id (NautilusView *view)
 
3587
{
 
3588
        return NAUTILUS_LIST_VIEW_ID;
 
3589
}
 
3590
 
 
3591
static void
 
3592
nautilus_list_view_class_init (NautilusListViewClass *class)
 
3593
{
 
3594
        NautilusViewClass *nautilus_view_class;
 
3595
 
 
3596
        nautilus_view_class = NAUTILUS_VIEW_CLASS (class);
 
3597
 
 
3598
        G_OBJECT_CLASS (class)->dispose = nautilus_list_view_dispose;
 
3599
        G_OBJECT_CLASS (class)->finalize = nautilus_list_view_finalize;
 
3600
 
 
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;
 
3635
}
 
3636
 
 
3637
static void
 
3638
nautilus_list_view_init (NautilusListView *list_view)
 
3639
{
 
3640
        list_view->details = g_new0 (NautilusListViewDetails, 1);
 
3641
 
 
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 ();
 
3644
 
 
3645
        create_and_set_up_tree_view (list_view);
 
3646
 
 
3647
        g_signal_connect_swapped (nautilus_preferences,
 
3648
                                  "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER,
 
3649
                                  G_CALLBACK (default_sort_order_changed_callback),
 
3650
                                  list_view);
 
3651
        g_signal_connect_swapped (nautilus_preferences,
 
3652
                                  "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER,
 
3653
                                  G_CALLBACK (default_sort_order_changed_callback),
 
3654
                                  list_view);
 
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),
 
3658
                                  list_view);
 
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),
 
3662
                                  list_view);
 
3663
 
 
3664
        nautilus_list_view_click_policy_changed (NAUTILUS_VIEW (list_view));
 
3665
 
 
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);
 
3668
 
 
3669
        list_view->details->hover_path = NULL;
 
3670
        list_view->details->clipboard_handler_id =
 
3671
                g_signal_connect (nautilus_clipboard_monitor_get (),
 
3672
                                  "clipboard-info",
 
3673
                                  G_CALLBACK (list_view_notify_clipboard_info), list_view);
 
3674
}
 
3675
 
 
3676
NautilusView *
 
3677
nautilus_list_view_new (NautilusWindowSlot *slot)
 
3678
{
 
3679
        return g_object_new (NAUTILUS_TYPE_LIST_VIEW,
 
3680
                             "window-slot", slot,
 
3681
                             NULL);
 
3682
}
 
3683
 
 
3684
GtkTreeView*
 
3685
nautilus_list_view_get_tree_view (NautilusListView *list_view)
 
3686
{
 
3687
        return list_view->details->tree_view;
 
3688
}