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)
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
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 */
27 #include <gdk/gdkkeysyms.h>
31 #include "view_iface.h"
32 #include "view_details.h"
41 #include "gui_support.h"
45 /* These are the column numbers in the ListStore */
56 #define COL_BG_COLOUR 10
59 static gpointer parent_class
= NULL
;
61 struct _ViewDetailsClass
{
62 GtkTreeViewClass parent
;
65 typedef struct _ViewItem ViewItem
;
70 int old_pos
; /* Used while sorting */
74 typedef struct _ViewDetails ViewDetails
;
79 FilerWindow
*filer_window
; /* Used for styles, etc */
81 GPtrArray
*items
; /* ViewItem */
85 int (*sort_fn
)(const void *, const void *);
87 int cursor_base
; /* Cursor when minibuffer opened */
90 /* Static prototypes */
91 static void view_details_finialize(GObject
*object
);
92 static void view_details_class_init(gpointer gclass
, gpointer data
);
93 static void view_details_init(GTypeInstance
*object
, gpointer gclass
);
95 static void view_details_iface_init(gpointer giface
, gpointer iface_data
);
97 static void view_details_sort(ViewIface
*view
);
98 static void view_details_style_changed(ViewIface
*view
, int flags
);
99 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
);
100 static void view_details_add_items(ViewIface
*view
, GPtrArray
*items
);
101 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
);
102 static void view_details_delete_if(ViewIface
*view
,
103 gboolean (*test
)(gpointer item
, gpointer data
),
105 static void view_details_clear(ViewIface
*view
);
106 static void view_details_select_all(ViewIface
*view
);
107 static void view_details_clear_selection(ViewIface
*view
);
108 static int view_details_count_items(ViewIface
*view
);
109 static int view_details_count_selected(ViewIface
*view
);
110 static void view_details_show_cursor(ViewIface
*view
);
111 static void view_details_get_iter(ViewIface
*view
,
112 ViewIter
*iter
, IterFlags flags
);
113 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
114 static void view_details_set_selected(ViewIface
*view
,
117 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
);
118 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
);
119 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
);
120 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
);
121 static void view_details_autosize(ViewIface
*view
);
122 static gboolean
view_details_cursor_visible(ViewIface
*view
);
123 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
);
124 static DirItem
*iter_peek(ViewIter
*iter
);
125 static DirItem
*iter_prev(ViewIter
*iter
);
126 static DirItem
*iter_next(ViewIter
*iter
);
127 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
129 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
);
130 static void view_details_tree_model_init(GtkTreeModelIface
*iface
);
131 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
132 gint
*sort_column_id
,
134 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
137 static void details_set_sort_func(GtkTreeSortable
*sortable
,
139 GtkTreeIterCompareFunc func
,
141 GtkDestroyNotify destroy
);
142 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
143 GtkTreeIterCompareFunc func
,
145 GtkDestroyNotify destroy
);
146 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
);
147 static void view_details_sortable_init(GtkTreeSortableIface
*iface
);
148 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
);
149 static gboolean
get_selected(ViewDetails
*view_details
, int i
);
152 /****************************************************************
153 * EXTERNAL INTERFACE *
154 ****************************************************************/
156 GtkWidget
*view_details_new(FilerWindow
*filer_window
)
158 ViewDetails
*view_details
;
160 view_details
= g_object_new(view_details_get_type(), NULL
);
161 view_details
->filer_window
= filer_window
;
163 gtk_range_set_adjustment(GTK_RANGE(filer_window
->scrollbar
),
164 gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(view_details
)));
166 return GTK_WIDGET(view_details
);
169 GType
view_details_get_type(void)
171 static GType type
= 0;
175 static const GTypeInfo info
=
177 sizeof (ViewDetailsClass
),
178 NULL
, /* base_init */
179 NULL
, /* base_finalise */
180 view_details_class_init
,
181 NULL
, /* class_finalise */
182 NULL
, /* class_data */
187 static const GInterfaceInfo view_iface_info
= {
188 view_details_iface_init
,
191 static const GInterfaceInfo tree_model_info
= {
192 (GInterfaceInitFunc
) view_details_tree_model_init
,
195 static const GInterfaceInfo sortable_info
= {
196 (GInterfaceInitFunc
) view_details_sortable_init
,
201 type
= g_type_register_static(gtk_tree_view_get_type(),
202 "ViewDetails", &info
, 0);
204 g_type_add_interface_static(type
, VIEW_TYPE_IFACE
,
206 g_type_add_interface_static(type
, GTK_TYPE_TREE_MODEL
,
208 g_type_add_interface_static(type
, GTK_TYPE_TREE_SORTABLE
,
215 /****************************************************************
216 * INTERNAL FUNCTIONS *
217 ****************************************************************/
219 /* Fulfill the GtkTreeModel requirements */
220 static guint
details_get_flags(GtkTreeModel
*tree_model
)
222 return GTK_TREE_MODEL_LIST_ONLY
;
225 static gint
details_get_n_columns(GtkTreeModel
*tree_model
)
230 static GType
details_get_column_type(GtkTreeModel
*tree_model
, gint index
)
232 g_return_val_if_fail(index
< N_COLUMNS
&& index
>= 0, G_TYPE_INVALID
);
234 if (index
== COL_COLOUR
|| index
== COL_BG_COLOUR
)
235 return GDK_TYPE_COLOR
;
236 else if (index
== COL_ITEM
)
237 return G_TYPE_POINTER
;
238 else if (index
== COL_ICON
)
239 return GDK_TYPE_PIXBUF
;
240 return G_TYPE_STRING
;
243 static gboolean
details_get_iter(GtkTreeModel
*tree_model
,
247 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
250 g_return_val_if_fail(gtk_tree_path_get_depth (path
) > 0, FALSE
);
252 i
= gtk_tree_path_get_indices(path
)[0];
254 if (i
>= view_details
->items
->len
)
257 iter
->user_data
= GINT_TO_POINTER(i
);
262 static GtkTreePath
*details_get_path(GtkTreeModel
*tree_model
,
267 retval
= gtk_tree_path_new();
268 gtk_tree_path_append_index(retval
, GPOINTER_TO_INT(iter
->user_data
));
273 static void details_get_value(GtkTreeModel
*tree_model
,
278 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
279 GtkStyle
*style
= ((GtkWidget
*) tree_model
)->style
;
281 GPtrArray
*items
= view_details
->items
;
286 g_return_if_fail(column
>= 0 && column
< N_COLUMNS
);
288 i
= GPOINTER_TO_INT(iter
->user_data
);
289 g_return_if_fail(i
>= 0 && i
< items
->len
);
290 view_item
= (ViewItem
*) items
->pdata
[i
];
291 item
= view_item
->item
;
293 /* g_print("[ get %d ]\n", column); */
295 if (column
== COL_LEAF
)
297 g_value_init(value
, G_TYPE_STRING
);
298 g_value_set_string(value
, item
->leafname
);
301 else if (column
== COL_ITEM
)
303 g_value_init(value
, G_TYPE_POINTER
);
304 g_value_set_pointer(value
, item
);
308 if (item
->base_type
== TYPE_UNKNOWN
)
311 type
= details_get_column_type(tree_model
, column
);
312 g_value_init(value
, type
);
313 if (type
== G_TYPE_STRING
)
314 g_value_set_string(value
, "");
315 else if (type
== GDK_TYPE_COLOR
)
316 g_value_set_boxed(value
, NULL
);
318 g_value_set_object(value
, NULL
);
327 g_value_init(value
, G_TYPE_STRING
);
328 g_value_set_string(value
, item
->leafname
);
331 g_value_init(value
, GDK_TYPE_PIXBUF
);
332 if (!item
->image
->sm_pixbuf
)
333 pixmap_make_small(item
->image
);
334 g_value_set_object(value
, item
->image
->sm_pixbuf
);
337 g_value_init(value
, GDK_TYPE_COLOR
);
338 g_value_set_boxed(value
, type_get_colour(item
, NULL
));
341 g_value_init(value
, GDK_TYPE_COLOR
);
342 g_value_set_boxed(value
, view_item
->selected
343 ? &style
->base
[GTK_STATE_SELECTED
]
344 : &style
->base
[GTK_STATE_NORMAL
]);
347 g_value_init(value
, G_TYPE_STRING
);
348 g_value_set_string(value
, user_name(item
->uid
));
351 g_value_init(value
, G_TYPE_STRING
);
352 g_value_set_string(value
, group_name(item
->gid
));
357 time
= pretty_time(&item
->mtime
);
358 g_value_init(value
, G_TYPE_STRING
);
359 g_value_set_string(value
, time
);
364 g_value_init(value
, G_TYPE_STRING
);
365 g_value_set_string(value
, pretty_permissions(m
));
368 g_value_init(value
, G_TYPE_STRING
);
369 if (item
->base_type
!= TYPE_DIRECTORY
)
370 g_value_set_string(value
,
371 format_size(item
->size
));
374 g_value_init(value
, G_TYPE_STRING
);
375 g_value_set_string(value
,
376 item
->flags
& ITEM_FLAG_APPDIR
? "App" :
378 S_ISCHR(m
) ? "Char" :
379 S_ISBLK(m
) ? "Blck" :
380 S_ISLNK(m
) ? "Link" :
381 S_ISSOCK(m
) ? "Sock" :
382 S_ISFIFO(m
) ? "Pipe" :
383 S_ISDOOR(m
) ? "Door" :
387 g_value_init(value
, G_TYPE_STRING
);
388 g_value_set_string(value
, "Hello");
393 static gboolean
details_iter_next(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
395 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
398 i
= GPOINTER_TO_INT(iter
->user_data
) + 1;
399 iter
->user_data
= GINT_TO_POINTER(i
);
401 return i
< view_details
->items
->len
;
404 static gboolean
details_iter_children(GtkTreeModel
*tree_model
,
408 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
410 /* this is a list, nodes have no children */
414 /* but if parent == NULL we return the list itself as children of the
418 if (view_details
->items
->len
)
420 iter
->user_data
= GINT_TO_POINTER(0);
427 static gboolean
details_iter_has_child(GtkTreeModel
*tree_model
,
433 static gint
details_iter_n_children(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
435 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
438 return view_details
->items
->len
;
443 static gboolean
details_iter_nth_child(GtkTreeModel
*tree_model
,
448 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
453 if (n
>= 0 && n
< view_details
->items
->len
)
455 iter
->user_data
= GINT_TO_POINTER(n
);
462 static gboolean
details_iter_parent(GtkTreeModel
*tree_model
,
469 /* A ViewDetails is both a GtkTreeView and a GtkTreeModel.
470 * The following functions implement the model interface...
473 static void view_details_tree_model_init(GtkTreeModelIface
*iface
)
475 iface
->get_flags
= details_get_flags
;
476 iface
->get_n_columns
= details_get_n_columns
;
477 iface
->get_column_type
= details_get_column_type
;
478 iface
->get_iter
= details_get_iter
;
479 iface
->get_path
= details_get_path
;
480 iface
->get_value
= details_get_value
;
481 iface
->iter_next
= details_iter_next
;
482 iface
->iter_children
= details_iter_children
;
483 iface
->iter_has_child
= details_iter_has_child
;
484 iface
->iter_n_children
= details_iter_n_children
;
485 iface
->iter_nth_child
= details_iter_nth_child
;
486 iface
->iter_parent
= details_iter_parent
;
489 static void view_details_sortable_init(GtkTreeSortableIface
*iface
)
491 iface
->get_sort_column_id
= details_get_sort_column_id
;
492 iface
->set_sort_column_id
= details_set_sort_column_id
;
493 iface
->set_sort_func
= details_set_sort_func
;
494 iface
->set_default_sort_func
= details_set_default_sort_func
;
495 iface
->has_default_sort_func
= details_has_default_sort_func
;
498 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
499 gint
*sort_column_id
,
502 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
504 if (view_details
->sort_column_id
== -1)
508 *sort_column_id
= view_details
->sort_column_id
;
510 *order
= view_details
->order
;
514 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
518 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
520 if (view_details
->sort_column_id
== sort_column_id
&&
521 view_details
->order
== order
)
524 view_details
->sort_column_id
= sort_column_id
;
525 view_details
->order
= order
;
527 switch (sort_column_id
)
530 view_details
->sort_fn
= sort_by_name
;
533 view_details
->sort_fn
= sort_by_size
;
536 view_details
->sort_fn
= sort_by_date
;
539 view_details
->sort_fn
= sort_by_type
;
542 view_details
->sort_fn
= sort_by_owner
;
545 view_details
->sort_fn
= sort_by_group
;
548 g_assert_not_reached();
551 view_details_sort((ViewIface
*) view_details
);
553 gtk_tree_sortable_sort_column_changed(sortable
);
556 static void details_set_sort_func(GtkTreeSortable
*sortable
,
558 GtkTreeIterCompareFunc func
,
560 GtkDestroyNotify destroy
)
562 g_assert_not_reached();
565 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
566 GtkTreeIterCompareFunc func
,
568 GtkDestroyNotify destroy
)
570 g_assert_not_reached();
573 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
)
579 /* End of model implementation */
581 static gboolean
is_selected(ViewDetails
*view_details
, int i
)
585 return view_details_get_selected((ViewIface
*) view_details
, &iter
);
588 static void perform_action(ViewDetails
*view_details
, GdkEventButton
*event
)
591 FilerWindow
*filer_window
= view_details
->filer_window
;
592 ViewIface
*view
= (ViewIface
*) view_details
;
593 DirItem
*item
= NULL
;
594 GtkTreeView
*tree
= (GtkTreeView
*) view_details
;
595 GtkTreePath
*path
= NULL
;
598 gboolean press
= event
->type
== GDK_BUTTON_PRESS
;
603 model
= gtk_tree_view_get_model(tree
);
605 if (gtk_tree_view_get_path_at_pos(tree
, event
->x
, event
->y
,
606 &path
, NULL
, NULL
, NULL
))
608 g_return_if_fail(path
!= NULL
);
610 i
= gtk_tree_path_get_indices(path
)[0];
611 gtk_tree_path_free(path
);
615 item
= ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
616 make_item_iter(view_details
, &viter
, i
);
617 iter
.user_data
= GINT_TO_POINTER(i
);
619 /* TODO: Cancel slow DnD */
621 if (filer_window
->target_cb
)
624 if (item
&& press
&& event
->button
== 1)
625 filer_window
->target_cb(filer_window
, &viter
,
626 filer_window
->target_data
);
628 filer_target_mode(filer_window
, NULL
, NULL
, NULL
);
633 action
= bind_lookup_bev(
634 item
? BIND_DIRECTORY_ICON
: BIND_DIRECTORY
,
639 case ACT_CLEAR_SELECTION
:
640 view_details_clear_selection(view
);
642 case ACT_TOGGLE_SELECTED
:
643 set_selected(view_details
, i
,
644 !get_selected(view_details
, i
));
646 case ACT_SELECT_EXCL
:
647 view_details_select_only(view
, &viter
);
653 if (event
->button
!= 1 || event
->state
& GDK_MOD1_MASK
)
654 flags
|= OPEN_CLOSE_WINDOW
;
656 flags
|= OPEN_SAME_WINDOW
;
657 if (o_new_button_1
.int_value
)
658 flags
^= OPEN_SAME_WINDOW
;
659 if (event
->type
== GDK_2BUTTON_PRESS
)
660 view_details_set_selected(view
, &viter
, FALSE
);
663 filer_openitem(filer_window
, &viter
, flags
);
670 show_filer_menu(filer_window
,
671 (GdkEvent
*) event
, &viter
);
673 case ACT_PRIME_AND_SELECT
:
674 if (item
&& !is_selected(view_details
, i
))
675 view_details_select_only(view
, &viter
);
676 dnd_motion_start(MOTION_READY_FOR_DND
);
678 case ACT_PRIME_AND_TOGGLE
:
679 set_selected(view_details
, i
,
680 !get_selected(view_details
, i
));
681 dnd_motion_start(MOTION_READY_FOR_DND
);
683 case ACT_PRIME_FOR_DND
:
684 dnd_motion_start(MOTION_READY_FOR_DND
);
687 if (press
&& event
->button
< 4)
690 view_details_wink_item(view
, &viter
);
691 dnd_motion_start(MOTION_NONE
);
694 case ACT_LASSO_CLEAR
:
695 view_details_clear_selection(view
);
697 case ACT_LASSO_MODIFY
:
699 collection_lasso_box(collection
, event
->x
, event
->y
);
703 filer_window_autosize(filer_window
);
706 g_warning("Unsupported action : %d\n", action
);
711 static gboolean
view_details_button_press(GtkWidget
*widget
,
714 if (dnd_motion_press(widget
, bev
))
715 perform_action((ViewDetails
*) widget
, bev
);
720 static gboolean
view_details_button_release(GtkWidget
*widget
,
723 if (!dnd_motion_release(bev
))
724 perform_action((ViewDetails
*) widget
, bev
);
729 static gint
view_details_key_press_event(GtkWidget
*widget
, GdkEventKey
*event
)
731 if (event
->keyval
== ' ')
733 ViewDetails
*view_details
= (ViewDetails
*) widget
;
734 FilerWindow
*filer_window
= view_details
->filer_window
;
736 filer_window_toggle_cursor_item_selected(filer_window
);
740 return GTK_WIDGET_CLASS(parent_class
)->key_press_event(widget
, event
);
743 static void view_details_destroy(GtkObject
*view_details
)
745 VIEW_DETAILS(view_details
)->filer_window
= NULL
;
748 static void view_details_finialize(GObject
*object
)
750 ViewDetails
*view_details
= (ViewDetails
*) object
;
752 g_ptr_array_free(view_details
->items
, TRUE
);
753 view_details
->items
= NULL
;
755 G_OBJECT_CLASS(parent_class
)->finalize(object
);
758 static void view_details_class_init(gpointer gclass
, gpointer data
)
760 GObjectClass
*object
= (GObjectClass
*) gclass
;
761 GtkWidgetClass
*widget
= (GtkWidgetClass
*) gclass
;
763 parent_class
= g_type_class_peek_parent(gclass
);
765 object
->finalize
= view_details_finialize
;
766 GTK_OBJECT_CLASS(object
)->destroy
= view_details_destroy
;
768 widget
->button_press_event
= view_details_button_press
;
769 widget
->button_release_event
= view_details_button_release
;
770 widget
->key_press_event
= view_details_key_press_event
;
773 static void view_details_init(GTypeInstance
*object
, gpointer gclass
)
775 GtkTreeView
*treeview
= (GtkTreeView
*) object
;
776 GtkTreeViewColumn
*column
;
777 GtkCellRenderer
*cell
;
778 GtkTreeSortable
*sortable_list
;
779 GtkTreeSelection
*selection
;
780 ViewDetails
*view_details
= (ViewDetails
*) object
;
782 view_details
->items
= g_ptr_array_new();
783 view_details
->cursor_base
= -1;
785 selection
= gtk_tree_view_get_selection(treeview
);
786 gtk_tree_selection_set_mode(selection
, GTK_SELECTION_NONE
);
789 view_details
->sort_column_id
= -1;
790 view_details
->sort_fn
= NULL
;
791 sortable_list
= GTK_TREE_SORTABLE(object
);
792 gtk_tree_sortable_set_sort_column_id(sortable_list
, COL_LEAF
,
795 gtk_tree_view_set_model(treeview
, GTK_TREE_MODEL(view_details
));
798 cell
= gtk_cell_renderer_pixbuf_new();
799 column
= gtk_tree_view_column_new_with_attributes(NULL
, cell
,
800 "pixbuf", COL_ICON
, NULL
);
801 gtk_tree_view_append_column(treeview
, column
);
804 cell
= gtk_cell_renderer_text_new();
805 column
= gtk_tree_view_column_new_with_attributes(_("Name"), cell
,
807 "foreground-gdk", COL_COLOUR
,
808 "background-gdk", COL_BG_COLOUR
,
810 gtk_tree_view_append_column(treeview
, column
);
811 gtk_tree_view_column_set_sort_column_id(column
, COL_LEAF
);
814 cell
= gtk_cell_renderer_text_new();
815 column
= gtk_tree_view_column_new_with_attributes(_("Type"), cell
,
817 "foreground-gdk", COL_COLOUR
,
818 "background-gdk", COL_BG_COLOUR
,
820 gtk_tree_view_append_column(treeview
, column
);
821 gtk_tree_view_column_set_sort_column_id(column
, COL_TYPE
);
824 cell
= gtk_cell_renderer_text_new();
825 column
= gtk_tree_view_column_new_with_attributes(_("Permissions"),
826 cell
, "text", COL_PERM
,
827 "foreground-gdk", COL_COLOUR
,
828 "background-gdk", COL_BG_COLOUR
,
830 gtk_tree_view_append_column(treeview
, column
);
833 cell
= gtk_cell_renderer_text_new();
834 column
= gtk_tree_view_column_new_with_attributes(_("Owner"), cell
,
836 "foreground-gdk", COL_COLOUR
,
837 "background-gdk", COL_BG_COLOUR
,
839 gtk_tree_view_append_column(treeview
, column
);
840 gtk_tree_view_column_set_sort_column_id(column
, COL_OWNER
);
843 cell
= gtk_cell_renderer_text_new();
844 column
= gtk_tree_view_column_new_with_attributes(_("Group"), cell
,
846 "foreground-gdk", COL_COLOUR
,
847 "background-gdk", COL_BG_COLOUR
,
849 gtk_tree_view_append_column(treeview
, column
);
850 gtk_tree_view_column_set_sort_column_id(column
, COL_GROUP
);
853 cell
= gtk_cell_renderer_text_new();
854 column
= gtk_tree_view_column_new_with_attributes(_("Size"), cell
,
856 "foreground-gdk", COL_COLOUR
,
857 "background-gdk", COL_BG_COLOUR
,
859 gtk_tree_view_append_column(treeview
, column
);
860 gtk_tree_view_column_set_sort_column_id(column
, COL_SIZE
);
863 cell
= gtk_cell_renderer_text_new();
864 column
= gtk_tree_view_column_new_with_attributes(_("M-Time"), cell
,
866 "foreground-gdk", COL_COLOUR
,
867 "background-gdk", COL_BG_COLOUR
,
869 gtk_tree_view_append_column(treeview
, column
);
870 gtk_tree_view_column_set_sort_column_id(column
, COL_MTIME
);
872 gtk_widget_set_size_request(GTK_WIDGET(treeview
), -1, 50);
875 /* Create the handers for the View interface */
876 static void view_details_iface_init(gpointer giface
, gpointer iface_data
)
878 ViewIfaceClass
*iface
= giface
;
880 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
883 iface
->sort
= view_details_sort
;
884 iface
->style_changed
= view_details_style_changed
;
885 iface
->autoselect
= view_details_autoselect
;
886 iface
->add_items
= view_details_add_items
;
887 iface
->update_items
= view_details_update_items
;
888 iface
->delete_if
= view_details_delete_if
;
889 iface
->clear
= view_details_clear
;
890 iface
->select_all
= view_details_select_all
;
891 iface
->clear_selection
= view_details_clear_selection
;
892 iface
->count_items
= view_details_count_items
;
893 iface
->count_selected
= view_details_count_selected
;
894 iface
->show_cursor
= view_details_show_cursor
;
895 iface
->get_iter
= view_details_get_iter
;
896 iface
->cursor_to_iter
= view_details_cursor_to_iter
;
897 iface
->set_selected
= view_details_set_selected
;
898 iface
->get_selected
= view_details_get_selected
;
899 iface
->set_frozen
= view_details_set_frozen
;
900 iface
->select_only
= view_details_select_only
;
901 iface
->wink_item
= view_details_wink_item
;
902 iface
->autosize
= view_details_autosize
;
903 iface
->cursor_visible
= view_details_cursor_visible
;
904 iface
->set_base
= view_details_set_base
;
907 /* Implementations of the View interface. See view_iface.c for comments. */
909 static void view_details_style_changed(ViewIface
*view
, int flags
)
913 static gint
wrap_sort(gconstpointer a
, gconstpointer b
,
914 ViewDetails
*view_details
)
916 ViewItem
*ia
= *(ViewItem
**) a
;
917 ViewItem
*ib
= *(ViewItem
**) b
;
919 if (view_details
->order
== GTK_SORT_ASCENDING
)
920 return view_details
->sort_fn(ia
->item
, ib
->item
);
922 return -view_details
->sort_fn(ia
->item
, ib
->item
);
925 static void view_details_sort(ViewIface
*view
)
927 ViewDetails
*view_details
= (ViewDetails
*) view
;
928 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
930 gint i
, len
= view_details
->items
->len
;
933 g_return_if_fail(view_details
->sort_fn
!= NULL
);
938 for (i
= len
- 1; i
>= 0; i
--)
939 items
[i
]->old_pos
= i
;
941 g_ptr_array_sort_with_data(view_details
->items
,
942 (GCompareDataFunc
) wrap_sort
,
945 new_order
= g_array_sized_new(FALSE
, FALSE
, sizeof(gint
), len
);
946 g_array_set_size(new_order
, len
);
948 for (i
= len
- 1; i
>= 0; i
--)
949 g_array_insert_val(new_order
, items
[i
]->old_pos
, i
);
951 path
= gtk_tree_path_new();
952 gtk_tree_model_rows_reordered((GtkTreeModel
*) view
,
954 (gint
*) new_order
->data
);
955 gtk_tree_path_free(path
);
956 g_array_free(new_order
, TRUE
);
959 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
)
964 static void view_details_add_items(ViewIface
*view
, GPtrArray
*new_items
)
966 ViewDetails
*view_details
= (ViewDetails
*) view
;
967 FilerWindow
*filer_window
= view_details
->filer_window
;
968 gboolean show_hidden
= filer_window
->show_hidden
;
969 GPtrArray
*items
= view_details
->items
;
973 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
975 iter
.user_data
= GINT_TO_POINTER(items
->len
);
976 path
= details_get_path(model
, &iter
);
978 for (i
= 0; i
< new_items
->len
; i
++)
980 DirItem
*item
= (DirItem
*) new_items
->pdata
[i
];
981 char *leafname
= item
->leafname
;
984 if (leafname
[0] == '.')
989 if (leafname
[1] == '\0')
990 continue; /* Never show '.' */
992 if (leafname
[1] == '.' &&
994 continue; /* Never show '..' */
997 vitem
= g_new(ViewItem
, 1);
1000 vitem
->selected
= FALSE
;
1002 g_ptr_array_add(items
, vitem
);
1004 iter
.user_data
= GINT_TO_POINTER(items
->len
- 1);
1005 gtk_tree_model_row_inserted(model
, path
, &iter
);
1006 gtk_tree_path_next(path
);
1009 gtk_tree_path_free(path
);
1011 view_details_sort(view
);
1014 /* Find an item in the sorted array.
1015 * Returns the item number, or -1 if not found.
1017 static int details_find_item(ViewDetails
*view_details
, DirItem
*item
)
1019 ViewItem
**items
, tmp
, *tmpp
;
1021 int (*compar
)(const void *, const void *);
1023 g_return_val_if_fail(view_details
!= NULL
, -1);
1024 g_return_val_if_fail(item
!= NULL
, -1);
1029 items
= (ViewItem
**) view_details
->items
->pdata
;
1030 compar
= view_details
->sort_fn
;
1032 g_return_val_if_fail(compar
!= NULL
, -1);
1034 /* If item is here, then: lower <= i < upper */
1036 upper
= view_details
->items
->len
;
1038 while (lower
< upper
)
1042 i
= (lower
+ upper
) >> 1;
1044 cmp
= wrap_sort(&items
[i
], &tmpp
, view_details
);
1057 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
)
1059 ViewDetails
*view_details
= (ViewDetails
*) view
;
1060 FilerWindow
*filer_window
= view_details
->filer_window
;
1062 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
1064 g_return_if_fail(items
->len
> 0);
1066 /* The item data has already been modified, so this gives the
1067 * final sort order...
1069 view_details_sort(view
);
1071 for (i
= 0; i
< items
->len
; i
++)
1073 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1074 const gchar
*leafname
= item
->leafname
;
1077 if (leafname
[0] == '.' && filer_window
->show_hidden
== FALSE
)
1080 j
= details_find_item(view_details
, item
);
1083 g_warning("Failed to find '%s'\n", leafname
);
1088 path
= gtk_tree_path_new();
1089 gtk_tree_path_append_index(path
, j
);
1090 iter
.user_data
= GINT_TO_POINTER(j
);
1091 gtk_tree_model_row_changed(model
, path
, &iter
);
1096 static void view_details_delete_if(ViewIface
*view
,
1097 gboolean (*test
)(gpointer item
, gpointer data
),
1101 ViewDetails
*view_details
= (ViewDetails
*) view
;
1103 GPtrArray
*items
= view_details
->items
;
1104 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1106 path
= gtk_tree_path_new();
1108 gtk_tree_path_append_index(path
, i
);
1110 while (i
< items
->len
)
1112 ViewItem
*item
= items
->pdata
[i
];
1114 if (test(item
->item
, data
))
1116 g_free(items
->pdata
[i
]);
1117 g_ptr_array_remove_index(items
, i
);
1118 gtk_tree_model_row_deleted(model
, path
);
1123 gtk_tree_path_next(path
);
1127 gtk_tree_path_free(path
);
1130 static void view_details_clear(ViewIface
*view
)
1133 GPtrArray
*items
= ((ViewDetails
*) view
)->items
;
1134 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1136 path
= gtk_tree_path_new();
1137 gtk_tree_path_append_index(path
, items
->len
);
1139 while (gtk_tree_path_prev(path
))
1140 gtk_tree_model_row_deleted(model
, path
);
1142 g_ptr_array_set_size(items
, 0);
1143 gtk_tree_path_free(path
);
1146 static void view_details_select_all(ViewIface
*view
)
1149 int n
= ((ViewDetails
*) view
)->items
->len
;
1151 for (i
= 0; i
< n
; i
++)
1155 view_details_set_selected(view
, &iter
, TRUE
);
1159 static void view_details_clear_selection(ViewIface
*view
)
1162 int n
= ((ViewDetails
*) view
)->items
->len
;
1164 for (i
= 0; i
< n
; i
++)
1168 view_details_set_selected(view
, &iter
, FALSE
);
1172 static int view_details_count_items(ViewIface
*view
)
1174 ViewDetails
*view_details
= (ViewDetails
*) view
;
1176 return view_details
->items
->len
;
1179 static int view_details_count_selected(ViewIface
*view
)
1181 ViewDetails
*view_details
= (ViewDetails
*) view
;
1182 int n
= view_details
->items
->len
;
1183 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
1187 for (i
= 0; i
< n
; i
++)
1188 if (items
[i
]->selected
)
1194 static void view_details_show_cursor(ViewIface
*view
)
1198 static void view_details_get_iter(ViewIface
*view
,
1199 ViewIter
*iter
, IterFlags flags
)
1201 make_iter((ViewDetails
*) view
, iter
, flags
);
1204 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
)
1210 /* XXX: How do we get rid of the cursor? */
1211 g_print("FIXME: Remove cursor\n");
1215 path
= gtk_tree_path_new();
1217 gtk_tree_path_append_index(path
, iter
->i
);
1218 gtk_tree_view_set_cursor((GtkTreeView
*) view
, path
, NULL
, FALSE
);
1219 gtk_tree_path_free(path
);
1222 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
)
1224 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
1227 GPtrArray
*items
= view_details
->items
;
1228 ViewItem
*view_item
;
1230 g_return_if_fail(i
>= 0 && i
< items
->len
);
1231 view_item
= (ViewItem
*) items
->pdata
[i
];
1233 if (view_item
->selected
== selected
)
1236 view_item
->selected
= selected
;
1238 path
= gtk_tree_path_new();
1239 gtk_tree_path_append_index(path
, i
);
1240 t_iter
.user_data
= GINT_TO_POINTER(i
);
1241 gtk_tree_model_row_changed(model
, path
, &t_iter
);
1242 gtk_tree_path_free(path
);
1245 static void view_details_set_selected(ViewIface
*view
,
1249 set_selected((ViewDetails
*) view
, iter
->i
, selected
);
1252 static gboolean
get_selected(ViewDetails
*view_details
, int i
)
1254 GPtrArray
*items
= view_details
->items
;
1256 g_return_val_if_fail(i
>= 0 && i
< items
->len
, FALSE
);
1258 return ((ViewItem
*) items
->pdata
[i
])->selected
;
1261 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
)
1263 return get_selected((ViewDetails
*) view
, iter
->i
);
1266 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
)
1268 ViewDetails
*view_details
= (ViewDetails
*) view
;
1270 int n
= view_details
->items
->len
;
1272 set_selected(view_details
, i
, TRUE
);
1279 set_selected(view_details
, n
, FALSE
);
1283 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
)
1287 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
)
1291 static void view_details_autosize(ViewIface
*view
)
1295 static gboolean
view_details_cursor_visible(ViewIface
*view
)
1300 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
)
1302 ViewDetails
*view_details
= (ViewDetails
*) view
;
1304 view_details
->cursor_base
= iter
->i
;
1307 static DirItem
*iter_init(ViewIter
*iter
)
1309 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1311 int n
= view_details
->items
->len
;
1312 int flags
= iter
->flags
;
1314 iter
->peek
= iter_peek
;
1316 if (iter
->n_remaining
== 0)
1319 if (flags
& VIEW_ITER_FROM_CURSOR
)
1322 gtk_tree_view_get_cursor((GtkTreeView
*) view_details
,
1325 return NULL
; /* No cursor */
1326 i
= gtk_tree_path_get_indices(path
)[0];
1327 gtk_tree_path_free(path
);
1329 else if (flags
& VIEW_ITER_FROM_BASE
)
1330 i
= view_details
->cursor_base
;
1332 if (i
< 0 || i
>= n
)
1334 /* Either a normal iteration, or an iteration from an
1335 * invalid starting point.
1337 if (flags
& VIEW_ITER_BACKWARDS
)
1343 if (i
< 0 || i
>= n
)
1344 return NULL
; /* No items at all! */
1346 iter
->next
= flags
& VIEW_ITER_BACKWARDS
? iter_prev
: iter_next
;
1347 iter
->n_remaining
--;
1350 if (flags
& VIEW_ITER_SELECTED
&& !is_selected(view_details
, i
))
1351 return iter
->next(iter
);
1352 return iter
->peek(iter
);
1355 static DirItem
*iter_prev(ViewIter
*iter
)
1357 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1358 int n
= view_details
->items
->len
;
1361 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1363 /* i is the last item returned (always valid) */
1365 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1367 while (iter
->n_remaining
)
1370 iter
->n_remaining
--;
1375 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1377 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1378 !is_selected(view_details
, i
))
1382 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1389 static DirItem
*iter_next(ViewIter
*iter
)
1391 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1392 int n
= view_details
->items
->len
;
1395 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1397 /* i is the last item returned (always valid) */
1399 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1401 while (iter
->n_remaining
)
1404 iter
->n_remaining
--;
1409 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1411 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1412 !is_selected(view_details
, i
))
1416 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1423 static DirItem
*iter_peek(ViewIter
*iter
)
1425 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1426 int n
= view_details
->items
->len
;
1432 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1434 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1437 /* Set the iterator to return 'i' on the next peek() */
1438 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
)
1440 make_iter(view_details
, iter
, 0);
1442 g_return_if_fail(i
>= -1 && i
< (int) view_details
->items
->len
);
1445 iter
->next
= iter_next
;
1446 iter
->peek
= iter_peek
;
1447 iter
->n_remaining
= 0;
1450 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
1453 iter
->view
= (ViewIface
*) view_details
;
1454 iter
->next
= iter_init
;
1458 iter
->flags
= flags
;
1460 if (flags
& VIEW_ITER_ONE_ONLY
)
1462 iter
->n_remaining
= 1;
1466 iter
->n_remaining
= view_details
->items
->len
;