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 */
30 #include "view_iface.h"
31 #include "view_details.h"
40 #include "gui_support.h"
43 /* These are the column numbers in the ListStore */
56 static gpointer parent_class
= NULL
;
58 struct _ViewDetailsClass
{
59 GtkTreeViewClass parent
;
62 typedef struct _ViewItem ViewItem
;
67 int old_pos
; /* Used while sorting */
70 typedef struct _ViewDetails ViewDetails
;
75 FilerWindow
*filer_window
; /* Used for styles, etc */
77 GPtrArray
*items
; /* ViewItem */
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
),
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
,
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
);
119 static DirItem
*iter_peek(ViewIter
*iter
);
120 static DirItem
*iter_next(ViewIter
*iter
);
122 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
124 static void make_item_iter(ViewDetails
*view_details
,
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
,
131 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
134 static void details_set_sort_func(GtkTreeSortable
*sortable
,
136 GtkTreeIterCompareFunc func
,
138 GtkDestroyNotify destroy
);
139 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
140 GtkTreeIterCompareFunc func
,
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;
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 */
182 static const GInterfaceInfo view_iface_info
= {
183 view_details_iface_init
,
186 static const GInterfaceInfo tree_model_info
= {
187 (GInterfaceInitFunc
) view_details_tree_model_init
,
190 static const GInterfaceInfo sortable_info
= {
191 (GInterfaceInitFunc
) view_details_sortable_init
,
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
,
201 g_type_add_interface_static(type
, GTK_TYPE_TREE_MODEL
,
203 g_type_add_interface_static(type
, GTK_TYPE_TREE_SORTABLE
,
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
)
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
,
242 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
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
)
252 iter
->user_data
= GINT_TO_POINTER(i
);
257 static GtkTreePath
*details_get_path(GtkTreeModel
*tree_model
,
262 retval
= gtk_tree_path_new();
263 gtk_tree_path_append_index(retval
, GPOINTER_TO_INT(iter
->user_data
));
268 static void details_get_value(GtkTreeModel
*tree_model
,
273 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
275 GPtrArray
*items
= view_details
->items
;
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
);
293 else if (column
== COL_ITEM
)
295 g_value_init(value
, G_TYPE_POINTER
);
296 g_value_set_pointer(value
, item
);
300 if (item
->base_type
== TYPE_UNKNOWN
)
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
);
310 g_value_set_object(value
, NULL
);
319 g_value_init(value
, G_TYPE_STRING
);
320 g_value_set_string(value
, item
->leafname
);
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
);
329 g_value_init(value
, GDK_TYPE_COLOR
);
330 g_value_set_boxed(value
, type_get_colour(item
, NULL
));
333 g_value_init(value
, G_TYPE_STRING
);
334 g_value_set_string(value
, user_name(item
->uid
));
337 g_value_init(value
, G_TYPE_STRING
);
338 g_value_set_string(value
, group_name(item
->gid
));
343 time
= pretty_time(&item
->mtime
);
344 g_value_init(value
, G_TYPE_STRING
);
345 g_value_set_string(value
, time
);
350 g_value_init(value
, G_TYPE_STRING
);
351 g_value_set_string(value
, pretty_permissions(m
));
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
));
360 g_value_init(value
, G_TYPE_STRING
);
361 g_value_set_string(value
,
362 item
->flags
& ITEM_FLAG_APPDIR
? "App" :
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" :
373 g_value_init(value
, G_TYPE_STRING
);
374 g_value_set_string(value
, "Hello");
379 static gboolean
details_iter_next(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
381 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
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
,
394 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
396 /* this is a list, nodes have no children */
400 /* but if parent == NULL we return the list itself as children of the
404 if (view_details
->items
->len
)
406 iter
->user_data
= GINT_TO_POINTER(0);
413 static gboolean
details_iter_has_child(GtkTreeModel
*tree_model
,
419 static gint
details_iter_n_children(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
421 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
424 return view_details
->items
->len
;
429 static gboolean
details_iter_nth_child(GtkTreeModel
*tree_model
,
434 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
439 if (n
>= 0 && n
< view_details
->items
->len
)
441 iter
->user_data
= GINT_TO_POINTER(n
);
448 static gboolean
details_iter_parent(GtkTreeModel
*tree_model
,
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
,
488 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
490 if (view_details
->sort_column_id
== -1)
494 *sort_column_id
= view_details
->sort_column_id
;
496 *order
= view_details
->order
;
500 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
504 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
506 if (view_details
->sort_column_id
== sort_column_id
&&
507 view_details
->order
== order
)
510 view_details
->sort_column_id
= sort_column_id
;
511 view_details
->order
= order
;
513 switch (sort_column_id
)
516 view_details
->sort_fn
= sort_by_name
;
519 view_details
->sort_fn
= sort_by_size
;
522 view_details
->sort_fn
= sort_by_date
;
525 view_details
->sort_fn
= sort_by_type
;
528 view_details
->sort_fn
= sort_by_owner
;
531 view_details
->sort_fn
= sort_by_group
;
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
,
544 GtkTreeIterCompareFunc func
,
546 GtkDestroyNotify destroy
)
548 g_assert_not_reached();
551 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
552 GtkTreeIterCompareFunc func
,
554 GtkDestroyNotify destroy
)
556 g_assert_not_reached();
559 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
)
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
);
572 gtk_tree_selection_select_iter(selection
, iter
);
575 static void perform_action(ViewDetails
*view_details
, GdkEventButton
*event
)
578 FilerWindow
*filer_window
= view_details
->filer_window
;
579 DirItem
*item
= NULL
;
580 GtkTreeView
*tree
= (GtkTreeView
*) view_details
;
581 GtkTreePath
*path
= NULL
;
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
,
609 case ACT_CLEAR_SELECTION
:
610 gtk_tree_selection_unselect_all(selection
);
612 case ACT_TOGGLE_SELECTED
:
613 toggle_selected(selection
, &iter
);
616 case ACT_SELECT_EXCL
:
617 collection_clear_except(collection
, item
);
626 make_item_iter(view_details
, &viter
, &iter
);
628 if (event
->button
!= 1 || event
->state
& GDK_MOD1_MASK
)
629 flags
|= OPEN_CLOSE_WINDOW
;
631 flags
|= OPEN_SAME_WINDOW
;
632 if (o_new_button_1
.int_value
)
633 flags
^= OPEN_SAME_WINDOW
;
635 if (event
->type
== GDK_2BUTTON_PRESS
)
636 collection_unselect_item(collection
, item
);
639 filer_openitem(filer_window
, &viter
, flags
);
650 make_item_iter(view_details
, &viter
, &iter
);
651 show_filer_menu(filer_window
,
652 (GdkEvent
*) event
, &viter
);
656 case ACT_PRIME_AND_SELECT
:
658 collection_clear_except(collection
, item
);
659 dnd_motion_start(MOTION_READY_FOR_DND
);
661 case ACT_PRIME_AND_TOGGLE
:
662 collection_toggle_item(collection
, item
);
663 dnd_motion_start(MOTION_READY_FOR_DND
);
665 case ACT_PRIME_FOR_DND
:
666 dnd_motion_start(MOTION_READY_FOR_DND
);
669 if (press
&& event
->button
< 4)
672 collection_wink_item(collection
, item
);
673 dnd_motion_start(MOTION_NONE
);
676 case ACT_LASSO_CLEAR
:
677 collection_clear_selection(collection
);
679 case ACT_LASSO_MODIFY
:
680 collection_lasso_box(collection
, event
->x
, event
->y
);
683 filer_window_autosize(filer_window
);
687 g_warning("Unsupported action : %d\n", action
);
692 static gboolean
view_details_button_press(GtkWidget
*widget
,
695 if (dnd_motion_press(widget
, bev
))
696 perform_action((ViewDetails
*) widget
, bev
);
701 static gboolean
view_details_button_release(GtkWidget
*widget
,
704 if (!dnd_motion_release(bev
))
705 perform_action((ViewDetails
*) widget
, bev
);
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();
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
,
756 gtk_tree_view_set_model(treeview
, GTK_TREE_MODEL(view_details
));
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();
768 column
= gtk_tree_view_column_new_with_attributes(_("Name"), cell
,
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
);
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
);
781 column
= gtk_tree_view_column_new_with_attributes(_("Permissions"),
782 cell
, "text", COL_PERM
, NULL
);
783 gtk_tree_view_append_column(treeview
, column
);
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
);
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
);
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
);
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
);
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
);
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
;
867 gint i
, len
= view_details
->items
->len
;
870 g_return_if_fail(view_details
->sort_fn
!= NULL
);
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
,
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
,
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
)
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
;
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
;
921 if (leafname
[0] == '.')
926 if (leafname
[1] == '\0')
927 continue; /* Never show '.' */
929 if (leafname
[1] == '.' &&
931 continue; /* Never show '..' */
934 vitem
= g_new(ViewItem
, 1);
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
;
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);
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 */
972 upper
= view_details
->items
->len
;
974 while (lower
< upper
)
978 i
= (lower
+ upper
) >> 1;
980 cmp
= wrap_sort(&items
[i
], &tmpp
, view_details
);
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
;
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
;
1013 if (leafname
[0] == '.' && filer_window
->show_hidden
== FALSE
)
1016 j
= details_find_item(view_details
, item
);
1019 g_warning("Failed to find '%s'\n", leafname
);
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
),
1038 static void view_details_clear(ViewIface
*view
)
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
)
1067 static int view_details_count_selected(ViewIface
*view
)
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
,
1092 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
)
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
)
1118 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
)
1122 static DirItem
*iter_init(ViewIter
*iter
)
1128 static DirItem
*iter_peek(ViewIter
*iter
)
1133 static DirItem
*iter_next(ViewIter
*iter
)
1139 /* Set the iterator to return 'i' on the next peek() */
1140 static void make_item_iter(ViewDetails
*view_details
,
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
,
1154 /* iter->view_details = view_details; */
1155 iter
->next
= iter_init
;
1158 iter
->flags
= flags
;