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"
42 #include "gui_support.h"
45 #include "cell_icon.h"
47 /* These are the column numbers in the ListStore */
58 #define COL_BG_COLOUR 10
61 static gpointer parent_class
= NULL
;
63 struct _ViewDetailsClass
{
64 GtkTreeViewClass parent
;
67 typedef struct _ViewItem ViewItem
;
72 int old_pos
; /* Used while sorting */
76 typedef struct _ViewDetails ViewDetails
;
81 FilerWindow
*filer_window
; /* Used for styles, etc */
83 GPtrArray
*items
; /* ViewItem */
87 int (*sort_fn
)(const void *, const void *);
89 int cursor_base
; /* Cursor when minibuffer opened */
92 /* Static prototypes */
93 static void view_details_finialize(GObject
*object
);
94 static void view_details_class_init(gpointer gclass
, gpointer data
);
95 static void view_details_init(GTypeInstance
*object
, gpointer gclass
);
97 static void view_details_iface_init(gpointer giface
, gpointer iface_data
);
99 static void view_details_sort(ViewIface
*view
);
100 static void view_details_style_changed(ViewIface
*view
, int flags
);
101 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
);
102 static void view_details_add_items(ViewIface
*view
, GPtrArray
*items
);
103 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
);
104 static void view_details_delete_if(ViewIface
*view
,
105 gboolean (*test
)(gpointer item
, gpointer data
),
107 static void view_details_clear(ViewIface
*view
);
108 static void view_details_select_all(ViewIface
*view
);
109 static void view_details_clear_selection(ViewIface
*view
);
110 static int view_details_count_items(ViewIface
*view
);
111 static int view_details_count_selected(ViewIface
*view
);
112 static void view_details_show_cursor(ViewIface
*view
);
113 static void view_details_get_iter(ViewIface
*view
,
114 ViewIter
*iter
, IterFlags flags
);
115 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
117 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
118 static void view_details_set_selected(ViewIface
*view
,
121 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
);
122 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
);
123 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
);
124 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
);
125 static void view_details_autosize(ViewIface
*view
);
126 static gboolean
view_details_cursor_visible(ViewIface
*view
);
127 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
);
128 static void view_details_start_lasso_box(ViewIface
*view
,
129 GdkEventButton
*event
);
130 static void view_details_extend_tip(ViewIface
*view
,
131 ViewIter
*iter
, GString
*tip
);
133 static DirItem
*iter_peek(ViewIter
*iter
);
134 static DirItem
*iter_prev(ViewIter
*iter
);
135 static DirItem
*iter_next(ViewIter
*iter
);
136 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
138 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
);
139 static void view_details_tree_model_init(GtkTreeModelIface
*iface
);
140 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
141 gint
*sort_column_id
,
143 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
146 static void details_set_sort_func(GtkTreeSortable
*sortable
,
148 GtkTreeIterCompareFunc func
,
150 GtkDestroyNotify destroy
);
151 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
152 GtkTreeIterCompareFunc func
,
154 GtkDestroyNotify destroy
);
155 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
);
156 static void view_details_sortable_init(GtkTreeSortableIface
*iface
);
157 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
);
158 static gboolean
get_selected(ViewDetails
*view_details
, int i
);
161 /****************************************************************
162 * EXTERNAL INTERFACE *
163 ****************************************************************/
165 GtkWidget
*view_details_new(FilerWindow
*filer_window
)
167 ViewDetails
*view_details
;
169 view_details
= g_object_new(view_details_get_type(), NULL
);
170 view_details
->filer_window
= filer_window
;
172 gtk_range_set_adjustment(GTK_RANGE(filer_window
->scrollbar
),
173 gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(view_details
)));
175 return GTK_WIDGET(view_details
);
178 GType
view_details_get_type(void)
180 static GType type
= 0;
184 static const GTypeInfo info
=
186 sizeof (ViewDetailsClass
),
187 NULL
, /* base_init */
188 NULL
, /* base_finalise */
189 view_details_class_init
,
190 NULL
, /* class_finalise */
191 NULL
, /* class_data */
196 static const GInterfaceInfo view_iface_info
= {
197 view_details_iface_init
,
200 static const GInterfaceInfo tree_model_info
= {
201 (GInterfaceInitFunc
) view_details_tree_model_init
,
204 static const GInterfaceInfo sortable_info
= {
205 (GInterfaceInitFunc
) view_details_sortable_init
,
210 type
= g_type_register_static(gtk_tree_view_get_type(),
211 "ViewDetails", &info
, 0);
213 g_type_add_interface_static(type
, VIEW_TYPE_IFACE
,
215 g_type_add_interface_static(type
, GTK_TYPE_TREE_MODEL
,
217 g_type_add_interface_static(type
, GTK_TYPE_TREE_SORTABLE
,
224 /****************************************************************
225 * INTERNAL FUNCTIONS *
226 ****************************************************************/
228 /* Fulfill the GtkTreeModel requirements */
229 static guint
details_get_flags(GtkTreeModel
*tree_model
)
231 return GTK_TREE_MODEL_LIST_ONLY
;
234 static gint
details_get_n_columns(GtkTreeModel
*tree_model
)
239 static GType
details_get_column_type(GtkTreeModel
*tree_model
, gint index
)
241 g_return_val_if_fail(index
< N_COLUMNS
&& index
>= 0, G_TYPE_INVALID
);
243 if (index
== COL_COLOUR
|| index
== COL_BG_COLOUR
)
244 return GDK_TYPE_COLOR
;
245 else if (index
== COL_ITEM
)
246 return G_TYPE_POINTER
;
247 else if (index
== COL_ICON
)
248 return GDK_TYPE_PIXBUF
;
249 return G_TYPE_STRING
;
252 static gboolean
details_get_iter(GtkTreeModel
*tree_model
,
256 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
259 g_return_val_if_fail(gtk_tree_path_get_depth (path
) > 0, FALSE
);
261 i
= gtk_tree_path_get_indices(path
)[0];
263 if (i
>= view_details
->items
->len
)
266 iter
->user_data
= GINT_TO_POINTER(i
);
271 static GtkTreePath
*details_get_path(GtkTreeModel
*tree_model
,
276 retval
= gtk_tree_path_new();
277 gtk_tree_path_append_index(retval
, GPOINTER_TO_INT(iter
->user_data
));
282 static void details_get_value(GtkTreeModel
*tree_model
,
287 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
288 GtkStyle
*style
= ((GtkWidget
*) tree_model
)->style
;
290 GPtrArray
*items
= view_details
->items
;
295 g_return_if_fail(column
>= 0 && column
< N_COLUMNS
);
297 i
= GPOINTER_TO_INT(iter
->user_data
);
298 g_return_if_fail(i
>= 0 && i
< items
->len
);
299 view_item
= (ViewItem
*) items
->pdata
[i
];
300 item
= view_item
->item
;
302 if (column
== COL_LEAF
)
304 g_value_init(value
, G_TYPE_STRING
);
305 g_value_set_string(value
, item
->leafname
);
308 else if (column
== COL_ITEM
)
310 g_value_init(value
, G_TYPE_POINTER
);
311 g_value_set_pointer(value
, item
);
315 if (item
->base_type
== TYPE_UNKNOWN
)
318 type
= details_get_column_type(tree_model
, column
);
319 g_value_init(value
, type
);
320 if (type
== G_TYPE_STRING
)
321 g_value_set_string(value
, "");
322 else if (type
== GDK_TYPE_COLOR
)
323 g_value_set_boxed(value
, NULL
);
325 g_value_set_object(value
, NULL
);
334 g_value_init(value
, G_TYPE_STRING
);
335 g_value_set_string(value
, item
->leafname
);
338 g_value_init(value
, GDK_TYPE_PIXBUF
);
339 if (!item
->image
->sm_pixbuf
)
340 pixmap_make_small(item
->image
);
341 g_value_set_object(value
, item
->image
->sm_pixbuf
);
344 g_value_init(value
, GDK_TYPE_COLOR
);
345 g_value_set_boxed(value
, type_get_colour(item
, NULL
));
348 g_value_init(value
, GDK_TYPE_COLOR
);
349 g_value_set_boxed(value
, view_item
->selected
350 ? &style
->base
[GTK_STATE_SELECTED
]
354 g_value_init(value
, G_TYPE_STRING
);
355 g_value_set_string(value
, user_name(item
->uid
));
358 g_value_init(value
, G_TYPE_STRING
);
359 g_value_set_string(value
, group_name(item
->gid
));
364 time
= pretty_time(&item
->mtime
);
365 g_value_init(value
, G_TYPE_STRING
);
366 g_value_set_string(value
, time
);
371 g_value_init(value
, G_TYPE_STRING
);
372 g_value_set_string(value
, pretty_permissions(m
));
375 g_value_init(value
, G_TYPE_STRING
);
376 if (item
->base_type
!= TYPE_DIRECTORY
)
377 g_value_set_string(value
,
378 format_size(item
->size
));
381 g_value_init(value
, G_TYPE_STRING
);
382 g_value_set_string(value
,
383 item
->flags
& ITEM_FLAG_APPDIR
? "App" :
385 S_ISCHR(m
) ? "Char" :
386 S_ISBLK(m
) ? "Blck" :
387 S_ISLNK(m
) ? "Link" :
388 S_ISSOCK(m
) ? "Sock" :
389 S_ISFIFO(m
) ? "Pipe" :
390 S_ISDOOR(m
) ? "Door" :
394 g_value_init(value
, G_TYPE_STRING
);
395 g_value_set_string(value
, "Hello");
400 static gboolean
details_iter_next(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
402 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
405 i
= GPOINTER_TO_INT(iter
->user_data
) + 1;
406 iter
->user_data
= GINT_TO_POINTER(i
);
408 return i
< view_details
->items
->len
;
411 static gboolean
details_iter_children(GtkTreeModel
*tree_model
,
415 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
417 /* this is a list, nodes have no children */
421 /* but if parent == NULL we return the list itself as children of the
425 if (view_details
->items
->len
)
427 iter
->user_data
= GINT_TO_POINTER(0);
434 static gboolean
details_iter_has_child(GtkTreeModel
*tree_model
,
440 static gint
details_iter_n_children(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
442 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
445 return view_details
->items
->len
;
450 static gboolean
details_iter_nth_child(GtkTreeModel
*tree_model
,
455 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
460 if (n
>= 0 && n
< view_details
->items
->len
)
462 iter
->user_data
= GINT_TO_POINTER(n
);
469 static gboolean
details_iter_parent(GtkTreeModel
*tree_model
,
476 /* A ViewDetails is both a GtkTreeView and a GtkTreeModel.
477 * The following functions implement the model interface...
480 static void view_details_tree_model_init(GtkTreeModelIface
*iface
)
482 iface
->get_flags
= details_get_flags
;
483 iface
->get_n_columns
= details_get_n_columns
;
484 iface
->get_column_type
= details_get_column_type
;
485 iface
->get_iter
= details_get_iter
;
486 iface
->get_path
= details_get_path
;
487 iface
->get_value
= details_get_value
;
488 iface
->iter_next
= details_iter_next
;
489 iface
->iter_children
= details_iter_children
;
490 iface
->iter_has_child
= details_iter_has_child
;
491 iface
->iter_n_children
= details_iter_n_children
;
492 iface
->iter_nth_child
= details_iter_nth_child
;
493 iface
->iter_parent
= details_iter_parent
;
496 static void view_details_sortable_init(GtkTreeSortableIface
*iface
)
498 iface
->get_sort_column_id
= details_get_sort_column_id
;
499 iface
->set_sort_column_id
= details_set_sort_column_id
;
500 iface
->set_sort_func
= details_set_sort_func
;
501 iface
->set_default_sort_func
= details_set_default_sort_func
;
502 iface
->has_default_sort_func
= details_has_default_sort_func
;
505 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
506 gint
*sort_column_id
,
509 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
511 if (view_details
->sort_column_id
== -1)
515 *sort_column_id
= view_details
->sort_column_id
;
517 *order
= view_details
->order
;
521 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
525 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
527 if (view_details
->sort_column_id
== sort_column_id
&&
528 view_details
->order
== order
)
531 view_details
->sort_column_id
= sort_column_id
;
532 view_details
->order
= order
;
534 switch (sort_column_id
)
537 view_details
->sort_fn
= sort_by_name
;
540 view_details
->sort_fn
= sort_by_size
;
543 view_details
->sort_fn
= sort_by_date
;
546 view_details
->sort_fn
= sort_by_type
;
549 view_details
->sort_fn
= sort_by_owner
;
552 view_details
->sort_fn
= sort_by_group
;
555 g_assert_not_reached();
558 view_details_sort((ViewIface
*) view_details
);
560 gtk_tree_sortable_sort_column_changed(sortable
);
563 static void details_set_sort_func(GtkTreeSortable
*sortable
,
565 GtkTreeIterCompareFunc func
,
567 GtkDestroyNotify destroy
)
569 g_assert_not_reached();
572 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
573 GtkTreeIterCompareFunc func
,
575 GtkDestroyNotify destroy
)
577 g_assert_not_reached();
580 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
)
586 /* End of model implementation */
588 static gboolean
is_selected(ViewDetails
*view_details
, int i
)
592 return view_details_get_selected((ViewIface
*) view_details
, &iter
);
595 static gboolean
view_details_button_press(GtkWidget
*widget
,
598 FilerWindow
*filer_window
= ((ViewDetails
*) widget
)->filer_window
;
600 if (dnd_motion_press(widget
, bev
))
601 filer_perform_action(filer_window
, bev
);
606 static gboolean
view_details_button_release(GtkWidget
*widget
,
609 FilerWindow
*filer_window
= ((ViewDetails
*) widget
)->filer_window
;
611 if (!dnd_motion_release(bev
))
612 filer_perform_action(filer_window
, bev
);
617 static gint
view_details_key_press_event(GtkWidget
*widget
, GdkEventKey
*event
)
619 ViewDetails
*view_details
= (ViewDetails
*) widget
;
620 FilerWindow
*filer_window
= view_details
->filer_window
;
622 switch (event
->keyval
)
625 filer_window_toggle_cursor_item_selected(filer_window
);
628 change_to_parent(filer_window
);
632 return GTK_WIDGET_CLASS(parent_class
)->key_press_event(widget
, event
);
635 static gint
view_details_motion_notify(GtkWidget
*widget
, GdkEventMotion
*event
)
637 ViewDetails
*view_details
= (ViewDetails
*) widget
;
639 return filer_motion_notify(view_details
->filer_window
, event
);
642 static gboolean
view_details_expose(GtkWidget
*widget
, GdkEventExpose
*event
)
644 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
645 GtkTreePath
*path
= NULL
;
646 GdkRectangle focus_rectangle
;
649 had_cursor
= (GTK_WIDGET_FLAGS(widget
) & GTK_HAS_FOCUS
) != 0;
652 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_HAS_FOCUS
);
653 GTK_WIDGET_CLASS(parent_class
)->expose_event(widget
, event
);
655 GTK_WIDGET_SET_FLAGS(widget
, GTK_HAS_FOCUS
);
657 if (event
->window
!= gtk_tree_view_get_bin_window(tree
))
658 return FALSE
; /* Not the main area */
660 gtk_tree_view_get_cursor(tree
, &path
, NULL
);
662 return FALSE
; /* No cursor */
663 gtk_tree_view_get_background_area(tree
, path
, NULL
, &focus_rectangle
);
664 gtk_tree_path_free(path
);
666 if (!focus_rectangle
.height
)
667 return FALSE
; /* Off screen */
669 focus_rectangle
.width
= widget
->allocation
.width
;
671 gtk_paint_focus(widget
->style
,
679 focus_rectangle
.width
,
680 focus_rectangle
.height
);
685 static void view_details_destroy(GtkObject
*view_details
)
687 VIEW_DETAILS(view_details
)->filer_window
= NULL
;
690 static void view_details_finialize(GObject
*object
)
692 ViewDetails
*view_details
= (ViewDetails
*) object
;
694 g_ptr_array_free(view_details
->items
, TRUE
);
695 view_details
->items
= NULL
;
697 G_OBJECT_CLASS(parent_class
)->finalize(object
);
700 static void view_details_class_init(gpointer gclass
, gpointer data
)
702 GObjectClass
*object
= (GObjectClass
*) gclass
;
703 GtkWidgetClass
*widget
= (GtkWidgetClass
*) gclass
;
705 parent_class
= g_type_class_peek_parent(gclass
);
707 object
->finalize
= view_details_finialize
;
708 GTK_OBJECT_CLASS(object
)->destroy
= view_details_destroy
;
710 widget
->button_press_event
= view_details_button_press
;
711 widget
->button_release_event
= view_details_button_release
;
712 widget
->key_press_event
= view_details_key_press_event
;
713 widget
->motion_notify_event
= view_details_motion_notify
;
714 widget
->expose_event
= view_details_expose
;
717 static void view_details_init(GTypeInstance
*object
, gpointer gclass
)
719 GtkTreeView
*treeview
= (GtkTreeView
*) object
;
720 GtkTreeViewColumn
*column
;
721 GtkCellRenderer
*cell
;
722 GtkTreeSortable
*sortable_list
;
723 GtkTreeSelection
*selection
;
724 ViewDetails
*view_details
= (ViewDetails
*) object
;
726 view_details
->items
= g_ptr_array_new();
727 view_details
->cursor_base
= -1;
729 selection
= gtk_tree_view_get_selection(treeview
);
730 gtk_tree_selection_set_mode(selection
, GTK_SELECTION_NONE
);
733 view_details
->sort_column_id
= -1;
734 view_details
->sort_fn
= NULL
;
735 sortable_list
= GTK_TREE_SORTABLE(object
);
736 gtk_tree_sortable_set_sort_column_id(sortable_list
, COL_LEAF
,
739 gtk_tree_view_set_model(treeview
, GTK_TREE_MODEL(view_details
));
742 cell
= cell_icon_new();
743 column
= gtk_tree_view_column_new_with_attributes(NULL
, cell
,
745 "background-gdk", COL_BG_COLOUR
,
747 gtk_tree_view_append_column(treeview
, column
);
750 cell
= gtk_cell_renderer_text_new();
751 column
= gtk_tree_view_column_new_with_attributes(_("_Name"), cell
,
753 "foreground-gdk", COL_COLOUR
,
754 "background-gdk", COL_BG_COLOUR
,
756 gtk_tree_view_append_column(treeview
, column
);
757 gtk_tree_view_column_set_sort_column_id(column
, COL_LEAF
);
760 cell
= gtk_cell_renderer_text_new();
761 column
= gtk_tree_view_column_new_with_attributes(_("_Type"), cell
,
763 "foreground-gdk", COL_COLOUR
,
764 "background-gdk", COL_BG_COLOUR
,
766 gtk_tree_view_append_column(treeview
, column
);
767 gtk_tree_view_column_set_sort_column_id(column
, COL_TYPE
);
770 cell
= gtk_cell_renderer_text_new();
771 column
= gtk_tree_view_column_new_with_attributes(_("_Permissions"),
772 cell
, "text", COL_PERM
,
773 "foreground-gdk", COL_COLOUR
,
774 "background-gdk", COL_BG_COLOUR
,
776 gtk_tree_view_append_column(treeview
, column
);
779 cell
= gtk_cell_renderer_text_new();
780 column
= gtk_tree_view_column_new_with_attributes(_("_Owner"), cell
,
782 "foreground-gdk", COL_COLOUR
,
783 "background-gdk", COL_BG_COLOUR
,
785 gtk_tree_view_append_column(treeview
, column
);
786 gtk_tree_view_column_set_sort_column_id(column
, COL_OWNER
);
789 cell
= gtk_cell_renderer_text_new();
790 column
= gtk_tree_view_column_new_with_attributes(_("_Group"), cell
,
792 "foreground-gdk", COL_COLOUR
,
793 "background-gdk", COL_BG_COLOUR
,
795 gtk_tree_view_append_column(treeview
, column
);
796 gtk_tree_view_column_set_sort_column_id(column
, COL_GROUP
);
799 cell
= gtk_cell_renderer_text_new();
800 column
= gtk_tree_view_column_new_with_attributes(_("_Size"), cell
,
802 "foreground-gdk", COL_COLOUR
,
803 "background-gdk", COL_BG_COLOUR
,
805 gtk_tree_view_append_column(treeview
, column
);
806 gtk_tree_view_column_set_sort_column_id(column
, COL_SIZE
);
809 cell
= gtk_cell_renderer_text_new();
810 column
= gtk_tree_view_column_new_with_attributes(_("_M-Time"), cell
,
812 "foreground-gdk", COL_COLOUR
,
813 "background-gdk", COL_BG_COLOUR
,
815 gtk_tree_view_append_column(treeview
, column
);
816 gtk_tree_view_column_set_sort_column_id(column
, COL_MTIME
);
818 gtk_widget_set_size_request(GTK_WIDGET(treeview
), -1, 50);
821 /* Create the handers for the View interface */
822 static void view_details_iface_init(gpointer giface
, gpointer iface_data
)
824 ViewIfaceClass
*iface
= giface
;
826 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
829 iface
->sort
= view_details_sort
;
830 iface
->style_changed
= view_details_style_changed
;
831 iface
->autoselect
= view_details_autoselect
;
832 iface
->add_items
= view_details_add_items
;
833 iface
->update_items
= view_details_update_items
;
834 iface
->delete_if
= view_details_delete_if
;
835 iface
->clear
= view_details_clear
;
836 iface
->select_all
= view_details_select_all
;
837 iface
->clear_selection
= view_details_clear_selection
;
838 iface
->count_items
= view_details_count_items
;
839 iface
->count_selected
= view_details_count_selected
;
840 iface
->show_cursor
= view_details_show_cursor
;
841 iface
->get_iter
= view_details_get_iter
;
842 iface
->get_iter_at_point
= view_details_get_iter_at_point
;
843 iface
->cursor_to_iter
= view_details_cursor_to_iter
;
844 iface
->set_selected
= view_details_set_selected
;
845 iface
->get_selected
= view_details_get_selected
;
846 iface
->set_frozen
= view_details_set_frozen
;
847 iface
->select_only
= view_details_select_only
;
848 iface
->wink_item
= view_details_wink_item
;
849 iface
->autosize
= view_details_autosize
;
850 iface
->cursor_visible
= view_details_cursor_visible
;
851 iface
->set_base
= view_details_set_base
;
852 iface
->start_lasso_box
= view_details_start_lasso_box
;
853 iface
->extend_tip
= view_details_extend_tip
;
856 /* Implementations of the View interface. See view_iface.c for comments. */
858 static void view_details_style_changed(ViewIface
*view
, int flags
)
862 static gint
wrap_sort(gconstpointer a
, gconstpointer b
,
863 ViewDetails
*view_details
)
865 ViewItem
*ia
= *(ViewItem
**) a
;
866 ViewItem
*ib
= *(ViewItem
**) b
;
868 if (view_details
->order
== GTK_SORT_ASCENDING
)
869 return view_details
->sort_fn(ia
->item
, ib
->item
);
871 return -view_details
->sort_fn(ia
->item
, ib
->item
);
874 static void view_details_sort(ViewIface
*view
)
876 ViewDetails
*view_details
= (ViewDetails
*) view
;
877 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
879 gint i
, len
= view_details
->items
->len
;
882 g_return_if_fail(view_details
->sort_fn
!= NULL
);
887 for (i
= len
- 1; i
>= 0; i
--)
888 items
[i
]->old_pos
= i
;
890 g_ptr_array_sort_with_data(view_details
->items
,
891 (GCompareDataFunc
) wrap_sort
,
894 new_order
= g_array_sized_new(FALSE
, FALSE
, sizeof(gint
), len
);
895 g_array_set_size(new_order
, len
);
897 for (i
= len
- 1; i
>= 0; i
--)
898 g_array_insert_val(new_order
, items
[i
]->old_pos
, i
);
900 path
= gtk_tree_path_new();
901 gtk_tree_model_rows_reordered((GtkTreeModel
*) view
,
903 (gint
*) new_order
->data
);
904 gtk_tree_path_free(path
);
905 g_array_free(new_order
, TRUE
);
908 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
)
913 static void view_details_add_items(ViewIface
*view
, GPtrArray
*new_items
)
915 ViewDetails
*view_details
= (ViewDetails
*) view
;
916 FilerWindow
*filer_window
= view_details
->filer_window
;
917 gboolean show_hidden
= filer_window
->show_hidden
;
918 GPtrArray
*items
= view_details
->items
;
922 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
924 iter
.user_data
= GINT_TO_POINTER(items
->len
);
925 path
= details_get_path(model
, &iter
);
927 for (i
= 0; i
< new_items
->len
; i
++)
929 DirItem
*item
= (DirItem
*) new_items
->pdata
[i
];
930 char *leafname
= item
->leafname
;
933 if (leafname
[0] == '.')
938 if (leafname
[1] == '\0')
939 continue; /* Never show '.' */
941 if (leafname
[1] == '.' &&
943 continue; /* Never show '..' */
946 vitem
= g_new(ViewItem
, 1);
949 vitem
->selected
= FALSE
;
951 g_ptr_array_add(items
, vitem
);
953 iter
.user_data
= GINT_TO_POINTER(items
->len
- 1);
954 gtk_tree_model_row_inserted(model
, path
, &iter
);
955 gtk_tree_path_next(path
);
958 gtk_tree_path_free(path
);
960 view_details_sort(view
);
963 /* Find an item in the sorted array.
964 * Returns the item number, or -1 if not found.
966 static int details_find_item(ViewDetails
*view_details
, DirItem
*item
)
968 ViewItem
**items
, tmp
, *tmpp
;
970 int (*compar
)(const void *, const void *);
972 g_return_val_if_fail(view_details
!= NULL
, -1);
973 g_return_val_if_fail(item
!= NULL
, -1);
978 items
= (ViewItem
**) view_details
->items
->pdata
;
979 compar
= view_details
->sort_fn
;
981 g_return_val_if_fail(compar
!= NULL
, -1);
983 /* If item is here, then: lower <= i < upper */
985 upper
= view_details
->items
->len
;
987 while (lower
< upper
)
991 i
= (lower
+ upper
) >> 1;
993 cmp
= wrap_sort(&items
[i
], &tmpp
, view_details
);
1006 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
)
1008 ViewDetails
*view_details
= (ViewDetails
*) view
;
1009 FilerWindow
*filer_window
= view_details
->filer_window
;
1011 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
1013 g_return_if_fail(items
->len
> 0);
1015 /* The item data has already been modified, so this gives the
1016 * final sort order...
1018 view_details_sort(view
);
1020 for (i
= 0; i
< items
->len
; i
++)
1022 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1023 const gchar
*leafname
= item
->leafname
;
1026 if (leafname
[0] == '.' && filer_window
->show_hidden
== FALSE
)
1029 j
= details_find_item(view_details
, item
);
1032 g_warning("Failed to find '%s'\n", leafname
);
1037 path
= gtk_tree_path_new();
1038 gtk_tree_path_append_index(path
, j
);
1039 iter
.user_data
= GINT_TO_POINTER(j
);
1040 gtk_tree_model_row_changed(model
, path
, &iter
);
1045 static void view_details_delete_if(ViewIface
*view
,
1046 gboolean (*test
)(gpointer item
, gpointer data
),
1050 ViewDetails
*view_details
= (ViewDetails
*) view
;
1052 GPtrArray
*items
= view_details
->items
;
1053 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1055 path
= gtk_tree_path_new();
1057 gtk_tree_path_append_index(path
, i
);
1059 while (i
< items
->len
)
1061 ViewItem
*item
= items
->pdata
[i
];
1063 if (test(item
->item
, data
))
1065 g_free(items
->pdata
[i
]);
1066 g_ptr_array_remove_index(items
, i
);
1067 gtk_tree_model_row_deleted(model
, path
);
1072 gtk_tree_path_next(path
);
1076 gtk_tree_path_free(path
);
1079 static void view_details_clear(ViewIface
*view
)
1082 GPtrArray
*items
= ((ViewDetails
*) view
)->items
;
1083 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1085 path
= gtk_tree_path_new();
1086 gtk_tree_path_append_index(path
, items
->len
);
1088 while (gtk_tree_path_prev(path
))
1089 gtk_tree_model_row_deleted(model
, path
);
1091 g_ptr_array_set_size(items
, 0);
1092 gtk_tree_path_free(path
);
1095 static void view_details_select_all(ViewIface
*view
)
1098 int n
= ((ViewDetails
*) view
)->items
->len
;
1100 for (i
= 0; i
< n
; i
++)
1104 view_details_set_selected(view
, &iter
, TRUE
);
1108 static void view_details_clear_selection(ViewIface
*view
)
1111 int n
= ((ViewDetails
*) view
)->items
->len
;
1113 for (i
= 0; i
< n
; i
++)
1117 view_details_set_selected(view
, &iter
, FALSE
);
1121 static int view_details_count_items(ViewIface
*view
)
1123 ViewDetails
*view_details
= (ViewDetails
*) view
;
1125 return view_details
->items
->len
;
1128 static int view_details_count_selected(ViewIface
*view
)
1130 ViewDetails
*view_details
= (ViewDetails
*) view
;
1131 int n
= view_details
->items
->len
;
1132 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
1136 for (i
= 0; i
< n
; i
++)
1137 if (items
[i
]->selected
)
1143 static void view_details_show_cursor(ViewIface
*view
)
1147 static void view_details_get_iter(ViewIface
*view
,
1148 ViewIter
*iter
, IterFlags flags
)
1150 make_iter((ViewDetails
*) view
, iter
, flags
);
1153 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
1156 ViewDetails
*view_details
= (ViewDetails
*) view
;
1157 GtkTreeModel
*model
;
1158 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1159 GtkTreePath
*path
= NULL
;
1162 model
= gtk_tree_view_get_model(tree
);
1164 if (gtk_tree_view_get_path_at_pos(tree
, x
, y
, &path
, NULL
, NULL
, NULL
))
1166 g_return_if_fail(path
!= NULL
);
1168 i
= gtk_tree_path_get_indices(path
)[0];
1169 gtk_tree_path_free(path
);
1172 make_item_iter(view_details
, iter
, i
);
1175 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
)
1178 ViewDetails
*view_details
= (ViewDetails
*) view
;
1180 path
= gtk_tree_path_new();
1183 gtk_tree_path_append_index(path
, iter
->i
);
1186 /* Using depth zero or index -1 gives an error, but this
1189 gtk_tree_path_append_index(path
, view_details
->items
->len
);
1192 gtk_tree_view_set_cursor((GtkTreeView
*) view
, path
, NULL
, FALSE
);
1193 gtk_tree_path_free(path
);
1196 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
)
1198 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
1201 GPtrArray
*items
= view_details
->items
;
1202 ViewItem
*view_item
;
1204 g_return_if_fail(i
>= 0 && i
< items
->len
);
1205 view_item
= (ViewItem
*) items
->pdata
[i
];
1207 if (view_item
->selected
== selected
)
1210 view_item
->selected
= selected
;
1212 path
= gtk_tree_path_new();
1213 gtk_tree_path_append_index(path
, i
);
1214 t_iter
.user_data
= GINT_TO_POINTER(i
);
1215 gtk_tree_model_row_changed(model
, path
, &t_iter
);
1216 gtk_tree_path_free(path
);
1219 static void view_details_set_selected(ViewIface
*view
,
1223 set_selected((ViewDetails
*) view
, iter
->i
, selected
);
1226 static gboolean
get_selected(ViewDetails
*view_details
, int i
)
1228 GPtrArray
*items
= view_details
->items
;
1230 g_return_val_if_fail(i
>= 0 && i
< items
->len
, FALSE
);
1232 return ((ViewItem
*) items
->pdata
[i
])->selected
;
1235 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
)
1237 return get_selected((ViewDetails
*) view
, iter
->i
);
1240 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
)
1242 ViewDetails
*view_details
= (ViewDetails
*) view
;
1244 int n
= view_details
->items
->len
;
1246 set_selected(view_details
, i
, TRUE
);
1253 set_selected(view_details
, n
, FALSE
);
1257 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
)
1261 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
)
1265 static void view_details_autosize(ViewIface
*view
)
1267 ViewDetails
*view_details
= (ViewDetails
*) view
;
1268 FilerWindow
*filer_window
= view_details
->filer_window
;
1270 int max_height
= (o_filer_size_limit
.int_value
* screen_height
) / 100;
1272 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1273 GtkTreeViewColumn
*column
;
1276 gtk_widget_size_request(GTK_WIDGET(view
), &req
);
1277 column
= gtk_tree_view_get_column(tree
, 1);
1278 gtk_tree_view_column_cell_get_size(column
, NULL
, NULL
, NULL
, NULL
, &h
);
1280 bin
= gtk_tree_view_get_bin_window(GTK_TREE_VIEW(view
));
1282 gdk_window_get_position(bin
, NULL
, &y
);
1284 h
= MAX(h
, SMALL_HEIGHT
);
1286 h
= (view_details
->items
->len
+ 2) * h
+ y
;
1288 h
= MIN(h
, max_height
);
1290 filer_window_set_size(filer_window
, 5, h
);
1293 static gboolean
view_details_cursor_visible(ViewIface
*view
)
1298 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
)
1300 ViewDetails
*view_details
= (ViewDetails
*) view
;
1302 view_details
->cursor_base
= iter
->i
;
1305 static void view_details_start_lasso_box(ViewIface
*view
, GdkEventButton
*event
)
1309 static void view_details_extend_tip(ViewIface
*view
,
1310 ViewIter
*iter
, GString
*tip
)
1314 static DirItem
*iter_init(ViewIter
*iter
)
1316 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1318 int n
= view_details
->items
->len
;
1319 int flags
= iter
->flags
;
1321 iter
->peek
= iter_peek
;
1323 if (iter
->n_remaining
== 0)
1326 if (flags
& VIEW_ITER_FROM_CURSOR
)
1329 gtk_tree_view_get_cursor((GtkTreeView
*) view_details
,
1332 return NULL
; /* No cursor */
1333 i
= gtk_tree_path_get_indices(path
)[0];
1334 gtk_tree_path_free(path
);
1336 else if (flags
& VIEW_ITER_FROM_BASE
)
1337 i
= view_details
->cursor_base
;
1339 if (i
< 0 || i
>= n
)
1341 /* Either a normal iteration, or an iteration from an
1342 * invalid starting point.
1344 if (flags
& VIEW_ITER_BACKWARDS
)
1350 if (i
< 0 || i
>= n
)
1351 return NULL
; /* No items at all! */
1353 iter
->next
= flags
& VIEW_ITER_BACKWARDS
? iter_prev
: iter_next
;
1354 iter
->n_remaining
--;
1357 if (flags
& VIEW_ITER_SELECTED
&& !is_selected(view_details
, i
))
1358 return iter
->next(iter
);
1359 return iter
->peek(iter
);
1362 static DirItem
*iter_prev(ViewIter
*iter
)
1364 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1365 int n
= view_details
->items
->len
;
1368 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1370 /* i is the last item returned (always valid) */
1372 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1374 while (iter
->n_remaining
)
1377 iter
->n_remaining
--;
1382 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1384 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1385 !is_selected(view_details
, i
))
1389 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1396 static DirItem
*iter_next(ViewIter
*iter
)
1398 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1399 int n
= view_details
->items
->len
;
1402 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1404 /* i is the last item returned (always valid) */
1406 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1408 while (iter
->n_remaining
)
1411 iter
->n_remaining
--;
1416 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1418 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1419 !is_selected(view_details
, i
))
1423 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1430 static DirItem
*iter_peek(ViewIter
*iter
)
1432 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1433 int n
= view_details
->items
->len
;
1439 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1441 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1444 /* Set the iterator to return 'i' on the next peek().
1445 * If i is -1, returns NULL on next peek().
1447 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
)
1449 make_iter(view_details
, iter
, 0);
1451 g_return_if_fail(i
>= -1 && i
< (int) view_details
->items
->len
);
1454 iter
->next
= iter_next
;
1455 iter
->peek
= iter_peek
;
1456 iter
->n_remaining
= 0;
1459 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
1462 iter
->view
= (ViewIface
*) view_details
;
1463 iter
->next
= iter_init
;
1467 iter
->flags
= flags
;
1469 if (flags
& VIEW_ITER_ONE_ONLY
)
1471 iter
->n_remaining
= 1;
1475 iter
->n_remaining
= view_details
->items
->len
;