~elementary-apps/pantheon-files/trunk

« back to all changes in this revision

Viewing changes to src/fm-list-model.c

  • Committer: am.monkeyd at gmail
  • Date: 2010-11-08 13:17:02 UTC
  • Revision ID: am.monkeyd@gmail.com-20101108131702-rqeywh4r5pyx2ycz
let's roll

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-model.h - a GtkTreeModel for file lists. 
 
4
 
 
5
   Copyright (C) 2001, 2002 Anders Carlsson
 
6
   Copyright (C) 2003, Soeren Sandmann
 
7
   Copyright (C) 2004, Novell, Inc.
 
8
 
 
9
   The Gnome Library is free software; you can redistribute it and/or
 
10
   modify it under the terms of the GNU Library General Public License as
 
11
   published by the Free Software Foundation; either version 2 of the
 
12
   License, or (at your option) any later version.
 
13
 
 
14
   The Gnome Library is distributed in the hope that it will be useful,
 
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
   Library General Public License for more details.
 
18
 
 
19
   You should have received a copy of the GNU Library General Public
 
20
   License along with the Gnome Library; see the file COPYING.LIB.  If not,
 
21
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
22
   Boston, MA 02111-1307, USA.
 
23
 
 
24
   Authors: Anders Carlsson <andersca@gnu.org>, Soeren Sandmann (sandmann@daimi.au.dk), Dave Camp <dave@ximian.com>
 
25
*/
 
26
 
 
27
#include <config.h>
 
28
//#include <libegg/eggtreemultidnd.h>
 
29
 
 
30
#include <string.h>
 
31
/*#include <eel/eel-gtk-macros.h>
 
32
#include <eel/eel-glib-extensions.h>
 
33
#include <eel/eel-gdk-pixbuf-extensions.h>*/
 
34
#include <gtk/gtk.h>
 
35
#include <glib/gi18n.h>
 
36
//#include <libnautilus-private/nautilus-dnd.h>
 
37
#include <glib.h>
 
38
#include "fm-list-model.h"
 
39
 
 
40
enum {
 
41
        SUBDIRECTORY_UNLOADED,
 
42
        LAST_SIGNAL
 
43
};
 
44
 
 
45
enum {
 
46
        PROP_0,
 
47
        PROP_HAS_CHILD,
 
48
};
 
49
 
 
50
static GQuark attribute_name_q,
 
51
        attribute_modification_date_q,
 
52
        attribute_date_modified_q;
 
53
 
 
54
static guint list_model_signals[LAST_SIGNAL] = { 0 };
 
55
 
 
56
static void     fm_list_model_get_property (GObject    *object,
 
57
                                            guint       prop_id,
 
58
                                            GValue     *value,
 
59
                                            GParamSpec *pspec);
 
60
static void     fm_list_model_set_property (GObject      *object,
 
61
                                            guint         prop_id,
 
62
                                            const GValue *value,
 
63
                                            GParamSpec   *pspec);
 
64
static int      fm_list_model_file_entry_compare_func (gconstpointer a,
 
65
                                                  gconstpointer b,
 
66
                                                  gpointer      user_data);
 
67
static void     fm_list_model_tree_model_init (GtkTreeModelIface *iface);
 
68
static void     fm_list_model_sortable_init (GtkTreeSortableIface *iface);
 
69
//static void fm_list_model_multi_drag_source_init (EggTreeMultiDragSourceIface *iface);
 
70
 
 
71
struct FMListModelDetails {
 
72
        GSequence *files;
 
73
        GHashTable *directory_reverse_map; /* map from directory to GSequenceIter's */
 
74
        GHashTable *top_reverse_map;       /* map from files in top dir to GSequenceIter's */
 
75
 
 
76
        int stamp;
 
77
        gboolean        has_child;
 
78
 
 
79
        //GQuark sort_attribute;
 
80
        gint            sort_id;
 
81
        GtkSortType     order;
 
82
 
 
83
        gboolean sort_directories_first;
 
84
 
 
85
        /*GtkTreeView *drag_view;
 
86
        int drag_begin_x;
 
87
        int drag_begin_y;*/
 
88
 
 
89
        //GPtrArray *columns;
 
90
};
 
91
 
 
92
/*typedef struct {
 
93
        FMListModel *model;
 
94
        
 
95
        GList *path_list;
 
96
} DragDataGetInfo;*/
 
97
 
 
98
typedef struct FileEntry FileEntry;
 
99
 
 
100
struct FileEntry {
 
101
        GOFFile *file;
 
102
        GHashTable *reverse_map;        /* map from files to GSequenceIter's */
 
103
        GOFDirectoryAsync *subdirectory;
 
104
        FileEntry *parent;
 
105
        GSequence *files;
 
106
        GSequenceIter *ptr;
 
107
        guint loaded : 1;
 
108
};
 
109
 
 
110
void    fm_list_model_remove_file (FMListModel *model, GOFFile *file,
 
111
                                   GOFDirectoryAsync *directory);
 
112
 
 
113
G_DEFINE_TYPE_WITH_CODE (FMListModel, fm_list_model, G_TYPE_OBJECT,
 
114
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
 
115
                                                fm_list_model_tree_model_init)
 
116
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
 
117
                                                fm_list_model_sortable_init));
 
118
/*                       G_IMPLEMENT_INTERFACE (EGG_TYPE_TREE_MULTI_DRAG_SOURCE,
 
119
                                                fm_list_model_multi_drag_source_init));*/
 
120
 
 
121
/*static const GtkTargetEntry drag_types [] = {
 
122
        { NAUTILUS_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NAUTILUS_ICON_DND_GNOME_ICON_LIST },
 
123
        { NAUTILUS_ICON_DND_URI_LIST_TYPE, 0, NAUTILUS_ICON_DND_URI_LIST },
 
124
};*/
 
125
 
 
126
//static GtkTargetList *drag_target_list = NULL;
 
127
 
 
128
static void
 
129
file_entry_free (FileEntry *file_entry)
 
130
{
 
131
        gof_file_unref (file_entry->file);
 
132
        //gof_file_unref (file_entry->file);
 
133
        if (file_entry->reverse_map) {
 
134
                g_hash_table_destroy (file_entry->reverse_map);
 
135
                file_entry->reverse_map = NULL;
 
136
        }
 
137
        if (file_entry->subdirectory != NULL) {
 
138
                g_object_unref (file_entry->subdirectory);
 
139
                file_entry->subdirectory = NULL;
 
140
        }
 
141
        if (file_entry->files != NULL) {
 
142
                g_sequence_free (file_entry->files);
 
143
        }
 
144
        g_free (file_entry);
 
145
}
 
146
 
 
147
//amtest
 
148
static GtkTreeModelFlags
 
149
fm_list_model_get_flags (GtkTreeModel *tree_model)
 
150
{
 
151
        //return GTK_TREE_MODEL_ITERS_PERSIST;
 
152
        return (GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST);
 
153
}
 
154
 
 
155
static int
 
156
fm_list_model_get_n_columns (GtkTreeModel *tree_model)
 
157
{
 
158
        //return FM_LIST_MODEL_NUM_COLUMNS + FM_LIST_MODEL (tree_model)->details->columns->len;
 
159
        return FM_LIST_MODEL_NUM_COLUMNS;
 
160
}
 
161
 
 
162
static GType
 
163
fm_list_model_get_column_type (GtkTreeModel *tree_model, int index)
 
164
{
 
165
        switch (index) {
 
166
        case FM_LIST_MODEL_FILE_COLUMN:
 
167
                return GOF_TYPE_FILE;
 
168
        /*case FM_LIST_MODEL_SUBDIRECTORY_COLUMN:
 
169
                return NAUTILUS_TYPE_DIRECTORY;*/
 
170
        /*case FM_LIST_MODEL_SMALLEST_ICON_COLUMN:
 
171
        case FM_LIST_MODEL_SMALLER_ICON_COLUMN:
 
172
        case FM_LIST_MODEL_SMALL_ICON_COLUMN:
 
173
        case FM_LIST_MODEL_STANDARD_ICON_COLUMN:
 
174
        case FM_LIST_MODEL_LARGE_ICON_COLUMN:
 
175
        case FM_LIST_MODEL_LARGER_ICON_COLUMN:
 
176
        case FM_LIST_MODEL_LARGEST_ICON_COLUMN:
 
177
        case FM_LIST_MODEL_SMALLEST_EMBLEM_COLUMN:
 
178
        case FM_LIST_MODEL_SMALLER_EMBLEM_COLUMN:
 
179
        case FM_LIST_MODEL_SMALL_EMBLEM_COLUMN:
 
180
        case FM_LIST_MODEL_STANDARD_EMBLEM_COLUMN:
 
181
        case FM_LIST_MODEL_LARGE_EMBLEM_COLUMN:
 
182
        case FM_LIST_MODEL_LARGER_EMBLEM_COLUMN:
 
183
        case FM_LIST_MODEL_LARGEST_EMBLEM_COLUMN:
 
184
                return GDK_TYPE_PIXBUF;
 
185
        case FM_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN:
 
186
                return G_TYPE_BOOLEAN;*/
 
187
        case FM_LIST_MODEL_ICON:
 
188
                return GDK_TYPE_PIXBUF;
 
189
        default:
 
190
                if (index < FM_LIST_MODEL_NUM_COLUMNS) {
 
191
                        return G_TYPE_STRING;
 
192
                } else {
 
193
                        return G_TYPE_INVALID;
 
194
                }
 
195
        }
 
196
        /*default:
 
197
                if (index < FM_LIST_MODEL_NUM_COLUMNS + FM_LIST_MODEL (tree_model)->details->columns->len) {
 
198
                        return G_TYPE_STRING;
 
199
                } else {
 
200
                        return G_TYPE_INVALID;
 
201
                }
 
202
        }*/
 
203
}
 
204
 
 
205
static void
 
206
fm_list_model_ptr_to_iter (FMListModel *model, GSequenceIter *ptr, GtkTreeIter *iter)
 
207
{
 
208
        g_assert (!g_sequence_iter_is_end (ptr));
 
209
        if (iter != NULL) {
 
210
                iter->stamp = model->details->stamp;
 
211
                iter->user_data = ptr;
 
212
        }
 
213
}
 
214
 
 
215
static gboolean
 
216
fm_list_model_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
 
217
{
 
218
        FMListModel *model;
 
219
        GSequence *files;
 
220
        GSequenceIter *ptr;
 
221
        FileEntry *file_entry;
 
222
        int i, d;
 
223
        
 
224
        model = (FMListModel *)tree_model;
 
225
        ptr = NULL;
 
226
        
 
227
        files = model->details->files;
 
228
        for (d = 0; d < gtk_tree_path_get_depth (path); d++) {
 
229
                i = gtk_tree_path_get_indices (path)[d];
 
230
 
 
231
                if (files == NULL || i >= g_sequence_get_length (files)) {
 
232
                        return FALSE;
 
233
                }
 
234
 
 
235
                ptr = g_sequence_get_iter_at_pos (files, i);
 
236
                file_entry = g_sequence_get (ptr);
 
237
                files = file_entry->files;
 
238
        }
 
239
 
 
240
        fm_list_model_ptr_to_iter (model, ptr, iter);
 
241
        
 
242
        return TRUE;
 
243
}
 
244
 
 
245
static GtkTreePath *
 
246
fm_list_model_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter)
 
247
{
 
248
        GtkTreePath *path;
 
249
        FMListModel *model;
 
250
        GSequenceIter *ptr;
 
251
        FileEntry *file_entry;
 
252
 
 
253
 
 
254
        model = (FMListModel *)tree_model;
 
255
        
 
256
        g_return_val_if_fail (iter->stamp == model->details->stamp, NULL);
 
257
 
 
258
        if (g_sequence_iter_is_end (iter->user_data)) {
 
259
                /* FIXME is this right? */
 
260
                return NULL;
 
261
        }
 
262
        
 
263
        path = gtk_tree_path_new ();
 
264
        ptr = iter->user_data;
 
265
        while (ptr != NULL) {
 
266
                gtk_tree_path_prepend_index (path, g_sequence_iter_get_position (ptr));
 
267
                file_entry = g_sequence_get (ptr);
 
268
                if (file_entry->parent != NULL) {
 
269
                        ptr = file_entry->parent->ptr;
 
270
                } else {
 
271
                        ptr = NULL;
 
272
                }
 
273
        }
 
274
 
 
275
        return path;
 
276
}
 
277
 
 
278
static void
 
279
fm_list_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, int column, GValue *value)
 
280
{
 
281
        FMListModel *model;
 
282
        FileEntry *file_entry;
 
283
        GOFFile *file;
 
284
        //char *str;
 
285
        //GdkPixbuf *icon;
 
286
        //GdkPixbuf *pix;
 
287
        //int icon_size;
 
288
        //guint emblem_size;
 
289
        //NautilusZoomLevel zoom_level;
 
290
        //GList *emblem_pixbufs;
 
291
        //GOFFile *parent_file;
 
292
        //char *emblems_to_ignore[3];
 
293
        //int i;
 
294
        //GOFFileIconFlags flags;
 
295
        
 
296
        model = (FMListModel *)tree_model;
 
297
 
 
298
        g_return_if_fail (model->details->stamp == iter->stamp);
 
299
        g_return_if_fail (!g_sequence_iter_is_end (iter->user_data));
 
300
 
 
301
        file_entry = g_sequence_get (iter->user_data);
 
302
        file = file_entry->file;
 
303
        //amtest
 
304
        switch (column) {
 
305
        case FM_LIST_MODEL_FILE_COLUMN:
 
306
                g_value_init (value, GOF_TYPE_FILE);
 
307
                if (file != NULL)
 
308
                        g_value_set_object (value, file);
 
309
                break;
 
310
 
 
311
        case FM_LIST_MODEL_ICON:
 
312
                g_value_init (value, GDK_TYPE_PIXBUF);
 
313
                if (file != NULL)
 
314
                        g_value_set_object (value, file->pix);
 
315
                break;
 
316
                
 
317
        case FM_LIST_MODEL_FILENAME:
 
318
                g_value_init (value, G_TYPE_STRING);
 
319
                if (file != NULL)
 
320
                        g_value_set_string(value, file->name);
 
321
                break;
 
322
 
 
323
        case FM_LIST_MODEL_SIZE:
 
324
                g_value_init (value, G_TYPE_STRING);
 
325
                if (file != NULL)
 
326
                        g_value_set_string(value, file->format_size);
 
327
                break;
 
328
        
 
329
        case FM_LIST_MODEL_TYPE:
 
330
                g_value_init (value, G_TYPE_STRING);
 
331
                if (file != NULL)
 
332
                        g_value_set_string(value, file->ftype);
 
333
                break;
 
334
 
 
335
        case FM_LIST_MODEL_MODIFIED:
 
336
                g_value_init (value, G_TYPE_STRING);
 
337
                if (file != NULL)
 
338
                        g_value_set_string(value, gof_file_get_date_as_string (file->modified));
 
339
                break;
 
340
 
 
341
        }
 
342
 
 
343
#if 0
 
344
/*      case FM_LIST_MODEL_SUBDIRECTORY_COLUMN:
 
345
                g_value_init (value, NAUTILUS_TYPE_DIRECTORY);
 
346
 
 
347
                g_value_set_object (value, file_entry->subdirectory);
 
348
                break;*/
 
349
        case FM_LIST_MODEL_SMALLEST_ICON_COLUMN:
 
350
        case FM_LIST_MODEL_SMALLER_ICON_COLUMN:
 
351
        case FM_LIST_MODEL_SMALL_ICON_COLUMN:
 
352
        case FM_LIST_MODEL_STANDARD_ICON_COLUMN:
 
353
        case FM_LIST_MODEL_LARGE_ICON_COLUMN:
 
354
        case FM_LIST_MODEL_LARGER_ICON_COLUMN:
 
355
        case FM_LIST_MODEL_LARGEST_ICON_COLUMN:
 
356
                g_value_init (value, GDK_TYPE_PIXBUF);
 
357
 
 
358
                if (file != NULL) {
 
359
                        //zoom_level = fm_list_model_get_zoom_level_from_column_id (column);
 
360
                        //icon_size = nautilus_get_icon_size_for_zoom_level (zoom_level);
 
361
                        icon_size = 16;
 
362
 
 
363
                        /*flags = NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS |
 
364
                                NAUTILUS_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE |
 
365
                                NAUTILUS_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM;*/
 
366
                        /*if (model->details->drag_view != NULL) {
 
367
                                GtkTreePath *path_a, *path_b;
 
368
                                
 
369
                                gtk_tree_view_get_drag_dest_row (model->details->drag_view,
 
370
                                                                 &path_a,
 
371
                                                                 NULL);
 
372
                                if (path_a != NULL) {
 
373
                                        path_b = gtk_tree_model_get_path (tree_model, iter);
 
374
 
 
375
                                        if (gtk_tree_path_compare (path_a, path_b) == 0) {
 
376
                                                flags |= NAUTILUS_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT;
 
377
                                        }
 
378
                                                
 
379
                                        gtk_tree_path_free (path_a);
 
380
                                        gtk_tree_path_free (path_b);
 
381
                                }
 
382
                        }*/
 
383
 
 
384
                        //icon = nautilus_file_get_icon_pixbuf (file, icon_size, TRUE, flags);
 
385
                        icon = NULL;
 
386
  
 
387
                        g_value_set_object (value, icon);
 
388
                        g_object_unref (icon);
 
389
                }
 
390
                break;
 
391
        case FM_LIST_MODEL_SMALLEST_EMBLEM_COLUMN:
 
392
        case FM_LIST_MODEL_SMALLER_EMBLEM_COLUMN:
 
393
        case FM_LIST_MODEL_SMALL_EMBLEM_COLUMN:
 
394
        case FM_LIST_MODEL_STANDARD_EMBLEM_COLUMN:
 
395
        case FM_LIST_MODEL_LARGE_EMBLEM_COLUMN:
 
396
        case FM_LIST_MODEL_LARGER_EMBLEM_COLUMN:
 
397
        case FM_LIST_MODEL_LARGEST_EMBLEM_COLUMN:
 
398
                g_value_init (value, GDK_TYPE_PIXBUF);
 
399
/*
 
400
                if (file != NULL) {
 
401
                        parent_file = nautilus_file_get_parent (file);
 
402
                        i = 0;
 
403
                        emblems_to_ignore[i++] = NAUTILUS_FILE_EMBLEM_NAME_TRASH;
 
404
                        if (parent_file) {
 
405
                                if (!nautilus_file_can_write (parent_file)) {
 
406
                                        emblems_to_ignore[i++] = NAUTILUS_FILE_EMBLEM_NAME_CANT_WRITE;
 
407
                                }
 
408
                                nautilus_file_unref (parent_file);
 
409
                        }
 
410
                        emblems_to_ignore[i++] = NULL;
 
411
                        
 
412
                        zoom_level = fm_list_model_get_zoom_level_from_emblem_column_id (column);
 
413
                        icon_size = nautilus_get_icon_size_for_zoom_level (zoom_level);
 
414
                        emblem_size = nautilus_icon_get_emblem_size_for_icon_size (icon_size);
 
415
                        if (emblem_size != 0) {
 
416
                                emblem_pixbufs = nautilus_file_get_emblem_pixbufs (file,
 
417
                                                                                   emblem_size,
 
418
                                                                                   TRUE,
 
419
                                                                                   emblems_to_ignore);
 
420
                                if (emblem_pixbufs != NULL) {
 
421
                                        icon = emblem_pixbufs->data;
 
422
                                        g_value_set_object (value, icon);
 
423
                                }
 
424
                                eel_gdk_pixbuf_list_free (emblem_pixbufs);
 
425
                        }
 
426
                }*/
 
427
                g_value_set_object (value, NULL);
 
428
                break;
 
429
        case FM_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN:
 
430
                g_value_init (value, G_TYPE_BOOLEAN);
 
431
                
 
432
                g_value_set_boolean (value, file != NULL && nautilus_file_can_rename (file));
 
433
                break;
 
434
        default:
 
435
                if (column >= FM_LIST_MODEL_NUM_COLUMNS || column < FM_LIST_MODEL_NUM_COLUMNS + model->details->columns->len) {
 
436
                        NautilusColumn *nautilus_column;
 
437
                        GQuark attribute;
 
438
                        nautilus_column = model->details->columns->pdata[column - FM_LIST_MODEL_NUM_COLUMNS];
 
439
                        
 
440
                        g_value_init (value, G_TYPE_STRING);
 
441
                        g_object_get (nautilus_column, 
 
442
                                      "attribute_q", &attribute, 
 
443
                                      NULL);
 
444
                        if (file != NULL) {
 
445
                                str = nautilus_file_get_string_attribute_with_default_q (file, 
 
446
                                                                                         attribute);
 
447
                                g_value_take_string (value, str);
 
448
                        } else if (attribute == attribute_name_q) {
 
449
                                if (file_entry->parent->loaded) {
 
450
                                        g_value_set_string (value, _("(Empty)"));
 
451
                                } else {
 
452
                                        g_value_set_string (value, _("Loading..."));
 
453
                                }
 
454
                        }
 
455
                } else {
 
456
                        g_assert_not_reached ();
 
457
                }
 
458
        }
 
459
#endif
 
460
}
 
461
 
 
462
static gboolean
 
463
fm_list_model_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter)
 
464
{
 
465
        FMListModel *model;
 
466
 
 
467
        model = (FMListModel *)tree_model;
 
468
 
 
469
        g_return_val_if_fail (model->details->stamp == iter->stamp, FALSE);
 
470
 
 
471
        iter->user_data = g_sequence_iter_next (iter->user_data);
 
472
 
 
473
        return !g_sequence_iter_is_end (iter->user_data);
 
474
}
 
475
 
 
476
static gboolean
 
477
fm_list_model_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent)
 
478
{
 
479
        FMListModel *model;
 
480
        GSequence *files;
 
481
        FileEntry *file_entry;
 
482
 
 
483
        model = (FMListModel *)tree_model;
 
484
        
 
485
        if (parent == NULL) {
 
486
                files = model->details->files;
 
487
        } else {
 
488
                file_entry = g_sequence_get (parent->user_data);
 
489
                files = file_entry->files;
 
490
        }
 
491
 
 
492
        if (files == NULL || g_sequence_get_length (files) == 0) {
 
493
                return FALSE;
 
494
        }
 
495
        
 
496
        iter->stamp = model->details->stamp;
 
497
        iter->user_data = g_sequence_get_begin_iter (files);
 
498
 
 
499
        return TRUE;
 
500
}
 
501
 
 
502
static gboolean
 
503
fm_list_model_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter)
 
504
{
 
505
        FMListModel *model = (FMListModel *)tree_model;
 
506
 
 
507
        if (!model->details->has_child)
 
508
                return FALSE;
 
509
        FileEntry *file_entry;
 
510
        
 
511
        if (iter == NULL) {
 
512
                return !fm_list_model_is_empty (FM_LIST_MODEL (tree_model));
 
513
        }
 
514
 
 
515
        file_entry = g_sequence_get (iter->user_data);
 
516
        return (file_entry->files != NULL && g_sequence_get_length (file_entry->files) > 0);
 
517
}
 
518
 
 
519
static int
 
520
fm_list_model_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter)
 
521
{
 
522
        FMListModel *model;
 
523
        GSequence *files;
 
524
        FileEntry *file_entry;
 
525
 
 
526
        model = (FMListModel *)tree_model;
 
527
 
 
528
        if (iter == NULL) {
 
529
                files = model->details->files;
 
530
        } else {
 
531
                file_entry = g_sequence_get (iter->user_data);
 
532
                files = file_entry->files;
 
533
        }
 
534
 
 
535
        return g_sequence_get_length (files);
 
536
}
 
537
 
 
538
static gboolean
 
539
fm_list_model_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, int n)
 
540
{
 
541
        FMListModel *model;
 
542
        GSequenceIter *child;
 
543
        GSequence *files;
 
544
        FileEntry *file_entry;
 
545
 
 
546
        model = (FMListModel *)tree_model;
 
547
        
 
548
        if (parent != NULL) {
 
549
                file_entry = g_sequence_get (parent->user_data);
 
550
                files = file_entry->files;
 
551
        } else {
 
552
                files = model->details->files;
 
553
        }
 
554
 
 
555
        child = g_sequence_get_iter_at_pos (files, n);
 
556
 
 
557
        if (g_sequence_iter_is_end (child)) {
 
558
                return FALSE;
 
559
        }
 
560
 
 
561
        iter->stamp = model->details->stamp;
 
562
        iter->user_data = child;
 
563
 
 
564
        return TRUE;
 
565
}
 
566
 
 
567
static gboolean
 
568
fm_list_model_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child)
 
569
{
 
570
        FMListModel *model;
 
571
        FileEntry *file_entry;
 
572
        
 
573
        model = (FMListModel *)tree_model;
 
574
        
 
575
        file_entry = g_sequence_get (child->user_data);
 
576
        
 
577
        if (file_entry->parent == NULL) {
 
578
                return FALSE;
 
579
        }
 
580
 
 
581
        iter->stamp = model->details->stamp;
 
582
        iter->user_data = file_entry->parent->ptr;
 
583
        
 
584
        return TRUE;
 
585
}
 
586
 
 
587
static GSequenceIter *
 
588
lookup_file (FMListModel *model, GOFFile *file, GOFDirectoryAsync *directory)
 
589
{
 
590
        FileEntry *file_entry;
 
591
        GSequenceIter *ptr, *parent_ptr;
 
592
 
 
593
        parent_ptr = NULL;
 
594
        if (directory) {
 
595
                parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map,
 
596
                                                  directory);
 
597
        }
 
598
        
 
599
        if (parent_ptr) {
 
600
                /* we re looking for a folder */
 
601
                if (file->is_directory)
 
602
                        return parent_ptr;
 
603
                file_entry = g_sequence_get (parent_ptr);
 
604
                ptr = g_hash_table_lookup (file_entry->reverse_map, file);
 
605
        } else {
 
606
                ptr = g_hash_table_lookup (model->details->top_reverse_map, file);
 
607
        }
 
608
 
 
609
        if (ptr) {
 
610
                g_assert (((FileEntry *)g_sequence_get (ptr))->file == file);
 
611
        }
 
612
 
 
613
        return ptr;
 
614
}
 
615
 
 
616
 
 
617
struct GetIters {
 
618
        FMListModel *model;
 
619
        GOFFile *file;
 
620
        GList *iters;
 
621
};
 
622
 
 
623
static void
 
624
dir_to_iters (struct GetIters *data,
 
625
              GHashTable *reverse_map)
 
626
{
 
627
        GSequenceIter *ptr;
 
628
        
 
629
        ptr = g_hash_table_lookup (reverse_map, data->file);
 
630
        if (ptr) {
 
631
                GtkTreeIter *iter;
 
632
                iter = g_new0 (GtkTreeIter, 1);
 
633
                fm_list_model_ptr_to_iter (data->model, ptr, iter);
 
634
                data->iters = g_list_prepend (data->iters, iter);
 
635
        }
 
636
}
 
637
 
 
638
static void
 
639
file_to_iter_cb (gpointer  key,
 
640
                 gpointer  value,
 
641
                 gpointer  user_data)
 
642
{
 
643
        struct GetIters *data;
 
644
        FileEntry *dir_file_entry;
 
645
 
 
646
        data = user_data;
 
647
        dir_file_entry = g_sequence_get ((GSequenceIter *)value);
 
648
        dir_to_iters (data, dir_file_entry->reverse_map);
 
649
}
 
650
 
 
651
GList *
 
652
fm_list_model_get_all_iters_for_file (FMListModel *model, GOFFile *file)
 
653
{
 
654
        struct GetIters data;
 
655
 
 
656
        data.file = file;
 
657
        data.model = model;
 
658
        data.iters = NULL;
 
659
        
 
660
        dir_to_iters (&data, model->details->top_reverse_map);
 
661
        g_hash_table_foreach (model->details->directory_reverse_map,
 
662
                              file_to_iter_cb, &data);
 
663
 
 
664
        return g_list_reverse (data.iters);
 
665
}
 
666
 
 
667
gboolean
 
668
fm_list_model_get_first_iter_for_file (FMListModel          *model,
 
669
                                       GOFFile              *file,
 
670
                                       GtkTreeIter          *iter)
 
671
{
 
672
        GList *list;
 
673
        gboolean res;
 
674
 
 
675
        res = FALSE;
 
676
        
 
677
        list = fm_list_model_get_all_iters_for_file (model, file);
 
678
        if (list != NULL) {
 
679
                res = TRUE;
 
680
                *iter = *(GtkTreeIter *)list->data;
 
681
        }
 
682
        //eel_g_list_free_deep (list);
 
683
        
 
684
        return res;
 
685
}
 
686
 
 
687
 
 
688
gboolean
 
689
fm_list_model_get_tree_iter_from_file (FMListModel *model, GOFFile *file,
 
690
                                       GOFDirectoryAsync *directory,
 
691
                                       GtkTreeIter *iter)
 
692
{
 
693
        GSequenceIter *ptr;
 
694
 
 
695
        ptr = lookup_file (model, file, directory);
 
696
        if (!ptr) {
 
697
                return FALSE;
 
698
        }
 
699
 
 
700
        fm_list_model_ptr_to_iter (model, ptr, iter);
 
701
        
 
702
        return TRUE;
 
703
}
 
704
 
 
705
static int
 
706
fm_list_model_file_entry_compare_func (gconstpointer a,
 
707
                                       gconstpointer b,
 
708
                                       gpointer      user_data)
 
709
{
 
710
        FileEntry *file_entry1;
 
711
        FileEntry *file_entry2;
 
712
        FMListModel *model;
 
713
        int result;
 
714
 
 
715
        model = (FMListModel *)user_data;
 
716
 
 
717
        file_entry1 = (FileEntry *)a;
 
718
        file_entry2 = (FileEntry *)b;
 
719
        
 
720
        if (file_entry1->file != NULL && file_entry2->file != NULL) {
 
721
                /*result = nautilus_file_compare_for_sort_by_attribute_q (file_entry1->file, file_entry2->file,
 
722
                                                                        model->details->sort_id,
 
723
                                                                        model->details->sort_directories_first,
 
724
                                                                        (model->details->order == GTK_SORT_DESCENDING));*/
 
725
                result = gof_file_compare_for_sort (file_entry1->file, file_entry2->file,
 
726
                                                                        model->details->sort_id,
 
727
                                                                        //model->details->sort_directories_first,
 
728
                                                                        TRUE,
 
729
                                                                        (model->details->order == GTK_SORT_DESCENDING));
 
730
                //result = 0;
 
731
        } else if (file_entry1->file == NULL) {
 
732
                return -1;
 
733
        } else {
 
734
                return 1;
 
735
        }
 
736
 
 
737
        return result;
 
738
}
 
739
 
 
740
int
 
741
fm_list_model_compare_func (FMListModel *model,
 
742
                            GOFFile *file1,
 
743
                            GOFFile *file2)
 
744
{
 
745
        int result;
 
746
 
 
747
        /*result = nautilus_file_compare_for_sort_by_attribute_q (file1, file2,
 
748
                                                                model->details->sort_id,
 
749
                                                                model->details->sort_directories_first,
 
750
                                                                (model->details->order == GTK_SORT_DESCENDING));*/
 
751
        result = 0;
 
752
 
 
753
        return result;
 
754
}
 
755
 
 
756
static void
 
757
fm_list_model_sort_file_entries (FMListModel *model, GSequence *files, GtkTreePath *path)
 
758
{
 
759
        GSequenceIter **old_order;
 
760
        GtkTreeIter iter;
 
761
        int *new_order;
 
762
        int length;
 
763
        int i;
 
764
        FileEntry *file_entry;
 
765
        gboolean has_iter;
 
766
 
 
767
        length = g_sequence_get_length (files);
 
768
 
 
769
        if (length <= 1) {
 
770
                return;
 
771
        }
 
772
        
 
773
        /* generate old order of GSequenceIter's */
 
774
        old_order = g_new (GSequenceIter *, length);
 
775
        for (i = 0; i < length; ++i) {
 
776
                GSequenceIter *ptr = g_sequence_get_iter_at_pos (files, i);
 
777
                
 
778
                file_entry = g_sequence_get (ptr);
 
779
                if (file_entry->files != NULL) {
 
780
                        gtk_tree_path_append_index (path, i);
 
781
                        fm_list_model_sort_file_entries (model, file_entry->files, path);
 
782
                        gtk_tree_path_up (path);
 
783
                }
 
784
 
 
785
                old_order[i] = ptr;
 
786
        }
 
787
 
 
788
        /* sort */
 
789
        g_sequence_sort (files, fm_list_model_file_entry_compare_func, model);
 
790
 
 
791
        /* generate new order */
 
792
        new_order = g_new (int, length);
 
793
        /* Note: new_order[newpos] = oldpos */
 
794
        for (i = 0; i < length; ++i) {
 
795
                new_order[g_sequence_iter_get_position (old_order[i])] = i;
 
796
        }
 
797
 
 
798
        /* Let the world know about our new order */
 
799
 
 
800
        g_assert (new_order != NULL);
 
801
 
 
802
        has_iter = FALSE;
 
803
        if (gtk_tree_path_get_depth (path) != 0) {
 
804
                gboolean get_iter_result;
 
805
                has_iter = TRUE;
 
806
                get_iter_result = gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
 
807
                g_assert (get_iter_result);
 
808
        }
 
809
 
 
810
        gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model),
 
811
                                       path, has_iter ? &iter : NULL, new_order);
 
812
 
 
813
        g_free (old_order);
 
814
        g_free (new_order);
 
815
}
 
816
 
 
817
static void
 
818
fm_list_model_sort (FMListModel *model)
 
819
{
 
820
        GtkTreePath *path;
 
821
 
 
822
        path = gtk_tree_path_new ();
 
823
 
 
824
        fm_list_model_sort_file_entries (model, model->details->files, path);
 
825
 
 
826
        gtk_tree_path_free (path);
 
827
}
 
828
 
 
829
static gboolean
 
830
fm_list_model_get_sort_column_id (GtkTreeSortable *sortable,
 
831
                                  gint            *sort_column_id,
 
832
                                  GtkSortType     *order)
 
833
{
 
834
        FMListModel *model;
 
835
        int id;
 
836
        
 
837
        model = (FMListModel *)sortable;
 
838
        
 
839
        id = model->details->sort_id;
 
840
        
 
841
        if (id == -1) {
 
842
                return FALSE;
 
843
        }
 
844
        
 
845
        if (sort_column_id != NULL) {
 
846
                *sort_column_id = id;
 
847
        }
 
848
 
 
849
        if (order != NULL) {
 
850
                *order = model->details->order;
 
851
        }
 
852
 
 
853
        return TRUE;
 
854
}
 
855
 
 
856
static void
 
857
fm_list_model_set_sort_column_id (GtkTreeSortable *sortable, gint sort_column_id, GtkSortType order)
 
858
{
 
859
        FMListModel *model;
 
860
 
 
861
        model = (FMListModel *)sortable;
 
862
 
 
863
        model->details->sort_id = sort_column_id; 
 
864
 
 
865
        model->details->order = order;
 
866
 
 
867
        fm_list_model_sort (model);
 
868
        gtk_tree_sortable_sort_column_changed (sortable);
 
869
}
 
870
 
 
871
static gboolean
 
872
fm_list_model_has_default_sort_func (GtkTreeSortable *sortable)
 
873
{
 
874
        return FALSE;
 
875
}
 
876
 
 
877
/*
 
878
static gboolean
 
879
fm_list_model_multi_row_draggable (EggTreeMultiDragSource *drag_source, GList *path_list)
 
880
{
 
881
        return TRUE;
 
882
}*/
 
883
 
 
884
#if 0
 
885
static void
 
886
each_path_get_data_binder (NautilusDragEachSelectedItemDataGet data_get,
 
887
                           gpointer context,
 
888
                           gpointer data)
 
889
{
 
890
        DragDataGetInfo *info;
 
891
        GList *l;
 
892
        GOFFile *file;
 
893
        GtkTreeRowReference *row;
 
894
        GtkTreePath *path;
 
895
        char *uri;
 
896
        GdkRectangle cell_area;
 
897
        GtkTreeViewColumn *column;
 
898
 
 
899
        info = context;
 
900
 
 
901
        g_return_if_fail (info->model->details->drag_view);
 
902
 
 
903
        column = gtk_tree_view_get_column (info->model->details->drag_view, 0);
 
904
 
 
905
        for (l = info->path_list; l != NULL; l = l->next) {
 
906
                row = l->data;
 
907
 
 
908
                path = gtk_tree_row_reference_get_path (row);
 
909
                file = fm_list_model_file_for_path (info->model, path);
 
910
                if (file) {
 
911
                        gtk_tree_view_get_cell_area
 
912
                                (info->model->details->drag_view,
 
913
                                 path, 
 
914
                                 column,
 
915
                                 &cell_area);
 
916
                                
 
917
                        uri = nautilus_file_get_uri (file);
 
918
                                
 
919
                        (*data_get) (uri, 
 
920
                                     0,
 
921
                                     cell_area.y - info->model->details->drag_begin_y,
 
922
                                     cell_area.width, cell_area.height, 
 
923
                                     data);
 
924
                                
 
925
                        g_free (uri);
 
926
                        
 
927
                        nautilus_file_unref (file);
 
928
                }
 
929
                
 
930
                gtk_tree_path_free (path);
 
931
        }
 
932
}
 
933
 
 
934
static gboolean
 
935
fm_list_model_multi_drag_data_get (EggTreeMultiDragSource *drag_source, 
 
936
                                   GList *path_list, 
 
937
                                   GtkSelectionData *selection_data)
 
938
{
 
939
        FMListModel *model;
 
940
        DragDataGetInfo context;
 
941
        guint target_info;
 
942
        
 
943
        model = FM_LIST_MODEL (drag_source);
 
944
 
 
945
        context.model = model;
 
946
        context.path_list = path_list;
 
947
 
 
948
        if (!drag_target_list) {
 
949
                drag_target_list = fm_list_model_get_drag_target_list ();
 
950
        }
 
951
 
 
952
        if (gtk_target_list_find (drag_target_list,
 
953
                                  selection_data->target,
 
954
                                  &target_info)) {
 
955
                nautilus_drag_drag_data_get (NULL,
 
956
                                             NULL,
 
957
                                             selection_data,
 
958
                                             target_info,
 
959
                                             GDK_CURRENT_TIME,
 
960
                                             &context,
 
961
                                             each_path_get_data_binder);
 
962
                return TRUE;
 
963
        } else {
 
964
                return FALSE;
 
965
        }
 
966
}
 
967
 
 
968
static gboolean
 
969
fm_list_model_multi_drag_data_delete (EggTreeMultiDragSource *drag_source, GList *path_list)
 
970
{
 
971
        return TRUE;
 
972
}
 
973
#endif
 
974
 
 
975
static void
 
976
add_dummy_row (FMListModel *model, FileEntry *parent_entry)
 
977
{
 
978
        FileEntry *dummy_file_entry;
 
979
        GtkTreeIter iter;
 
980
        GtkTreePath *path;
 
981
        
 
982
        dummy_file_entry = g_new0 (FileEntry, 1);
 
983
        //amtest
 
984
        //dummy_file_entry->file = parent_entry->file;
 
985
        dummy_file_entry->parent = parent_entry;
 
986
        dummy_file_entry->ptr = g_sequence_insert_sorted (parent_entry->files, dummy_file_entry,
 
987
                                                          fm_list_model_file_entry_compare_func, model);
 
988
        iter.stamp = model->details->stamp;
 
989
        iter.user_data = dummy_file_entry->ptr;
 
990
        
 
991
        path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
 
992
        gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
 
993
        gtk_tree_path_free (path);
 
994
}
 
995
 
 
996
gboolean
 
997
fm_list_model_add_file (FMListModel *model, GOFFile *file, 
 
998
                        GOFDirectoryAsync *directory)
 
999
{
 
1000
        GtkTreeIter iter;
 
1001
        GtkTreePath *path;
 
1002
        FileEntry *file_entry;
 
1003
        GSequenceIter *ptr, *parent_ptr;
 
1004
        GSequence *files;
 
1005
        gboolean replace_dummy;
 
1006
        GHashTable *parent_hash;
 
1007
 
 
1008
        parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map,
 
1009
                                          directory);
 
1010
        if (parent_ptr) {
 
1011
                file_entry = g_sequence_get (parent_ptr);
 
1012
                ptr = g_hash_table_lookup (file_entry->reverse_map, file);
 
1013
        } else {
 
1014
                file_entry = NULL;
 
1015
                ptr = g_hash_table_lookup (model->details->top_reverse_map, file);
 
1016
        }
 
1017
 
 
1018
        if (ptr != NULL) {
 
1019
                g_warning ("file already in tree (parent_ptr: %p)!!!\n", parent_ptr);
 
1020
                return FALSE;
 
1021
        }
 
1022
        
 
1023
        file_entry = g_new0 (FileEntry, 1);
 
1024
        //file_entry->file = gof_file_ref (file);
 
1025
        file_entry->file = file;
 
1026
        file_entry->parent = NULL;
 
1027
        file_entry->subdirectory = NULL;
 
1028
        file_entry->files = NULL;
 
1029
        
 
1030
        files = model->details->files;
 
1031
        parent_hash = model->details->top_reverse_map;
 
1032
        
 
1033
        replace_dummy = FALSE;
 
1034
 
 
1035
        if (parent_ptr != NULL) {
 
1036
                //printf ("parent_ptr != NULL %s\n", file->name);
 
1037
                file_entry->parent = g_sequence_get (parent_ptr);
 
1038
                /* At this point we set loaded. Either we saw
 
1039
                 * "done" and ignored it waiting for this, or we do this
 
1040
                 * earlier, but then we replace the dummy row anyway,
 
1041
                 * so it doesn't matter */
 
1042
                file_entry->parent->loaded = 1;
 
1043
                parent_hash = file_entry->parent->reverse_map;
 
1044
                files = file_entry->parent->files;
 
1045
                if (g_sequence_get_length (files) == 1) {
 
1046
                        GSequenceIter *dummy_ptr = g_sequence_get_iter_at_pos (files, 0);
 
1047
                        FileEntry *dummy_entry = g_sequence_get (dummy_ptr);
 
1048
                        if (dummy_entry->file == NULL) {
 
1049
                                /* replace the dummy loading entry */
 
1050
                                model->details->stamp++;
 
1051
                                g_sequence_remove (dummy_ptr);
 
1052
                                
 
1053
                                replace_dummy = TRUE;
 
1054
                        }
 
1055
                }
 
1056
        }
 
1057
 
 
1058
        
 
1059
        file_entry->ptr = g_sequence_insert_sorted (files, file_entry,
 
1060
                                            fm_list_model_file_entry_compare_func, model);
 
1061
 
 
1062
        g_hash_table_insert (parent_hash, file, file_entry->ptr);
 
1063
        
 
1064
        iter.stamp = model->details->stamp;
 
1065
        iter.user_data = file_entry->ptr;
 
1066
 
 
1067
        path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
 
1068
        if (replace_dummy) {
 
1069
                gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
 
1070
        } else {
 
1071
                gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
 
1072
        }
 
1073
 
 
1074
        if (file->is_directory) {
 
1075
                file_entry->files = g_sequence_new ((GDestroyNotify)file_entry_free);
 
1076
 
 
1077
                add_dummy_row (model, file_entry);
 
1078
 
 
1079
                gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model),
 
1080
                                                      path, &iter);
 
1081
        }
 
1082
        gtk_tree_path_free (path);
 
1083
        
 
1084
        return TRUE;
 
1085
}
 
1086
 
 
1087
#if 0
 
1088
void
 
1089
fm_list_model_file_changed (FMListModel *model, GOFFile *file,
 
1090
                            NautilusDirectory *directory)
 
1091
{
 
1092
        FileEntry *parent_file_entry;
 
1093
        GtkTreeIter iter;
 
1094
        GtkTreePath *path, *parent_path;
 
1095
        GSequenceIter *ptr;
 
1096
        int pos_before, pos_after, length, i, old;
 
1097
        int *new_order;
 
1098
        gboolean has_iter;
 
1099
        GSequence *files;
 
1100
 
 
1101
        ptr = lookup_file (model, file, directory);
 
1102
        if (!ptr) {
 
1103
                return;
 
1104
        }
 
1105
 
 
1106
        
 
1107
        pos_before = g_sequence_iter_get_position (ptr);
 
1108
                
 
1109
        g_sequence_sort_changed (ptr, fm_list_model_file_entry_compare_func, model);
 
1110
 
 
1111
        pos_after = g_sequence_iter_get_position (ptr);
 
1112
 
 
1113
        if (pos_before != pos_after) {
 
1114
                /* The file moved, we need to send rows_reordered */
 
1115
                
 
1116
                parent_file_entry = ((FileEntry *)g_sequence_get (ptr))->parent;
 
1117
 
 
1118
                if (parent_file_entry == NULL) {
 
1119
                        has_iter = FALSE;
 
1120
                        parent_path = gtk_tree_path_new ();
 
1121
                        files = model->details->files;
 
1122
                } else {
 
1123
                        has_iter = TRUE;
 
1124
                        fm_list_model_ptr_to_iter (model, parent_file_entry->ptr, &iter);
 
1125
                        parent_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
 
1126
                        files = parent_file_entry->files;
 
1127
                }
 
1128
 
 
1129
                length = g_sequence_get_length (files);
 
1130
                new_order = g_new (int, length);
 
1131
                /* Note: new_order[newpos] = oldpos */
 
1132
                for (i = 0, old = 0; i < length; ++i) {
 
1133
                        if (i == pos_after) {
 
1134
                                new_order[i] = pos_before;
 
1135
                        } else {
 
1136
                                if (old == pos_before)
 
1137
                                        old++;
 
1138
                                new_order[i] = old++;
 
1139
                        }
 
1140
                }
 
1141
 
 
1142
                gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model),
 
1143
                                               parent_path, has_iter ? &iter : NULL, new_order);
 
1144
 
 
1145
                gtk_tree_path_free (parent_path);
 
1146
                g_free (new_order);
 
1147
        }
 
1148
        
 
1149
        fm_list_model_ptr_to_iter (model, ptr, &iter);
 
1150
        path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
 
1151
        gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
 
1152
        gtk_tree_path_free (path);
 
1153
}
 
1154
#endif
 
1155
 
 
1156
gboolean
 
1157
fm_list_model_is_empty (FMListModel *model)
 
1158
{
 
1159
        return (g_sequence_get_length (model->details->files) == 0);
 
1160
}
 
1161
 
 
1162
guint
 
1163
fm_list_model_get_length (FMListModel *model)
 
1164
{
 
1165
        return g_sequence_get_length (model->details->files);
 
1166
}
 
1167
 
 
1168
static void
 
1169
fm_list_model_remove (FMListModel *model, GtkTreeIter *iter)
 
1170
{
 
1171
        GSequenceIter *ptr, *child_ptr;
 
1172
        FileEntry *file_entry, *child_file_entry, *parent_file_entry;
 
1173
        GtkTreePath *path;
 
1174
        GtkTreeIter parent_iter;
 
1175
 
 
1176
        ptr = iter->user_data;
 
1177
        file_entry = g_sequence_get (ptr);
 
1178
        if (file_entry->files != NULL) {
 
1179
                while (g_sequence_get_length (file_entry->files) > 0) {
 
1180
                        child_ptr = g_sequence_get_begin_iter (file_entry->files);
 
1181
                        child_file_entry = g_sequence_get (child_ptr);
 
1182
                        if (child_file_entry->file != NULL) {
 
1183
                                fm_list_model_remove_file (model,
 
1184
                                                           child_file_entry->file,
 
1185
                                                           file_entry->subdirectory);
 
1186
                        } else {
 
1187
                                path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
 
1188
                                gtk_tree_path_append_index (path, 0);
 
1189
                                model->details->stamp++;
 
1190
                                g_sequence_remove (child_ptr);
 
1191
                                gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
 
1192
                                gtk_tree_path_free (path);
 
1193
                        }
 
1194
                        
 
1195
                        /* the parent iter didn't actually change */
 
1196
                        iter->stamp = model->details->stamp;
 
1197
                }
 
1198
                        
 
1199
        }
 
1200
 
 
1201
        if (file_entry->file != NULL) { /* Don't try to remove dummy row */
 
1202
                if (file_entry->parent != NULL) {
 
1203
                        g_hash_table_remove (file_entry->parent->reverse_map, file_entry->file);
 
1204
                } else {
 
1205
                        g_hash_table_remove (model->details->top_reverse_map, file_entry->file);
 
1206
                }
 
1207
        }
 
1208
 
 
1209
        parent_file_entry = file_entry->parent;
 
1210
        if (parent_file_entry && g_sequence_get_length (parent_file_entry->files) == 1 &&
 
1211
            file_entry->file != NULL) {
 
1212
                /* this is the last non-dummy child, add a dummy node */
 
1213
                /* We need to do this before removing the last file to avoid
 
1214
                 * collapsing the row.
 
1215
                 */
 
1216
                add_dummy_row (model, parent_file_entry);
 
1217
        }
 
1218
        /* FIXME we don't need to unref file here - clean up this part */
 
1219
        /*if (file_entry->file != NULL) {
 
1220
                //printf ("remove file %s\n", file_entry->file->name);
 
1221
                g_object_unref (file_entry->file);
 
1222
        }*/
 
1223
 
 
1224
        if (file_entry->subdirectory != NULL) {
 
1225
                g_signal_emit (model,
 
1226
                               list_model_signals[SUBDIRECTORY_UNLOADED], 0,
 
1227
                               file_entry->subdirectory);
 
1228
        }
 
1229
 
 
1230
        path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
 
1231
        
 
1232
        g_sequence_remove (ptr);
 
1233
        model->details->stamp++;
 
1234
        gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
 
1235
        
 
1236
        gtk_tree_path_free (path);
 
1237
 
 
1238
        if (parent_file_entry && g_sequence_get_length (parent_file_entry->files) == 0) {
 
1239
                parent_iter.stamp = model->details->stamp;
 
1240
                parent_iter.user_data = parent_file_entry->ptr;
 
1241
                path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &parent_iter);
 
1242
                gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model),
 
1243
                                                      path, &parent_iter);
 
1244
                gtk_tree_path_free (path);
 
1245
        }
 
1246
}
 
1247
 
 
1248
void
 
1249
fm_list_model_remove_file (FMListModel *model, GOFFile *file,
 
1250
                           GOFDirectoryAsync *directory)
 
1251
{
 
1252
        GtkTreeIter iter;
 
1253
 
 
1254
        if (fm_list_model_get_tree_iter_from_file (model, file, directory, &iter)) {
 
1255
                //printf ("remove file %s\n", file->name);
 
1256
                fm_list_model_remove (model, &iter);
 
1257
        }
 
1258
}
 
1259
 
 
1260
static void
 
1261
fm_list_model_clear_directory (FMListModel *model, GSequence *files)
 
1262
{
 
1263
        GtkTreeIter iter;
 
1264
        FileEntry *file_entry;
 
1265
 
 
1266
        while (g_sequence_get_length (files) > 0) {
 
1267
                iter.user_data = g_sequence_get_begin_iter (files);
 
1268
 
 
1269
                file_entry = g_sequence_get (iter.user_data);
 
1270
                if (file_entry->files != NULL) {
 
1271
                        fm_list_model_clear_directory (model, file_entry->files);
 
1272
                }
 
1273
                
 
1274
                iter.stamp = model->details->stamp;
 
1275
                fm_list_model_remove (model, &iter);
 
1276
        }
 
1277
}
 
1278
 
 
1279
void
 
1280
fm_list_model_clear (FMListModel *model)
 
1281
{
 
1282
        g_return_if_fail (model != NULL);
 
1283
 
 
1284
        fm_list_model_clear_directory (model, model->details->files);
 
1285
}
 
1286
 
 
1287
GOFFile *
 
1288
fm_list_model_file_for_path (FMListModel *model, GtkTreePath *path)
 
1289
{
 
1290
        GOFFile *file;
 
1291
        GtkTreeIter iter;
 
1292
 
 
1293
        file = NULL;
 
1294
        if (gtk_tree_model_get_iter (GTK_TREE_MODEL (model), 
 
1295
                                     &iter, path)) {
 
1296
                gtk_tree_model_get (GTK_TREE_MODEL (model), 
 
1297
                                    &iter, 
 
1298
                                    FM_LIST_MODEL_FILE_COLUMN, &file,
 
1299
                                    -1);
 
1300
        }
 
1301
        return file;
 
1302
}
 
1303
 
 
1304
void fm_list_model_get_directory_file (FMListModel *model, GtkTreePath *path, GOFDirectoryAsync **directory, GOFFile **file)
 
1305
{
 
1306
        GtkTreeIter iter;
 
1307
        FileEntry *file_entry;
 
1308
 
 
1309
        *directory = NULL;
 
1310
        *file = NULL;
 
1311
        if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path)) {
 
1312
                return;
 
1313
        }
 
1314
        file_entry = g_sequence_get (iter.user_data);
 
1315
        *directory = file_entry->subdirectory;
 
1316
        *file = file_entry->file;
 
1317
}
 
1318
 
 
1319
gboolean
 
1320
fm_list_model_load_subdirectory (FMListModel *model, GtkTreePath *path, GOFDirectoryAsync **directory)
 
1321
{
 
1322
        GtkTreeIter iter;
 
1323
        FileEntry *file_entry;
 
1324
        
 
1325
        if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path)) {
 
1326
                return FALSE;
 
1327
        }
 
1328
 
 
1329
        file_entry = g_sequence_get (iter.user_data);
 
1330
        if (file_entry->file == NULL ||
 
1331
            file_entry->subdirectory != NULL) {
 
1332
                return FALSE;
 
1333
        }
 
1334
 
 
1335
        file_entry->subdirectory = gof_directory_async_get_for_file (file_entry->file);
 
1336
 
 
1337
        /* FIXME not sure the hash lookup is really needed gof_driectory_async_get_for_file is a always a new object */
 
1338
        if (g_hash_table_lookup (model->details->directory_reverse_map,
 
1339
                                 file_entry->subdirectory) != NULL) {
 
1340
                g_object_unref (file_entry->subdirectory);
 
1341
                g_warning ("Already in directory_reverse_map, failing\n");
 
1342
                return FALSE;
 
1343
        }
 
1344
        
 
1345
        g_hash_table_insert (model->details->directory_reverse_map,
 
1346
                             file_entry->subdirectory, file_entry->ptr);
 
1347
        file_entry->reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
 
1348
 
 
1349
        /* Return a ref too */
 
1350
        //gof_directory_ref (file_entry->subdirectory);
 
1351
        *directory = file_entry->subdirectory;
 
1352
 
 
1353
        load_dir_async (file_entry->subdirectory);
 
1354
 
 
1355
        return TRUE;
 
1356
}
 
1357
 
 
1358
/* removes all children of the subfolder and unloads the subdirectory */
 
1359
void
 
1360
fm_list_model_unload_subdirectory (FMListModel *model, GtkTreeIter *iter)
 
1361
{
 
1362
        GSequenceIter *child_ptr;
 
1363
        FileEntry *file_entry, *child_file_entry;
 
1364
        GtkTreeIter child_iter;
 
1365
 
 
1366
        file_entry = g_sequence_get (iter->user_data);
 
1367
        if (file_entry->file == NULL ||
 
1368
            file_entry->subdirectory == NULL) {
 
1369
                return;
 
1370
        }
 
1371
 
 
1372
        load_dir_async_cancel (file_entry->subdirectory);
 
1373
        g_hash_table_remove (model->details->directory_reverse_map,
 
1374
                             file_entry->subdirectory);
 
1375
        file_entry->loaded = 0;
 
1376
        
 
1377
        printf("remove all children\n");        
 
1378
        //printf("remove all children %d\n", g_sequence_get_length (file_entry->files));
 
1379
        /* Remove all children */
 
1380
        while (g_sequence_get_length (file_entry->files) > 0) {
 
1381
                child_ptr = g_sequence_get_begin_iter (file_entry->files);
 
1382
                child_file_entry = g_sequence_get (child_ptr);
 
1383
                if (child_file_entry->file == NULL) {
 
1384
                        /* Don't delete the dummy node */
 
1385
                        break;
 
1386
                } else {
 
1387
                        fm_list_model_ptr_to_iter (model, child_ptr, &child_iter);
 
1388
                        fm_list_model_remove (model, &child_iter);
 
1389
                }
 
1390
        }
 
1391
 
 
1392
        /* Emit unload signal */
 
1393
        g_signal_emit (model,
 
1394
                       list_model_signals[SUBDIRECTORY_UNLOADED], 0,
 
1395
                       file_entry->subdirectory);
 
1396
 
 
1397
        g_object_unref (file_entry->subdirectory);
 
1398
        file_entry->subdirectory = NULL;
 
1399
        g_assert (g_hash_table_size (file_entry->reverse_map) == 0);
 
1400
        g_hash_table_destroy (file_entry->reverse_map);
 
1401
        file_entry->reverse_map = NULL;
 
1402
}
 
1403
 
 
1404
void
 
1405
fm_list_model_set_should_sort_directories_first (FMListModel *model, gboolean sort_directories_first)
 
1406
{
 
1407
        if (model->details->sort_directories_first == sort_directories_first) {
 
1408
                return;
 
1409
        }
 
1410
 
 
1411
        model->details->sort_directories_first = sort_directories_first;
 
1412
        fm_list_model_sort (model);
 
1413
}
 
1414
 
 
1415
#if 0
 
1416
int
 
1417
fm_list_model_get_sort_column_id_from_attribute (FMListModel *model,
 
1418
                                                 GQuark attribute)
 
1419
{
 
1420
        guint i;
 
1421
 
 
1422
        if (attribute == 0) {
 
1423
                return -1;
 
1424
        }
 
1425
 
 
1426
        /* Hack - the preferences dialog sets modification_date for some 
 
1427
         * rather than date_modified for some reason.  Make sure that 
 
1428
         * works. */
 
1429
        if (attribute == attribute_modification_date_q) {
 
1430
                attribute = attribute_date_modified_q;
 
1431
        }
 
1432
 
 
1433
        for (i = 0; i < model->details->columns->len; i++) {
 
1434
                NautilusColumn *column;
 
1435
                GQuark column_attribute;
 
1436
                
 
1437
                column = 
 
1438
                        NAUTILUS_COLUMN (model->details->columns->pdata[i]);
 
1439
                g_object_get (G_OBJECT (column), 
 
1440
                              "attribute_q", &column_attribute, 
 
1441
                              NULL);
 
1442
                if (column_attribute == attribute) {
 
1443
                        return FM_LIST_MODEL_NUM_COLUMNS + i;
 
1444
                }
 
1445
        }
 
1446
        
 
1447
        return -1;
 
1448
}
 
1449
 
 
1450
GQuark
 
1451
fm_list_model_get_attribute_from_sort_column_id (FMListModel *model,
 
1452
                                                 int sort_column_id)
 
1453
{
 
1454
        NautilusColumn *column;
 
1455
        int index;
 
1456
        GQuark attribute;
 
1457
        
 
1458
        index = sort_column_id - FM_LIST_MODEL_NUM_COLUMNS;
 
1459
 
 
1460
        if (index < 0 || index >= model->details->columns->len) {
 
1461
                g_warning ("unknown sort column id: %d", sort_column_id);
 
1462
                return 0;
 
1463
        }
 
1464
 
 
1465
        column = NAUTILUS_COLUMN (model->details->columns->pdata[index]);
 
1466
        g_object_get (G_OBJECT (column), "attribute_q", &attribute, NULL);
 
1467
 
 
1468
        return attribute;
 
1469
}
 
1470
 
 
1471
NautilusZoomLevel
 
1472
fm_list_model_get_zoom_level_from_column_id (int column)
 
1473
{
 
1474
        switch (column) {
 
1475
        case FM_LIST_MODEL_SMALLEST_ICON_COLUMN:
 
1476
                return NAUTILUS_ZOOM_LEVEL_SMALLEST;
 
1477
        case FM_LIST_MODEL_SMALLER_ICON_COLUMN:
 
1478
                return NAUTILUS_ZOOM_LEVEL_SMALLER;
 
1479
        case FM_LIST_MODEL_SMALL_ICON_COLUMN:
 
1480
                return NAUTILUS_ZOOM_LEVEL_SMALL;
 
1481
        case FM_LIST_MODEL_STANDARD_ICON_COLUMN:
 
1482
                return NAUTILUS_ZOOM_LEVEL_STANDARD;
 
1483
        case FM_LIST_MODEL_LARGE_ICON_COLUMN:
 
1484
                return NAUTILUS_ZOOM_LEVEL_LARGE;
 
1485
        case FM_LIST_MODEL_LARGER_ICON_COLUMN:
 
1486
                return NAUTILUS_ZOOM_LEVEL_LARGER;
 
1487
        case FM_LIST_MODEL_LARGEST_ICON_COLUMN:
 
1488
                return NAUTILUS_ZOOM_LEVEL_LARGEST;
 
1489
        }
 
1490
 
 
1491
        g_return_val_if_reached (NAUTILUS_ZOOM_LEVEL_STANDARD);
 
1492
}
 
1493
 
 
1494
int
 
1495
fm_list_model_get_column_id_from_zoom_level (NautilusZoomLevel zoom_level)
 
1496
{
 
1497
        switch (zoom_level) {
 
1498
        case NAUTILUS_ZOOM_LEVEL_SMALLEST:
 
1499
                return FM_LIST_MODEL_SMALLEST_ICON_COLUMN;
 
1500
        case NAUTILUS_ZOOM_LEVEL_SMALLER:
 
1501
                return FM_LIST_MODEL_SMALLER_ICON_COLUMN;
 
1502
        case NAUTILUS_ZOOM_LEVEL_SMALL:
 
1503
                return FM_LIST_MODEL_SMALL_ICON_COLUMN;
 
1504
        case NAUTILUS_ZOOM_LEVEL_STANDARD:
 
1505
                return FM_LIST_MODEL_STANDARD_ICON_COLUMN;
 
1506
        case NAUTILUS_ZOOM_LEVEL_LARGE:
 
1507
                return FM_LIST_MODEL_LARGE_ICON_COLUMN;
 
1508
        case NAUTILUS_ZOOM_LEVEL_LARGER:
 
1509
                return FM_LIST_MODEL_LARGER_ICON_COLUMN;
 
1510
        case NAUTILUS_ZOOM_LEVEL_LARGEST:
 
1511
                return FM_LIST_MODEL_LARGEST_ICON_COLUMN;
 
1512
        }
 
1513
 
 
1514
        g_return_val_if_reached (FM_LIST_MODEL_STANDARD_ICON_COLUMN);
 
1515
}
 
1516
 
 
1517
NautilusZoomLevel
 
1518
fm_list_model_get_zoom_level_from_emblem_column_id (int column)
 
1519
{
 
1520
        switch (column) {
 
1521
        case FM_LIST_MODEL_SMALLEST_EMBLEM_COLUMN:
 
1522
                return NAUTILUS_ZOOM_LEVEL_SMALLEST;
 
1523
        case FM_LIST_MODEL_SMALLER_EMBLEM_COLUMN:
 
1524
                return NAUTILUS_ZOOM_LEVEL_SMALLER;
 
1525
        case FM_LIST_MODEL_SMALL_EMBLEM_COLUMN:
 
1526
                return NAUTILUS_ZOOM_LEVEL_SMALL;
 
1527
        case FM_LIST_MODEL_STANDARD_EMBLEM_COLUMN:
 
1528
                return NAUTILUS_ZOOM_LEVEL_STANDARD;
 
1529
        case FM_LIST_MODEL_LARGE_EMBLEM_COLUMN:
 
1530
                return NAUTILUS_ZOOM_LEVEL_LARGE;
 
1531
        case FM_LIST_MODEL_LARGER_EMBLEM_COLUMN:
 
1532
                return NAUTILUS_ZOOM_LEVEL_LARGER;
 
1533
        case FM_LIST_MODEL_LARGEST_EMBLEM_COLUMN:
 
1534
                return NAUTILUS_ZOOM_LEVEL_LARGEST;
 
1535
        }
 
1536
 
 
1537
        g_return_val_if_reached (NAUTILUS_ZOOM_LEVEL_STANDARD);
 
1538
}
 
1539
 
 
1540
int
 
1541
fm_list_model_get_emblem_column_id_from_zoom_level (NautilusZoomLevel zoom_level)
 
1542
{
 
1543
        switch (zoom_level) {
 
1544
        case NAUTILUS_ZOOM_LEVEL_SMALLEST:
 
1545
                return FM_LIST_MODEL_SMALLEST_EMBLEM_COLUMN;
 
1546
        case NAUTILUS_ZOOM_LEVEL_SMALLER:
 
1547
                return FM_LIST_MODEL_SMALLER_EMBLEM_COLUMN;
 
1548
        case NAUTILUS_ZOOM_LEVEL_SMALL:
 
1549
                return FM_LIST_MODEL_SMALL_EMBLEM_COLUMN;
 
1550
        case NAUTILUS_ZOOM_LEVEL_STANDARD:
 
1551
                return FM_LIST_MODEL_STANDARD_EMBLEM_COLUMN;
 
1552
        case NAUTILUS_ZOOM_LEVEL_LARGE:
 
1553
                return FM_LIST_MODEL_LARGE_EMBLEM_COLUMN;
 
1554
        case NAUTILUS_ZOOM_LEVEL_LARGER:
 
1555
                return FM_LIST_MODEL_LARGER_EMBLEM_COLUMN;
 
1556
        case NAUTILUS_ZOOM_LEVEL_LARGEST:
 
1557
                return FM_LIST_MODEL_LARGEST_EMBLEM_COLUMN;
 
1558
        }
 
1559
 
 
1560
        g_return_val_if_reached (FM_LIST_MODEL_STANDARD_EMBLEM_COLUMN);
 
1561
}
 
1562
#endif
 
1563
 
 
1564
/*
 
1565
void
 
1566
fm_list_model_set_drag_view (FMListModel *model,
 
1567
                             GtkTreeView *view,
 
1568
                             int drag_begin_x,
 
1569
                             int drag_begin_y)
 
1570
{
 
1571
        g_return_if_fail (model != NULL);
 
1572
        g_return_if_fail (FM_IS_LIST_MODEL (model));
 
1573
        g_return_if_fail (!view || GTK_IS_TREE_VIEW (view));
 
1574
        
 
1575
        model->details->drag_view = view;
 
1576
        model->details->drag_begin_x = drag_begin_x;
 
1577
        model->details->drag_begin_y = drag_begin_y;
 
1578
}
 
1579
 
 
1580
GtkTargetList *
 
1581
fm_list_model_get_drag_target_list ()
 
1582
{
 
1583
        GtkTargetList *target_list;
 
1584
 
 
1585
        target_list = gtk_target_list_new (drag_types, G_N_ELEMENTS (drag_types));
 
1586
        gtk_target_list_add_text_targets (target_list, NAUTILUS_ICON_DND_TEXT);
 
1587
 
 
1588
        return target_list;
 
1589
}*/
 
1590
/*
 
1591
int               
 
1592
fm_list_model_add_column (FMListModel *model,
 
1593
                          NautilusColumn *column)
 
1594
{
 
1595
        g_ptr_array_add (model->details->columns, column);
 
1596
        g_object_ref (column);
 
1597
 
 
1598
        return FM_LIST_MODEL_NUM_COLUMNS + (model->details->columns->len - 1);
 
1599
}
 
1600
 
 
1601
int
 
1602
fm_list_model_get_column_number (FMListModel *model,
 
1603
                                 const char *column_name)
 
1604
{
 
1605
        int i;
 
1606
 
 
1607
        for (i = 0; i < model->details->columns->len; i++) {
 
1608
                NautilusColumn *column;
 
1609
                char *name;
 
1610
                
 
1611
                column = model->details->columns->pdata[i];
 
1612
 
 
1613
                g_object_get (G_OBJECT (column), "name", &name, NULL);
 
1614
 
 
1615
                if (!strcmp (name, column_name)) {
 
1616
                        g_free (name);
 
1617
                        return FM_LIST_MODEL_NUM_COLUMNS + i;
 
1618
                }
 
1619
                g_free (name);
 
1620
        }
 
1621
 
 
1622
        return -1;
 
1623
}*/
 
1624
 
 
1625
static void
 
1626
fm_list_model_dispose (GObject *object)
 
1627
{
 
1628
        FMListModel *model;
 
1629
        //int i;
 
1630
 
 
1631
        model = FM_LIST_MODEL (object);
 
1632
 
 
1633
        /*if (model->details->columns) {
 
1634
                for (i = 0; i < model->details->columns->len; i++) {
 
1635
                        g_object_unref (model->details->columns->pdata[i]);
 
1636
                }
 
1637
                g_ptr_array_free (model->details->columns, TRUE);
 
1638
                model->details->columns = NULL;
 
1639
        }*/
 
1640
 
 
1641
        if (model->details->files) {
 
1642
                g_sequence_free (model->details->files);
 
1643
                model->details->files = NULL;
 
1644
        }
 
1645
        
 
1646
        if (model->details->top_reverse_map) {
 
1647
                g_hash_table_destroy (model->details->top_reverse_map);
 
1648
                model->details->top_reverse_map = NULL;
 
1649
        }
 
1650
        if (model->details->directory_reverse_map) {
 
1651
                g_hash_table_destroy (model->details->directory_reverse_map);
 
1652
                model->details->directory_reverse_map = NULL;
 
1653
        }
 
1654
 
 
1655
        G_OBJECT_CLASS (fm_list_model_parent_class)->dispose (object);
 
1656
}
 
1657
 
 
1658
static void
 
1659
fm_list_model_finalize (GObject *object)
 
1660
{
 
1661
        FMListModel *model = FM_LIST_MODEL (object);
 
1662
 
 
1663
        printf ("$$ %s\n", G_STRFUNC);
 
1664
        g_free (model->details);
 
1665
        
 
1666
        G_OBJECT_CLASS (fm_list_model_parent_class)->finalize (object);
 
1667
}
 
1668
 
 
1669
static void
 
1670
fm_list_model_init (FMListModel *model)
 
1671
{
 
1672
        model->details = g_new0 (FMListModelDetails, 1);
 
1673
        model->details->files = g_sequence_new ((GDestroyNotify)file_entry_free);
 
1674
        model->details->top_reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
 
1675
        model->details->directory_reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
 
1676
        model->details->stamp = g_random_int ();
 
1677
        model->details->sort_id = FM_LIST_MODEL_FILENAME;
 
1678
        //model->details->columns = g_ptr_array_new ();
 
1679
}
 
1680
 
 
1681
static void
 
1682
fm_list_model_class_init (FMListModelClass *klass)
 
1683
{
 
1684
        GObjectClass *object_class;
 
1685
 
 
1686
        attribute_name_q = g_quark_from_static_string ("name");
 
1687
        attribute_modification_date_q = g_quark_from_static_string ("modification_date");
 
1688
        attribute_date_modified_q = g_quark_from_static_string ("date_modified");
 
1689
        
 
1690
        object_class = (GObjectClass *)klass;
 
1691
        object_class->finalize = fm_list_model_finalize;
 
1692
        object_class->dispose = fm_list_model_dispose;
 
1693
        object_class->get_property = fm_list_model_get_property;
 
1694
        object_class->set_property = fm_list_model_set_property;
 
1695
 
 
1696
        g_object_class_install_property (object_class,
 
1697
                                         PROP_HAS_CHILD,
 
1698
                                         g_param_spec_boolean ("has-child",
 
1699
                                                               "has-child",
 
1700
                                                               "Whether the model list has child(s) and the treeview can expand subfolders",
 
1701
                                                               FALSE,
 
1702
                                                               G_PARAM_READWRITE));
 
1703
 
 
1704
 
 
1705
        list_model_signals[SUBDIRECTORY_UNLOADED] =
 
1706
        g_signal_new ("subdirectory_unloaded",
 
1707
                      FM_TYPE_LIST_MODEL,
 
1708
                      G_SIGNAL_RUN_FIRST,
 
1709
                      G_STRUCT_OFFSET (FMListModelClass, subdirectory_unloaded),
 
1710
                      NULL, NULL,
 
1711
                      g_cclosure_marshal_VOID__OBJECT,
 
1712
                      G_TYPE_NONE, 1,
 
1713
                      GOF_TYPE_DIRECTORY_ASYNC);
 
1714
}
 
1715
 
 
1716
static void
 
1717
fm_list_model_tree_model_init (GtkTreeModelIface *iface)
 
1718
{
 
1719
        iface->get_flags = fm_list_model_get_flags;
 
1720
        iface->get_n_columns = fm_list_model_get_n_columns;
 
1721
        iface->get_column_type = fm_list_model_get_column_type;
 
1722
        iface->get_iter = fm_list_model_get_iter;
 
1723
        iface->get_path = fm_list_model_get_path;
 
1724
        iface->get_value = fm_list_model_get_value;
 
1725
        iface->iter_next = fm_list_model_iter_next;
 
1726
        iface->iter_children = fm_list_model_iter_children;
 
1727
        iface->iter_has_child = fm_list_model_iter_has_child;
 
1728
        iface->iter_n_children = fm_list_model_iter_n_children;
 
1729
        iface->iter_nth_child = fm_list_model_iter_nth_child;
 
1730
        iface->iter_parent = fm_list_model_iter_parent;
 
1731
}
 
1732
 
 
1733
static void
 
1734
fm_list_model_sortable_init (GtkTreeSortableIface *iface)
 
1735
{
 
1736
        iface->get_sort_column_id = fm_list_model_get_sort_column_id;
 
1737
        iface->set_sort_column_id = fm_list_model_set_sort_column_id;
 
1738
        iface->has_default_sort_func = fm_list_model_has_default_sort_func;
 
1739
}
 
1740
 
 
1741
static void
 
1742
fm_list_model_set_has_child (FMListModel *model, gboolean has_child)
 
1743
{
 
1744
        g_return_if_fail (FM_IS_LIST_MODEL (model));
 
1745
 
 
1746
        model->details->has_child = has_child;
 
1747
        /*if (model->details->has_child != has_child)
 
1748
        {
 
1749
                model->details->has_child = has_child;
 
1750
                //g_object_notify (G_OBJECT (tree_view), "single-click");
 
1751
        }*/
 
1752
}
 
1753
 
 
1754
static void
 
1755
fm_list_model_get_property (GObject    *object,
 
1756
                            guint       prop_id,
 
1757
                            GValue     *value,
 
1758
                            GParamSpec *pspec)
 
1759
{
 
1760
        FMListModel *model = FM_LIST_MODEL (object);
 
1761
 
 
1762
        switch (prop_id)
 
1763
        {
 
1764
        case PROP_HAS_CHILD:
 
1765
                g_value_set_boolean (value, model->details->has_child);
 
1766
                break;
 
1767
 
 
1768
        default:
 
1769
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
1770
                break;
 
1771
        }
 
1772
}
 
1773
 
 
1774
static void
 
1775
fm_list_model_set_property (GObject      *object,
 
1776
                            guint         prop_id,
 
1777
                            const GValue *value,
 
1778
                            GParamSpec   *pspec)
 
1779
{
 
1780
        FMListModel *model = FM_LIST_MODEL (object);
 
1781
 
 
1782
        switch (prop_id)
 
1783
        {
 
1784
        case PROP_HAS_CHILD:
 
1785
                fm_list_model_set_has_child (model, g_value_get_boolean (value));
 
1786
                break;
 
1787
 
 
1788
        default:
 
1789
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
1790
                break;
 
1791
        }
 
1792
}
 
1793
 
 
1794
 
 
1795
/*
 
1796
static void
 
1797
fm_list_model_multi_drag_source_init (EggTreeMultiDragSourceIface *iface)
 
1798
{
 
1799
        iface->row_draggable = fm_list_model_multi_row_draggable;
 
1800
        iface->drag_data_get = fm_list_model_multi_drag_data_get;
 
1801
        iface->drag_data_delete = fm_list_model_multi_drag_data_delete;
 
1802
}*/
 
1803
 
 
1804
#if 0
 
1805
void
 
1806
fm_list_model_subdirectory_done_loading (FMListModel *model, NautilusDirectory *directory)
 
1807
{
 
1808
        GtkTreeIter iter;
 
1809
        GtkTreePath *path;
 
1810
        FileEntry *file_entry, *dummy_entry;
 
1811
        GSequenceIter *parent_ptr, *dummy_ptr;
 
1812
        GSequence *files;
 
1813
        
 
1814
        if (model == NULL || model->details->directory_reverse_map == NULL) {
 
1815
                return;
 
1816
        }
 
1817
        parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map,
 
1818
                                          directory);
 
1819
        if (parent_ptr == NULL) {
 
1820
                return;
 
1821
        }
 
1822
        
 
1823
        file_entry = g_sequence_get (parent_ptr);
 
1824
        files = file_entry->files;
 
1825
 
 
1826
        /* Only swap loading -> empty if we saw no files yet at "done",
 
1827
         * otherwise, toggle loading at first added file to the model.
 
1828
         */
 
1829
        if (!nautilus_directory_is_not_empty (directory) &&
 
1830
            g_sequence_get_length (files) == 1) {
 
1831
                dummy_ptr = g_sequence_get_iter_at_pos (file_entry->files, 0);
 
1832
                dummy_entry = g_sequence_get (dummy_ptr);
 
1833
                if (dummy_entry->file == NULL) {
 
1834
                        /* was the dummy file */
 
1835
                        file_entry->loaded = 1;
 
1836
                        
 
1837
                        iter.stamp = model->details->stamp;
 
1838
                        iter.user_data = dummy_ptr;
 
1839
                        
 
1840
                        path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
 
1841
                        gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
 
1842
                        gtk_tree_path_free (path);
 
1843
                }
 
1844
        }
 
1845
}
 
1846
#endif