r2215: Switch to our own model for details view. Much faster.
[rox-filer.git] / ROX-Filer / src / view_details.c
bloba4691429d291450adf1dd68abe6725ab0000b972
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2002, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* view_details.c - display a list of files in a TreeView */
24 #include "config.h"
26 #include <gtk/gtk.h>
28 #include "global.h"
30 #include "view_iface.h"
31 #include "view_details.h"
32 #include "diritem.h"
33 #include "support.h"
34 #include "type.h"
35 #include "filer.h"
36 #include "display.h"
37 #include "pixmaps.h"
38 #include "dnd.h"
39 #include "bind.h"
40 #include "gui_support.h"
41 #include "menu.h"
43 /* These are the column numbers in the ListStore */
44 #define COL_LEAF 0
45 #define COL_TYPE 1
46 #define COL_PERM 2
47 #define COL_OWNER 3
48 #define COL_GROUP 4
49 #define COL_SIZE 5
50 #define COL_MTIME 6
51 #define COL_ITEM 7
52 #define COL_COLOUR 8
53 #define COL_ICON 9
54 #define N_COLUMNS 10
56 static gpointer parent_class = NULL;
58 struct _ViewDetailsClass {
59 GtkTreeViewClass parent;
62 typedef struct _ViewItem ViewItem;
64 struct _ViewItem {
65 DirItem *item;
66 GdkPixbuf *image;
67 int old_pos; /* Used while sorting */
70 typedef struct _ViewDetails ViewDetails;
72 struct _ViewDetails {
73 GtkTreeView treeview;
75 FilerWindow *filer_window; /* Used for styles, etc */
77 GPtrArray *items; /* ViewItem */
79 gint sort_column_id;
80 GtkSortType order;
81 int (*sort_fn)(const void *, const void *);
84 /* Static prototypes */
85 static void view_details_finialize(GObject *object);
86 static void view_details_class_init(gpointer gclass, gpointer data);
87 static void view_details_init(GTypeInstance *object, gpointer gclass);
89 static void view_details_iface_init(gpointer giface, gpointer iface_data);
91 static void view_details_sort(ViewIface *view);
92 static void view_details_style_changed(ViewIface *view, int flags);
93 static gboolean view_details_autoselect(ViewIface *view, const gchar *leaf);
94 static void view_details_add_items(ViewIface *view, GPtrArray *items);
95 static void view_details_update_items(ViewIface *view, GPtrArray *items);
96 static void view_details_delete_if(ViewIface *view,
97 gboolean (*test)(gpointer item, gpointer data),
98 gpointer data);
99 static void view_details_clear(ViewIface *view);
100 static void view_details_select_all(ViewIface *view);
101 static void view_details_clear_selection(ViewIface *view);
102 static int view_details_count_items(ViewIface *view);
103 static int view_details_count_selected(ViewIface *view);
104 static void view_details_show_cursor(ViewIface *view);
105 static void view_details_get_iter(ViewIface *view,
106 ViewIter *iter, IterFlags flags);
107 static void view_details_cursor_to_iter(ViewIface *view, ViewIter *iter);
108 static void view_details_set_selected(ViewIface *view,
109 ViewIter *iter,
110 gboolean selected);
111 static gboolean view_details_get_selected(ViewIface *view, ViewIter *iter);
112 static void view_details_select_only(ViewIface *view, ViewIter *iter);
113 static void view_details_set_frozen(ViewIface *view, gboolean frozen);
114 static void view_details_wink_item(ViewIface *view, ViewIter *iter);
115 static void view_details_autosize(ViewIface *view);
116 static gboolean view_details_cursor_visible(ViewIface *view);
117 static void view_details_set_base(ViewIface *view, ViewIter *iter);
118 #if 0
119 static DirItem *iter_peek(ViewIter *iter);
120 static DirItem *iter_next(ViewIter *iter);
121 #endif
122 static void make_iter(ViewDetails *view_details, ViewIter *iter,
123 IterFlags flags);
124 static void make_item_iter(ViewDetails *view_details,
125 ViewIter *v_iter,
126 GtkTreeIter *t_iter);
127 static void view_details_tree_model_init(GtkTreeModelIface *iface);
128 static gboolean details_get_sort_column_id(GtkTreeSortable *sortable,
129 gint *sort_column_id,
130 GtkSortType *order);
131 static void details_set_sort_column_id(GtkTreeSortable *sortable,
132 gint sort_column_id,
133 GtkSortType order);
134 static void details_set_sort_func(GtkTreeSortable *sortable,
135 gint sort_column_id,
136 GtkTreeIterCompareFunc func,
137 gpointer data,
138 GtkDestroyNotify destroy);
139 static void details_set_default_sort_func(GtkTreeSortable *sortable,
140 GtkTreeIterCompareFunc func,
141 gpointer data,
142 GtkDestroyNotify destroy);
143 static gboolean details_has_default_sort_func(GtkTreeSortable *sortable);
144 static void view_details_sortable_init(GtkTreeSortableIface *iface);
147 /****************************************************************
148 * EXTERNAL INTERFACE *
149 ****************************************************************/
151 GtkWidget *view_details_new(FilerWindow *filer_window)
153 ViewDetails *view_details;
155 view_details = g_object_new(view_details_get_type(), NULL);
156 view_details->filer_window = filer_window;
158 gtk_range_set_adjustment(GTK_RANGE(filer_window->scrollbar),
159 gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(view_details)));
161 return GTK_WIDGET(view_details);
164 GType view_details_get_type(void)
166 static GType type = 0;
168 if (!type)
170 static const GTypeInfo info =
172 sizeof (ViewDetailsClass),
173 NULL, /* base_init */
174 NULL, /* base_finalise */
175 view_details_class_init,
176 NULL, /* class_finalise */
177 NULL, /* class_data */
178 sizeof(ViewDetails),
179 0, /* n_preallocs */
180 view_details_init
182 static const GInterfaceInfo view_iface_info = {
183 view_details_iface_init,
184 NULL, NULL
186 static const GInterfaceInfo tree_model_info = {
187 (GInterfaceInitFunc) view_details_tree_model_init,
188 NULL, NULL
190 static const GInterfaceInfo sortable_info = {
191 (GInterfaceInitFunc) view_details_sortable_init,
192 NULL, NULL
196 type = g_type_register_static(gtk_tree_view_get_type(),
197 "ViewDetails", &info, 0);
199 g_type_add_interface_static(type, VIEW_TYPE_IFACE,
200 &view_iface_info);
201 g_type_add_interface_static(type, GTK_TYPE_TREE_MODEL,
202 &tree_model_info);
203 g_type_add_interface_static(type, GTK_TYPE_TREE_SORTABLE,
204 &sortable_info);
207 return type;
210 /****************************************************************
211 * INTERNAL FUNCTIONS *
212 ****************************************************************/
214 /* Fulfill the GtkTreeModel requirements */
215 static guint details_get_flags(GtkTreeModel *tree_model)
217 return GTK_TREE_MODEL_LIST_ONLY;
220 static gint details_get_n_columns(GtkTreeModel *tree_model)
222 return N_COLUMNS;
225 static GType details_get_column_type(GtkTreeModel *tree_model, gint index)
227 g_return_val_if_fail(index < N_COLUMNS && index >= 0, G_TYPE_INVALID);
229 if (index == COL_COLOUR)
230 return GDK_TYPE_COLOR;
231 else if (index == COL_ITEM)
232 return G_TYPE_POINTER;
233 else if (index == COL_ICON)
234 return GDK_TYPE_PIXBUF;
235 return G_TYPE_STRING;
238 static gboolean details_get_iter(GtkTreeModel *tree_model,
239 GtkTreeIter *iter,
240 GtkTreePath *path)
242 ViewDetails *view_details = (ViewDetails *) tree_model;
243 gint i;
245 g_return_val_if_fail(gtk_tree_path_get_depth (path) > 0, FALSE);
247 i = gtk_tree_path_get_indices(path)[0];
249 if (i >= view_details->items->len)
250 return FALSE;
252 iter->user_data = GINT_TO_POINTER(i);
254 return TRUE;
257 static GtkTreePath *details_get_path(GtkTreeModel *tree_model,
258 GtkTreeIter *iter)
260 GtkTreePath *retval;
262 retval = gtk_tree_path_new();
263 gtk_tree_path_append_index(retval, GPOINTER_TO_INT(iter->user_data));
265 return retval;
268 static void details_get_value(GtkTreeModel *tree_model,
269 GtkTreeIter *iter,
270 gint column,
271 GValue *value)
273 ViewDetails *view_details = (ViewDetails *) tree_model;
274 gint i;
275 GPtrArray *items = view_details->items;
276 DirItem *item;
277 mode_t m;
279 g_return_if_fail(column >= 0 && column < N_COLUMNS);
281 i = GPOINTER_TO_INT(iter->user_data);
282 g_return_if_fail(i >= 0 && i < items->len);
283 item = ((ViewItem *) items->pdata[i])->item;
285 /* g_print("[ get %d ]\n", column); */
287 if (column == COL_LEAF)
289 g_value_init(value, G_TYPE_STRING);
290 g_value_set_string(value, item->leafname);
291 return;
293 else if (column == COL_ITEM)
295 g_value_init(value, G_TYPE_POINTER);
296 g_value_set_pointer(value, item);
297 return;
300 if (item->base_type == TYPE_UNKNOWN)
302 GType type;
303 type = details_get_column_type(tree_model, column);
304 g_value_init(value, type);
305 if (type == G_TYPE_STRING)
306 g_value_set_string(value, "");
307 else if (type == GDK_TYPE_COLOR)
308 g_value_set_boxed(value, NULL);
309 else
310 g_value_set_object(value, NULL);
312 return;
314 m = item->mode;
316 switch (column)
318 case COL_LEAF:
319 g_value_init(value, G_TYPE_STRING);
320 g_value_set_string(value, item->leafname);
321 break;
322 case COL_ICON:
323 g_value_init(value, GDK_TYPE_PIXBUF);
324 if (!item->image->sm_pixbuf)
325 pixmap_make_small(item->image);
326 g_value_set_object(value, item->image->sm_pixbuf);
327 break;
328 case COL_COLOUR:
329 g_value_init(value, GDK_TYPE_COLOR);
330 g_value_set_boxed(value, type_get_colour(item, NULL));
331 break;
332 case COL_OWNER:
333 g_value_init(value, G_TYPE_STRING);
334 g_value_set_string(value, user_name(item->uid));
335 break;
336 case COL_GROUP:
337 g_value_init(value, G_TYPE_STRING);
338 g_value_set_string(value, group_name(item->gid));
339 break;
340 case COL_MTIME:
342 gchar *time;
343 time = pretty_time(&item->mtime);
344 g_value_init(value, G_TYPE_STRING);
345 g_value_set_string(value, time);
346 g_free(time);
347 break;
349 case COL_PERM:
350 g_value_init(value, G_TYPE_STRING);
351 g_value_set_string(value, pretty_permissions(m));
352 break;
353 case COL_SIZE:
354 g_value_init(value, G_TYPE_STRING);
355 if (item->base_type != TYPE_DIRECTORY)
356 g_value_set_string(value,
357 format_size(item->size));
358 break;
359 case COL_TYPE:
360 g_value_init(value, G_TYPE_STRING);
361 g_value_set_string(value,
362 item->flags & ITEM_FLAG_APPDIR? "App" :
363 S_ISDIR(m) ? "Dir" :
364 S_ISCHR(m) ? "Char" :
365 S_ISBLK(m) ? "Blck" :
366 S_ISLNK(m) ? "Link" :
367 S_ISSOCK(m) ? "Sock" :
368 S_ISFIFO(m) ? "Pipe" :
369 S_ISDOOR(m) ? "Door" :
370 "File");
371 break;
372 default:
373 g_value_init(value, G_TYPE_STRING);
374 g_value_set_string(value, "Hello");
375 break;
379 static gboolean details_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter)
381 ViewDetails *view_details = (ViewDetails *) tree_model;
382 int i;
384 i = GPOINTER_TO_INT(iter->user_data) + 1;
385 iter->user_data = GINT_TO_POINTER(i);
387 return i < view_details->items->len;
390 static gboolean details_iter_children(GtkTreeModel *tree_model,
391 GtkTreeIter *iter,
392 GtkTreeIter *parent)
394 ViewDetails *view_details = (ViewDetails *) tree_model;
396 /* this is a list, nodes have no children */
397 if (parent)
398 return FALSE;
400 /* but if parent == NULL we return the list itself as children of the
401 * "root"
404 if (view_details->items->len)
406 iter->user_data = GINT_TO_POINTER(0);
407 return TRUE;
409 else
410 return FALSE;
413 static gboolean details_iter_has_child(GtkTreeModel *tree_model,
414 GtkTreeIter *iter)
416 return FALSE;
419 static gint details_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter)
421 ViewDetails *view_details = (ViewDetails *) tree_model;
423 if (iter == NULL)
424 return view_details->items->len;
426 return 0;
429 static gboolean details_iter_nth_child(GtkTreeModel *tree_model,
430 GtkTreeIter *iter,
431 GtkTreeIter *parent,
432 gint n)
434 ViewDetails *view_details = (ViewDetails *) tree_model;
436 if (parent)
437 return FALSE;
439 if (n >= 0 && n < view_details->items->len)
441 iter->user_data = GINT_TO_POINTER(n);
442 return TRUE;
444 else
445 return FALSE;
448 static gboolean details_iter_parent(GtkTreeModel *tree_model,
449 GtkTreeIter *iter,
450 GtkTreeIter *child)
452 return FALSE;
455 /* A ViewDetails is both a GtkTreeView and a GtkTreeModel.
456 * The following functions implement the model interface...
459 static void view_details_tree_model_init(GtkTreeModelIface *iface)
461 iface->get_flags = details_get_flags;
462 iface->get_n_columns = details_get_n_columns;
463 iface->get_column_type = details_get_column_type;
464 iface->get_iter = details_get_iter;
465 iface->get_path = details_get_path;
466 iface->get_value = details_get_value;
467 iface->iter_next = details_iter_next;
468 iface->iter_children = details_iter_children;
469 iface->iter_has_child = details_iter_has_child;
470 iface->iter_n_children = details_iter_n_children;
471 iface->iter_nth_child = details_iter_nth_child;
472 iface->iter_parent = details_iter_parent;
475 static void view_details_sortable_init(GtkTreeSortableIface *iface)
477 iface->get_sort_column_id = details_get_sort_column_id;
478 iface->set_sort_column_id = details_set_sort_column_id;
479 iface->set_sort_func = details_set_sort_func;
480 iface->set_default_sort_func = details_set_default_sort_func;
481 iface->has_default_sort_func = details_has_default_sort_func;
484 static gboolean details_get_sort_column_id(GtkTreeSortable *sortable,
485 gint *sort_column_id,
486 GtkSortType *order)
488 ViewDetails *view_details = (ViewDetails *) sortable;
490 if (view_details->sort_column_id == -1)
491 return FALSE;
493 if (sort_column_id)
494 *sort_column_id = view_details->sort_column_id;
495 if (order)
496 *order = view_details->order;
497 return TRUE;
500 static void details_set_sort_column_id(GtkTreeSortable *sortable,
501 gint sort_column_id,
502 GtkSortType order)
504 ViewDetails *view_details = (ViewDetails *) sortable;
506 if (view_details->sort_column_id == sort_column_id &&
507 view_details->order == order)
508 return;
510 view_details->sort_column_id = sort_column_id;
511 view_details->order = order;
513 switch (sort_column_id)
515 case COL_LEAF:
516 view_details->sort_fn = sort_by_name;
517 break;
518 case COL_SIZE:
519 view_details->sort_fn = sort_by_size;
520 break;
521 case COL_MTIME:
522 view_details->sort_fn = sort_by_date;
523 break;
524 case COL_TYPE:
525 view_details->sort_fn = sort_by_type;
526 break;
527 case COL_OWNER:
528 view_details->sort_fn = sort_by_owner;
529 break;
530 case COL_GROUP:
531 view_details->sort_fn = sort_by_group;
532 break;
533 default:
534 g_assert_not_reached();
537 view_details_sort((ViewIface *) view_details);
539 gtk_tree_sortable_sort_column_changed(sortable);
542 static void details_set_sort_func(GtkTreeSortable *sortable,
543 gint sort_column_id,
544 GtkTreeIterCompareFunc func,
545 gpointer data,
546 GtkDestroyNotify destroy)
548 g_assert_not_reached();
551 static void details_set_default_sort_func(GtkTreeSortable *sortable,
552 GtkTreeIterCompareFunc func,
553 gpointer data,
554 GtkDestroyNotify destroy)
556 g_assert_not_reached();
559 static gboolean details_has_default_sort_func(GtkTreeSortable *sortable)
561 return FALSE;
565 /* End of model implementation */
567 static void toggle_selected(GtkTreeSelection *selection, GtkTreeIter *iter)
569 if (gtk_tree_selection_iter_is_selected(selection, iter))
570 gtk_tree_selection_unselect_iter(selection, iter);
571 else
572 gtk_tree_selection_select_iter(selection, iter);
575 static void perform_action(ViewDetails *view_details, GdkEventButton *event)
577 BindAction action;
578 FilerWindow *filer_window = view_details->filer_window;
579 DirItem *item = NULL;
580 GtkTreeView *tree = (GtkTreeView *) view_details;
581 GtkTreePath *path = NULL;
582 GtkTreeIter iter;
583 GtkTreeModel *model;
584 GtkTreeSelection *selection;
585 /* OpenFlags flags = 0; */
587 model = gtk_tree_view_get_model(tree);
588 selection = gtk_tree_view_get_selection(tree);
590 if (gtk_tree_view_get_path_at_pos(tree, event->x, event->y,
591 &path, NULL, NULL, NULL))
593 g_return_if_fail(path != NULL);
595 gtk_tree_model_get_iter(model, &iter, path);
597 gtk_tree_model_get(model, &iter, COL_ITEM, &item, -1);
600 /* TODO: Cancel slow DnD */
601 /* TODO: Target callbacks */
603 action = bind_lookup_bev(
604 item ? BIND_DIRECTORY_ICON : BIND_DIRECTORY,
605 event);
607 switch (action)
609 case ACT_CLEAR_SELECTION:
610 gtk_tree_selection_unselect_all(selection);
611 break;
612 case ACT_TOGGLE_SELECTED:
613 toggle_selected(selection, &iter);
614 break;
615 #if 0
616 case ACT_SELECT_EXCL:
617 collection_clear_except(collection, item);
618 break;
619 case ACT_EDIT_ITEM:
620 flags |= OPEN_SHIFT;
621 /* (no break) */
622 case ACT_OPEN_ITEM:
624 ViewIter viter;
626 make_item_iter(view_details, &viter, &iter);
628 if (event->button != 1 || event->state & GDK_MOD1_MASK)
629 flags |= OPEN_CLOSE_WINDOW;
630 else
631 flags |= OPEN_SAME_WINDOW;
632 if (o_new_button_1.int_value)
633 flags ^= OPEN_SAME_WINDOW;
634 /* TODO */
635 if (event->type == GDK_2BUTTON_PRESS)
636 collection_unselect_item(collection, item);
637 dnd_motion_ungrab();
639 filer_openitem(filer_window, &viter, flags);
640 break;
642 #endif
643 case ACT_POPUP_MENU:
645 ViewIter viter;
647 dnd_motion_ungrab();
648 tooltip_show(NULL);
650 make_item_iter(view_details, &viter, &iter);
651 show_filer_menu(filer_window,
652 (GdkEvent *) event, &viter);
653 break;
655 #if 0
656 case ACT_PRIME_AND_SELECT:
657 if (!selected)
658 collection_clear_except(collection, item);
659 dnd_motion_start(MOTION_READY_FOR_DND);
660 break;
661 case ACT_PRIME_AND_TOGGLE:
662 collection_toggle_item(collection, item);
663 dnd_motion_start(MOTION_READY_FOR_DND);
664 break;
665 case ACT_PRIME_FOR_DND:
666 dnd_motion_start(MOTION_READY_FOR_DND);
667 break;
668 case ACT_IGNORE:
669 if (press && event->button < 4)
671 if (item)
672 collection_wink_item(collection, item);
673 dnd_motion_start(MOTION_NONE);
675 break;
676 case ACT_LASSO_CLEAR:
677 collection_clear_selection(collection);
678 /* (no break) */
679 case ACT_LASSO_MODIFY:
680 collection_lasso_box(collection, event->x, event->y);
681 break;
682 case ACT_RESIZE:
683 filer_window_autosize(filer_window);
684 break;
685 #endif
686 default:
687 g_warning("Unsupported action : %d\n", action);
688 break;
692 static gboolean view_details_button_press(GtkWidget *widget,
693 GdkEventButton *bev)
695 if (dnd_motion_press(widget, bev))
696 perform_action((ViewDetails *) widget, bev);
698 return TRUE;
701 static gboolean view_details_button_release(GtkWidget *widget,
702 GdkEventButton *bev)
704 if (!dnd_motion_release(bev))
705 perform_action((ViewDetails *) widget, bev);
707 return TRUE;
710 static void view_details_destroy(GtkObject *view_details)
712 VIEW_DETAILS(view_details)->filer_window = NULL;
715 static void view_details_finialize(GObject *object)
717 ViewDetails *view_details = (ViewDetails *) object;
719 g_ptr_array_free(view_details->items, TRUE);
720 view_details->items = NULL;
722 G_OBJECT_CLASS(parent_class)->finalize(object);
725 static void view_details_class_init(gpointer gclass, gpointer data)
727 GObjectClass *object = (GObjectClass *) gclass;
728 GtkWidgetClass *widget = (GtkWidgetClass *) gclass;
730 parent_class = g_type_class_peek_parent(gclass);
732 object->finalize = view_details_finialize;
733 GTK_OBJECT_CLASS(object)->destroy = view_details_destroy;
735 widget->button_press_event = view_details_button_press;
736 widget->button_release_event = view_details_button_release;
739 static void view_details_init(GTypeInstance *object, gpointer gclass)
741 GtkTreeView *treeview = (GtkTreeView *) object;
742 GtkTreeViewColumn *column;
743 GtkCellRenderer *cell;
744 GtkTreeSortable *sortable_list;
745 ViewDetails *view_details = (ViewDetails *) object;
747 view_details->items = g_ptr_array_new();
749 /* Sorting */
750 view_details->sort_column_id = -1;
751 view_details->sort_fn = NULL;
752 sortable_list = GTK_TREE_SORTABLE(object);
753 gtk_tree_sortable_set_sort_column_id(sortable_list, COL_LEAF,
754 GTK_SORT_ASCENDING);
756 gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(view_details));
758 /* Icon */
759 cell = gtk_cell_renderer_pixbuf_new();
760 column = gtk_tree_view_column_new_with_attributes(NULL, cell,
761 "pixbuf", COL_ICON, NULL);
762 gtk_tree_view_append_column(treeview, column);
764 /* The rest are text... */
765 cell = gtk_cell_renderer_text_new();
767 /* Name */
768 column = gtk_tree_view_column_new_with_attributes(_("Name"), cell,
769 "text", COL_LEAF,
770 "foreground-gdk", COL_COLOUR, NULL);
771 gtk_tree_view_append_column(treeview, column);
772 gtk_tree_view_column_set_sort_column_id(column, COL_LEAF);
774 /* Type */
775 column = gtk_tree_view_column_new_with_attributes(_("Type"), cell,
776 "text", COL_TYPE, NULL);
777 gtk_tree_view_append_column(treeview, column);
778 gtk_tree_view_column_set_sort_column_id(column, COL_TYPE);
780 /* Perm */
781 column = gtk_tree_view_column_new_with_attributes(_("Permissions"),
782 cell, "text", COL_PERM, NULL);
783 gtk_tree_view_append_column(treeview, column);
785 /* Owner */
786 column = gtk_tree_view_column_new_with_attributes(_("Owner"), cell,
787 "text", COL_OWNER, NULL);
788 gtk_tree_view_append_column(treeview, column);
789 gtk_tree_view_column_set_sort_column_id(column, COL_OWNER);
791 /* Group */
792 column = gtk_tree_view_column_new_with_attributes(_("Group"), cell,
793 "text", COL_GROUP, NULL);
794 gtk_tree_view_append_column(treeview, column);
795 gtk_tree_view_column_set_sort_column_id(column, COL_GROUP);
797 /* Size */
798 column = gtk_tree_view_column_new_with_attributes(_("Size"), cell,
799 "text", COL_SIZE, NULL);
800 gtk_tree_view_append_column(treeview, column);
801 gtk_tree_view_column_set_sort_column_id(column, COL_SIZE);
803 /* MTime */
804 column = gtk_tree_view_column_new_with_attributes(_("M-Time"), cell,
805 "text", COL_MTIME, NULL);
806 gtk_tree_view_append_column(treeview, column);
807 gtk_tree_view_column_set_sort_column_id(column, COL_MTIME);
809 gtk_widget_set_size_request(GTK_WIDGET(treeview), -1, 50);
812 /* Create the handers for the View interface */
813 static void view_details_iface_init(gpointer giface, gpointer iface_data)
815 ViewIfaceClass *iface = giface;
817 g_assert(G_TYPE_FROM_INTERFACE(iface) == VIEW_TYPE_IFACE);
819 /* override stuff */
820 iface->sort = view_details_sort;
821 iface->style_changed = view_details_style_changed;
822 iface->autoselect = view_details_autoselect;
823 iface->add_items = view_details_add_items;
824 iface->update_items = view_details_update_items;
825 iface->delete_if = view_details_delete_if;
826 iface->clear = view_details_clear;
827 iface->select_all = view_details_select_all;
828 iface->clear_selection = view_details_clear_selection;
829 iface->count_items = view_details_count_items;
830 iface->count_selected = view_details_count_selected;
831 iface->show_cursor = view_details_show_cursor;
832 iface->get_iter = view_details_get_iter;
833 iface->cursor_to_iter = view_details_cursor_to_iter;
834 iface->set_selected = view_details_set_selected;
835 iface->get_selected = view_details_get_selected;
836 iface->set_frozen = view_details_set_frozen;
837 iface->select_only = view_details_select_only;
838 iface->wink_item = view_details_wink_item;
839 iface->autosize = view_details_autosize;
840 iface->cursor_visible = view_details_cursor_visible;
841 iface->set_base = view_details_set_base;
844 /* Implementations of the View interface. See view_iface.c for comments. */
846 static void view_details_style_changed(ViewIface *view, int flags)
850 static gint wrap_sort(gconstpointer a, gconstpointer b,
851 ViewDetails *view_details)
853 ViewItem *ia = *(ViewItem **) a;
854 ViewItem *ib = *(ViewItem **) b;
856 if (view_details->order == GTK_SORT_ASCENDING)
857 return view_details->sort_fn(ia->item, ib->item);
858 else
859 return -view_details->sort_fn(ia->item, ib->item);
862 static void view_details_sort(ViewIface *view)
864 ViewDetails *view_details = (ViewDetails *) view;
865 ViewItem **items = (ViewItem **) view_details->items->pdata;
866 GArray *new_order;
867 gint i, len = view_details->items->len;
868 GtkTreePath *path;
870 g_return_if_fail(view_details->sort_fn != NULL);
872 if (!len)
873 return;
875 for (i = len - 1; i >= 0; i--)
876 items[i]->old_pos = i;
878 g_ptr_array_sort_with_data(view_details->items,
879 (GCompareDataFunc) wrap_sort,
880 view_details);
882 new_order = g_array_sized_new(FALSE, FALSE, sizeof(gint), len);
883 g_array_set_size(new_order, len);
885 for (i = len - 1; i >= 0; i--)
886 g_array_insert_val(new_order, items[i]->old_pos, i);
888 path = gtk_tree_path_new();
889 gtk_tree_model_rows_reordered((GtkTreeModel *) view,
890 path, NULL,
891 (gint *) new_order->data);
892 gtk_tree_path_free(path);
893 g_array_free(new_order, TRUE);
896 static gboolean view_details_autoselect(ViewIface *view, const gchar *leaf)
898 return FALSE;
901 static void view_details_add_items(ViewIface *view, GPtrArray *new_items)
903 ViewDetails *view_details = (ViewDetails *) view;
904 FilerWindow *filer_window = view_details->filer_window;
905 gboolean show_hidden = filer_window->show_hidden;
906 GPtrArray *items = view_details->items;
907 GtkTreeIter iter;
908 int i;
909 GtkTreePath *path;
910 GtkTreeModel *model = (GtkTreeModel *) view;
912 iter.user_data = GINT_TO_POINTER(items->len);
913 path = details_get_path(model, &iter);
915 for (i = 0; i < new_items->len; i++)
917 DirItem *item = (DirItem *) new_items->pdata[i];
918 char *leafname = item->leafname;
919 ViewItem *vitem;
921 if (leafname[0] == '.')
923 if (!show_hidden)
924 continue;
926 if (leafname[1] == '\0')
927 continue; /* Never show '.' */
929 if (leafname[1] == '.' &&
930 leafname[2] == '\0')
931 continue; /* Never show '..' */
934 vitem = g_new(ViewItem, 1);
935 vitem->item = item;
936 vitem->image = NULL;
938 g_ptr_array_add(items, vitem);
940 iter.user_data = GINT_TO_POINTER(items->len - 1);
941 gtk_tree_model_row_inserted(model, path, &iter);
942 gtk_tree_path_next(path);
945 gtk_tree_path_free(path);
947 view_details_sort(view);
950 /* Find an item in the sorted array.
951 * Returns the item number, or -1 if not found.
953 static int details_find_item(ViewDetails *view_details, DirItem *item)
955 ViewItem **items, tmp, *tmpp;
956 int lower, upper;
957 int (*compar)(const void *, const void *);
959 g_return_val_if_fail(view_details != NULL, -1);
960 g_return_val_if_fail(item != NULL, -1);
962 tmp.item = item;
963 tmpp = &tmp;
965 items = (ViewItem **) view_details->items->pdata;
966 compar = view_details->sort_fn;
968 g_return_val_if_fail(compar != NULL, -1);
970 /* If item is here, then: lower <= i < upper */
971 lower = 0;
972 upper = view_details->items->len;
974 while (lower < upper)
976 int i, cmp;
978 i = (lower + upper) >> 1;
980 cmp = wrap_sort(&items[i], &tmpp, view_details);
981 if (cmp == 0)
982 return i;
984 if (cmp > 0)
985 upper = i;
986 else
987 lower = i + 1;
990 return -1;
993 static void view_details_update_items(ViewIface *view, GPtrArray *items)
995 ViewDetails *view_details = (ViewDetails *) view;
996 FilerWindow *filer_window = view_details->filer_window;
997 int i;
998 GtkTreeModel *model = (GtkTreeModel *) view_details;
1000 g_return_if_fail(items->len > 0);
1002 /* The item data has already been modified, so this gives the
1003 * final sort order...
1005 view_details_sort(view);
1007 for (i = 0; i < items->len; i++)
1009 DirItem *item = (DirItem *) items->pdata[i];
1010 const gchar *leafname = item->leafname;
1011 int j;
1013 if (leafname[0] == '.' && filer_window->show_hidden == FALSE)
1014 continue;
1016 j = details_find_item(view_details, item);
1018 if (j < 0)
1019 g_warning("Failed to find '%s'\n", leafname);
1020 else
1022 GtkTreePath *path;
1023 GtkTreeIter iter;
1024 path = gtk_tree_path_new();
1025 gtk_tree_path_append_index(path, j);
1026 iter.user_data = GINT_TO_POINTER(j);
1027 gtk_tree_model_row_changed(model, path, &iter);
1032 static void view_details_delete_if(ViewIface *view,
1033 gboolean (*test)(gpointer item, gpointer data),
1034 gpointer data)
1038 static void view_details_clear(ViewIface *view)
1040 GtkTreePath *path;
1041 GPtrArray *items = ((ViewDetails *) view)->items;
1042 GtkTreeModel *model = (GtkTreeModel *) view;
1044 path = gtk_tree_path_new();
1045 gtk_tree_path_append_index(path, items->len);
1047 while (gtk_tree_path_prev(path))
1048 gtk_tree_model_row_deleted(model, path);
1050 g_ptr_array_set_size(items, 0);
1051 gtk_tree_path_free(path);
1054 static void view_details_select_all(ViewIface *view)
1058 static void view_details_clear_selection(ViewIface *view)
1062 static int view_details_count_items(ViewIface *view)
1064 return 0;
1067 static int view_details_count_selected(ViewIface *view)
1069 return 0;
1072 static void view_details_show_cursor(ViewIface *view)
1076 static void view_details_get_iter(ViewIface *view,
1077 ViewIter *iter, IterFlags flags)
1079 make_iter((ViewDetails *) view, iter, flags);
1082 static void view_details_cursor_to_iter(ViewIface *view, ViewIter *iter)
1086 static void view_details_set_selected(ViewIface *view,
1087 ViewIter *iter,
1088 gboolean selected)
1092 static gboolean view_details_get_selected(ViewIface *view, ViewIter *iter)
1094 return FALSE;
1097 static void view_details_select_only(ViewIface *view, ViewIter *iter)
1101 static void view_details_set_frozen(ViewIface *view, gboolean frozen)
1105 static void view_details_wink_item(ViewIface *view, ViewIter *iter)
1109 static void view_details_autosize(ViewIface *view)
1113 static gboolean view_details_cursor_visible(ViewIface *view)
1115 return FALSE;
1118 static void view_details_set_base(ViewIface *view, ViewIter *iter)
1122 static DirItem *iter_init(ViewIter *iter)
1124 return NULL;
1127 #if 0
1128 static DirItem *iter_peek(ViewIter *iter)
1130 return NULL;
1133 static DirItem *iter_next(ViewIter *iter)
1135 return NULL;
1137 #endif
1139 /* Set the iterator to return 'i' on the next peek() */
1140 static void make_item_iter(ViewDetails *view_details,
1141 ViewIter *iter,
1142 GtkTreeIter *t_iter)
1144 make_iter(view_details, iter, 0);
1146 iter->next = iter_init;
1147 iter->peek = iter_init;
1148 iter->n_remaining = 0;
1151 static void make_iter(ViewDetails *view_details, ViewIter *iter,
1152 IterFlags flags)
1154 /* iter->view_details = view_details; */
1155 iter->next = iter_init;
1156 iter->peek = NULL;
1158 iter->flags = flags;