~ubuntu-branches/ubuntu/karmic/gnome-disk-utility/karmic

« back to all changes in this revision

Viewing changes to src/palimpsest/gdu-tree.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-02 23:33:14 UTC
  • Revision ID: james.westby@ubuntu.com-20090302233314-6t4zbyzvpqxs2v96
Tags: upstream-0.3
ImportĀ upstreamĀ versionĀ 0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
 
2
/* gdu-tree.c
 
3
 *
 
4
 * Copyright (C) 2007 David Zeuthen
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public License
 
8
 * as published by the Free Software Foundation; either version 2 of
 
9
 * the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful, but
 
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Lesser General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with this library; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
19
 * 02111-1307, USA.
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
#include <glib/gi18n.h>
 
24
#include <string.h>
 
25
 
 
26
#include <gdu-gtk/gdu-gtk.h>
 
27
 
 
28
#include "gdu-tree.h"
 
29
 
 
30
 
 
31
struct _GduDeviceTreePrivate
 
32
{
 
33
        GduPresentable *presentable;
 
34
        GduPool *pool;
 
35
};
 
36
 
 
37
static GObjectClass *parent_class = NULL;
 
38
 
 
39
G_DEFINE_TYPE (GduDeviceTree, gdu_device_tree, GTK_TYPE_TREE_VIEW)
 
40
 
 
41
static void device_tree_presentable_added (GduPool *pool, GduPresentable *presentable, gpointer user_data);
 
42
static void device_tree_presentable_removed (GduPool *pool, GduPresentable *presentable, gpointer user_data);
 
43
static void device_tree_presentable_changed (GduPool *pool, GduPresentable *presentable, gpointer user_data);
 
44
static void add_presentable_to_tree (GduDeviceTree *device_tree, GduPresentable *presentable, GtkTreeIter *iter_out);
 
45
 
 
46
static gint sort_iter_compare_func (GtkTreeModel *model, GtkTreeIter  *a, GtkTreeIter  *b, gpointer userdata);
 
47
 
 
48
enum {
 
49
        PROP_0,
 
50
        PROP_POOL,
 
51
};
 
52
 
 
53
enum
 
54
{
 
55
        ICON_COLUMN,
 
56
        TITLE_COLUMN,
 
57
        PRESENTABLE_OBJ_COLUMN,
 
58
        SORTNAME_COLUMN,
 
59
        N_COLUMNS
 
60
};
 
61
 
 
62
static void
 
63
update_pool (GduDeviceTree *device_tree)
 
64
{
 
65
        GList *presentables;
 
66
        GList *l;
 
67
 
 
68
        presentables = gdu_pool_get_presentables (device_tree->priv->pool);
 
69
        for (l = presentables; l != NULL; l = l->next) {
 
70
                GduPresentable *presentable = GDU_PRESENTABLE (l->data);
 
71
                add_presentable_to_tree (device_tree, presentable, NULL);
 
72
                g_object_unref (presentable);
 
73
        }
 
74
        g_list_free (presentables);
 
75
 
 
76
        /* add/remove/change rows when the pool reports presentable add/remove/change */
 
77
        g_signal_connect (device_tree->priv->pool, "presentable-added",
 
78
                          (GCallback) device_tree_presentable_added, device_tree);
 
79
        g_signal_connect (device_tree->priv->pool, "presentable-removed",
 
80
                          (GCallback) device_tree_presentable_removed, device_tree);
 
81
        g_signal_connect (device_tree->priv->pool, "presentable-changed",
 
82
                          (GCallback) device_tree_presentable_changed, device_tree);
 
83
}
 
84
 
 
85
static void
 
86
gdu_device_tree_set_property (GObject      *object,
 
87
                              guint         prop_id,
 
88
                              const GValue *value,
 
89
                              GParamSpec   *pspec)
 
90
{
 
91
        GduDeviceTree *device_tree = GDU_DEVICE_TREE (object);
 
92
        gpointer obj;
 
93
 
 
94
        switch (prop_id) {
 
95
        case PROP_POOL:
 
96
                if (device_tree->priv->pool != NULL)
 
97
                        g_object_unref (device_tree->priv->pool);
 
98
                obj = g_value_get_object (value);
 
99
                device_tree->priv->pool = (obj == NULL ? NULL : g_object_ref (obj));
 
100
                update_pool (device_tree);
 
101
                break;
 
102
 
 
103
        default:
 
104
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
105
                break;
 
106
        }
 
107
}
 
108
 
 
109
static void
 
110
gdu_device_tree_get_property (GObject     *object,
 
111
                                    guint        prop_id,
 
112
                                    GValue      *value,
 
113
                                    GParamSpec  *pspec)
 
114
{
 
115
        GduDeviceTree *device_tree = GDU_DEVICE_TREE (object);
 
116
 
 
117
        switch (prop_id) {
 
118
        case PROP_POOL:
 
119
                g_value_set_object (value, device_tree->priv->pool);
 
120
                break;
 
121
 
 
122
        default:
 
123
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
124
                break;
 
125
    }
 
126
}
 
127
 
 
128
static void
 
129
gdu_device_tree_finalize (GduDeviceTree *device_tree)
 
130
{
 
131
        g_signal_handlers_disconnect_by_func (device_tree->priv->pool, device_tree_presentable_added, device_tree);
 
132
        g_signal_handlers_disconnect_by_func (device_tree->priv->pool, device_tree_presentable_removed, device_tree);
 
133
        g_signal_handlers_disconnect_by_func (device_tree->priv->pool, device_tree_presentable_changed, device_tree);
 
134
 
 
135
        if (device_tree->priv->pool != NULL)
 
136
                g_object_unref (device_tree->priv->pool);
 
137
 
 
138
        if (G_OBJECT_CLASS (parent_class)->finalize)
 
139
                (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (device_tree));
 
140
}
 
141
 
 
142
static void
 
143
gdu_device_tree_class_init (GduDeviceTreeClass *klass)
 
144
{
 
145
        GObjectClass *obj_class = (GObjectClass *) klass;
 
146
 
 
147
        parent_class = g_type_class_peek_parent (klass);
 
148
 
 
149
        obj_class->finalize = (GObjectFinalizeFunc) gdu_device_tree_finalize;
 
150
        obj_class->set_property = gdu_device_tree_set_property;
 
151
        obj_class->get_property = gdu_device_tree_get_property;
 
152
 
 
153
        g_type_class_add_private (klass, sizeof (GduDeviceTreePrivate));
 
154
 
 
155
        /**
 
156
         * GduDeviceTree:pool:
 
157
         *
 
158
         * The #GduPool instance we are getting information from
 
159
         */
 
160
        g_object_class_install_property (obj_class,
 
161
                                         PROP_POOL,
 
162
                                         g_param_spec_object ("pool",
 
163
                                                              NULL,
 
164
                                                              NULL,
 
165
                                                              GDU_TYPE_POOL,
 
166
                                                              G_PARAM_WRITABLE |
 
167
                                                              G_PARAM_READABLE |
 
168
                                                              G_PARAM_CONSTRUCT_ONLY));
 
169
}
 
170
 
 
171
static void
 
172
gdu_device_tree_init (GduDeviceTree *device_tree)
 
173
{
 
174
        GtkCellRenderer *renderer;
 
175
        GtkTreeViewColumn *column;
 
176
        GtkTreeStore *store;
 
177
 
 
178
        device_tree->priv = G_TYPE_INSTANCE_GET_PRIVATE (device_tree, GDU_TYPE_DEVICE_TREE, GduDeviceTreePrivate);
 
179
 
 
180
        store = gtk_tree_store_new (N_COLUMNS,
 
181
                                    GDK_TYPE_PIXBUF,
 
182
                                    G_TYPE_STRING,
 
183
                                    GDU_TYPE_PRESENTABLE,
 
184
                                    G_TYPE_STRING);
 
185
 
 
186
        gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), SORTNAME_COLUMN, sort_iter_compare_func,
 
187
                                         NULL, NULL);
 
188
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), SORTNAME_COLUMN, GTK_SORT_ASCENDING);
 
189
 
 
190
        gtk_tree_view_set_model (GTK_TREE_VIEW (device_tree), GTK_TREE_MODEL (store));
 
191
        /* TODO: when GTK 2.12 is available... we can do this */
 
192
        /*gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (tree), FALSE);*/
 
193
 
 
194
        column = gtk_tree_view_column_new ();
 
195
        gtk_tree_view_column_set_title (column, "Title");
 
196
        renderer = gtk_cell_renderer_pixbuf_new ();
 
197
        gtk_tree_view_column_pack_start (column, renderer, FALSE);
 
198
        gtk_tree_view_column_set_attributes (column, renderer,
 
199
                                             "pixbuf", ICON_COLUMN,
 
200
                                             NULL);
 
201
        renderer = gtk_cell_renderer_text_new ();
 
202
        gtk_tree_view_column_pack_start (column, renderer, TRUE);
 
203
        gtk_tree_view_column_set_attributes (column, renderer,
 
204
                                             "text", TITLE_COLUMN,
 
205
                                             NULL);
 
206
        gtk_tree_view_append_column (GTK_TREE_VIEW (device_tree), column);
 
207
 
 
208
        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (device_tree), FALSE);
 
209
 
 
210
        gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (device_tree), FALSE);
 
211
        gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (device_tree), 16);
 
212
 
 
213
}
 
214
 
 
215
static gint
 
216
sort_iter_compare_func (GtkTreeModel *model,
 
217
                        GtkTreeIter  *a,
 
218
                        GtkTreeIter  *b,
 
219
                        gpointer      userdata)
 
220
{
 
221
        char *s1;
 
222
        char *s2;
 
223
        int result;
 
224
 
 
225
        gtk_tree_model_get (model, a, SORTNAME_COLUMN, &s1, -1);
 
226
        gtk_tree_model_get (model, b, SORTNAME_COLUMN, &s2, -1);
 
227
        if (s1 == NULL || s2 == NULL)
 
228
                result = 0;
 
229
        else
 
230
                result = g_ascii_strcasecmp (s1, s2);
 
231
        g_free (s2);
 
232
        g_free (s1);
 
233
 
 
234
        return result;
 
235
}
 
236
 
 
237
typedef struct {
 
238
        const char *udi;
 
239
        GduPresentable *presentable;
 
240
        gboolean found;
 
241
        GtkTreeIter iter;
 
242
} FIBDData;
 
243
 
 
244
static gboolean
 
245
find_iter_by_presentable_foreach (GtkTreeModel *model,
 
246
                                  GtkTreePath *path,
 
247
                                  GtkTreeIter *iter,
 
248
                                  gpointer data)
 
249
{
 
250
        gboolean ret;
 
251
        GduPresentable *presentable = NULL;
 
252
        FIBDData *fibd_data = (FIBDData *) data;
 
253
 
 
254
        ret = FALSE;
 
255
        gtk_tree_model_get (model, iter, PRESENTABLE_OBJ_COLUMN, &presentable, -1);
 
256
        if (presentable == fibd_data->presentable) {
 
257
                fibd_data->found = TRUE;
 
258
                fibd_data->iter = *iter;
 
259
                ret = TRUE;
 
260
        }
 
261
        if (presentable != NULL)
 
262
                g_object_unref (presentable);
 
263
 
 
264
        return ret;
 
265
}
 
266
 
 
267
 
 
268
static gboolean
 
269
find_iter_by_presentable (GtkTreeStore *store, GduPresentable *presentable, GtkTreeIter *iter)
 
270
{
 
271
        FIBDData fibd_data;
 
272
        gboolean ret;
 
273
 
 
274
        fibd_data.presentable = presentable;
 
275
        fibd_data.found = FALSE;
 
276
        gtk_tree_model_foreach (GTK_TREE_MODEL (store), find_iter_by_presentable_foreach, &fibd_data);
 
277
        if (fibd_data.found) {
 
278
                if (iter != NULL)
 
279
                        *iter = fibd_data.iter;
 
280
                ret = TRUE;
 
281
        } else {
 
282
                ret = FALSE;
 
283
        }
 
284
 
 
285
        return ret;
 
286
}
 
287
 
 
288
static void
 
289
device_tree_presentable_changed (GduPool *pool, GduPresentable *presentable, gpointer user_data)
 
290
{
 
291
        GtkTreeView *tree_view = GTK_TREE_VIEW (user_data);
 
292
        char *name;
 
293
        GtkTreeStore *store;
 
294
        GtkTreeIter iter;
 
295
        GdkPixbuf *pixbuf;
 
296
        GduDevice *device;
 
297
 
 
298
        store = GTK_TREE_STORE (gtk_tree_view_get_model (tree_view));
 
299
 
 
300
        /* update name and icon */
 
301
        if (find_iter_by_presentable (store, presentable, &iter)) {
 
302
 
 
303
                name = gdu_presentable_get_name (presentable);
 
304
                device = gdu_presentable_get_device (presentable);
 
305
 
 
306
                pixbuf = gdu_util_get_pixbuf_for_presentable (presentable, GTK_ICON_SIZE_MENU);
 
307
 
 
308
                gtk_tree_store_set (store,
 
309
                                    &iter,
 
310
                                    ICON_COLUMN, pixbuf,
 
311
                                    TITLE_COLUMN, name,
 
312
                                    -1);
 
313
 
 
314
                g_free (name);
 
315
                if (pixbuf != NULL)
 
316
                        g_object_unref (pixbuf);
 
317
                if (device != NULL)
 
318
                        g_object_unref (device);
 
319
        }
 
320
}
 
321
 
 
322
static void
 
323
add_presentable_to_tree (GduDeviceTree *device_tree, GduPresentable *presentable, GtkTreeIter *iter_out)
 
324
{
 
325
        GtkTreeIter  iter;
 
326
        GtkTreeIter  iter2;
 
327
        GtkTreeIter *parent_iter;
 
328
        GdkPixbuf   *pixbuf;
 
329
        char        *name;
 
330
        GtkTreeStore *store;
 
331
        GduDevice *device;
 
332
        GduPresentable *enclosing_presentable;
 
333
        const char  *object_path;
 
334
        char *sortname;
 
335
 
 
336
        device = NULL;
 
337
 
 
338
        store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (device_tree)));
 
339
 
 
340
        /* check to see if presentable is already added */
 
341
        if (find_iter_by_presentable (store, presentable, NULL))
 
342
                goto out;
 
343
 
 
344
        /* set up parent relationship */
 
345
        parent_iter = NULL;
 
346
        enclosing_presentable = gdu_presentable_get_enclosing_presentable (presentable);
 
347
        if (enclosing_presentable != NULL) {
 
348
                if (find_iter_by_presentable (store, enclosing_presentable, &iter2)) {
 
349
                        parent_iter = &iter2;
 
350
                } else {
 
351
                        /* add parent if it's not already added */
 
352
                        /*g_debug ("we have no parent for %s (%p)", gdu_presentable_get_id (enclosing_presentable), enclosing_presentable);*/
 
353
                        add_presentable_to_tree (device_tree, enclosing_presentable, &iter2);
 
354
                        parent_iter = &iter2;
 
355
                }
 
356
                g_object_unref (enclosing_presentable);
 
357
        }
 
358
 
 
359
        device = gdu_presentable_get_device (presentable);
 
360
        if (device != NULL)
 
361
                object_path = gdu_device_get_object_path (device);
 
362
        else
 
363
                object_path = "";
 
364
 
 
365
        /* compute the name */
 
366
        name = gdu_presentable_get_name (presentable);
 
367
        pixbuf = gdu_util_get_pixbuf_for_presentable (presentable, GTK_ICON_SIZE_MENU);
 
368
 
 
369
        /* sort by offset so we get partitions in the right order */
 
370
        sortname = g_strdup_printf ("%016" G_GINT64_FORMAT "_%s", gdu_presentable_get_offset (presentable), object_path);
 
371
 
 
372
        /*g_debug ("adding %s (%p)", gdu_presentable_get_id (presentable), presentable);*/
 
373
 
 
374
        gtk_tree_store_append (store, &iter, parent_iter);
 
375
        gtk_tree_store_set (store, &iter,
 
376
                            ICON_COLUMN, pixbuf,
 
377
                            TITLE_COLUMN, name,
 
378
                            PRESENTABLE_OBJ_COLUMN, presentable,
 
379
                            SORTNAME_COLUMN, sortname,
 
380
                            -1);
 
381
        g_free (sortname);
 
382
 
 
383
        if (iter_out != NULL)
 
384
                *iter_out = iter;
 
385
 
 
386
        g_free (name);
 
387
        if (pixbuf != NULL)
 
388
                g_object_unref (pixbuf);
 
389
 
 
390
        if (parent_iter != NULL) {
 
391
                GtkTreePath *path;
 
392
                path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), parent_iter);
 
393
                if (path != NULL) {
 
394
                        gtk_tree_view_expand_row (GTK_TREE_VIEW (device_tree), path, TRUE);
 
395
                        gtk_tree_path_free (path);
 
396
                }
 
397
        }
 
398
 
 
399
out:
 
400
        if (device != NULL)
 
401
                g_object_unref (device);
 
402
}
 
403
 
 
404
static void
 
405
device_tree_presentable_added (GduPool *pool, GduPresentable *presentable, gpointer user_data)
 
406
{
 
407
        GduDeviceTree *device_tree = GDU_DEVICE_TREE (user_data);
 
408
        add_presentable_to_tree (device_tree, presentable, NULL);
 
409
}
 
410
 
 
411
static void
 
412
device_tree_presentable_removed (GduPool *pool, GduPresentable *presentable, gpointer user_data)
 
413
{
 
414
        GduDeviceTree *device_tree = GDU_DEVICE_TREE (user_data);
 
415
        GtkTreeIter iter;
 
416
        GtkTreeStore *store;
 
417
 
 
418
        store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (device_tree)));
 
419
        if (find_iter_by_presentable (store, presentable, &iter)) {
 
420
                gtk_tree_store_remove (store, &iter);
 
421
        }
 
422
}
 
423
 
 
424
GtkWidget *
 
425
gdu_device_tree_new (GduPool *pool)
 
426
{
 
427
        return GTK_WIDGET (g_object_new (GDU_TYPE_DEVICE_TREE, "pool", pool, NULL));
 
428
}
 
429
 
 
430
GduPresentable *
 
431
gdu_device_tree_get_selected_presentable (GtkTreeView *tree_view)
 
432
{
 
433
        GduPresentable *presentable;
 
434
        GtkTreePath *path;
 
435
        GtkTreeModel *presentable_tree_model;
 
436
 
 
437
        presentable = NULL;
 
438
 
 
439
        presentable_tree_model = gtk_tree_view_get_model (tree_view);
 
440
        gtk_tree_view_get_cursor (tree_view, &path, NULL);
 
441
        if (path != NULL) {
 
442
                GtkTreeIter iter;
 
443
 
 
444
                if (gtk_tree_model_get_iter (presentable_tree_model, &iter, path)) {
 
445
 
 
446
                        gtk_tree_model_get (presentable_tree_model, &iter,
 
447
                                            PRESENTABLE_OBJ_COLUMN,
 
448
                                            &presentable,
 
449
                                            -1);
 
450
 
 
451
                        if (presentable != NULL)
 
452
                                g_object_unref (presentable);
 
453
                }
 
454
 
 
455
                gtk_tree_path_free (path);
 
456
        }
 
457
 
 
458
        return presentable;
 
459
}
 
460
 
 
461
void
 
462
gdu_device_tree_select_presentable (GtkTreeView *tree_view, GduPresentable *presentable)
 
463
{
 
464
        GtkTreePath *path;
 
465
        GtkTreeModel *tree_model;
 
466
        GtkTreeIter iter;
 
467
 
 
468
        if (presentable == NULL)
 
469
                goto out;
 
470
 
 
471
        tree_model = gtk_tree_view_get_model (tree_view);
 
472
        if (!find_iter_by_presentable (GTK_TREE_STORE (tree_model), presentable, &iter))
 
473
                goto out;
 
474
 
 
475
        path = gtk_tree_model_get_path (tree_model, &iter);
 
476
        if (path == NULL)
 
477
                goto out;
 
478
 
 
479
        gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
 
480
        gtk_tree_path_free (path);
 
481
out:
 
482
        ;
 
483
}
 
484
 
 
485
void
 
486
gdu_device_tree_select_first_presentable (GtkTreeView *tree_view)
 
487
{
 
488
        GtkTreePath *path;
 
489
        GtkTreeModel *tree_model;
 
490
        GtkTreeIter iter;
 
491
 
 
492
        tree_model = gtk_tree_view_get_model (tree_view);
 
493
 
 
494
        if (gtk_tree_model_get_iter_first (tree_model, &iter)) {
 
495
                path = gtk_tree_model_get_path (tree_model, &iter);
 
496
                if (path == NULL)
 
497
                        goto out;
 
498
 
 
499
                gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
 
500
                gtk_tree_path_free (path);
 
501
        }
 
502
out:
 
503
        ;
 
504
}