~ubuntu-branches/ubuntu/lucid/giggle/lucid

« back to all changes in this revision

Viewing changes to src/giggle-file-list.c

  • Committer: Bazaar Package Importer
  • Author(s): Andrea Corradi
  • Date: 2007-05-09 21:16:35 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070509211635-p0wst0b2b7qdns12
Tags: 0.3-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
#include "giggle-git-add.h"
32
32
#include "giggle-git-diff-tree.h"
33
33
#include "giggle-revision.h"
 
34
#include "giggle-enums.h"
34
35
 
35
36
typedef struct GiggleFileListPriv GiggleFileListPriv;
36
37
 
48
49
 
49
50
        GtkWidget    *diff_window;
50
51
 
 
52
        GHashTable   *idle_jobs;
 
53
 
51
54
        guint         show_all : 1;
52
55
        guint         compact_mode : 1;
53
56
};
54
57
 
 
58
typedef struct IdleLoaderData IdleLoaderData;
 
59
 
 
60
struct IdleLoaderData {
 
61
        GiggleFileList *list;
 
62
        gchar          *directory;
 
63
        gchar          *rel_path;
 
64
        GtkTreeIter     parent_iter;
 
65
};
 
66
 
55
67
static void       file_list_finalize           (GObject        *object);
56
68
static void       file_list_get_property       (GObject        *object,
57
69
                                                guint           param_id,
63
75
                                                GParamSpec     *pspec);
64
76
static gboolean   file_list_button_press       (GtkWidget      *widget,
65
77
                                                GdkEventButton *event);
 
78
static void       file_list_project_loaded     (GiggleFileList *list);
 
79
static void       file_list_status_changed     (GiggleFileList *list);
66
80
 
67
81
static void       file_list_directory_changed  (GObject        *object,
68
82
                                                GParamSpec     *pspec,
69
83
                                                gpointer        user_data);
70
 
static void       file_list_managed_files_changed (GiggleFileList *list);
 
84
static void       file_list_files_status_changed (GiggleFileList *list);
71
85
 
72
86
static void       file_list_populate           (GiggleFileList *list);
73
87
static void       file_list_populate_dir       (GiggleFileList *list,
114
128
                                                       GtkTreeModel    *tree_model,
115
129
                                                       GtkTreeIter     *iter,
116
130
                                                       gpointer         data);
 
131
static void       file_list_cell_pixbuf_func          (GtkCellLayout   *cell_layout,
 
132
                                                       GtkCellRenderer *renderer,
 
133
                                                       GtkTreeModel    *tree_model,
 
134
                                                       GtkTreeIter     *iter,
 
135
                                                       gpointer         data);
 
136
static void       file_list_idle_data_free            (IdleLoaderData  *data);
 
137
 
117
138
 
118
139
G_DEFINE_TYPE (GiggleFileList, giggle_file_list, GTK_TYPE_TREE_VIEW)
119
140
 
122
143
enum {
123
144
        COL_NAME,
124
145
        COL_REL_PATH,
125
 
        COL_PIXBUF,
 
146
        COL_FILE_STATUS,
126
147
        COL_GIT_IGNORE,
127
 
        COL_MANAGED, /* File managed by git */
128
148
        COL_HIGHLIGHT,
129
149
        LAST_COL
130
150
};
137
157
 
138
158
enum {
139
159
        PATH_SELECTED,
 
160
        PROJECT_LOADED,
 
161
        STATUS_CHANGED,
140
162
        LAST_SIGNAL
141
163
};
142
164
 
143
165
static guint signals[LAST_SIGNAL] = { 0, };
144
166
 
145
167
static GtkActionEntry menu_items [] = {
146
 
        { "Diff",     NULL,             N_("_Diff"),                   NULL, NULL, G_CALLBACK (file_list_diff_file) },
 
168
        { "Commit",   NULL,             N_("_Commit Changes"),         NULL, NULL, G_CALLBACK (file_list_diff_file) },
147
169
        { "AddFile",  NULL,             N_("A_dd file to repository"), NULL, NULL, G_CALLBACK (file_list_add_file) },
148
170
        { "Ignore",   GTK_STOCK_ADD,    N_("_Add to .gitignore"),      NULL, NULL, G_CALLBACK (file_list_ignore_file) },
149
171
        { "Unignore", GTK_STOCK_REMOVE, N_("_Remove from .gitignore"), NULL, NULL, G_CALLBACK (file_list_unignore_file) },
156
178
static const gchar *ui_description =
157
179
        "<ui>"
158
180
        "  <popup name='PopupMenu'>"
159
 
        "    <menuitem action='Diff'/>"
 
181
        "    <menuitem action='Commit'/>"
160
182
        "    <separator/>"
161
183
        "    <menuitem action='AddFile'/>"
162
184
        "    <separator/>"
179
201
        object_class->set_property = file_list_set_property;
180
202
 
181
203
        widget_class->button_press_event = file_list_button_press;
 
204
        class->project_loaded = file_list_project_loaded;
 
205
        class->status_changed = file_list_status_changed;
182
206
 
183
207
        g_object_class_install_property (object_class,
184
208
                                         PROP_SHOW_ALL,
205
229
                              G_TYPE_NONE,
206
230
                              1, G_TYPE_STRING);
207
231
 
 
232
        signals[PROJECT_LOADED] =
 
233
                g_signal_new ("project-loaded",
 
234
                              G_OBJECT_CLASS_TYPE (object_class),
 
235
                              G_SIGNAL_RUN_LAST,
 
236
                              G_STRUCT_OFFSET (GiggleFileListClass, project_loaded),
 
237
                              NULL, NULL,
 
238
                              g_cclosure_marshal_VOID__VOID,
 
239
                              G_TYPE_NONE, 0);
 
240
 
 
241
        signals[STATUS_CHANGED] =
 
242
                g_signal_new ("status-changed",
 
243
                              G_OBJECT_CLASS_TYPE (object_class),
 
244
                              G_SIGNAL_RUN_LAST,
 
245
                              G_STRUCT_OFFSET (GiggleFileListClass, status_changed),
 
246
                              NULL, NULL,
 
247
                              g_cclosure_marshal_VOID__VOID,
 
248
                              G_TYPE_NONE, 0);
 
249
 
208
250
        g_type_class_add_private (object_class, sizeof (GiggleFileListPriv));
209
251
}
210
252
 
211
253
static void
212
 
giggle_file_list_init (GiggleFileList *list)
 
254
file_list_create_store (GiggleFileList *list)
213
255
{
214
256
        GiggleFileListPriv *priv;
215
 
        GtkCellRenderer    *renderer;
216
 
        GtkTreeViewColumn  *column;
217
 
        GtkActionGroup     *action_group;
218
 
        GtkTreeSelection   *selection;
219
257
 
220
258
        priv = GET_PRIV (list);
221
259
 
222
 
        priv->git = giggle_git_get ();
223
 
        g_signal_connect (priv->git, "notify::project-dir",
224
 
                          G_CALLBACK (file_list_directory_changed), list);
225
 
        g_signal_connect_swapped (priv->git, "notify::git-dir",
226
 
                                  G_CALLBACK (file_list_managed_files_changed), list);
227
 
 
228
 
        priv->icon_theme = gtk_icon_theme_get_default ();
229
 
 
230
 
        priv->store = gtk_tree_store_new (LAST_COL, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF,
231
 
                                          GIGGLE_TYPE_GIT_IGNORE, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
 
260
        gtk_tree_view_set_model (GTK_TREE_VIEW (list), NULL);
 
261
 
 
262
        if (priv->store) {
 
263
                g_object_unref (priv->store);
 
264
        }
 
265
 
 
266
        if (priv->filter_model) {
 
267
                g_object_unref (priv->filter_model);
 
268
        }
 
269
 
 
270
        priv->store = gtk_tree_store_new (LAST_COL, G_TYPE_STRING, G_TYPE_STRING, GIGGLE_TYPE_GIT_LIST_FILES_STATUS,
 
271
                                          GIGGLE_TYPE_GIT_IGNORE, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
232
272
        priv->filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->store), NULL);
233
273
 
234
274
        gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter_model),
241
281
 
242
282
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->store),
243
283
                                              COL_NAME, GTK_SORT_ASCENDING);
244
 
 
245
 
        gtk_tree_view_set_model (GTK_TREE_VIEW (list), priv->filter_model);
 
284
}
 
285
 
 
286
static void
 
287
giggle_file_list_init (GiggleFileList *list)
 
288
{
 
289
        GiggleFileListPriv *priv;
 
290
        GtkCellRenderer    *renderer;
 
291
        GtkTreeViewColumn  *column;
 
292
        GtkActionGroup     *action_group;
 
293
        GtkTreeSelection   *selection;
 
294
 
 
295
        priv = GET_PRIV (list);
 
296
 
 
297
        priv->idle_jobs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
 
298
                                                 (GDestroyNotify) file_list_idle_data_free,
 
299
                                                 (GDestroyNotify) g_source_remove);
 
300
 
 
301
        priv->git = giggle_git_get ();
 
302
        g_signal_connect (priv->git, "notify::project-dir",
 
303
                          G_CALLBACK (file_list_directory_changed), list);
 
304
        g_signal_connect_swapped (priv->git, "changed",
 
305
                                  G_CALLBACK (file_list_files_status_changed), list);
 
306
 
 
307
        priv->icon_theme = gtk_icon_theme_get_default ();
246
308
 
247
309
        gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (list),
248
310
                                             file_list_search_equal_func,
249
311
                                             NULL, NULL);
250
 
        
 
312
 
251
313
        column = gtk_tree_view_column_new ();
252
314
        gtk_tree_view_column_set_title (column, _("Project"));
253
315
 
254
316
        renderer = gtk_cell_renderer_pixbuf_new ();
255
317
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer, FALSE);
256
 
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer,
257
 
                                        "pixbuf", COL_PIXBUF,
258
 
                                        NULL);
259
 
        gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer,
260
 
                                            file_list_cell_data_sensitive_func,
261
 
                                            list, NULL);
262
 
        gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer,
263
 
                                            file_list_cell_data_background_func,
 
318
 
 
319
        gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer,
 
320
                                            file_list_cell_pixbuf_func,
264
321
                                            list, NULL);
265
322
 
266
323
        renderer = gtk_cell_renderer_text_new ();
274
331
                                            list, NULL);
275
332
 
276
333
        gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
277
 
        file_list_populate (list);
278
334
 
279
335
        /* create the popup menu */
280
336
        action_group = gtk_action_group_new ("PopupActions");
283
339
                                      G_N_ELEMENTS (menu_items), list);
284
340
        gtk_action_group_add_toggle_actions (action_group, toggle_menu_items,
285
341
                                             G_N_ELEMENTS (toggle_menu_items), list);
286
 
        
 
342
 
287
343
        priv->ui_manager = gtk_ui_manager_new ();
288
344
        gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, 0);
289
345
 
328
384
 
329
385
        g_object_unref (priv->ui_manager);
330
386
 
 
387
        g_hash_table_destroy (priv->idle_jobs);
 
388
 
331
389
        G_OBJECT_CLASS (giggle_file_list_parent_class)->finalize (object);
332
390
}
333
391
 
383
441
file_list_button_press (GtkWidget      *widget,
384
442
                        GdkEventButton *event)
385
443
{
386
 
        GiggleFileList     *list;
387
 
        GiggleFileListPriv *priv;
388
 
        gboolean            add, ignore, unignore;
389
 
        gchar              *file_path;
390
 
        GiggleGitIgnore    *git_ignore;
391
 
        GtkAction          *action;
392
 
        GtkTreeSelection   *selection;
393
 
        GtkTreeModel       *model;
394
 
        GList              *rows, *l;
395
 
        GtkTreeIter         iter;
396
 
        GtkTreePath        *path;
 
444
        GiggleFileList           *list;
 
445
        GiggleFileListPriv       *priv;
 
446
        gboolean                  add, ignore, unignore;
 
447
        gchar                    *file_path;
 
448
        GiggleGitIgnore          *git_ignore;
 
449
        GtkAction                *action;
 
450
        GtkTreeSelection         *selection;
 
451
        GtkTreeModel             *model;
 
452
        GList                    *rows, *l;
 
453
        GtkTreeIter               iter;
 
454
        GtkTreePath              *path;
 
455
        GiggleGitListFilesStatus  status;
397
456
 
398
457
        list = GIGGLE_FILE_LIST (widget);
399
458
        priv = GET_PRIV (list);
422
481
                        gtk_tree_model_get_iter (model, &iter, l->data);
423
482
 
424
483
                        gtk_tree_model_get (model, &iter,
425
 
                                            COL_MANAGED, &add,
 
484
                                            COL_FILE_STATUS, &status,
426
485
                                            -1);
427
486
 
 
487
                        add = (status == GIGGLE_GIT_FILE_STATUS_OTHER);
 
488
 
428
489
                        if (file_list_get_path_and_ignore_for_iter (list, &iter, &file_path, &git_ignore)) {
429
490
                                if (giggle_git_ignore_path_matches (git_ignore, file_path)) {
430
491
                                        unignore = TRUE;
443
504
                gtk_action_set_sensitive (action, ignore);
444
505
                action = gtk_ui_manager_get_action (priv->ui_manager, "/ui/PopupMenu/Unignore");
445
506
                gtk_action_set_sensitive (action, unignore);
446
 
                
 
507
 
447
508
                gtk_menu_popup (GTK_MENU (priv->popup), NULL, NULL,
448
509
                                NULL, NULL, event->button, event->time);
449
510
 
458
519
                        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
459
520
                        rows = gtk_tree_selection_get_selected_rows (selection, &model);
460
521
 
461
 
                        g_assert (rows != NULL);
462
 
 
463
 
                        /* there should be just one item selected */
464
 
                        gtk_tree_model_get_iter (model, &iter, rows->data);
465
 
 
466
 
                        file_list_get_path_and_ignore_for_iter (list, &iter, &file_path, NULL);
467
 
                        g_signal_emit (widget, signals[PATH_SELECTED], 0, file_path);
468
 
                        g_free (file_path);
 
522
                        if (rows) {
 
523
                                gtk_tree_model_get_iter (model, &iter, rows->data);
 
524
 
 
525
                                file_list_get_path_and_ignore_for_iter (list, &iter, &file_path, NULL);
 
526
                                g_signal_emit (widget, signals[PATH_SELECTED], 0, file_path);
 
527
                                g_free (file_path);
 
528
                        }
469
529
                }
470
530
        }
471
531
 
473
533
}
474
534
 
475
535
static void
 
536
file_list_project_loaded (GiggleFileList *list)
 
537
{
 
538
        /* update files status */
 
539
        file_list_files_status_changed (list);
 
540
}
 
541
 
 
542
static void
 
543
file_list_status_changed (GiggleFileList *list)
 
544
{
 
545
        GiggleFileListPriv *priv;
 
546
        GtkTreePath        *path;
 
547
 
 
548
        if (gtk_tree_view_get_model (GTK_TREE_VIEW (list))) {
 
549
                return;
 
550
        }
 
551
 
 
552
        priv = GET_PRIV (list);
 
553
        gtk_tree_view_set_model (GTK_TREE_VIEW (list), priv->filter_model);
 
554
 
 
555
        /* expand the project folder */
 
556
        path = gtk_tree_path_new_first ();
 
557
        gtk_tree_view_expand_row (GTK_TREE_VIEW (list), path, FALSE);
 
558
        gtk_tree_path_free (path);
 
559
}
 
560
 
 
561
static void
476
562
file_list_directory_changed (GObject    *object,
477
563
                             GParamSpec *pspec,
478
564
                             gpointer    user_data)
483
569
        list = GIGGLE_FILE_LIST (user_data);
484
570
        priv = GET_PRIV (list);
485
571
 
486
 
        gtk_tree_store_clear (priv->store);
 
572
        /* remove old directory idles */
 
573
        g_hash_table_remove_all (priv->idle_jobs);
 
574
 
 
575
        file_list_create_store (list);
487
576
        file_list_populate (list);
488
577
}
489
578
 
490
579
static void
491
 
file_list_update_managed (GiggleFileList *file_list,
492
 
                          GtkTreeIter    *parent,
493
 
                          const gchar    *parent_path,
494
 
                          GList          *files)
 
580
file_list_update_files_status (GiggleFileList     *file_list,
 
581
                               GtkTreeIter        *parent,
 
582
                               GiggleGitListFiles *list_files)
495
583
{
496
 
        GiggleFileListPriv *priv;
497
 
        GtkTreeIter         iter;
498
 
        gboolean            valid;
499
 
        GiggleGitIgnore    *git_ignore;
500
 
        gchar              *name, *path;
501
 
        gboolean            managed;
 
584
        GiggleFileListPriv        *priv;
 
585
        GtkTreeIter               iter;
 
586
        gboolean                  valid;
 
587
        gchar                    *rel_path;
 
588
        GiggleGitListFilesStatus  status;
502
589
 
503
590
        priv = GET_PRIV (file_list);
504
591
 
511
598
 
512
599
        while (valid) {
513
600
                gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
514
 
                                    COL_NAME, &name,
515
 
                                    COL_GIT_IGNORE, &git_ignore,
 
601
                                    COL_REL_PATH, &rel_path,
516
602
                                    -1);
517
603
 
518
 
                if (parent_path) {
519
 
                        path = g_build_filename (parent_path, name, NULL);
520
 
                        managed = (g_list_find_custom (files, path, (GCompareFunc) strcmp) != NULL);
 
604
                if (rel_path) {
 
605
                        status = giggle_git_list_files_get_file_status (list_files, rel_path);
521
606
                } else {
522
 
                        /* we don't want the project basename included */
523
 
                        path = g_strdup ("");
524
 
                        managed = FALSE;
 
607
                        status = GIGGLE_GIT_FILE_STATUS_CACHED;
 
608
                }
 
609
 
 
610
                if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (priv->store), &iter)) {
 
611
                        /* it's a directory */
 
612
                        file_list_update_files_status (file_list, &iter, list_files);
 
613
                        status = GIGGLE_GIT_FILE_STATUS_CACHED;
525
614
                }
526
615
 
527
616
                gtk_tree_store_set (priv->store, &iter,
528
 
                                    COL_MANAGED, managed,
 
617
                                    COL_FILE_STATUS, status,
529
618
                                    -1);
530
619
 
531
 
                if (git_ignore) {
532
 
                        /* it's a directory */
533
 
                        file_list_update_managed (file_list, &iter, path, files);
534
 
                        g_object_unref (git_ignore);
535
 
                }
536
 
 
537
 
                g_free (path);
538
 
                g_free (name);
 
620
                g_free (rel_path);
539
621
                valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), &iter);
540
622
        }
541
623
}
548
630
{
549
631
        GiggleFileList     *list;
550
632
        GiggleFileListPriv *priv;
551
 
        GList              *files;
552
633
 
553
634
        list = GIGGLE_FILE_LIST (user_data);
554
635
        priv = GET_PRIV (list);
566
647
                gtk_dialog_run (GTK_DIALOG (dialog));
567
648
                gtk_widget_destroy (dialog);
568
649
        } else {
569
 
                files = giggle_git_list_files_get_files (GIGGLE_GIT_LIST_FILES (priv->job));
570
 
                file_list_update_managed (list, NULL, NULL, files);
 
650
                file_list_update_files_status (list, NULL, GIGGLE_GIT_LIST_FILES (priv->job));
 
651
                g_signal_emit (list, signals[STATUS_CHANGED], 0);
571
652
        }
572
653
 
573
654
        g_object_unref (priv->job);
575
656
}
576
657
 
577
658
static void
578
 
file_list_managed_files_changed (GiggleFileList *list)
 
659
file_list_files_status_changed (GiggleFileList *list)
579
660
{
580
661
        GiggleFileListPriv *priv;
581
662
 
582
663
        priv = GET_PRIV (list);
583
664
 
584
 
        file_list_update_managed (list, NULL, NULL, NULL);
585
 
 
586
665
        if (priv->job) {
587
666
                giggle_git_cancel_job (priv->git, priv->job);
588
667
                g_object_unref (priv->job);
616
695
        gtk_widget_show (priv->diff_window);
617
696
}
618
697
 
 
698
static gboolean
 
699
file_list_populate_dir_idle (gpointer user_data)
 
700
{
 
701
        GiggleFileListPriv *priv;
 
702
        GiggleFileList     *list;
 
703
        IdleLoaderData     *data;
 
704
        GiggleGitIgnore    *git_ignore;
 
705
        gchar              *full_path;
 
706
 
 
707
        data = (IdleLoaderData *) user_data;
 
708
        list = g_object_ref (data->list);
 
709
        priv = GET_PRIV (list);
 
710
 
 
711
        full_path = g_build_filename (data->directory, data->rel_path, NULL);
 
712
        git_ignore = giggle_git_ignore_new (full_path);
 
713
 
 
714
        gtk_tree_store_set (priv->store, &data->parent_iter,
 
715
                            COL_GIT_IGNORE, git_ignore,
 
716
                            -1);
 
717
 
 
718
        file_list_populate_dir (data->list, data->directory,
 
719
                                data->rel_path, &data->parent_iter);
 
720
 
 
721
        /* remove this data from the table */
 
722
        g_hash_table_remove (priv->idle_jobs, data);
 
723
 
 
724
        if (g_hash_table_size (priv->idle_jobs) == 0) {
 
725
                /* no remaining jobs */
 
726
                g_signal_emit (list, signals[PROJECT_LOADED], 0);
 
727
        }
 
728
 
 
729
        g_object_unref (git_ignore);
 
730
        g_object_unref (list);
 
731
        g_free (full_path);
 
732
 
 
733
        return FALSE;
 
734
}
 
735
 
 
736
static void
 
737
file_list_idle_data_free (IdleLoaderData *data)
 
738
{
 
739
        g_free (data->directory);
 
740
        g_free (data->rel_path);
 
741
        g_object_unref (data->list);
 
742
        g_free (data);
 
743
}
 
744
 
619
745
static void
620
746
file_list_add_element (GiggleFileList *list,
621
747
                       const gchar    *directory,
624
750
                       GtkTreeIter    *parent_iter)
625
751
{
626
752
        GiggleFileListPriv *priv;
627
 
        GdkPixbuf          *pixbuf;
628
753
        GtkTreeIter         iter;
629
754
        gboolean            is_dir;
630
 
        GiggleGitIgnore    *git_ignore = NULL;
631
755
        gchar              *full_path;
632
756
 
633
757
        priv = GET_PRIV (list);
639
763
                               &iter,
640
764
                               parent_iter);
641
765
 
642
 
        if (is_dir) {
643
 
                file_list_populate_dir (list, directory, rel_path, &iter);
644
 
                pixbuf = gtk_icon_theme_load_icon (priv->icon_theme,
645
 
                                                   "folder", 16, 0, NULL);;
646
 
                git_ignore = giggle_git_ignore_new (full_path);
647
 
        } else {
648
 
                pixbuf = gtk_icon_theme_load_icon (priv->icon_theme,
649
 
                                                   "text-x-generic", 16, 0, NULL);;
650
 
        }
651
 
 
652
766
        gtk_tree_store_set (priv->store, &iter,
653
 
                            COL_PIXBUF, pixbuf,
654
767
                            COL_NAME, (name) ? name : full_path,
655
768
                            COL_REL_PATH, rel_path,
656
 
                            COL_GIT_IGNORE, git_ignore,
657
769
                            -1);
658
 
        if (pixbuf) {
659
 
                g_object_unref (pixbuf);
660
 
        }
661
 
 
662
 
        if (git_ignore) {
663
 
                g_object_unref (git_ignore);
 
770
 
 
771
        if (is_dir) {
 
772
                IdleLoaderData *data;
 
773
                guint           idle_id;
 
774
 
 
775
                data = g_new0 (IdleLoaderData, 1);
 
776
                data->list = g_object_ref (list);
 
777
                data->directory = g_strdup (directory);
 
778
                data->rel_path = g_strdup (rel_path);
 
779
                data->parent_iter = iter;
 
780
 
 
781
                idle_id = g_idle_add_full (GDK_PRIORITY_REDRAW + 1,
 
782
                                           file_list_populate_dir_idle,
 
783
                                           data, NULL);
 
784
 
 
785
                g_hash_table_insert (priv->idle_jobs, data, GUINT_TO_POINTER (idle_id));
664
786
        }
665
787
 
666
788
        g_free (full_path);
698
820
{
699
821
        GiggleFileListPriv *priv;
700
822
        const gchar        *directory;
701
 
        GtkTreePath        *path;
702
823
 
703
824
        priv = GET_PRIV (list);
704
825
        directory = giggle_git_get_project_dir (priv->git);
705
826
 
706
 
        file_list_add_element (list, directory, "", NULL, NULL);
707
 
 
708
 
        /* expand the project folder */
709
 
        path = gtk_tree_path_new_first ();
710
 
        gtk_tree_view_expand_row (GTK_TREE_VIEW (list), path, FALSE);
711
 
        gtk_tree_path_free (path);
 
827
        if (directory) {
 
828
                file_list_add_element (list, directory, "", NULL, NULL);
 
829
        }
712
830
}
713
831
 
714
832
static void
742
860
                g_object_unref (priv->job);
743
861
                priv->job = NULL;
744
862
 
745
 
                file_list_managed_files_changed (list);
 
863
                file_list_files_status_changed (list);
746
864
        }
747
865
}
748
866
 
879
997
        gchar    *normalized_key, *normalized_str;
880
998
        gchar    *casefold_key, *casefold_str;
881
999
        gboolean  ret;
882
 
        
 
1000
 
883
1001
        gtk_tree_model_get (model, iter, column, &str, -1);
884
1002
 
885
1003
        normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
1095
1213
        }
1096
1214
 
1097
1215
        if (value) {
1098
 
                /* check whether the file is managed by git */
 
1216
                GiggleGitListFilesStatus status;
 
1217
 
1099
1218
                gtk_tree_model_get (tree_model, iter,
1100
 
                                    COL_MANAGED, &value,
 
1219
                                    COL_FILE_STATUS, &status,
1101
1220
                                    -1);
1102
 
                value ^= 1;
 
1221
 
 
1222
                value = !(status == GIGGLE_GIT_FILE_STATUS_OTHER);
1103
1223
        }
1104
1224
 
1105
1225
        if (GTK_IS_CELL_RENDERER_TEXT (renderer)) {
1127
1247
        GiggleFileListPriv *priv;
1128
1248
        GiggleFileList     *file_list;
1129
1249
        gboolean            highlight;
 
1250
        gchar              *rel_path;
1130
1251
 
1131
1252
        file_list = GIGGLE_FILE_LIST (data);
1132
1253
        priv = GET_PRIV (file_list);
1133
1254
 
1134
1255
        gtk_tree_model_get (tree_model, iter,
 
1256
                            COL_REL_PATH, &rel_path,
1135
1257
                            COL_HIGHLIGHT, &highlight,
1136
1258
                            -1);
1137
1259
 
1138
 
        g_object_set (G_OBJECT (renderer),
1139
 
                      "cell-background-gdk", (highlight) ? &color : NULL,
 
1260
        g_object_set (G_OBJECT (renderer), "cell-background-gdk",
 
1261
                      (rel_path && *rel_path && highlight) ? &color : NULL,
1140
1262
                      NULL);
 
1263
 
 
1264
        g_free (rel_path);
 
1265
}
 
1266
 
 
1267
static void
 
1268
file_list_cell_pixbuf_func (GtkCellLayout   *layout,
 
1269
                            GtkCellRenderer *renderer,
 
1270
                            GtkTreeModel    *tree_model,
 
1271
                            GtkTreeIter     *iter,
 
1272
                            gpointer         data)
 
1273
{
 
1274
        GiggleFileListPriv       *priv;
 
1275
        GiggleGitIgnore          *git_ignore;
 
1276
        GiggleGitListFilesStatus  status;
 
1277
        GdkPixbuf                *pixbuf = NULL;
 
1278
        const gchar              *icon_name;
 
1279
 
 
1280
        file_list_cell_data_sensitive_func (layout, renderer, tree_model, iter, data);
 
1281
 
 
1282
        priv = GET_PRIV (data);
 
1283
 
 
1284
        gtk_tree_model_get (tree_model, iter,
 
1285
                            COL_FILE_STATUS, &status,
 
1286
                            COL_GIT_IGNORE, &git_ignore,
 
1287
                            -1);
 
1288
 
 
1289
        if (git_ignore) {
 
1290
                /* it's a folder */
 
1291
                icon_name = "folder";
 
1292
                g_object_unref (git_ignore);
 
1293
        } else {
 
1294
                switch (status) {
 
1295
                case GIGGLE_GIT_FILE_STATUS_OTHER:
 
1296
                case GIGGLE_GIT_FILE_STATUS_CACHED:
 
1297
                        icon_name = "text-x-generic";
 
1298
                        break;
 
1299
                case GIGGLE_GIT_FILE_STATUS_CHANGED:
 
1300
                        icon_name = "gtk-new";
 
1301
                        break;
 
1302
                case GIGGLE_GIT_FILE_STATUS_DELETED:
 
1303
                case GIGGLE_GIT_FILE_STATUS_UNMERGED:
 
1304
                        icon_name = "gtk-delete";
 
1305
                        break;
 
1306
                case GIGGLE_GIT_FILE_STATUS_KILLED:
 
1307
                        icon_name = "gtk-stop";
 
1308
                        break;
 
1309
                default:
 
1310
                        g_assert_not_reached ();
 
1311
                }
 
1312
        }
 
1313
 
 
1314
        if (icon_name) {
 
1315
                pixbuf = gtk_icon_theme_load_icon (priv->icon_theme,
 
1316
                                                   icon_name, 16, 0, NULL);
 
1317
 
 
1318
                g_object_set (renderer, "pixbuf", pixbuf, NULL);
 
1319
 
 
1320
                if (pixbuf) {
 
1321
                        g_object_unref (pixbuf);
 
1322
                }
 
1323
        } else {
 
1324
                g_object_set (renderer, "pixbuf", NULL, NULL);
 
1325
        }
1141
1326
}
1142
1327
 
1143
1328
GtkWidget *
1270
1455
        GtkTreeIter         iter;
1271
1456
        gboolean            valid;
1272
1457
        GiggleGitIgnore    *git_ignore;
1273
 
        gchar              *rel_path, *name;
 
1458
        gchar              *rel_path;
1274
1459
        gboolean            highlight;
1275
1460
 
1276
1461
        priv = GET_PRIV (file_list);
1284
1469
 
1285
1470
        while (valid) {
1286
1471
                gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
1287
 
                                    COL_NAME, &name,
1288
1472
                                    COL_REL_PATH, &rel_path,
1289
1473
                                    COL_GIT_IGNORE, &git_ignore,
1290
1474
                                    -1);
1291
1475
 
1292
 
                if (rel_path && *rel_path) {
1293
 
                        highlight = (g_list_find_custom (files, rel_path, (GCompareFunc) file_list_compare_prefix) != NULL);
1294
 
                } else {
1295
 
                        /* we don't want the project basename included */
1296
 
                        highlight = FALSE;
1297
 
                }
 
1476
                highlight = (g_list_find_custom (files, rel_path, (GCompareFunc) file_list_compare_prefix) != NULL);
1298
1477
 
1299
1478
                gtk_tree_store_set (priv->store, &iter,
1300
1479
                                    COL_HIGHLIGHT, highlight,
1301
1480
                                    -1);
1302
1481
 
1303
 
                if (git_ignore) {
 
1482
                if (highlight && git_ignore) {
1304
1483
                        /* it's a directory */
1305
1484
                        file_list_update_highlight (file_list, &iter, rel_path, files);
1306
1485
                        g_object_unref (git_ignore);
1353
1532
        GiggleFileListPriv *priv;
1354
1533
 
1355
1534
        g_return_if_fail (GIGGLE_IS_FILE_LIST (list));
1356
 
        g_return_if_fail (GIGGLE_IS_REVISION (from));
1357
 
        g_return_if_fail (GIGGLE_IS_REVISION (to));
 
1535
        g_return_if_fail (!from || GIGGLE_IS_REVISION (from));
 
1536
        g_return_if_fail (!to || GIGGLE_IS_REVISION (to));
1358
1537
 
1359
1538
        priv = GET_PRIV (list);
1360
1539
 
1361
1540
        /* clear highlights */
1362
1541
        file_list_update_highlight (list, NULL, NULL, NULL);
1363
1542
 
1364
 
        if (priv->job) {
1365
 
                giggle_git_cancel_job (priv->git, priv->job);
1366
 
                g_object_unref (priv->job);
1367
 
                priv->job = NULL;
 
1543
        if (from && to) {
 
1544
                if (priv->job) {
 
1545
                        giggle_git_cancel_job (priv->git, priv->job);
 
1546
                        g_object_unref (priv->job);
 
1547
                        priv->job = NULL;
 
1548
                }
 
1549
 
 
1550
                priv->job = giggle_git_diff_tree_new (from, to);
 
1551
 
 
1552
                giggle_git_run_job (priv->git,
 
1553
                                    priv->job,
 
1554
                                    file_list_job_callback,
 
1555
                                    list);
1368
1556
        }
1369
 
 
1370
 
        priv->job = giggle_git_diff_tree_new (from, to);
1371
 
 
1372
 
        giggle_git_run_job (priv->git,
1373
 
                            priv->job,
1374
 
                            file_list_job_callback,
1375
 
                            list);
1376
1557
}