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 *);
83 int cursor_base
; /* Cursor when minibuffer opened */
86 /* Static prototypes */
87 static void view_details_finialize(GObject
*object
);
88 static void view_details_class_init(gpointer gclass
, gpointer data
);
89 static void view_details_init(GTypeInstance
*object
, gpointer gclass
);
91 static void view_details_iface_init(gpointer giface
, gpointer iface_data
);
93 static void view_details_sort(ViewIface
*view
);
94 static void view_details_style_changed(ViewIface
*view
, int flags
);
95 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
);
96 static void view_details_add_items(ViewIface
*view
, GPtrArray
*items
);
97 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
);
98 static void view_details_delete_if(ViewIface
*view
,
99 gboolean (*test
)(gpointer item
, gpointer data
),
101 static void view_details_clear(ViewIface
*view
);
102 static void view_details_select_all(ViewIface
*view
);
103 static void view_details_clear_selection(ViewIface
*view
);
104 static int view_details_count_items(ViewIface
*view
);
105 static int view_details_count_selected(ViewIface
*view
);
106 static void view_details_show_cursor(ViewIface
*view
);
107 static void view_details_get_iter(ViewIface
*view
,
108 ViewIter
*iter
, IterFlags flags
);
109 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
110 static void view_details_set_selected(ViewIface
*view
,
113 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
);
114 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
);
115 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
);
116 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
);
117 static void view_details_autosize(ViewIface
*view
);
118 static gboolean
view_details_cursor_visible(ViewIface
*view
);
119 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
);
120 static DirItem
*iter_peek(ViewIter
*iter
);
121 static DirItem
*iter_prev(ViewIter
*iter
);
122 static DirItem
*iter_next(ViewIter
*iter
);
123 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
125 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
);
126 static void view_details_tree_model_init(GtkTreeModelIface
*iface
);
127 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
128 gint
*sort_column_id
,
130 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
133 static void details_set_sort_func(GtkTreeSortable
*sortable
,
135 GtkTreeIterCompareFunc func
,
137 GtkDestroyNotify destroy
);
138 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
139 GtkTreeIterCompareFunc func
,
141 GtkDestroyNotify destroy
);
142 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
);
143 static void view_details_sortable_init(GtkTreeSortableIface
*iface
);
146 /****************************************************************
147 * EXTERNAL INTERFACE *
148 ****************************************************************/
150 GtkWidget
*view_details_new(FilerWindow
*filer_window
)
152 ViewDetails
*view_details
;
154 view_details
= g_object_new(view_details_get_type(), NULL
);
155 view_details
->filer_window
= filer_window
;
157 gtk_range_set_adjustment(GTK_RANGE(filer_window
->scrollbar
),
158 gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(view_details
)));
160 return GTK_WIDGET(view_details
);
163 GType
view_details_get_type(void)
165 static GType type
= 0;
169 static const GTypeInfo info
=
171 sizeof (ViewDetailsClass
),
172 NULL
, /* base_init */
173 NULL
, /* base_finalise */
174 view_details_class_init
,
175 NULL
, /* class_finalise */
176 NULL
, /* class_data */
181 static const GInterfaceInfo view_iface_info
= {
182 view_details_iface_init
,
185 static const GInterfaceInfo tree_model_info
= {
186 (GInterfaceInitFunc
) view_details_tree_model_init
,
189 static const GInterfaceInfo sortable_info
= {
190 (GInterfaceInitFunc
) view_details_sortable_init
,
195 type
= g_type_register_static(gtk_tree_view_get_type(),
196 "ViewDetails", &info
, 0);
198 g_type_add_interface_static(type
, VIEW_TYPE_IFACE
,
200 g_type_add_interface_static(type
, GTK_TYPE_TREE_MODEL
,
202 g_type_add_interface_static(type
, GTK_TYPE_TREE_SORTABLE
,
209 /****************************************************************
210 * INTERNAL FUNCTIONS *
211 ****************************************************************/
213 /* Fulfill the GtkTreeModel requirements */
214 static guint
details_get_flags(GtkTreeModel
*tree_model
)
216 return GTK_TREE_MODEL_LIST_ONLY
;
219 static gint
details_get_n_columns(GtkTreeModel
*tree_model
)
224 static GType
details_get_column_type(GtkTreeModel
*tree_model
, gint index
)
226 g_return_val_if_fail(index
< N_COLUMNS
&& index
>= 0, G_TYPE_INVALID
);
228 if (index
== COL_COLOUR
)
229 return GDK_TYPE_COLOR
;
230 else if (index
== COL_ITEM
)
231 return G_TYPE_POINTER
;
232 else if (index
== COL_ICON
)
233 return GDK_TYPE_PIXBUF
;
234 return G_TYPE_STRING
;
237 static gboolean
details_get_iter(GtkTreeModel
*tree_model
,
241 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
244 g_return_val_if_fail(gtk_tree_path_get_depth (path
) > 0, FALSE
);
246 i
= gtk_tree_path_get_indices(path
)[0];
248 if (i
>= view_details
->items
->len
)
251 iter
->user_data
= GINT_TO_POINTER(i
);
256 static GtkTreePath
*details_get_path(GtkTreeModel
*tree_model
,
261 retval
= gtk_tree_path_new();
262 gtk_tree_path_append_index(retval
, GPOINTER_TO_INT(iter
->user_data
));
267 static void details_get_value(GtkTreeModel
*tree_model
,
272 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
274 GPtrArray
*items
= view_details
->items
;
278 g_return_if_fail(column
>= 0 && column
< N_COLUMNS
);
280 i
= GPOINTER_TO_INT(iter
->user_data
);
281 g_return_if_fail(i
>= 0 && i
< items
->len
);
282 item
= ((ViewItem
*) items
->pdata
[i
])->item
;
284 /* g_print("[ get %d ]\n", column); */
286 if (column
== COL_LEAF
)
288 g_value_init(value
, G_TYPE_STRING
);
289 g_value_set_string(value
, item
->leafname
);
292 else if (column
== COL_ITEM
)
294 g_value_init(value
, G_TYPE_POINTER
);
295 g_value_set_pointer(value
, item
);
299 if (item
->base_type
== TYPE_UNKNOWN
)
302 type
= details_get_column_type(tree_model
, column
);
303 g_value_init(value
, type
);
304 if (type
== G_TYPE_STRING
)
305 g_value_set_string(value
, "");
306 else if (type
== GDK_TYPE_COLOR
)
307 g_value_set_boxed(value
, NULL
);
309 g_value_set_object(value
, NULL
);
318 g_value_init(value
, G_TYPE_STRING
);
319 g_value_set_string(value
, item
->leafname
);
322 g_value_init(value
, GDK_TYPE_PIXBUF
);
323 if (!item
->image
->sm_pixbuf
)
324 pixmap_make_small(item
->image
);
325 g_value_set_object(value
, item
->image
->sm_pixbuf
);
328 g_value_init(value
, GDK_TYPE_COLOR
);
329 g_value_set_boxed(value
, type_get_colour(item
, NULL
));
332 g_value_init(value
, G_TYPE_STRING
);
333 g_value_set_string(value
, user_name(item
->uid
));
336 g_value_init(value
, G_TYPE_STRING
);
337 g_value_set_string(value
, group_name(item
->gid
));
342 time
= pretty_time(&item
->mtime
);
343 g_value_init(value
, G_TYPE_STRING
);
344 g_value_set_string(value
, time
);
349 g_value_init(value
, G_TYPE_STRING
);
350 g_value_set_string(value
, pretty_permissions(m
));
353 g_value_init(value
, G_TYPE_STRING
);
354 if (item
->base_type
!= TYPE_DIRECTORY
)
355 g_value_set_string(value
,
356 format_size(item
->size
));
359 g_value_init(value
, G_TYPE_STRING
);
360 g_value_set_string(value
,
361 item
->flags
& ITEM_FLAG_APPDIR
? "App" :
363 S_ISCHR(m
) ? "Char" :
364 S_ISBLK(m
) ? "Blck" :
365 S_ISLNK(m
) ? "Link" :
366 S_ISSOCK(m
) ? "Sock" :
367 S_ISFIFO(m
) ? "Pipe" :
368 S_ISDOOR(m
) ? "Door" :
372 g_value_init(value
, G_TYPE_STRING
);
373 g_value_set_string(value
, "Hello");
378 static gboolean
details_iter_next(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
380 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
383 i
= GPOINTER_TO_INT(iter
->user_data
) + 1;
384 iter
->user_data
= GINT_TO_POINTER(i
);
386 return i
< view_details
->items
->len
;
389 static gboolean
details_iter_children(GtkTreeModel
*tree_model
,
393 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
395 /* this is a list, nodes have no children */
399 /* but if parent == NULL we return the list itself as children of the
403 if (view_details
->items
->len
)
405 iter
->user_data
= GINT_TO_POINTER(0);
412 static gboolean
details_iter_has_child(GtkTreeModel
*tree_model
,
418 static gint
details_iter_n_children(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
420 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
423 return view_details
->items
->len
;
428 static gboolean
details_iter_nth_child(GtkTreeModel
*tree_model
,
433 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
438 if (n
>= 0 && n
< view_details
->items
->len
)
440 iter
->user_data
= GINT_TO_POINTER(n
);
447 static gboolean
details_iter_parent(GtkTreeModel
*tree_model
,
454 /* A ViewDetails is both a GtkTreeView and a GtkTreeModel.
455 * The following functions implement the model interface...
458 static void view_details_tree_model_init(GtkTreeModelIface
*iface
)
460 iface
->get_flags
= details_get_flags
;
461 iface
->get_n_columns
= details_get_n_columns
;
462 iface
->get_column_type
= details_get_column_type
;
463 iface
->get_iter
= details_get_iter
;
464 iface
->get_path
= details_get_path
;
465 iface
->get_value
= details_get_value
;
466 iface
->iter_next
= details_iter_next
;
467 iface
->iter_children
= details_iter_children
;
468 iface
->iter_has_child
= details_iter_has_child
;
469 iface
->iter_n_children
= details_iter_n_children
;
470 iface
->iter_nth_child
= details_iter_nth_child
;
471 iface
->iter_parent
= details_iter_parent
;
474 static void view_details_sortable_init(GtkTreeSortableIface
*iface
)
476 iface
->get_sort_column_id
= details_get_sort_column_id
;
477 iface
->set_sort_column_id
= details_set_sort_column_id
;
478 iface
->set_sort_func
= details_set_sort_func
;
479 iface
->set_default_sort_func
= details_set_default_sort_func
;
480 iface
->has_default_sort_func
= details_has_default_sort_func
;
483 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
484 gint
*sort_column_id
,
487 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
489 if (view_details
->sort_column_id
== -1)
493 *sort_column_id
= view_details
->sort_column_id
;
495 *order
= view_details
->order
;
499 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
503 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
505 if (view_details
->sort_column_id
== sort_column_id
&&
506 view_details
->order
== order
)
509 view_details
->sort_column_id
= sort_column_id
;
510 view_details
->order
= order
;
512 switch (sort_column_id
)
515 view_details
->sort_fn
= sort_by_name
;
518 view_details
->sort_fn
= sort_by_size
;
521 view_details
->sort_fn
= sort_by_date
;
524 view_details
->sort_fn
= sort_by_type
;
527 view_details
->sort_fn
= sort_by_owner
;
530 view_details
->sort_fn
= sort_by_group
;
533 g_assert_not_reached();
536 view_details_sort((ViewIface
*) view_details
);
538 gtk_tree_sortable_sort_column_changed(sortable
);
541 static void details_set_sort_func(GtkTreeSortable
*sortable
,
543 GtkTreeIterCompareFunc func
,
545 GtkDestroyNotify destroy
)
547 g_assert_not_reached();
550 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
551 GtkTreeIterCompareFunc func
,
553 GtkDestroyNotify destroy
)
555 g_assert_not_reached();
558 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
)
564 /* End of model implementation */
566 static gboolean
is_selected(ViewDetails
*view_details
, int i
)
569 GtkTreeSelection
*selection
;
571 selection
= gtk_tree_view_get_selection((GtkTreeView
*) view_details
);
573 iter
.user_data
= GINT_TO_POINTER(i
);
574 return gtk_tree_selection_iter_is_selected(selection
, &iter
);
577 static void toggle_selected(GtkTreeSelection
*selection
, GtkTreeIter
*iter
)
579 if (gtk_tree_selection_iter_is_selected(selection
, iter
))
580 gtk_tree_selection_unselect_iter(selection
, iter
);
582 gtk_tree_selection_select_iter(selection
, iter
);
585 static void perform_action(ViewDetails
*view_details
, GdkEventButton
*event
)
588 FilerWindow
*filer_window
= view_details
->filer_window
;
589 DirItem
*item
= NULL
;
590 GtkTreeView
*tree
= (GtkTreeView
*) view_details
;
591 GtkTreePath
*path
= NULL
;
594 GtkTreeSelection
*selection
;
596 /* OpenFlags flags = 0; */
598 model
= gtk_tree_view_get_model(tree
);
599 selection
= gtk_tree_view_get_selection(tree
);
601 if (gtk_tree_view_get_path_at_pos(tree
, event
->x
, event
->y
,
602 &path
, NULL
, NULL
, NULL
))
604 g_return_if_fail(path
!= NULL
);
606 i
= gtk_tree_path_get_indices(path
)[0];
607 gtk_tree_path_free(path
);
611 item
= ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
613 g_print("[ item %d clicked ]\n", i
);
615 /* TODO: Cancel slow DnD */
616 /* TODO: Target callbacks */
618 action
= bind_lookup_bev(
619 item
? BIND_DIRECTORY_ICON
: BIND_DIRECTORY
,
624 case ACT_CLEAR_SELECTION
:
625 gtk_tree_selection_unselect_all(selection
);
627 case ACT_TOGGLE_SELECTED
:
628 toggle_selected(selection
, &iter
);
631 case ACT_SELECT_EXCL
:
632 collection_clear_except(collection
, item
);
641 make_item_iter(view_details
, &viter
, &iter
);
643 if (event
->button
!= 1 || event
->state
& GDK_MOD1_MASK
)
644 flags
|= OPEN_CLOSE_WINDOW
;
646 flags
|= OPEN_SAME_WINDOW
;
647 if (o_new_button_1
.int_value
)
648 flags
^= OPEN_SAME_WINDOW
;
650 if (event
->type
== GDK_2BUTTON_PRESS
)
651 collection_unselect_item(collection
, item
);
654 filer_openitem(filer_window
, &viter
, flags
);
665 make_item_iter(view_details
, &viter
, i
);
666 show_filer_menu(filer_window
,
667 (GdkEvent
*) event
, &viter
);
671 case ACT_PRIME_AND_SELECT
:
673 collection_clear_except(collection
, item
);
674 dnd_motion_start(MOTION_READY_FOR_DND
);
676 case ACT_PRIME_AND_TOGGLE
:
677 collection_toggle_item(collection
, item
);
678 dnd_motion_start(MOTION_READY_FOR_DND
);
680 case ACT_PRIME_FOR_DND
:
681 dnd_motion_start(MOTION_READY_FOR_DND
);
684 if (press
&& event
->button
< 4)
687 collection_wink_item(collection
, item
);
688 dnd_motion_start(MOTION_NONE
);
691 case ACT_LASSO_CLEAR
:
692 collection_clear_selection(collection
);
694 case ACT_LASSO_MODIFY
:
695 collection_lasso_box(collection
, event
->x
, event
->y
);
698 filer_window_autosize(filer_window
);
702 g_warning("Unsupported action : %d\n", action
);
707 static gboolean
view_details_button_press(GtkWidget
*widget
,
710 if (dnd_motion_press(widget
, bev
))
711 perform_action((ViewDetails
*) widget
, bev
);
716 static gboolean
view_details_button_release(GtkWidget
*widget
,
719 if (!dnd_motion_release(bev
))
720 perform_action((ViewDetails
*) widget
, bev
);
725 static void view_details_destroy(GtkObject
*view_details
)
727 VIEW_DETAILS(view_details
)->filer_window
= NULL
;
730 static void view_details_finialize(GObject
*object
)
732 ViewDetails
*view_details
= (ViewDetails
*) object
;
734 g_ptr_array_free(view_details
->items
, TRUE
);
735 view_details
->items
= NULL
;
737 G_OBJECT_CLASS(parent_class
)->finalize(object
);
740 static void view_details_class_init(gpointer gclass
, gpointer data
)
742 GObjectClass
*object
= (GObjectClass
*) gclass
;
743 GtkWidgetClass
*widget
= (GtkWidgetClass
*) gclass
;
745 parent_class
= g_type_class_peek_parent(gclass
);
747 object
->finalize
= view_details_finialize
;
748 GTK_OBJECT_CLASS(object
)->destroy
= view_details_destroy
;
750 widget
->button_press_event
= view_details_button_press
;
751 widget
->button_release_event
= view_details_button_release
;
754 static void view_details_init(GTypeInstance
*object
, gpointer gclass
)
756 GtkTreeView
*treeview
= (GtkTreeView
*) object
;
757 GtkTreeViewColumn
*column
;
758 GtkCellRenderer
*cell
;
759 GtkTreeSortable
*sortable_list
;
760 ViewDetails
*view_details
= (ViewDetails
*) object
;
762 view_details
->items
= g_ptr_array_new();
763 view_details
->cursor_base
= -1;
766 view_details
->sort_column_id
= -1;
767 view_details
->sort_fn
= NULL
;
768 sortable_list
= GTK_TREE_SORTABLE(object
);
769 gtk_tree_sortable_set_sort_column_id(sortable_list
, COL_LEAF
,
772 gtk_tree_view_set_model(treeview
, GTK_TREE_MODEL(view_details
));
775 cell
= gtk_cell_renderer_pixbuf_new();
776 column
= gtk_tree_view_column_new_with_attributes(NULL
, cell
,
777 "pixbuf", COL_ICON
, NULL
);
778 gtk_tree_view_append_column(treeview
, column
);
780 /* The rest are text... */
781 cell
= gtk_cell_renderer_text_new();
784 column
= gtk_tree_view_column_new_with_attributes(_("Name"), cell
,
786 "foreground-gdk", COL_COLOUR
, NULL
);
787 gtk_tree_view_append_column(treeview
, column
);
788 gtk_tree_view_column_set_sort_column_id(column
, COL_LEAF
);
791 column
= gtk_tree_view_column_new_with_attributes(_("Type"), cell
,
792 "text", COL_TYPE
, NULL
);
793 gtk_tree_view_append_column(treeview
, column
);
794 gtk_tree_view_column_set_sort_column_id(column
, COL_TYPE
);
797 column
= gtk_tree_view_column_new_with_attributes(_("Permissions"),
798 cell
, "text", COL_PERM
, NULL
);
799 gtk_tree_view_append_column(treeview
, column
);
802 column
= gtk_tree_view_column_new_with_attributes(_("Owner"), cell
,
803 "text", COL_OWNER
, NULL
);
804 gtk_tree_view_append_column(treeview
, column
);
805 gtk_tree_view_column_set_sort_column_id(column
, COL_OWNER
);
808 column
= gtk_tree_view_column_new_with_attributes(_("Group"), cell
,
809 "text", COL_GROUP
, NULL
);
810 gtk_tree_view_append_column(treeview
, column
);
811 gtk_tree_view_column_set_sort_column_id(column
, COL_GROUP
);
814 column
= gtk_tree_view_column_new_with_attributes(_("Size"), cell
,
815 "text", COL_SIZE
, NULL
);
816 gtk_tree_view_append_column(treeview
, column
);
817 gtk_tree_view_column_set_sort_column_id(column
, COL_SIZE
);
820 column
= gtk_tree_view_column_new_with_attributes(_("M-Time"), cell
,
821 "text", COL_MTIME
, NULL
);
822 gtk_tree_view_append_column(treeview
, column
);
823 gtk_tree_view_column_set_sort_column_id(column
, COL_MTIME
);
825 gtk_widget_set_size_request(GTK_WIDGET(treeview
), -1, 50);
828 /* Create the handers for the View interface */
829 static void view_details_iface_init(gpointer giface
, gpointer iface_data
)
831 ViewIfaceClass
*iface
= giface
;
833 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
836 iface
->sort
= view_details_sort
;
837 iface
->style_changed
= view_details_style_changed
;
838 iface
->autoselect
= view_details_autoselect
;
839 iface
->add_items
= view_details_add_items
;
840 iface
->update_items
= view_details_update_items
;
841 iface
->delete_if
= view_details_delete_if
;
842 iface
->clear
= view_details_clear
;
843 iface
->select_all
= view_details_select_all
;
844 iface
->clear_selection
= view_details_clear_selection
;
845 iface
->count_items
= view_details_count_items
;
846 iface
->count_selected
= view_details_count_selected
;
847 iface
->show_cursor
= view_details_show_cursor
;
848 iface
->get_iter
= view_details_get_iter
;
849 iface
->cursor_to_iter
= view_details_cursor_to_iter
;
850 iface
->set_selected
= view_details_set_selected
;
851 iface
->get_selected
= view_details_get_selected
;
852 iface
->set_frozen
= view_details_set_frozen
;
853 iface
->select_only
= view_details_select_only
;
854 iface
->wink_item
= view_details_wink_item
;
855 iface
->autosize
= view_details_autosize
;
856 iface
->cursor_visible
= view_details_cursor_visible
;
857 iface
->set_base
= view_details_set_base
;
860 /* Implementations of the View interface. See view_iface.c for comments. */
862 static void view_details_style_changed(ViewIface
*view
, int flags
)
866 static gint
wrap_sort(gconstpointer a
, gconstpointer b
,
867 ViewDetails
*view_details
)
869 ViewItem
*ia
= *(ViewItem
**) a
;
870 ViewItem
*ib
= *(ViewItem
**) b
;
872 if (view_details
->order
== GTK_SORT_ASCENDING
)
873 return view_details
->sort_fn(ia
->item
, ib
->item
);
875 return -view_details
->sort_fn(ia
->item
, ib
->item
);
878 static void view_details_sort(ViewIface
*view
)
880 ViewDetails
*view_details
= (ViewDetails
*) view
;
881 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
883 gint i
, len
= view_details
->items
->len
;
886 g_return_if_fail(view_details
->sort_fn
!= NULL
);
891 for (i
= len
- 1; i
>= 0; i
--)
892 items
[i
]->old_pos
= i
;
894 g_ptr_array_sort_with_data(view_details
->items
,
895 (GCompareDataFunc
) wrap_sort
,
898 new_order
= g_array_sized_new(FALSE
, FALSE
, sizeof(gint
), len
);
899 g_array_set_size(new_order
, len
);
901 for (i
= len
- 1; i
>= 0; i
--)
902 g_array_insert_val(new_order
, items
[i
]->old_pos
, i
);
904 path
= gtk_tree_path_new();
905 gtk_tree_model_rows_reordered((GtkTreeModel
*) view
,
907 (gint
*) new_order
->data
);
908 gtk_tree_path_free(path
);
909 g_array_free(new_order
, TRUE
);
912 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
)
917 static void view_details_add_items(ViewIface
*view
, GPtrArray
*new_items
)
919 ViewDetails
*view_details
= (ViewDetails
*) view
;
920 FilerWindow
*filer_window
= view_details
->filer_window
;
921 gboolean show_hidden
= filer_window
->show_hidden
;
922 GPtrArray
*items
= view_details
->items
;
926 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
928 iter
.user_data
= GINT_TO_POINTER(items
->len
);
929 path
= details_get_path(model
, &iter
);
931 for (i
= 0; i
< new_items
->len
; i
++)
933 DirItem
*item
= (DirItem
*) new_items
->pdata
[i
];
934 char *leafname
= item
->leafname
;
937 if (leafname
[0] == '.')
942 if (leafname
[1] == '\0')
943 continue; /* Never show '.' */
945 if (leafname
[1] == '.' &&
947 continue; /* Never show '..' */
950 vitem
= g_new(ViewItem
, 1);
954 g_ptr_array_add(items
, vitem
);
956 iter
.user_data
= GINT_TO_POINTER(items
->len
- 1);
957 gtk_tree_model_row_inserted(model
, path
, &iter
);
958 gtk_tree_path_next(path
);
961 gtk_tree_path_free(path
);
963 view_details_sort(view
);
966 /* Find an item in the sorted array.
967 * Returns the item number, or -1 if not found.
969 static int details_find_item(ViewDetails
*view_details
, DirItem
*item
)
971 ViewItem
**items
, tmp
, *tmpp
;
973 int (*compar
)(const void *, const void *);
975 g_return_val_if_fail(view_details
!= NULL
, -1);
976 g_return_val_if_fail(item
!= NULL
, -1);
981 items
= (ViewItem
**) view_details
->items
->pdata
;
982 compar
= view_details
->sort_fn
;
984 g_return_val_if_fail(compar
!= NULL
, -1);
986 /* If item is here, then: lower <= i < upper */
988 upper
= view_details
->items
->len
;
990 while (lower
< upper
)
994 i
= (lower
+ upper
) >> 1;
996 cmp
= wrap_sort(&items
[i
], &tmpp
, view_details
);
1009 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
)
1011 ViewDetails
*view_details
= (ViewDetails
*) view
;
1012 FilerWindow
*filer_window
= view_details
->filer_window
;
1014 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
1016 g_return_if_fail(items
->len
> 0);
1018 /* The item data has already been modified, so this gives the
1019 * final sort order...
1021 view_details_sort(view
);
1023 for (i
= 0; i
< items
->len
; i
++)
1025 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1026 const gchar
*leafname
= item
->leafname
;
1029 if (leafname
[0] == '.' && filer_window
->show_hidden
== FALSE
)
1032 j
= details_find_item(view_details
, item
);
1035 g_warning("Failed to find '%s'\n", leafname
);
1040 path
= gtk_tree_path_new();
1041 gtk_tree_path_append_index(path
, j
);
1042 iter
.user_data
= GINT_TO_POINTER(j
);
1043 gtk_tree_model_row_changed(model
, path
, &iter
);
1048 static void view_details_delete_if(ViewIface
*view
,
1049 gboolean (*test
)(gpointer item
, gpointer data
),
1054 static void view_details_clear(ViewIface
*view
)
1057 GPtrArray
*items
= ((ViewDetails
*) view
)->items
;
1058 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1060 path
= gtk_tree_path_new();
1061 gtk_tree_path_append_index(path
, items
->len
);
1063 while (gtk_tree_path_prev(path
))
1064 gtk_tree_model_row_deleted(model
, path
);
1066 g_ptr_array_set_size(items
, 0);
1067 gtk_tree_path_free(path
);
1070 static void view_details_select_all(ViewIface
*view
)
1074 static void view_details_clear_selection(ViewIface
*view
)
1078 static int view_details_count_items(ViewIface
*view
)
1080 ViewDetails
*view_details
= (ViewDetails
*) view
;
1082 return view_details
->items
->len
;
1085 static void inc(GtkTreeModel
*model
, GtkTreePath
*path
,
1086 GtkTreeIter
*iter
, gpointer data
)
1088 (*((int *) data
))++;
1091 static int view_details_count_selected(ViewIface
*view
)
1093 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1094 GtkTreeSelection
*selection
;
1097 selection
= gtk_tree_view_get_selection(tree
);
1099 gtk_tree_selection_selected_foreach(selection
, inc
, &count
);
1103 static void view_details_show_cursor(ViewIface
*view
)
1107 static void view_details_get_iter(ViewIface
*view
,
1108 ViewIter
*iter
, IterFlags flags
)
1110 make_iter((ViewDetails
*) view
, iter
, flags
);
1113 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
)
1117 path
= gtk_tree_path_new();
1119 /* XXX: How do we get rid of the cursor? */
1121 gtk_tree_path_append_index(path
, iter
->i
);
1122 gtk_tree_view_set_cursor((GtkTreeView
*) view
, path
, NULL
, FALSE
);
1123 gtk_tree_path_free(path
);
1126 static void view_details_set_selected(ViewIface
*view
,
1130 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1131 GtkTreeSelection
*selection
;
1134 selection
= gtk_tree_view_get_selection(tree
);
1136 t_iter
.user_data
= GINT_TO_POINTER(iter
->i
);
1138 gtk_tree_selection_select_iter(selection
, &t_iter
);
1140 gtk_tree_selection_unselect_iter(selection
, &t_iter
);
1143 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
)
1148 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
)
1152 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
)
1156 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
)
1160 static void view_details_autosize(ViewIface
*view
)
1164 static gboolean
view_details_cursor_visible(ViewIface
*view
)
1169 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
)
1171 ViewDetails
*view_details
= (ViewDetails
*) view
;
1173 view_details
->cursor_base
= iter
->i
;
1176 static DirItem
*iter_init(ViewIter
*iter
)
1178 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1180 int n
= view_details
->items
->len
;
1181 int flags
= iter
->flags
;
1183 iter
->peek
= iter_peek
;
1185 if (iter
->n_remaining
== 0)
1188 if (flags
& VIEW_ITER_FROM_CURSOR
)
1191 gtk_tree_view_get_cursor((GtkTreeView
*) view_details
,
1194 return NULL
; /* No cursor */
1195 i
= gtk_tree_path_get_indices(path
)[0];
1196 gtk_tree_path_free(path
);
1198 else if (flags
& VIEW_ITER_FROM_BASE
)
1199 i
= view_details
->cursor_base
;
1201 if (i
< 0 || i
>= n
)
1203 /* Either a normal iteration, or an iteration from an
1204 * invalid starting point.
1206 if (flags
& VIEW_ITER_BACKWARDS
)
1212 if (i
< 0 || i
>= n
)
1213 return NULL
; /* No items at all! */
1215 iter
->next
= flags
& VIEW_ITER_BACKWARDS
? iter_prev
: iter_next
;
1216 iter
->n_remaining
--;
1219 if (flags
& VIEW_ITER_SELECTED
&& !is_selected(view_details
, i
))
1220 return iter
->next(iter
);
1221 return iter
->peek(iter
);
1224 static DirItem
*iter_prev(ViewIter
*iter
)
1226 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1227 int n
= view_details
->items
->len
;
1230 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1232 /* i is the last item returned (always valid) */
1234 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1236 while (iter
->n_remaining
)
1239 iter
->n_remaining
--;
1244 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1246 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1247 !is_selected(view_details
, i
))
1251 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1258 static DirItem
*iter_next(ViewIter
*iter
)
1260 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1261 int n
= view_details
->items
->len
;
1264 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1266 /* i is the last item returned (always valid) */
1268 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1270 while (iter
->n_remaining
)
1273 iter
->n_remaining
--;
1278 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1280 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1281 !is_selected(view_details
, i
))
1285 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1292 static DirItem
*iter_peek(ViewIter
*iter
)
1294 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1295 int n
= view_details
->items
->len
;
1301 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1303 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1306 /* Set the iterator to return 'i' on the next peek() */
1307 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
)
1309 make_iter(view_details
, iter
, 0);
1311 g_return_if_fail(i
>= -1 && i
< (int) view_details
->items
->len
);
1314 iter
->next
= iter_next
;
1315 iter
->peek
= iter_peek
;
1316 iter
->n_remaining
= 0;
1319 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
1322 iter
->view
= (ViewIface
*) view_details
;
1323 iter
->next
= iter_init
;
1327 iter
->flags
= flags
;
1329 if (flags
& VIEW_ITER_ONE_ONLY
)
1331 iter
->n_remaining
= 1;
1335 iter
->n_remaining
= view_details
->items
->len
;