~mfisch/brasero/update-to-3.8.0

« back to all changes in this revision

Viewing changes to src/brasero-data-tree-model.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2009-06-03 10:36:30 UTC
  • mfrom: (1.1.23 upstream)
  • Revision ID: james.westby@ubuntu.com-20090603103630-2r72408gk45sc0ws
Tags: 2.27.2-0ubuntu1
* New upstream release (LP: #380850)
  - Split burning backend into a new library called libbrasero-burn
  - Split some utilities into a new library called libbrasero-utils
  - Use Brasero as a single instance application using libunique
  - Data spanning
  - Memleak fixes
  - Bug Fixes
  - String fixes
  - Use autogenerated Changelog via git
  - Translation Updates
  - Fixes (LP: #360671)
* Bump GTK+ requirement and add libunique requirement

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
 
 * brasero
4
 
 * Copyright (C) Philippe Rouquier 2007-2008 <bonfire-app@wanadoo.fr>
5
 
 * 
6
 
 *  Brasero is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 * 
11
 
 * brasero is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
 
 * See the GNU General Public License for more details.
15
 
 * 
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with brasero.  If not, write to:
18
 
 *      The Free Software Foundation, Inc.,
19
 
 *      51 Franklin Street, Fifth Floor
20
 
 *      Boston, MA  02110-1301, USA.
21
 
 */
22
 
 
23
 
#ifdef HAVE_CONFIG_H
24
 
#  include <config.h>
25
 
#endif
26
 
 
27
 
#include <glib.h>
28
 
#include <glib/gi18n-lib.h>
29
 
 
30
 
#include <gtk/gtk.h>
31
 
 
32
 
#include "burn-basics.h"
33
 
 
34
 
#include "brasero-data-tree-model.h"
35
 
#include "brasero-data-project.h"
36
 
#include "brasero-data-vfs.h"
37
 
#include "brasero-file-node.h"
38
 
#include "brasero-utils.h"
39
 
 
40
 
#include "eggtreemultidnd.h"
41
 
 
42
 
typedef struct _BraseroDataTreeModelPrivate BraseroDataTreeModelPrivate;
43
 
struct _BraseroDataTreeModelPrivate
44
 
{
45
 
        guint stamp;
46
 
 
47
 
        GtkIconTheme *theme;
48
 
 
49
 
        GSList *shown;
50
 
 
51
 
        gint sort_column;
52
 
        GtkSortType sort_type;
53
 
};
54
 
 
55
 
#define BRASERO_DATA_TREE_MODEL_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_DATA_TREE_MODEL, BraseroDataTreeModelPrivate))
56
 
 
57
 
typedef enum {
58
 
        BRASERO_ROW_REGULAR             = 0,
59
 
        BRASERO_ROW_BOGUS
60
 
} BraseroFileRowType;
61
 
 
62
 
static void
63
 
brasero_data_tree_model_multi_drag_source_iface_init (gpointer g_iface, gpointer data);
64
 
static void
65
 
brasero_data_tree_model_drag_source_iface_init (gpointer g_iface, gpointer data);
66
 
static void
67
 
brasero_data_tree_model_drag_dest_iface_init (gpointer g_iface, gpointer data);
68
 
static void
69
 
brasero_data_tree_model_sortable_iface_init (gpointer g_iface, gpointer data);
70
 
static void
71
 
brasero_data_tree_model_iface_init (gpointer g_iface, gpointer data);
72
 
 
73
 
G_DEFINE_TYPE_WITH_CODE (BraseroDataTreeModel,
74
 
                         brasero_data_tree_model,
75
 
                         BRASERO_TYPE_DATA_VFS,
76
 
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
77
 
                                                brasero_data_tree_model_iface_init)
78
 
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
79
 
                                                brasero_data_tree_model_drag_dest_iface_init)
80
 
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
81
 
                                                brasero_data_tree_model_drag_source_iface_init)
82
 
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
83
 
                                                brasero_data_tree_model_sortable_iface_init)
84
 
                         G_IMPLEMENT_INTERFACE (EGG_TYPE_TREE_MULTI_DRAG_SOURCE,
85
 
                                                brasero_data_tree_model_multi_drag_source_iface_init));
86
 
 
87
 
 
88
 
static gboolean
89
 
brasero_data_tree_model_iter_parent (GtkTreeModel *model,
90
 
                                     GtkTreeIter *iter,
91
 
                                     GtkTreeIter *child)
92
 
{
93
 
        BraseroDataTreeModelPrivate *priv;
94
 
        BraseroFileNode *node;
95
 
 
96
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (model);
97
 
 
98
 
        /* make sure that iter comes from us */
99
 
        g_return_val_if_fail (priv->stamp == child->stamp, FALSE);
100
 
        g_return_val_if_fail (child->user_data != NULL, FALSE);
101
 
 
102
 
        node = child->user_data;
103
 
        if (child->user_data2 == GINT_TO_POINTER (BRASERO_ROW_BOGUS)) {
104
 
                /* This is a bogus row intended for empty directories
105
 
                 * user_data has the parent empty directory. */
106
 
                iter->user_data2 = GINT_TO_POINTER (BRASERO_ROW_REGULAR);
107
 
                iter->user_data = child->user_data;
108
 
                iter->stamp = priv->stamp;
109
 
                return TRUE;
110
 
        }
111
 
 
112
 
        if (!node->parent) {
113
 
                iter->user_data = NULL;
114
 
                return FALSE;
115
 
        }
116
 
 
117
 
        iter->stamp = priv->stamp;
118
 
        iter->user_data = node->parent;
119
 
        iter->user_data2 = GINT_TO_POINTER (BRASERO_ROW_REGULAR);
120
 
        return TRUE;
121
 
}
122
 
 
123
 
static gboolean
124
 
brasero_data_tree_model_iter_nth_child (GtkTreeModel *model,
125
 
                                        GtkTreeIter *iter,
126
 
                                        GtkTreeIter *parent,
127
 
                                        gint n)
128
 
{
129
 
        BraseroDataTreeModelPrivate *priv;
130
 
        BraseroFileNode *node;
131
 
 
132
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (model);
133
 
 
134
 
        if (parent) {
135
 
                /* make sure that iter comes from us */
136
 
                g_return_val_if_fail (priv->stamp == parent->stamp, FALSE);
137
 
                g_return_val_if_fail (parent->user_data != NULL, FALSE);
138
 
 
139
 
                if (parent->user_data2 == GINT_TO_POINTER (BRASERO_ROW_BOGUS)) {
140
 
                        /* This is a bogus row intended for empty directories,
141
 
                         * it hasn't got children. */
142
 
                        return FALSE;
143
 
                }
144
 
 
145
 
                node = parent->user_data;
146
 
        }
147
 
        else
148
 
                node = brasero_data_project_get_root (BRASERO_DATA_PROJECT (model));
149
 
 
150
 
        iter->user_data = brasero_file_node_nth_child (node, n);
151
 
        if (!iter->user_data)
152
 
                return FALSE;
153
 
 
154
 
        iter->stamp = priv->stamp;
155
 
        iter->user_data2 = GINT_TO_POINTER (BRASERO_ROW_REGULAR);
156
 
        return TRUE;
157
 
}
158
 
 
159
 
static gint
160
 
brasero_data_tree_model_iter_n_children (GtkTreeModel *model,
161
 
                                         GtkTreeIter *iter)
162
 
{
163
 
        BraseroDataTreeModelPrivate *priv;
164
 
        BraseroFileNode *node;
165
 
 
166
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (model);
167
 
 
168
 
        if (iter == NULL) {
169
 
                /* special case */
170
 
                node = brasero_data_project_get_root (BRASERO_DATA_PROJECT (model));
171
 
                return brasero_file_node_get_n_children (node);
172
 
        }
173
 
 
174
 
        /* make sure that iter comes from us */
175
 
        g_return_val_if_fail (priv->stamp == iter->stamp, 0);
176
 
        g_return_val_if_fail (iter->user_data != NULL, 0);
177
 
 
178
 
        if (iter->user_data2 == GINT_TO_POINTER (BRASERO_ROW_BOGUS))
179
 
                return 0;
180
 
 
181
 
        node = iter->user_data;
182
 
        if (node->is_file)
183
 
                return 0;
184
 
 
185
 
        /* return at least one for the bogus row labelled "empty". */
186
 
        if (!BRASERO_FILE_NODE_CHILDREN (node))
187
 
                return 1;
188
 
 
189
 
        return brasero_file_node_get_n_children (node);
190
 
}
191
 
 
192
 
static gboolean
193
 
brasero_data_tree_model_iter_has_child (GtkTreeModel *model,
194
 
                                        GtkTreeIter *iter)
195
 
{
196
 
        BraseroDataTreeModelPrivate *priv;
197
 
        BraseroFileNode *node;
198
 
 
199
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (model);
200
 
 
201
 
        /* make sure that iter comes from us */
202
 
        g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
203
 
        g_return_val_if_fail (iter->user_data != NULL, FALSE);
204
 
 
205
 
        if (iter->user_data2 == GINT_TO_POINTER (BRASERO_ROW_BOGUS)) {
206
 
                /* This is a bogus row intended for empty directories
207
 
                 * it hasn't got children */
208
 
                return FALSE;
209
 
        }
210
 
 
211
 
        node = iter->user_data;
212
 
 
213
 
        /* This is a workaround for a warning in gailtreeview.c line 2946 where
214
 
         * gail uses the GtkTreePath and not a copy which if the node inserted
215
 
         * declares to have children and is not expanded leads to the path being
216
 
         * upped and therefore wrong. */
217
 
        if (node->is_inserting)
218
 
                return FALSE;
219
 
 
220
 
        if (node->is_file)
221
 
                return FALSE;
222
 
 
223
 
        /* always return TRUE here when it's a directory since even if
224
 
         * it's empty we'll add a row written empty underneath it
225
 
         * anyway. */
226
 
        return TRUE;
227
 
}
228
 
 
229
 
static gboolean
230
 
brasero_data_tree_model_iter_children (GtkTreeModel *model,
231
 
                                       GtkTreeIter *iter,
232
 
                                       GtkTreeIter *parent)
233
 
{
234
 
        BraseroDataTreeModelPrivate *priv;
235
 
        BraseroFileNode *node;
236
 
 
237
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (model);
238
 
 
239
 
        if (!parent) {
240
 
                BraseroFileNode *root;
241
 
 
242
 
                /* This is for the top directory */
243
 
                root = brasero_data_project_get_root (BRASERO_DATA_PROJECT (model));
244
 
                if (!root || !BRASERO_FILE_NODE_CHILDREN (root))
245
 
                        return FALSE;
246
 
 
247
 
                iter->stamp = priv->stamp;
248
 
                iter->user_data = BRASERO_FILE_NODE_CHILDREN (root);
249
 
                iter->user_data2 = GINT_TO_POINTER (BRASERO_ROW_REGULAR);
250
 
                return TRUE;
251
 
        }
252
 
 
253
 
        /* make sure that iter comes from us */
254
 
        g_return_val_if_fail (priv->stamp == parent->stamp, FALSE);
255
 
        g_return_val_if_fail (parent->user_data != NULL, FALSE);
256
 
 
257
 
        if (parent->user_data2 == GINT_TO_POINTER (BRASERO_ROW_BOGUS)) {
258
 
                iter->user_data = NULL;
259
 
                return FALSE;
260
 
        }
261
 
 
262
 
        node = parent->user_data;
263
 
        if (node->is_file) {
264
 
                iter->user_data = NULL;
265
 
                return FALSE;
266
 
        }
267
 
 
268
 
        iter->stamp = priv->stamp;
269
 
        if (!BRASERO_FILE_NODE_CHILDREN (node)) {
270
 
                /* This is a directory but it hasn't got any child; yet
271
 
                 * we show a row written empty for that. Set bogus in
272
 
                 * user_data and put parent in user_data. */
273
 
                iter->user_data = parent->user_data;
274
 
                iter->user_data2 = GINT_TO_POINTER (BRASERO_ROW_BOGUS);
275
 
                return TRUE;
276
 
        }
277
 
 
278
 
        iter->user_data = BRASERO_FILE_NODE_CHILDREN (node);
279
 
        iter->user_data2 = GINT_TO_POINTER (BRASERO_ROW_REGULAR);
280
 
        return TRUE;
281
 
}
282
 
 
283
 
static gboolean
284
 
brasero_data_tree_model_iter_next (GtkTreeModel *model,
285
 
                                   GtkTreeIter *iter)
286
 
{
287
 
        BraseroDataTreeModelPrivate *priv;
288
 
        BraseroFileNode *node;
289
 
 
290
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (model);
291
 
 
292
 
        /* make sure that iter comes from us */
293
 
        g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
294
 
        g_return_val_if_fail (iter->user_data != NULL, FALSE);
295
 
 
296
 
        if (iter->user_data2 == GINT_TO_POINTER (BRASERO_ROW_BOGUS)) {
297
 
                /* This is a bogus row intended for empty directories
298
 
                 * user_data has the parent empty directory. It hasn't
299
 
                 * got any peer.*/
300
 
                iter->user_data = NULL;
301
 
                return FALSE;
302
 
        }
303
 
 
304
 
        node = iter->user_data;
305
 
        iter->user_data = node->next;
306
 
        if (!node->next)
307
 
                return FALSE;
308
 
 
309
 
        return TRUE;
310
 
}
311
 
 
312
 
static void
313
 
brasero_data_tree_model_node_shown (GtkTreeModel *model,
314
 
                                    GtkTreeIter *iter)
315
 
{
316
 
        BraseroFileNode *node;
317
 
        BraseroDataTreeModelPrivate *priv;
318
 
 
319
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (model);
320
 
        node = iter->user_data;
321
 
 
322
 
        /* Check if that's a BOGUS row. In this case that means the parent was
323
 
         * expanded. Therefore ask vfs to increase its priority if it's loading
324
 
         * its contents. */
325
 
        if (iter->user_data2 == GINT_TO_POINTER (BRASERO_ROW_BOGUS)) {
326
 
                /* NOTE: this has to be a directory */
327
 
                /* NOTE: there is no need to check for is_loading case here
328
 
                 * since before showing its BOGUS row the tree will have shown
329
 
                 * its parent itself and therefore that's the cases that follow
330
 
                 */
331
 
                if (node->is_exploring) {
332
 
                        /* the directory is being explored increase priority */
333
 
                        brasero_data_vfs_require_directory_contents (BRASERO_DATA_VFS (model), node);
334
 
                }
335
 
 
336
 
                /* Otherwise, that's simply a BOGUS row and its parent was
337
 
                 * loaded but it is empty. Nothing to do. */
338
 
 
339
 
                return;
340
 
        }
341
 
 
342
 
        if (!node)
343
 
                return;
344
 
 
345
 
        node->is_visible ++;
346
 
 
347
 
        if (node->is_imported) {
348
 
                if (node->is_fake && !node->is_file) {
349
 
                        /* we don't load all nodes when importing a session do it now */
350
 
                        brasero_data_session_load_directory_contents (BRASERO_DATA_SESSION (model), node, NULL);
351
 
                }
352
 
 
353
 
                return;
354
 
        }
355
 
 
356
 
        if (node->is_visible > 1)
357
 
                return;
358
 
 
359
 
        /* NOTE: no need to see if that's a directory being explored here. If it
360
 
         * is being explored then it has a BOGUS row and that's the above case 
361
 
         * that is reached. */
362
 
        if (node->is_loading) {
363
 
                /* in this case have vfs to increase priority for this node */
364
 
                brasero_data_vfs_require_node_load (BRASERO_DATA_VFS (model), node);
365
 
        }
366
 
        else if (!BRASERO_FILE_NODE_MIME (node)) {
367
 
                /* that means that file wasn't completly loaded. To save
368
 
                 * some time we delayed the detection of the mime type
369
 
                 * since that takes a lot of time. */
370
 
                brasero_data_vfs_load_mime (BRASERO_DATA_VFS (model), node);
371
 
        }
372
 
 
373
 
        /* add the node to the visible list that is used to update the disc 
374
 
         * share for the node (we don't want to update the whole tree).
375
 
         * Moreover, we only want files since directories don't have space. */
376
 
        priv->shown = g_slist_prepend (priv->shown, node);
377
 
}
378
 
 
379
 
static void
380
 
brasero_data_tree_model_node_hidden (GtkTreeModel *model,
381
 
                                     GtkTreeIter *iter)
382
 
{
383
 
        BraseroFileNode *node;
384
 
        BraseroDataTreeModelPrivate *priv;
385
 
 
386
 
        /* if it's a BOGUS row stop here since they are not added to shown list.
387
 
         * In the same way returns if it is a file. */
388
 
        if (iter->user_data2 == GINT_TO_POINTER (BRASERO_ROW_BOGUS))
389
 
                return;
390
 
 
391
 
        node = iter->user_data;
392
 
 
393
 
        if (!node)
394
 
                return;
395
 
 
396
 
        node->is_visible --;
397
 
 
398
 
        if (node->is_imported)
399
 
                return;
400
 
 
401
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (model);
402
 
 
403
 
        /* update shown list */
404
 
        if (!node->is_visible)
405
 
                priv->shown = g_slist_remove (priv->shown, node);
406
 
}
407
 
 
408
 
static void
409
 
brasero_data_tree_model_get_value (GtkTreeModel *model,
410
 
                                   GtkTreeIter *iter,
411
 
                                   gint column,
412
 
                                   GValue *value)
413
 
{
414
 
        BraseroDataTreeModelPrivate *priv;
415
 
        BraseroDataTreeModel *self;
416
 
        BraseroFileNode *node;
417
 
 
418
 
        self = BRASERO_DATA_TREE_MODEL (model);
419
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (model);
420
 
 
421
 
        /* make sure that iter comes from us */
422
 
        g_return_if_fail (priv->stamp == iter->stamp);
423
 
        g_return_if_fail (iter->user_data != NULL);
424
 
 
425
 
        node = iter->user_data;
426
 
 
427
 
        if (iter->user_data2 == GINT_TO_POINTER (BRASERO_ROW_BOGUS)) {
428
 
                switch (column) {
429
 
                case BRASERO_DATA_TREE_MODEL_NAME:
430
 
                        g_value_init (value, G_TYPE_STRING);
431
 
                        if (node->is_exploring)
432
 
                                g_value_set_string (value, _("(loading ...)"));
433
 
                        else
434
 
                                g_value_set_string (value, _("Empty"));
435
 
 
436
 
                        return;
437
 
 
438
 
                case BRASERO_DATA_TREE_MODEL_MIME_DESC:
439
 
                case BRASERO_DATA_TREE_MODEL_MIME_ICON:
440
 
                case BRASERO_DATA_TREE_MODEL_SIZE:
441
 
                        g_value_init (value, G_TYPE_STRING);
442
 
                        g_value_set_string (value, NULL);
443
 
                        return;
444
 
 
445
 
                case BRASERO_DATA_TREE_MODEL_SHOW_PERCENT:
446
 
                        g_value_init (value, G_TYPE_BOOLEAN);
447
 
                        g_value_set_boolean (value, FALSE);
448
 
                        return;
449
 
 
450
 
                case BRASERO_DATA_TREE_MODEL_PERCENT:
451
 
                        g_value_init (value, G_TYPE_INT);
452
 
                        g_value_set_int (value, 0);
453
 
                        return;
454
 
 
455
 
                case BRASERO_DATA_TREE_MODEL_STYLE:
456
 
                        g_value_init (value, PANGO_TYPE_STYLE);
457
 
                        g_value_set_enum (value, PANGO_STYLE_ITALIC);
458
 
                        return;
459
 
 
460
 
                case BRASERO_DATA_TREE_MODEL_EDITABLE:
461
 
                        g_value_init (value, G_TYPE_BOOLEAN);
462
 
                        g_value_set_boolean (value, FALSE);
463
 
                        return;
464
 
        
465
 
                case BRASERO_DATA_TREE_MODEL_COLOR:
466
 
                        g_value_init (value, G_TYPE_STRING);
467
 
                        g_value_set_string (value, NULL);
468
 
                        return;
469
 
 
470
 
                default:
471
 
                        return;
472
 
                }
473
 
 
474
 
                return;
475
 
        }
476
 
 
477
 
        switch (column) {
478
 
        case BRASERO_DATA_TREE_MODEL_EDITABLE:
479
 
                g_value_init (value, G_TYPE_BOOLEAN);
480
 
                g_value_set_boolean (value, (node->is_imported == FALSE) && node->is_selected);
481
 
                return;
482
 
 
483
 
        case BRASERO_DATA_TREE_MODEL_NAME: {
484
 
                gchar *filename;
485
 
 
486
 
                g_value_init (value, G_TYPE_STRING);
487
 
                filename = g_filename_to_utf8 (BRASERO_FILE_NODE_NAME (node),
488
 
                                               -1,
489
 
                                               NULL,
490
 
                                               NULL,
491
 
                                               NULL);
492
 
                if (!filename)
493
 
                        filename = brasero_utils_validate_utf8 (BRASERO_FILE_NODE_NAME (node));
494
 
 
495
 
                if (filename)
496
 
                        g_value_set_string (value, filename);
497
 
                else    /* Glib section on g_convert advise to use a string like
498
 
                         * "Invalid Filename". */
499
 
                        g_value_set_string (value, BRASERO_FILE_NODE_NAME (node));
500
 
 
501
 
                g_free (filename);
502
 
                return;
503
 
        }
504
 
 
505
 
        case BRASERO_DATA_TREE_MODEL_MIME_DESC:
506
 
                g_value_init (value, G_TYPE_STRING);
507
 
                if (node->is_loading)
508
 
                        g_value_set_string (value, _("(loading ...)"));
509
 
                else if (!node->is_file) {
510
 
                        gchar *description;
511
 
 
512
 
                        description = g_content_type_get_description ("inode/directory");
513
 
                        g_value_set_string (value, description);
514
 
                        g_free (description);
515
 
                }
516
 
                else if (node->is_imported)
517
 
                        g_value_set_string (value, _("Disc file"));
518
 
                else if (!BRASERO_FILE_NODE_MIME (node))
519
 
                        g_value_set_string (value, _("(loading ...)"));
520
 
                else {
521
 
                        gchar *description;
522
 
 
523
 
                        description = g_content_type_get_description (BRASERO_FILE_NODE_MIME (node));
524
 
                        g_value_set_string (value, description);
525
 
                        g_free (description);
526
 
                }
527
 
 
528
 
                return;
529
 
 
530
 
        case BRASERO_DATA_TREE_MODEL_MIME_ICON:
531
 
                g_value_init (value, G_TYPE_STRING);
532
 
                if (node->is_loading)
533
 
                        g_value_set_string (value, "image-loading");
534
 
                else if (!node->is_file) {
535
 
                        /* Here we have two states collapsed and expanded */
536
 
                        if (node->is_expanded)
537
 
                                g_value_set_string (value, "folder-open");
538
 
                        else if (node->is_imported)
539
 
                                /* that's for all the imported folders */
540
 
                                g_value_set_string (value, "folder-visiting");
541
 
                        else
542
 
                                g_value_set_string (value, "folder");
543
 
                }
544
 
                else if (node->is_imported) {
545
 
                        g_value_set_string (value, "media-cdrom");
546
 
                }
547
 
                else if (BRASERO_FILE_NODE_MIME (node)) {
548
 
                        const gchar *icon_string = BRASERO_DEFAULT_ICON;
549
 
                        GIcon *icon;
550
 
 
551
 
                        /* NOTE: implemented in glib 2.15.6 (not for windows though) */
552
 
                        icon = g_content_type_get_icon (BRASERO_FILE_NODE_MIME (node));
553
 
                        if (G_IS_THEMED_ICON (icon)) {
554
 
                                const gchar * const *names = NULL;
555
 
 
556
 
                                names = g_themed_icon_get_names (G_THEMED_ICON (icon));
557
 
                                if (names) {
558
 
                                        gint i;
559
 
 
560
 
                                        for (i = 0; names [i]; i++) {
561
 
                                                if (gtk_icon_theme_has_icon (priv->theme, names [i])) {
562
 
                                                        icon_string = names [i];
563
 
                                                        break;
564
 
                                                }
565
 
                                        }
566
 
                                }
567
 
                        }
568
 
 
569
 
                        g_value_set_string (value, icon_string);
570
 
                        g_object_unref (icon);
571
 
                }
572
 
                else
573
 
                        g_value_set_string (value, "image-loading");
574
 
 
575
 
                return;
576
 
 
577
 
        case BRASERO_DATA_TREE_MODEL_SIZE:
578
 
                g_value_init (value, G_TYPE_STRING);
579
 
                if (node->is_loading)
580
 
                        g_value_set_string (value, _("(loading ...)"));
581
 
                else if (!node->is_file) {
582
 
                        guint nb_items;
583
 
 
584
 
                        if (node->is_exploring) {
585
 
                                g_value_set_string (value, _("(loading ...)"));
586
 
                                return;
587
 
                        }
588
 
 
589
 
                        nb_items = brasero_file_node_get_n_children (node);
590
 
                        if (!nb_items)
591
 
                                g_value_set_string (value, _("Empty"));
592
 
                        else {
593
 
                                gchar *text;
594
 
 
595
 
                                text = g_strdup_printf (ngettext ("%d item", "%d items", nb_items), nb_items);
596
 
                                g_value_set_string (value, text);
597
 
                                g_free (text);
598
 
                        }
599
 
                }
600
 
                else {
601
 
                        gchar *text;
602
 
 
603
 
                        text = g_format_size_for_display (BRASERO_FILE_NODE_SECTORS (node) * 2048);
604
 
                        g_value_set_string (value, text);
605
 
                        g_free (text);
606
 
                }
607
 
 
608
 
                return;
609
 
 
610
 
        case BRASERO_DATA_TREE_MODEL_SHOW_PERCENT:
611
 
                g_value_init (value, G_TYPE_BOOLEAN);
612
 
                if (node->is_imported || node->is_loading)
613
 
                        g_value_set_boolean (value, FALSE);
614
 
                else
615
 
                        g_value_set_boolean (value, TRUE);
616
 
 
617
 
                return;
618
 
 
619
 
        case BRASERO_DATA_TREE_MODEL_PERCENT:
620
 
                g_value_init (value, G_TYPE_INT);
621
 
                if (!node->is_imported && !brasero_data_vfs_is_active (BRASERO_DATA_VFS (self))) {
622
 
                        gint64 size;
623
 
                        guint node_size;
624
 
 
625
 
                        size = brasero_data_project_get_size (BRASERO_DATA_PROJECT (self));
626
 
 
627
 
                        if (!node->is_file)
628
 
                                node_size = brasero_data_project_get_folder_size (BRASERO_DATA_PROJECT (self), node);
629
 
                        else
630
 
                                node_size = BRASERO_FILE_NODE_SECTORS (node);
631
 
                        if (size)
632
 
                                g_value_set_int (value, MAX (0, MIN (node_size * 100 / size, 100)));
633
 
                        else
634
 
                                g_value_set_int (value, 0);
635
 
                }
636
 
                else
637
 
                        g_value_set_int (value, 0);
638
 
 
639
 
                return;
640
 
 
641
 
        case BRASERO_DATA_TREE_MODEL_STYLE:
642
 
                g_value_init (value, PANGO_TYPE_STYLE);
643
 
                if (node->is_imported)
644
 
                        g_value_set_enum (value, PANGO_STYLE_ITALIC);
645
 
 
646
 
                return;
647
 
 
648
 
        case BRASERO_DATA_TREE_MODEL_COLOR:
649
 
                g_value_init (value, G_TYPE_STRING);
650
 
                if (node->is_imported)
651
 
                        g_value_set_string (value, "grey50");
652
 
 
653
 
                return;
654
 
 
655
 
        default:
656
 
                return;
657
 
        }
658
 
 
659
 
        return;
660
 
}
661
 
 
662
 
GtkTreePath *
663
 
brasero_data_tree_model_node_to_path (BraseroDataTreeModel *self,
664
 
                                      BraseroFileNode *node)
665
 
{
666
 
        BraseroDataTreeModelPrivate *priv;
667
 
        GtkTreePath *path;
668
 
 
669
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (self);
670
 
 
671
 
        path = gtk_tree_path_new ();
672
 
        for (; node->parent && !node->is_root; node = node->parent) {
673
 
                guint nth;
674
 
 
675
 
                nth = brasero_file_node_get_pos_as_child (node);
676
 
                gtk_tree_path_prepend_index (path, nth);
677
 
        }
678
 
 
679
 
        return path;
680
 
}
681
 
 
682
 
static GtkTreePath *
683
 
brasero_data_tree_model_get_path (GtkTreeModel *model,
684
 
                                  GtkTreeIter *iter)
685
 
{
686
 
        BraseroDataTreeModelPrivate *priv;
687
 
        BraseroFileNode *node;
688
 
        GtkTreePath *path;
689
 
 
690
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (model);
691
 
 
692
 
        /* make sure that iter comes from us */
693
 
        g_return_val_if_fail (priv->stamp == iter->stamp, NULL);
694
 
        g_return_val_if_fail (iter->user_data != NULL, NULL);
695
 
 
696
 
        node = iter->user_data;
697
 
 
698
 
        /* NOTE: there is only one single node without a name: root */
699
 
        path = brasero_data_tree_model_node_to_path (BRASERO_DATA_TREE_MODEL (model), node);
700
 
 
701
 
        /* Add index 0 for empty bogus row */
702
 
        if (iter->user_data2 == GINT_TO_POINTER (BRASERO_ROW_BOGUS))
703
 
                gtk_tree_path_append_index (path, 0);
704
 
 
705
 
        return path;
706
 
}
707
 
 
708
 
BraseroFileNode *
709
 
brasero_data_tree_model_path_to_node (BraseroDataTreeModel *self,
710
 
                                      GtkTreePath *path)
711
 
{
712
 
        BraseroDataTreeModelPrivate *priv;
713
 
        BraseroFileNode *node;
714
 
        gint *indices;
715
 
        guint depth;
716
 
        guint i;
717
 
 
718
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (self);
719
 
 
720
 
        indices = gtk_tree_path_get_indices (path);
721
 
        depth = gtk_tree_path_get_depth (path);
722
 
 
723
 
        node = brasero_data_project_get_root (BRASERO_DATA_PROJECT (self));
724
 
        for (i = 0; i < depth; i ++) {
725
 
                BraseroFileNode *parent;
726
 
 
727
 
                parent = node;
728
 
                node = brasero_file_node_nth_child (parent, indices [i]);
729
 
                if (!node)
730
 
                        return NULL;
731
 
        }
732
 
        return node;
733
 
}
734
 
 
735
 
static gboolean
736
 
brasero_data_tree_model_get_iter (GtkTreeModel *model,
737
 
                                  GtkTreeIter *iter,
738
 
                                  GtkTreePath *path)
739
 
{
740
 
        BraseroDataTreeModelPrivate *priv;
741
 
        BraseroFileNode *root;
742
 
        BraseroFileNode *node;
743
 
        const gint *indices;
744
 
        guint depth;
745
 
        guint i;
746
 
 
747
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (model);
748
 
 
749
 
        indices = gtk_tree_path_get_indices (path);
750
 
        depth = gtk_tree_path_get_depth (path);
751
 
 
752
 
        root = brasero_data_project_get_root (BRASERO_DATA_PROJECT (model));
753
 
        /* NOTE: if we're in reset, then root won't exist anymore */
754
 
        if (!root)
755
 
                return FALSE;
756
 
                
757
 
        node = brasero_file_node_nth_child (root, indices [0]);
758
 
        if (!node)
759
 
                return FALSE;
760
 
 
761
 
        for (i = 1; i < depth; i ++) {
762
 
                BraseroFileNode *parent;
763
 
 
764
 
                parent = node;
765
 
                node = brasero_file_node_nth_child (parent, indices [i]);
766
 
                if (!node) {
767
 
                        /* There is one case where this can happen and
768
 
                         * is allowed: that's when the parent is an
769
 
                         * empty directory. Then index must be 0. */
770
 
                        if (!parent->is_file
771
 
                        &&  !BRASERO_FILE_NODE_CHILDREN (parent)
772
 
                        &&   indices [i] == 0) {
773
 
                                iter->stamp = priv->stamp;
774
 
                                iter->user_data = parent;
775
 
                                iter->user_data2 = GINT_TO_POINTER (BRASERO_ROW_BOGUS);
776
 
                                return TRUE;
777
 
                        }
778
 
 
779
 
                        iter->user_data = NULL;
780
 
                        return FALSE;
781
 
                }
782
 
        }
783
 
 
784
 
        iter->user_data2 = GINT_TO_POINTER (BRASERO_ROW_REGULAR);
785
 
        iter->stamp = priv->stamp;
786
 
        iter->user_data = node;
787
 
 
788
 
        return TRUE;
789
 
}
790
 
 
791
 
static GType
792
 
brasero_data_tree_model_get_column_type (GtkTreeModel *model,
793
 
                                         gint index)
794
 
{
795
 
        switch (index) {
796
 
        case BRASERO_DATA_TREE_MODEL_NAME:
797
 
                return G_TYPE_STRING;
798
 
 
799
 
        case BRASERO_DATA_TREE_MODEL_MIME_DESC:
800
 
                return G_TYPE_STRING;
801
 
 
802
 
        case BRASERO_DATA_TREE_MODEL_MIME_ICON:
803
 
                return G_TYPE_STRING;
804
 
 
805
 
        case BRASERO_DATA_TREE_MODEL_SIZE:
806
 
                return G_TYPE_STRING;
807
 
 
808
 
        case BRASERO_DATA_TREE_MODEL_SHOW_PERCENT:
809
 
                return G_TYPE_BOOLEAN;
810
 
 
811
 
        case BRASERO_DATA_TREE_MODEL_PERCENT:
812
 
                return G_TYPE_INT;
813
 
 
814
 
        case BRASERO_DATA_TREE_MODEL_STYLE:
815
 
                return PANGO_TYPE_STYLE;
816
 
 
817
 
        case BRASERO_DATA_TREE_MODEL_COLOR:
818
 
                return G_TYPE_STRING;
819
 
 
820
 
        case BRASERO_DATA_TREE_MODEL_EDITABLE:
821
 
                return G_TYPE_BOOLEAN;
822
 
 
823
 
        default:
824
 
                break;
825
 
        }
826
 
 
827
 
        return G_TYPE_INVALID;
828
 
}
829
 
 
830
 
static gint
831
 
brasero_data_tree_model_get_n_columns (GtkTreeModel *model)
832
 
{
833
 
        return BRASERO_DATA_TREE_MODEL_COL_NUM;
834
 
}
835
 
 
836
 
static GtkTreeModelFlags
837
 
brasero_data_tree_model_get_flags (GtkTreeModel *model)
838
 
{
839
 
        return 0;
840
 
}
841
 
 
842
 
static gboolean
843
 
brasero_data_tree_model_multi_row_draggable (EggTreeMultiDragSource *drag_source,
844
 
                                             GList *path_list)
845
 
{
846
 
        GList *iter;
847
 
 
848
 
        for (iter = path_list; iter && iter->data; iter = iter->next) {
849
 
                GtkTreeRowReference *reference;
850
 
                BraseroFileNode *node;
851
 
                GtkTreePath *treepath;
852
 
 
853
 
                reference = iter->data;
854
 
                treepath = gtk_tree_row_reference_get_path (reference);
855
 
                node = brasero_data_tree_model_path_to_node (BRASERO_DATA_TREE_MODEL (drag_source), treepath);
856
 
                gtk_tree_path_free (treepath);
857
 
 
858
 
                /* at least one row must not be an imported row. */
859
 
                if (node && !node->is_imported)
860
 
                        return TRUE;
861
 
        }
862
 
 
863
 
        return FALSE;
864
 
}
865
 
 
866
 
static gboolean
867
 
brasero_data_tree_model_multi_drag_data_get (EggTreeMultiDragSource *drag_source,
868
 
                                             GList *path_list,
869
 
                                             GtkSelectionData *selection_data)
870
 
{
871
 
        if (selection_data->target == gdk_atom_intern (BRASERO_DND_TARGET_SELF_FILE_NODES, TRUE)) {
872
 
                BraseroDNDDataContext context;
873
 
 
874
 
                context.model = GTK_TREE_MODEL (drag_source);
875
 
                context.references = path_list;
876
 
 
877
 
                gtk_selection_data_set (selection_data,
878
 
                                        gdk_atom_intern_static_string (BRASERO_DND_TARGET_SELF_FILE_NODES),
879
 
                                        8,
880
 
                                        (void *) &context,
881
 
                                        sizeof (context));
882
 
        }
883
 
        else
884
 
                return FALSE;
885
 
 
886
 
        return TRUE;
887
 
}
888
 
 
889
 
static gboolean
890
 
brasero_data_tree_model_multi_drag_data_delete (EggTreeMultiDragSource *drag_source,
891
 
                                                GList *path_list)
892
 
{
893
 
        /* NOTE: it's not the data in the selection_data here that should be
894
 
         * deleted but rather the rows selected when there is a move. FALSE
895
 
         * here means that we didn't delete anything. */
896
 
        /* return TRUE to stop other handlers */
897
 
        return TRUE;
898
 
}
899
 
 
900
 
static gboolean
901
 
brasero_data_tree_model_drag_data_received (GtkTreeDragDest *drag_dest,
902
 
                                            GtkTreePath *dest_path,
903
 
                                            GtkSelectionData *selection_data)
904
 
{
905
 
        BraseroFileNode *node;
906
 
        BraseroFileNode *parent;
907
 
        GtkTreePath *dest_parent;
908
 
        BraseroDataTreeModel *self;
909
 
 
910
 
        self = BRASERO_DATA_TREE_MODEL (drag_dest);
911
 
 
912
 
        /* NOTE: dest_path is the path to insert before; so we may not have a 
913
 
         * valid path if it's in an empty directory */
914
 
 
915
 
        dest_parent = gtk_tree_path_copy (dest_path);
916
 
        gtk_tree_path_up (dest_parent);
917
 
        parent = brasero_data_tree_model_path_to_node (self, dest_parent);
918
 
        if (!parent) {
919
 
                gtk_tree_path_up (dest_parent);
920
 
                parent = brasero_data_tree_model_path_to_node (self, dest_parent);
921
 
        }
922
 
        else if (parent->is_file)
923
 
                parent = parent->parent;
924
 
 
925
 
        gtk_tree_path_free (dest_parent);
926
 
 
927
 
        /* Received data: see where it comes from:
928
 
         * - from us, then that's a simple move
929
 
         * - from another widget then it's going to be URIS and we add
930
 
         *   them to the DataProject */
931
 
        if (selection_data->target == gdk_atom_intern (BRASERO_DND_TARGET_SELF_FILE_NODES, TRUE)) {
932
 
                BraseroDNDDataContext *context;
933
 
                GList *iter;
934
 
 
935
 
                context = (BraseroDNDDataContext *) selection_data->data;
936
 
                if (context->model != GTK_TREE_MODEL (drag_dest))
937
 
                        return TRUE;
938
 
 
939
 
                /* That's us: move the row and its children. */
940
 
                for (iter = context->references; iter; iter = iter->next) {
941
 
                        GtkTreeRowReference *reference;
942
 
                        GtkTreePath *treepath;
943
 
 
944
 
                        reference = iter->data;
945
 
                        treepath = gtk_tree_row_reference_get_path (reference);
946
 
 
947
 
                        node = brasero_data_tree_model_path_to_node (BRASERO_DATA_TREE_MODEL (drag_dest), treepath);
948
 
                        gtk_tree_path_free (treepath);
949
 
 
950
 
                        brasero_data_project_move_node (BRASERO_DATA_PROJECT (self), node, parent);
951
 
                }
952
 
        }
953
 
        else if (selection_data->target == gdk_atom_intern ("text/uri-list", TRUE)) {
954
 
                gint i;
955
 
                gchar **uris;
956
 
                gboolean success = FALSE;
957
 
 
958
 
                /* NOTE: there can be many URIs at the same time. One
959
 
                 * success is enough to return TRUE. */
960
 
                success = FALSE;
961
 
                uris = gtk_selection_data_get_uris (selection_data);
962
 
                if (!uris)
963
 
                        return TRUE;
964
 
 
965
 
                for (i = 0; uris [i]; i ++) {
966
 
                        BraseroFileNode *node;
967
 
 
968
 
                        /* Add the URIs to the project */
969
 
                        node = brasero_data_project_add_loading_node (BRASERO_DATA_PROJECT (self),
970
 
                                                                      uris [i],
971
 
                                                                      parent);
972
 
                        if (node)
973
 
                                success = TRUE;
974
 
                }
975
 
                g_strfreev (uris);
976
 
        }
977
 
        else
978
 
                return FALSE;
979
 
 
980
 
        return TRUE;
981
 
}
982
 
 
983
 
static gboolean
984
 
brasero_data_tree_model_row_drop_possible (GtkTreeDragDest *drag_dest,
985
 
                                           GtkTreePath *dest_path,
986
 
                                           GtkSelectionData *selection_data)
987
 
{
988
 
        /* See if we are dropping to ourselves */
989
 
        if (selection_data->target == gdk_atom_intern_static_string (BRASERO_DND_TARGET_SELF_FILE_NODES)) {
990
 
                BraseroDNDDataContext *context;
991
 
                GtkTreePath *dest_parent;
992
 
                BraseroFileNode *parent;
993
 
                GList *iter;
994
 
 
995
 
                context = (BraseroDNDDataContext *) selection_data->data;
996
 
                if (context->model != GTK_TREE_MODEL (drag_dest))
997
 
                        return FALSE;
998
 
 
999
 
                /* make sure the parent is a directory.
1000
 
                 * NOTE: in this case dest_path is the exact path where it
1001
 
                 * should be inserted. */
1002
 
                dest_parent = gtk_tree_path_copy (dest_path);
1003
 
                gtk_tree_path_up (dest_parent);
1004
 
 
1005
 
                parent = brasero_data_tree_model_path_to_node (BRASERO_DATA_TREE_MODEL (drag_dest), dest_parent);
1006
 
 
1007
 
                if (!parent) {
1008
 
                        /* See if that isn't a BOGUS row; if so, try with parent */
1009
 
                        gtk_tree_path_up (dest_parent);
1010
 
                        parent = brasero_data_tree_model_path_to_node (BRASERO_DATA_TREE_MODEL (drag_dest), dest_parent);
1011
 
 
1012
 
                        if (!parent) {
1013
 
                                gtk_tree_path_free (dest_parent);
1014
 
                                return FALSE;
1015
 
                        }
1016
 
                }
1017
 
                else if (parent->is_file) {
1018
 
                        /* if that's a file try with parent */
1019
 
                        gtk_tree_path_up (dest_parent);
1020
 
                        parent = parent->parent;
1021
 
                }
1022
 
 
1023
 
                if (parent->is_loading) {
1024
 
                        gtk_tree_path_free (dest_parent);
1025
 
                        return FALSE;
1026
 
                }
1027
 
 
1028
 
                for (iter = context->references; iter; iter = iter->next) {
1029
 
                        GtkTreePath *src_path;
1030
 
                        GtkTreeRowReference *reference;
1031
 
 
1032
 
                        reference = iter->data;
1033
 
                        src_path = gtk_tree_row_reference_get_path (reference);
1034
 
 
1035
 
                        /* see if we are not moving a parent to one of its children */
1036
 
                        if (gtk_tree_path_is_ancestor (src_path, dest_path)) {
1037
 
                                gtk_tree_path_free (src_path);
1038
 
                                continue;
1039
 
                        }
1040
 
 
1041
 
                        if (gtk_tree_path_up (src_path)) {
1042
 
                                /* check that node was moved to another directory */
1043
 
                                if (!parent->parent) {
1044
 
                                        if (gtk_tree_path_get_depth (src_path)) {
1045
 
                                                gtk_tree_path_free (src_path);
1046
 
                                                gtk_tree_path_free (dest_parent);
1047
 
                                                return TRUE;
1048
 
                                        }
1049
 
                                }
1050
 
                                else if (!gtk_tree_path_get_depth (src_path)
1051
 
                                     ||   gtk_tree_path_compare (src_path, dest_parent)) {
1052
 
                                        gtk_tree_path_free (src_path);
1053
 
                                        gtk_tree_path_free (dest_parent);
1054
 
                                        return TRUE;
1055
 
                                }
1056
 
                        }
1057
 
 
1058
 
                        gtk_tree_path_free (src_path);
1059
 
                }
1060
 
 
1061
 
                gtk_tree_path_free (dest_parent);
1062
 
                return FALSE;
1063
 
        }
1064
 
        else if (selection_data->target == gdk_atom_intern_static_string ("text/uri-list"))
1065
 
                return TRUE;
1066
 
 
1067
 
        return FALSE;
1068
 
}
1069
 
 
1070
 
static gboolean
1071
 
brasero_data_tree_model_drag_data_delete (GtkTreeDragSource *source,
1072
 
                                          GtkTreePath *treepath)
1073
 
{
1074
 
        return TRUE;
1075
 
}
1076
 
 
1077
 
/**
1078
 
 * Sorting part
1079
 
 */
1080
 
static gboolean
1081
 
brasero_data_tree_model_get_sort_column_id (GtkTreeSortable *sortable,
1082
 
                                            gint *column,
1083
 
                                            GtkSortType *type)
1084
 
{
1085
 
        BraseroDataTreeModelPrivate *priv;
1086
 
 
1087
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (sortable);
1088
 
 
1089
 
        if (column)
1090
 
                *column = priv->sort_column;
1091
 
 
1092
 
        if (type)
1093
 
                *type = priv->sort_type;
1094
 
 
1095
 
        return TRUE;
1096
 
}
1097
 
 
1098
 
static void
1099
 
brasero_data_tree_model_set_sort_column_id (GtkTreeSortable *sortable,
1100
 
                                            gint column,
1101
 
                                            GtkSortType type)
1102
 
{
1103
 
        BraseroDataTreeModelPrivate *priv;
1104
 
 
1105
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (sortable);
1106
 
        priv->sort_column = column;
1107
 
        priv->sort_type = type;
1108
 
 
1109
 
        switch (column) {
1110
 
        case BRASERO_DATA_TREE_MODEL_NAME:
1111
 
                brasero_data_project_set_sort_function (BRASERO_DATA_PROJECT (sortable),
1112
 
                                                        type,
1113
 
                                                        brasero_file_node_sort_name_cb);
1114
 
                break;
1115
 
        case BRASERO_DATA_TREE_MODEL_SIZE:
1116
 
                brasero_data_project_set_sort_function (BRASERO_DATA_PROJECT (sortable),
1117
 
                                                        type,
1118
 
                                                        brasero_file_node_sort_size_cb);
1119
 
                break;
1120
 
        case BRASERO_DATA_TREE_MODEL_MIME_DESC:
1121
 
                brasero_data_project_set_sort_function (BRASERO_DATA_PROJECT (sortable),
1122
 
                                                        type,
1123
 
                                                        brasero_file_node_sort_mime_cb);
1124
 
                break;
1125
 
        default:
1126
 
                brasero_data_project_set_sort_function (BRASERO_DATA_PROJECT (sortable),
1127
 
                                                        type,
1128
 
                                                        brasero_file_node_sort_default_cb);
1129
 
                break;
1130
 
        }
1131
 
 
1132
 
        gtk_tree_sortable_sort_column_changed (sortable);
1133
 
}
1134
 
 
1135
 
static gboolean
1136
 
brasero_data_tree_model_has_default_sort_func (GtkTreeSortable *sortable)
1137
 
{
1138
 
        /* That's always true since we sort files and directories */
1139
 
        return TRUE;
1140
 
}
1141
 
 
1142
 
static void
1143
 
brasero_data_tree_model_clear (BraseroDataTreeModel *self, 
1144
 
                               guint num_nodes)
1145
 
{
1146
 
        guint i;
1147
 
        GtkTreePath *treepath;
1148
 
        BraseroDataTreeModelPrivate *priv;
1149
 
 
1150
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (self);
1151
 
        if (priv->shown) {
1152
 
                g_slist_free (priv->shown);
1153
 
                priv->shown = NULL;
1154
 
        }
1155
 
 
1156
 
        /* NOTE: no need to move to the next row since previous one was deleted */
1157
 
        treepath = gtk_tree_path_new_first ();
1158
 
        for (i = 0; i < num_nodes; i ++)
1159
 
                gtk_tree_model_row_deleted (GTK_TREE_MODEL (self), treepath);
1160
 
 
1161
 
        gtk_tree_path_free (treepath);
1162
 
}
1163
 
 
1164
 
static void
1165
 
brasero_data_tree_model_reset (BraseroDataProject *project,
1166
 
                               guint num_nodes)
1167
 
{
1168
 
        brasero_data_tree_model_clear (BRASERO_DATA_TREE_MODEL (project), num_nodes);
1169
 
 
1170
 
        /* chain up this function except if we invalidated the node */
1171
 
        if (BRASERO_DATA_PROJECT_CLASS (brasero_data_tree_model_parent_class)->reset)
1172
 
                BRASERO_DATA_PROJECT_CLASS (brasero_data_tree_model_parent_class)->reset (project, num_nodes);
1173
 
}
1174
 
 
1175
 
static gboolean
1176
 
brasero_data_tree_model_node_added (BraseroDataProject *project,
1177
 
                                    BraseroFileNode *node,
1178
 
                                    const gchar *uri)
1179
 
{
1180
 
        BraseroDataTreeModelPrivate *priv;
1181
 
        BraseroFileNode *parent;
1182
 
        GtkTreePath *path;
1183
 
        GtkTreeIter iter;
1184
 
 
1185
 
        /* see if we really need to tell the treeview we changed */
1186
 
        if (node->parent
1187
 
        && !node->parent->is_root
1188
 
        && !node->parent->is_visible)
1189
 
                goto end;
1190
 
 
1191
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (project);
1192
 
 
1193
 
        iter.stamp = priv->stamp;
1194
 
        iter.user_data = node;
1195
 
        iter.user_data2 = GINT_TO_POINTER (BRASERO_ROW_REGULAR);
1196
 
 
1197
 
        path = brasero_data_tree_model_node_to_path (BRASERO_DATA_TREE_MODEL (project), node);
1198
 
 
1199
 
        /* if the node is reloading (because of a file system change or because
1200
 
         * it was a node that was a tmp folder) then no need to signal an added
1201
 
         * signal but a changed one */
1202
 
        if (node->is_reloading) {
1203
 
                gtk_tree_model_row_changed (GTK_TREE_MODEL (project), path, &iter);
1204
 
                gtk_tree_path_free (path);
1205
 
                goto end;
1206
 
        }
1207
 
 
1208
 
        /* Add the row itself */
1209
 
        /* This is a workaround for a warning in gailtreeview.c line 2946 where
1210
 
         * gail uses the GtkTreePath and not a copy which if the node inserted
1211
 
         * declares to have children and is not expanded leads to the path being
1212
 
         * upped and therefore wrong. */
1213
 
        node->is_inserting = 1;
1214
 
        gtk_tree_model_row_inserted (GTK_TREE_MODEL (project),
1215
 
                                     path,
1216
 
                                     &iter);
1217
 
        node->is_inserting = 0;
1218
 
        gtk_tree_path_free (path);
1219
 
 
1220
 
        parent = node->parent;
1221
 
        if (!parent->is_root) {
1222
 
                /* Tell the tree that the parent changed (since the number of children
1223
 
                 * changed as well). */
1224
 
                iter.user_data = parent;
1225
 
                path = brasero_data_tree_model_node_to_path (BRASERO_DATA_TREE_MODEL (project), parent);
1226
 
 
1227
 
                gtk_tree_model_row_changed (GTK_TREE_MODEL (project), path, &iter);
1228
 
 
1229
 
                /* Check if the parent of this node is empty if so remove the BOGUS row.
1230
 
                 * Do it afterwards to prevent the parent row to be collapsed if it was
1231
 
                 * previously expanded. */
1232
 
                if (parent && brasero_file_node_get_n_children (parent) == 1) {
1233
 
                        gtk_tree_path_append_index (path, 1);
1234
 
                        gtk_tree_model_row_deleted (GTK_TREE_MODEL (project), path);
1235
 
                }
1236
 
 
1237
 
                gtk_tree_path_free (path);
1238
 
        }
1239
 
 
1240
 
        /* Now see if this is a directory which is empty and needs a BOGUS */
1241
 
        if (!node->is_file && !node->is_loading) {
1242
 
                /* emit child-toggled. Thanks to bogus rows we only need to emit
1243
 
                 * this signal once since a directory will always have a child
1244
 
                 * in the tree */
1245
 
                path = brasero_data_tree_model_node_to_path (BRASERO_DATA_TREE_MODEL (project), node);
1246
 
                gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (project), path, &iter);
1247
 
                gtk_tree_path_free (path);
1248
 
        }
1249
 
 
1250
 
        /* we also have to set the is_visible property as all nodes added to 
1251
 
         * root are always visible but ref_node is not necessarily called on
1252
 
         * these nodes. */
1253
 
//      if (parent->is_root)
1254
 
//              node->is_visible = TRUE;
1255
 
 
1256
 
end:
1257
 
        /* chain up this function */
1258
 
        if (BRASERO_DATA_PROJECT_CLASS (brasero_data_tree_model_parent_class)->node_added)
1259
 
                return BRASERO_DATA_PROJECT_CLASS (brasero_data_tree_model_parent_class)->node_added (project, node, uri);
1260
 
 
1261
 
        return TRUE;
1262
 
}
1263
 
 
1264
 
static void
1265
 
brasero_data_tree_model_node_removed (BraseroDataProject *project,
1266
 
                                      BraseroFileNode *former_parent,
1267
 
                                      guint former_position,
1268
 
                                      BraseroFileNode *node)
1269
 
{
1270
 
        BraseroDataTreeModelPrivate *priv;
1271
 
        GSList *iter, *next;
1272
 
        GtkTreePath *path;
1273
 
 
1274
 
        /* see if we really need to tell the treeview we changed */
1275
 
        if (!node->is_visible
1276
 
        &&   former_parent
1277
 
        &&  !former_parent->is_root
1278
 
        &&  !former_parent->is_visible)
1279
 
                goto end;
1280
 
 
1281
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (project);
1282
 
 
1283
 
        /* remove it from the shown list and all its children as well */
1284
 
        priv->shown = g_slist_remove (priv->shown, node);
1285
 
        for (iter = priv->shown; iter; iter = next) {
1286
 
                BraseroFileNode *tmp;
1287
 
 
1288
 
                tmp = iter->data;
1289
 
                next = iter->next;
1290
 
                if (brasero_file_node_is_ancestor (node, tmp))
1291
 
                        priv->shown = g_slist_remove (priv->shown, tmp);
1292
 
        }
1293
 
 
1294
 
        /* See if the parent of this node still has children. If not we need to
1295
 
         * add a bogus row. If it hasn't got children then it only remains our
1296
 
         * node in the list.
1297
 
         * NOTE: parent has to be a directory. */
1298
 
        if (!former_parent->is_root && !BRASERO_FILE_NODE_CHILDREN (former_parent)) {
1299
 
                GtkTreeIter iter;
1300
 
 
1301
 
                iter.stamp = priv->stamp;
1302
 
                iter.user_data = former_parent;
1303
 
                iter.user_data2 = GINT_TO_POINTER (BRASERO_ROW_BOGUS);
1304
 
 
1305
 
                path = brasero_data_tree_model_node_to_path (BRASERO_DATA_TREE_MODEL (project), former_parent);
1306
 
                gtk_tree_path_append_index (path, 1);
1307
 
 
1308
 
                gtk_tree_model_row_inserted (GTK_TREE_MODEL (project), path, &iter);
1309
 
                gtk_tree_path_free (path);
1310
 
        }
1311
 
 
1312
 
        /* remove the node. Do it after adding a possible BOGUS row.
1313
 
         * NOTE since BOGUS row has been added move row. */
1314
 
        path = brasero_data_tree_model_node_to_path (BRASERO_DATA_TREE_MODEL (project), former_parent);
1315
 
        gtk_tree_path_append_index (path, former_position);
1316
 
 
1317
 
        gtk_tree_model_row_deleted (GTK_TREE_MODEL (project), path);
1318
 
        gtk_tree_path_free (path);
1319
 
 
1320
 
end:
1321
 
        /* chain up this function */
1322
 
        if (BRASERO_DATA_PROJECT_CLASS (brasero_data_tree_model_parent_class)->node_removed)
1323
 
                BRASERO_DATA_PROJECT_CLASS (brasero_data_tree_model_parent_class)->node_removed (project,
1324
 
                                                                                                 former_parent,
1325
 
                                                                                                 former_position,
1326
 
                                                                                                 node);
1327
 
}
1328
 
 
1329
 
static void
1330
 
brasero_data_tree_model_node_changed (BraseroDataProject *project,
1331
 
                                      BraseroFileNode *node)
1332
 
{
1333
 
        BraseroDataTreeModelPrivate *priv;
1334
 
        GtkTreePath *path;
1335
 
        GtkTreeIter iter;
1336
 
 
1337
 
        /* see if we really need to tell the treeview we changed */
1338
 
        if (node->parent
1339
 
        && !node->parent->is_root
1340
 
        && !node->parent->is_visible)
1341
 
                goto end;
1342
 
 
1343
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (project);
1344
 
 
1345
 
        /* Get the iter for the node */
1346
 
        iter.stamp = priv->stamp;
1347
 
        iter.user_data = node;
1348
 
        iter.user_data2 = GINT_TO_POINTER (BRASERO_ROW_REGULAR);
1349
 
 
1350
 
        path = brasero_data_tree_model_node_to_path (BRASERO_DATA_TREE_MODEL (project), node);
1351
 
        gtk_tree_model_row_changed (GTK_TREE_MODEL (project),
1352
 
                                    path,
1353
 
                                    &iter);
1354
 
 
1355
 
        /* Now see if this is a directory which is empty and needs a BOGUS */
1356
 
        if (!node->is_file) {
1357
 
                /* NOTE: No need to check for the number of children ... */
1358
 
 
1359
 
                /* emit child-toggled. Thanks to bogus rows we only need to emit
1360
 
                 * this signal once since a directory will always have a child
1361
 
                 * in the tree */
1362
 
                gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (project),
1363
 
                                                      path,
1364
 
                                                      &iter);
1365
 
 
1366
 
                /* The problem is that without that, the folder contents on disc
1367
 
                 * won't be added to the tree if the node it replaced was
1368
 
                 * already visible. */
1369
 
                if (node->is_imported
1370
 
                &&  node->is_visible
1371
 
                &&  node->is_fake)
1372
 
                        brasero_data_session_load_directory_contents (BRASERO_DATA_SESSION (project),
1373
 
                                                                      node,
1374
 
                                                                      NULL);
1375
 
 
1376
 
                /* add the row */
1377
 
                if (!BRASERO_FILE_NODE_CHILDREN (node))  {
1378
 
                        iter.user_data2 = GINT_TO_POINTER (BRASERO_ROW_BOGUS);
1379
 
                        gtk_tree_path_append_index (path, 0);
1380
 
 
1381
 
                        gtk_tree_model_row_inserted (GTK_TREE_MODEL (project),
1382
 
                                                     path,
1383
 
                                                     &iter);
1384
 
                }
1385
 
        }
1386
 
        gtk_tree_path_free (path);
1387
 
 
1388
 
end:
1389
 
        /* chain up this function */
1390
 
        if (BRASERO_DATA_PROJECT_CLASS (brasero_data_tree_model_parent_class)->node_changed)
1391
 
                BRASERO_DATA_PROJECT_CLASS (brasero_data_tree_model_parent_class)->node_changed (project, node);
1392
 
}
1393
 
 
1394
 
static void
1395
 
brasero_data_tree_model_node_reordered (BraseroDataProject *project,
1396
 
                                        BraseroFileNode *parent,
1397
 
                                        gint *new_order)
1398
 
{
1399
 
        GtkTreePath *treepath;
1400
 
        BraseroDataTreeModelPrivate *priv;
1401
 
 
1402
 
        /* see if we really need to tell the treeview we changed */
1403
 
        if (!parent->is_root
1404
 
        &&  !parent->is_visible)
1405
 
                goto end;
1406
 
 
1407
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (project);
1408
 
 
1409
 
        treepath = brasero_data_tree_model_node_to_path (BRASERO_DATA_TREE_MODEL (project), parent);
1410
 
        if (parent != brasero_data_project_get_root (project)) {
1411
 
                GtkTreeIter iter;
1412
 
 
1413
 
                iter.stamp = priv->stamp;
1414
 
                iter.user_data = parent;
1415
 
                iter.user_data2 = GINT_TO_POINTER (BRASERO_ROW_REGULAR);
1416
 
 
1417
 
                gtk_tree_model_rows_reordered (GTK_TREE_MODEL (project),
1418
 
                                               treepath,
1419
 
                                               &iter,
1420
 
                                               new_order);
1421
 
        }
1422
 
        else
1423
 
                gtk_tree_model_rows_reordered (GTK_TREE_MODEL (project),
1424
 
                                               treepath,
1425
 
                                               NULL,
1426
 
                                               new_order);
1427
 
 
1428
 
        gtk_tree_path_free (treepath);
1429
 
 
1430
 
end:
1431
 
        /* chain up this function */
1432
 
        if (BRASERO_DATA_PROJECT_CLASS (brasero_data_tree_model_parent_class)->node_reordered)
1433
 
                BRASERO_DATA_PROJECT_CLASS (brasero_data_tree_model_parent_class)->node_reordered (project, parent, new_order);
1434
 
}
1435
 
 
1436
 
static void
1437
 
brasero_data_tree_model_activity_changed (BraseroDataVFS *vfs,
1438
 
                                          gboolean active)
1439
 
{
1440
 
        GtkTreeIter iter;
1441
 
        GSList *nodes;
1442
 
        BraseroDataTreeModelPrivate *priv;
1443
 
 
1444
 
        if (brasero_data_vfs_is_active (vfs))
1445
 
                return;
1446
 
 
1447
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (vfs);
1448
 
 
1449
 
        iter.stamp = priv->stamp;
1450
 
        iter.user_data2 = GINT_TO_POINTER (BRASERO_ROW_REGULAR);
1451
 
 
1452
 
        /* NOTE: we shouldn't need to use reference here as unref_node is used */
1453
 
        for (nodes = priv->shown; nodes; nodes = nodes->next) {
1454
 
                GtkTreePath *treepath;
1455
 
 
1456
 
                iter.user_data = nodes->data;
1457
 
                treepath = brasero_data_tree_model_node_to_path (BRASERO_DATA_TREE_MODEL (vfs), nodes->data);
1458
 
 
1459
 
                gtk_tree_model_row_changed (GTK_TREE_MODEL (vfs), treepath, &iter);
1460
 
                gtk_tree_path_free (treepath);
1461
 
        }
1462
 
 
1463
 
        /* chain up this function */
1464
 
        if (BRASERO_DATA_VFS_CLASS (brasero_data_tree_model_parent_class)->activity_changed)
1465
 
                BRASERO_DATA_VFS_CLASS (brasero_data_tree_model_parent_class)->activity_changed (vfs, active);
1466
 
}
1467
 
 
1468
 
static void
1469
 
brasero_data_tree_model_init (BraseroDataTreeModel *object)
1470
 
{
1471
 
        BraseroDataTreeModelPrivate *priv;
1472
 
 
1473
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (object);
1474
 
 
1475
 
        priv->sort_column = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
1476
 
        do {
1477
 
                priv->stamp = g_random_int ();
1478
 
        } while (!priv->stamp);
1479
 
 
1480
 
        priv->theme = gtk_icon_theme_get_default ();
1481
 
}
1482
 
 
1483
 
static void
1484
 
brasero_data_tree_model_finalize (GObject *object)
1485
 
{
1486
 
        BraseroDataTreeModelPrivate *priv;
1487
 
 
1488
 
        priv = BRASERO_DATA_TREE_MODEL_PRIVATE (object);
1489
 
 
1490
 
        if (priv->shown) {
1491
 
                g_slist_free (priv->shown);
1492
 
                priv->shown = NULL;
1493
 
        }
1494
 
 
1495
 
        G_OBJECT_CLASS (brasero_data_tree_model_parent_class)->finalize (object);
1496
 
}
1497
 
 
1498
 
static void
1499
 
brasero_data_tree_model_iface_init (gpointer g_iface, gpointer data)
1500
 
{
1501
 
        GtkTreeModelIface *iface = g_iface;
1502
 
        static gboolean initialized = FALSE;
1503
 
 
1504
 
        if (initialized)
1505
 
                return;
1506
 
 
1507
 
        initialized = TRUE;
1508
 
 
1509
 
        iface->ref_node = brasero_data_tree_model_node_shown;
1510
 
        iface->unref_node = brasero_data_tree_model_node_hidden;
1511
 
 
1512
 
        iface->get_flags = brasero_data_tree_model_get_flags;
1513
 
        iface->get_n_columns = brasero_data_tree_model_get_n_columns;
1514
 
        iface->get_column_type = brasero_data_tree_model_get_column_type;
1515
 
        iface->get_iter = brasero_data_tree_model_get_iter;
1516
 
        iface->get_path = brasero_data_tree_model_get_path;
1517
 
        iface->get_value = brasero_data_tree_model_get_value;
1518
 
        iface->iter_next = brasero_data_tree_model_iter_next;
1519
 
        iface->iter_children = brasero_data_tree_model_iter_children;
1520
 
        iface->iter_has_child = brasero_data_tree_model_iter_has_child;
1521
 
        iface->iter_n_children = brasero_data_tree_model_iter_n_children;
1522
 
        iface->iter_nth_child = brasero_data_tree_model_iter_nth_child;
1523
 
        iface->iter_parent = brasero_data_tree_model_iter_parent;
1524
 
}
1525
 
 
1526
 
static void
1527
 
brasero_data_tree_model_multi_drag_source_iface_init (gpointer g_iface, gpointer data)
1528
 
{
1529
 
        EggTreeMultiDragSourceIface *iface = g_iface;
1530
 
        static gboolean initialized = FALSE;
1531
 
 
1532
 
        if (initialized)
1533
 
                return;
1534
 
 
1535
 
        initialized = TRUE;
1536
 
 
1537
 
        iface->row_draggable = brasero_data_tree_model_multi_row_draggable;
1538
 
        iface->drag_data_get = brasero_data_tree_model_multi_drag_data_get;
1539
 
        iface->drag_data_delete = brasero_data_tree_model_multi_drag_data_delete;
1540
 
}
1541
 
 
1542
 
static void
1543
 
brasero_data_tree_model_drag_source_iface_init (gpointer g_iface, gpointer data)
1544
 
{
1545
 
        GtkTreeDragSourceIface *iface = g_iface;
1546
 
        static gboolean initialized = FALSE;
1547
 
 
1548
 
        if (initialized)
1549
 
                return;
1550
 
 
1551
 
        initialized = TRUE;
1552
 
 
1553
 
        iface->drag_data_delete = brasero_data_tree_model_drag_data_delete;
1554
 
}
1555
 
 
1556
 
static void
1557
 
brasero_data_tree_model_drag_dest_iface_init (gpointer g_iface, gpointer data)
1558
 
{
1559
 
        GtkTreeDragDestIface *iface = g_iface;
1560
 
        static gboolean initialized = FALSE;
1561
 
 
1562
 
        if (initialized)
1563
 
                return;
1564
 
 
1565
 
        initialized = TRUE;
1566
 
 
1567
 
        iface->drag_data_received = brasero_data_tree_model_drag_data_received;
1568
 
        iface->row_drop_possible = brasero_data_tree_model_row_drop_possible;
1569
 
}
1570
 
 
1571
 
static void
1572
 
brasero_data_tree_model_sortable_iface_init (gpointer g_iface, gpointer data)
1573
 
{
1574
 
        GtkTreeSortableIface *iface = g_iface;
1575
 
        static gboolean initialized = FALSE;
1576
 
 
1577
 
        if (initialized)
1578
 
                return;
1579
 
 
1580
 
        initialized = TRUE;
1581
 
 
1582
 
        iface->get_sort_column_id = brasero_data_tree_model_get_sort_column_id;
1583
 
        iface->set_sort_column_id = brasero_data_tree_model_set_sort_column_id;
1584
 
        iface->has_default_sort_func = brasero_data_tree_model_has_default_sort_func;
1585
 
}
1586
 
 
1587
 
static void
1588
 
brasero_data_tree_model_class_init (BraseroDataTreeModelClass *klass)
1589
 
{
1590
 
        GObjectClass* object_class = G_OBJECT_CLASS (klass);
1591
 
        BraseroDataVFSClass *vfs_class = BRASERO_DATA_VFS_CLASS (klass);
1592
 
        BraseroDataProjectClass *data_project_class = BRASERO_DATA_PROJECT_CLASS (klass);
1593
 
 
1594
 
        g_type_class_add_private (klass, sizeof (BraseroDataTreeModelPrivate));
1595
 
 
1596
 
        object_class->finalize = brasero_data_tree_model_finalize;
1597
 
 
1598
 
        vfs_class->activity_changed = brasero_data_tree_model_activity_changed;
1599
 
 
1600
 
        data_project_class->reset = brasero_data_tree_model_reset;
1601
 
        data_project_class->node_added = brasero_data_tree_model_node_added;
1602
 
        data_project_class->node_removed = brasero_data_tree_model_node_removed;
1603
 
        data_project_class->node_changed = brasero_data_tree_model_node_changed;
1604
 
        data_project_class->node_reordered = brasero_data_tree_model_node_reordered;
1605
 
}
1606
 
 
1607
 
BraseroDataTreeModel *
1608
 
brasero_data_tree_model_new (void)
1609
 
{
1610
 
        return g_object_new (BRASERO_TYPE_DATA_TREE_MODEL, NULL);
1611
 
}