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"
46 /* These are the column numbers in the ListStore */
57 #define COL_BG_COLOUR 10
60 static gpointer parent_class
= NULL
;
62 struct _ViewDetailsClass
{
63 GtkTreeViewClass parent
;
66 typedef struct _ViewItem ViewItem
;
71 int old_pos
; /* Used while sorting */
75 typedef struct _ViewDetails ViewDetails
;
80 FilerWindow
*filer_window
; /* Used for styles, etc */
82 GPtrArray
*items
; /* ViewItem */
86 int (*sort_fn
)(const void *, const void *);
88 int cursor_base
; /* Cursor when minibuffer opened */
91 /* Static prototypes */
92 static void view_details_finialize(GObject
*object
);
93 static void view_details_class_init(gpointer gclass
, gpointer data
);
94 static void view_details_init(GTypeInstance
*object
, gpointer gclass
);
96 static void view_details_iface_init(gpointer giface
, gpointer iface_data
);
98 static void view_details_sort(ViewIface
*view
);
99 static void view_details_style_changed(ViewIface
*view
, int flags
);
100 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
);
101 static void view_details_add_items(ViewIface
*view
, GPtrArray
*items
);
102 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
);
103 static void view_details_delete_if(ViewIface
*view
,
104 gboolean (*test
)(gpointer item
, gpointer data
),
106 static void view_details_clear(ViewIface
*view
);
107 static void view_details_select_all(ViewIface
*view
);
108 static void view_details_clear_selection(ViewIface
*view
);
109 static int view_details_count_items(ViewIface
*view
);
110 static int view_details_count_selected(ViewIface
*view
);
111 static void view_details_show_cursor(ViewIface
*view
);
112 static void view_details_get_iter(ViewIface
*view
,
113 ViewIter
*iter
, IterFlags flags
);
114 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
116 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
117 static void view_details_set_selected(ViewIface
*view
,
120 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
);
121 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
);
122 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
);
123 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
);
124 static void view_details_autosize(ViewIface
*view
);
125 static gboolean
view_details_cursor_visible(ViewIface
*view
);
126 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
);
127 static void view_details_start_lasso_box(ViewIface
*view
,
128 GdkEventButton
*event
);
129 static void view_details_extend_tip(ViewIface
*view
,
130 ViewIter
*iter
, GString
*tip
);
132 static DirItem
*iter_peek(ViewIter
*iter
);
133 static DirItem
*iter_prev(ViewIter
*iter
);
134 static DirItem
*iter_next(ViewIter
*iter
);
135 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
137 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
);
138 static void view_details_tree_model_init(GtkTreeModelIface
*iface
);
139 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
140 gint
*sort_column_id
,
142 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
145 static void details_set_sort_func(GtkTreeSortable
*sortable
,
147 GtkTreeIterCompareFunc func
,
149 GtkDestroyNotify destroy
);
150 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
151 GtkTreeIterCompareFunc func
,
153 GtkDestroyNotify destroy
);
154 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
);
155 static void view_details_sortable_init(GtkTreeSortableIface
*iface
);
156 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
);
157 static gboolean
get_selected(ViewDetails
*view_details
, int i
);
160 /****************************************************************
161 * EXTERNAL INTERFACE *
162 ****************************************************************/
164 GtkWidget
*view_details_new(FilerWindow
*filer_window
)
166 ViewDetails
*view_details
;
168 view_details
= g_object_new(view_details_get_type(), NULL
);
169 view_details
->filer_window
= filer_window
;
171 gtk_range_set_adjustment(GTK_RANGE(filer_window
->scrollbar
),
172 gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(view_details
)));
174 return GTK_WIDGET(view_details
);
177 GType
view_details_get_type(void)
179 static GType type
= 0;
183 static const GTypeInfo info
=
185 sizeof (ViewDetailsClass
),
186 NULL
, /* base_init */
187 NULL
, /* base_finalise */
188 view_details_class_init
,
189 NULL
, /* class_finalise */
190 NULL
, /* class_data */
195 static const GInterfaceInfo view_iface_info
= {
196 view_details_iface_init
,
199 static const GInterfaceInfo tree_model_info
= {
200 (GInterfaceInitFunc
) view_details_tree_model_init
,
203 static const GInterfaceInfo sortable_info
= {
204 (GInterfaceInitFunc
) view_details_sortable_init
,
209 type
= g_type_register_static(gtk_tree_view_get_type(),
210 "ViewDetails", &info
, 0);
212 g_type_add_interface_static(type
, VIEW_TYPE_IFACE
,
214 g_type_add_interface_static(type
, GTK_TYPE_TREE_MODEL
,
216 g_type_add_interface_static(type
, GTK_TYPE_TREE_SORTABLE
,
223 /****************************************************************
224 * INTERNAL FUNCTIONS *
225 ****************************************************************/
227 /* Fulfill the GtkTreeModel requirements */
228 static guint
details_get_flags(GtkTreeModel
*tree_model
)
230 return GTK_TREE_MODEL_LIST_ONLY
;
233 static gint
details_get_n_columns(GtkTreeModel
*tree_model
)
238 static GType
details_get_column_type(GtkTreeModel
*tree_model
, gint index
)
240 g_return_val_if_fail(index
< N_COLUMNS
&& index
>= 0, G_TYPE_INVALID
);
242 if (index
== COL_COLOUR
|| index
== COL_BG_COLOUR
)
243 return GDK_TYPE_COLOR
;
244 else if (index
== COL_ITEM
)
245 return G_TYPE_POINTER
;
246 else if (index
== COL_ICON
)
247 return GDK_TYPE_PIXBUF
;
248 return G_TYPE_STRING
;
251 static gboolean
details_get_iter(GtkTreeModel
*tree_model
,
255 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
258 g_return_val_if_fail(gtk_tree_path_get_depth (path
) > 0, FALSE
);
260 i
= gtk_tree_path_get_indices(path
)[0];
262 if (i
>= view_details
->items
->len
)
265 iter
->user_data
= GINT_TO_POINTER(i
);
270 static GtkTreePath
*details_get_path(GtkTreeModel
*tree_model
,
275 retval
= gtk_tree_path_new();
276 gtk_tree_path_append_index(retval
, GPOINTER_TO_INT(iter
->user_data
));
281 static void details_get_value(GtkTreeModel
*tree_model
,
286 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
287 GtkStyle
*style
= ((GtkWidget
*) tree_model
)->style
;
289 GPtrArray
*items
= view_details
->items
;
294 g_return_if_fail(column
>= 0 && column
< N_COLUMNS
);
296 i
= GPOINTER_TO_INT(iter
->user_data
);
297 g_return_if_fail(i
>= 0 && i
< items
->len
);
298 view_item
= (ViewItem
*) items
->pdata
[i
];
299 item
= view_item
->item
;
301 /* g_print("[ get %d ]\n", column); */
303 if (column
== COL_LEAF
)
305 g_value_init(value
, G_TYPE_STRING
);
306 g_value_set_string(value
, item
->leafname
);
309 else if (column
== COL_ITEM
)
311 g_value_init(value
, G_TYPE_POINTER
);
312 g_value_set_pointer(value
, item
);
316 if (item
->base_type
== TYPE_UNKNOWN
)
319 type
= details_get_column_type(tree_model
, column
);
320 g_value_init(value
, type
);
321 if (type
== G_TYPE_STRING
)
322 g_value_set_string(value
, "");
323 else if (type
== GDK_TYPE_COLOR
)
324 g_value_set_boxed(value
, NULL
);
326 g_value_set_object(value
, NULL
);
335 g_value_init(value
, G_TYPE_STRING
);
336 g_value_set_string(value
, item
->leafname
);
339 g_value_init(value
, GDK_TYPE_PIXBUF
);
340 if (!item
->image
->sm_pixbuf
)
341 pixmap_make_small(item
->image
);
342 g_value_set_object(value
, item
->image
->sm_pixbuf
);
345 g_value_init(value
, GDK_TYPE_COLOR
);
346 g_value_set_boxed(value
, type_get_colour(item
, NULL
));
349 g_value_init(value
, GDK_TYPE_COLOR
);
350 g_value_set_boxed(value
, view_item
->selected
351 ? &style
->base
[GTK_STATE_SELECTED
]
352 : &style
->base
[GTK_STATE_NORMAL
]);
355 g_value_init(value
, G_TYPE_STRING
);
356 g_value_set_string(value
, user_name(item
->uid
));
359 g_value_init(value
, G_TYPE_STRING
);
360 g_value_set_string(value
, group_name(item
->gid
));
365 time
= pretty_time(&item
->mtime
);
366 g_value_init(value
, G_TYPE_STRING
);
367 g_value_set_string(value
, time
);
372 g_value_init(value
, G_TYPE_STRING
);
373 g_value_set_string(value
, pretty_permissions(m
));
376 g_value_init(value
, G_TYPE_STRING
);
377 if (item
->base_type
!= TYPE_DIRECTORY
)
378 g_value_set_string(value
,
379 format_size(item
->size
));
382 g_value_init(value
, G_TYPE_STRING
);
383 g_value_set_string(value
,
384 item
->flags
& ITEM_FLAG_APPDIR
? "App" :
386 S_ISCHR(m
) ? "Char" :
387 S_ISBLK(m
) ? "Blck" :
388 S_ISLNK(m
) ? "Link" :
389 S_ISSOCK(m
) ? "Sock" :
390 S_ISFIFO(m
) ? "Pipe" :
391 S_ISDOOR(m
) ? "Door" :
395 g_value_init(value
, G_TYPE_STRING
);
396 g_value_set_string(value
, "Hello");
401 static gboolean
details_iter_next(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
403 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
406 i
= GPOINTER_TO_INT(iter
->user_data
) + 1;
407 iter
->user_data
= GINT_TO_POINTER(i
);
409 return i
< view_details
->items
->len
;
412 static gboolean
details_iter_children(GtkTreeModel
*tree_model
,
416 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
418 /* this is a list, nodes have no children */
422 /* but if parent == NULL we return the list itself as children of the
426 if (view_details
->items
->len
)
428 iter
->user_data
= GINT_TO_POINTER(0);
435 static gboolean
details_iter_has_child(GtkTreeModel
*tree_model
,
441 static gint
details_iter_n_children(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
443 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
446 return view_details
->items
->len
;
451 static gboolean
details_iter_nth_child(GtkTreeModel
*tree_model
,
456 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
461 if (n
>= 0 && n
< view_details
->items
->len
)
463 iter
->user_data
= GINT_TO_POINTER(n
);
470 static gboolean
details_iter_parent(GtkTreeModel
*tree_model
,
477 /* A ViewDetails is both a GtkTreeView and a GtkTreeModel.
478 * The following functions implement the model interface...
481 static void view_details_tree_model_init(GtkTreeModelIface
*iface
)
483 iface
->get_flags
= details_get_flags
;
484 iface
->get_n_columns
= details_get_n_columns
;
485 iface
->get_column_type
= details_get_column_type
;
486 iface
->get_iter
= details_get_iter
;
487 iface
->get_path
= details_get_path
;
488 iface
->get_value
= details_get_value
;
489 iface
->iter_next
= details_iter_next
;
490 iface
->iter_children
= details_iter_children
;
491 iface
->iter_has_child
= details_iter_has_child
;
492 iface
->iter_n_children
= details_iter_n_children
;
493 iface
->iter_nth_child
= details_iter_nth_child
;
494 iface
->iter_parent
= details_iter_parent
;
497 static void view_details_sortable_init(GtkTreeSortableIface
*iface
)
499 iface
->get_sort_column_id
= details_get_sort_column_id
;
500 iface
->set_sort_column_id
= details_set_sort_column_id
;
501 iface
->set_sort_func
= details_set_sort_func
;
502 iface
->set_default_sort_func
= details_set_default_sort_func
;
503 iface
->has_default_sort_func
= details_has_default_sort_func
;
506 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
507 gint
*sort_column_id
,
510 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
512 if (view_details
->sort_column_id
== -1)
516 *sort_column_id
= view_details
->sort_column_id
;
518 *order
= view_details
->order
;
522 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
526 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
528 if (view_details
->sort_column_id
== sort_column_id
&&
529 view_details
->order
== order
)
532 view_details
->sort_column_id
= sort_column_id
;
533 view_details
->order
= order
;
535 switch (sort_column_id
)
538 view_details
->sort_fn
= sort_by_name
;
541 view_details
->sort_fn
= sort_by_size
;
544 view_details
->sort_fn
= sort_by_date
;
547 view_details
->sort_fn
= sort_by_type
;
550 view_details
->sort_fn
= sort_by_owner
;
553 view_details
->sort_fn
= sort_by_group
;
556 g_assert_not_reached();
559 view_details_sort((ViewIface
*) view_details
);
561 gtk_tree_sortable_sort_column_changed(sortable
);
564 static void details_set_sort_func(GtkTreeSortable
*sortable
,
566 GtkTreeIterCompareFunc func
,
568 GtkDestroyNotify destroy
)
570 g_assert_not_reached();
573 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
574 GtkTreeIterCompareFunc func
,
576 GtkDestroyNotify destroy
)
578 g_assert_not_reached();
581 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
)
587 /* End of model implementation */
589 static gboolean
is_selected(ViewDetails
*view_details
, int i
)
593 return view_details_get_selected((ViewIface
*) view_details
, &iter
);
596 static gboolean
view_details_button_press(GtkWidget
*widget
,
599 FilerWindow
*filer_window
= ((ViewDetails
*) widget
)->filer_window
;
601 if (dnd_motion_press(widget
, bev
))
602 filer_perform_action(filer_window
, bev
);
607 static gboolean
view_details_button_release(GtkWidget
*widget
,
610 FilerWindow
*filer_window
= ((ViewDetails
*) widget
)->filer_window
;
612 if (!dnd_motion_release(bev
))
613 filer_perform_action(filer_window
, bev
);
618 static gint
view_details_key_press_event(GtkWidget
*widget
, GdkEventKey
*event
)
620 if (event
->keyval
== ' ')
622 ViewDetails
*view_details
= (ViewDetails
*) widget
;
623 FilerWindow
*filer_window
= view_details
->filer_window
;
625 filer_window_toggle_cursor_item_selected(filer_window
);
629 return GTK_WIDGET_CLASS(parent_class
)->key_press_event(widget
, event
);
632 static gint
view_details_motion_notify(GtkWidget
*widget
, GdkEventMotion
*event
)
634 ViewDetails
*view_details
= (ViewDetails
*) widget
;
636 return filer_motion_notify(view_details
->filer_window
, event
);
639 static void view_details_destroy(GtkObject
*view_details
)
641 VIEW_DETAILS(view_details
)->filer_window
= NULL
;
644 static void view_details_finialize(GObject
*object
)
646 ViewDetails
*view_details
= (ViewDetails
*) object
;
648 g_ptr_array_free(view_details
->items
, TRUE
);
649 view_details
->items
= NULL
;
651 G_OBJECT_CLASS(parent_class
)->finalize(object
);
654 static void view_details_class_init(gpointer gclass
, gpointer data
)
656 GObjectClass
*object
= (GObjectClass
*) gclass
;
657 GtkWidgetClass
*widget
= (GtkWidgetClass
*) gclass
;
659 parent_class
= g_type_class_peek_parent(gclass
);
661 object
->finalize
= view_details_finialize
;
662 GTK_OBJECT_CLASS(object
)->destroy
= view_details_destroy
;
664 widget
->button_press_event
= view_details_button_press
;
665 widget
->button_release_event
= view_details_button_release
;
666 widget
->key_press_event
= view_details_key_press_event
;
667 widget
->motion_notify_event
= view_details_motion_notify
;
670 static void view_details_init(GTypeInstance
*object
, gpointer gclass
)
672 GtkTreeView
*treeview
= (GtkTreeView
*) object
;
673 GtkTreeViewColumn
*column
;
674 GtkCellRenderer
*cell
;
675 GtkTreeSortable
*sortable_list
;
676 GtkTreeSelection
*selection
;
677 ViewDetails
*view_details
= (ViewDetails
*) object
;
679 view_details
->items
= g_ptr_array_new();
680 view_details
->cursor_base
= -1;
682 selection
= gtk_tree_view_get_selection(treeview
);
683 gtk_tree_selection_set_mode(selection
, GTK_SELECTION_NONE
);
686 view_details
->sort_column_id
= -1;
687 view_details
->sort_fn
= NULL
;
688 sortable_list
= GTK_TREE_SORTABLE(object
);
689 gtk_tree_sortable_set_sort_column_id(sortable_list
, COL_LEAF
,
692 gtk_tree_view_set_model(treeview
, GTK_TREE_MODEL(view_details
));
695 cell
= gtk_cell_renderer_pixbuf_new();
696 column
= gtk_tree_view_column_new_with_attributes(NULL
, cell
,
697 "pixbuf", COL_ICON
, NULL
);
698 gtk_tree_view_append_column(treeview
, column
);
701 cell
= gtk_cell_renderer_text_new();
702 column
= gtk_tree_view_column_new_with_attributes(_("Name"), cell
,
704 "foreground-gdk", COL_COLOUR
,
705 "background-gdk", COL_BG_COLOUR
,
707 gtk_tree_view_append_column(treeview
, column
);
708 gtk_tree_view_column_set_sort_column_id(column
, COL_LEAF
);
711 cell
= gtk_cell_renderer_text_new();
712 column
= gtk_tree_view_column_new_with_attributes(_("Type"), cell
,
714 "foreground-gdk", COL_COLOUR
,
715 "background-gdk", COL_BG_COLOUR
,
717 gtk_tree_view_append_column(treeview
, column
);
718 gtk_tree_view_column_set_sort_column_id(column
, COL_TYPE
);
721 cell
= gtk_cell_renderer_text_new();
722 column
= gtk_tree_view_column_new_with_attributes(_("Permissions"),
723 cell
, "text", COL_PERM
,
724 "foreground-gdk", COL_COLOUR
,
725 "background-gdk", COL_BG_COLOUR
,
727 gtk_tree_view_append_column(treeview
, column
);
730 cell
= gtk_cell_renderer_text_new();
731 column
= gtk_tree_view_column_new_with_attributes(_("Owner"), cell
,
733 "foreground-gdk", COL_COLOUR
,
734 "background-gdk", COL_BG_COLOUR
,
736 gtk_tree_view_append_column(treeview
, column
);
737 gtk_tree_view_column_set_sort_column_id(column
, COL_OWNER
);
740 cell
= gtk_cell_renderer_text_new();
741 column
= gtk_tree_view_column_new_with_attributes(_("Group"), cell
,
743 "foreground-gdk", COL_COLOUR
,
744 "background-gdk", COL_BG_COLOUR
,
746 gtk_tree_view_append_column(treeview
, column
);
747 gtk_tree_view_column_set_sort_column_id(column
, COL_GROUP
);
750 cell
= gtk_cell_renderer_text_new();
751 column
= gtk_tree_view_column_new_with_attributes(_("Size"), 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_SIZE
);
760 cell
= gtk_cell_renderer_text_new();
761 column
= gtk_tree_view_column_new_with_attributes(_("M-Time"), 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_MTIME
);
769 gtk_widget_set_size_request(GTK_WIDGET(treeview
), -1, 50);
772 /* Create the handers for the View interface */
773 static void view_details_iface_init(gpointer giface
, gpointer iface_data
)
775 ViewIfaceClass
*iface
= giface
;
777 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
780 iface
->sort
= view_details_sort
;
781 iface
->style_changed
= view_details_style_changed
;
782 iface
->autoselect
= view_details_autoselect
;
783 iface
->add_items
= view_details_add_items
;
784 iface
->update_items
= view_details_update_items
;
785 iface
->delete_if
= view_details_delete_if
;
786 iface
->clear
= view_details_clear
;
787 iface
->select_all
= view_details_select_all
;
788 iface
->clear_selection
= view_details_clear_selection
;
789 iface
->count_items
= view_details_count_items
;
790 iface
->count_selected
= view_details_count_selected
;
791 iface
->show_cursor
= view_details_show_cursor
;
792 iface
->get_iter
= view_details_get_iter
;
793 iface
->get_iter_at_point
= view_details_get_iter_at_point
;
794 iface
->cursor_to_iter
= view_details_cursor_to_iter
;
795 iface
->set_selected
= view_details_set_selected
;
796 iface
->get_selected
= view_details_get_selected
;
797 iface
->set_frozen
= view_details_set_frozen
;
798 iface
->select_only
= view_details_select_only
;
799 iface
->wink_item
= view_details_wink_item
;
800 iface
->autosize
= view_details_autosize
;
801 iface
->cursor_visible
= view_details_cursor_visible
;
802 iface
->set_base
= view_details_set_base
;
803 iface
->start_lasso_box
= view_details_start_lasso_box
;
804 iface
->extend_tip
= view_details_extend_tip
;
807 /* Implementations of the View interface. See view_iface.c for comments. */
809 static void view_details_style_changed(ViewIface
*view
, int flags
)
813 static gint
wrap_sort(gconstpointer a
, gconstpointer b
,
814 ViewDetails
*view_details
)
816 ViewItem
*ia
= *(ViewItem
**) a
;
817 ViewItem
*ib
= *(ViewItem
**) b
;
819 if (view_details
->order
== GTK_SORT_ASCENDING
)
820 return view_details
->sort_fn(ia
->item
, ib
->item
);
822 return -view_details
->sort_fn(ia
->item
, ib
->item
);
825 static void view_details_sort(ViewIface
*view
)
827 ViewDetails
*view_details
= (ViewDetails
*) view
;
828 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
830 gint i
, len
= view_details
->items
->len
;
833 g_return_if_fail(view_details
->sort_fn
!= NULL
);
838 for (i
= len
- 1; i
>= 0; i
--)
839 items
[i
]->old_pos
= i
;
841 g_ptr_array_sort_with_data(view_details
->items
,
842 (GCompareDataFunc
) wrap_sort
,
845 new_order
= g_array_sized_new(FALSE
, FALSE
, sizeof(gint
), len
);
846 g_array_set_size(new_order
, len
);
848 for (i
= len
- 1; i
>= 0; i
--)
849 g_array_insert_val(new_order
, items
[i
]->old_pos
, i
);
851 path
= gtk_tree_path_new();
852 gtk_tree_model_rows_reordered((GtkTreeModel
*) view
,
854 (gint
*) new_order
->data
);
855 gtk_tree_path_free(path
);
856 g_array_free(new_order
, TRUE
);
859 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
)
864 static void view_details_add_items(ViewIface
*view
, GPtrArray
*new_items
)
866 ViewDetails
*view_details
= (ViewDetails
*) view
;
867 FilerWindow
*filer_window
= view_details
->filer_window
;
868 gboolean show_hidden
= filer_window
->show_hidden
;
869 GPtrArray
*items
= view_details
->items
;
873 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
875 iter
.user_data
= GINT_TO_POINTER(items
->len
);
876 path
= details_get_path(model
, &iter
);
878 for (i
= 0; i
< new_items
->len
; i
++)
880 DirItem
*item
= (DirItem
*) new_items
->pdata
[i
];
881 char *leafname
= item
->leafname
;
884 if (leafname
[0] == '.')
889 if (leafname
[1] == '\0')
890 continue; /* Never show '.' */
892 if (leafname
[1] == '.' &&
894 continue; /* Never show '..' */
897 vitem
= g_new(ViewItem
, 1);
900 vitem
->selected
= FALSE
;
902 g_ptr_array_add(items
, vitem
);
904 iter
.user_data
= GINT_TO_POINTER(items
->len
- 1);
905 gtk_tree_model_row_inserted(model
, path
, &iter
);
906 gtk_tree_path_next(path
);
909 gtk_tree_path_free(path
);
911 view_details_sort(view
);
914 /* Find an item in the sorted array.
915 * Returns the item number, or -1 if not found.
917 static int details_find_item(ViewDetails
*view_details
, DirItem
*item
)
919 ViewItem
**items
, tmp
, *tmpp
;
921 int (*compar
)(const void *, const void *);
923 g_return_val_if_fail(view_details
!= NULL
, -1);
924 g_return_val_if_fail(item
!= NULL
, -1);
929 items
= (ViewItem
**) view_details
->items
->pdata
;
930 compar
= view_details
->sort_fn
;
932 g_return_val_if_fail(compar
!= NULL
, -1);
934 /* If item is here, then: lower <= i < upper */
936 upper
= view_details
->items
->len
;
938 while (lower
< upper
)
942 i
= (lower
+ upper
) >> 1;
944 cmp
= wrap_sort(&items
[i
], &tmpp
, view_details
);
957 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
)
959 ViewDetails
*view_details
= (ViewDetails
*) view
;
960 FilerWindow
*filer_window
= view_details
->filer_window
;
962 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
964 g_return_if_fail(items
->len
> 0);
966 /* The item data has already been modified, so this gives the
967 * final sort order...
969 view_details_sort(view
);
971 for (i
= 0; i
< items
->len
; i
++)
973 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
974 const gchar
*leafname
= item
->leafname
;
977 if (leafname
[0] == '.' && filer_window
->show_hidden
== FALSE
)
980 j
= details_find_item(view_details
, item
);
983 g_warning("Failed to find '%s'\n", leafname
);
988 path
= gtk_tree_path_new();
989 gtk_tree_path_append_index(path
, j
);
990 iter
.user_data
= GINT_TO_POINTER(j
);
991 gtk_tree_model_row_changed(model
, path
, &iter
);
996 static void view_details_delete_if(ViewIface
*view
,
997 gboolean (*test
)(gpointer item
, gpointer data
),
1001 ViewDetails
*view_details
= (ViewDetails
*) view
;
1003 GPtrArray
*items
= view_details
->items
;
1004 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1006 path
= gtk_tree_path_new();
1008 gtk_tree_path_append_index(path
, i
);
1010 while (i
< items
->len
)
1012 ViewItem
*item
= items
->pdata
[i
];
1014 if (test(item
->item
, data
))
1016 g_free(items
->pdata
[i
]);
1017 g_ptr_array_remove_index(items
, i
);
1018 gtk_tree_model_row_deleted(model
, path
);
1023 gtk_tree_path_next(path
);
1027 gtk_tree_path_free(path
);
1030 static void view_details_clear(ViewIface
*view
)
1033 GPtrArray
*items
= ((ViewDetails
*) view
)->items
;
1034 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1036 path
= gtk_tree_path_new();
1037 gtk_tree_path_append_index(path
, items
->len
);
1039 while (gtk_tree_path_prev(path
))
1040 gtk_tree_model_row_deleted(model
, path
);
1042 g_ptr_array_set_size(items
, 0);
1043 gtk_tree_path_free(path
);
1046 static void view_details_select_all(ViewIface
*view
)
1049 int n
= ((ViewDetails
*) view
)->items
->len
;
1051 for (i
= 0; i
< n
; i
++)
1055 view_details_set_selected(view
, &iter
, TRUE
);
1059 static void view_details_clear_selection(ViewIface
*view
)
1062 int n
= ((ViewDetails
*) view
)->items
->len
;
1064 for (i
= 0; i
< n
; i
++)
1068 view_details_set_selected(view
, &iter
, FALSE
);
1072 static int view_details_count_items(ViewIface
*view
)
1074 ViewDetails
*view_details
= (ViewDetails
*) view
;
1076 return view_details
->items
->len
;
1079 static int view_details_count_selected(ViewIface
*view
)
1081 ViewDetails
*view_details
= (ViewDetails
*) view
;
1082 int n
= view_details
->items
->len
;
1083 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
1087 for (i
= 0; i
< n
; i
++)
1088 if (items
[i
]->selected
)
1094 static void view_details_show_cursor(ViewIface
*view
)
1098 static void view_details_get_iter(ViewIface
*view
,
1099 ViewIter
*iter
, IterFlags flags
)
1101 make_iter((ViewDetails
*) view
, iter
, flags
);
1104 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
1107 ViewDetails
*view_details
= (ViewDetails
*) view
;
1108 GtkTreeModel
*model
;
1109 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1110 GtkTreePath
*path
= NULL
;
1113 model
= gtk_tree_view_get_model(tree
);
1115 if (gtk_tree_view_get_path_at_pos(tree
, x
, y
, &path
, NULL
, NULL
, NULL
))
1117 g_return_if_fail(path
!= NULL
);
1119 i
= gtk_tree_path_get_indices(path
)[0];
1120 gtk_tree_path_free(path
);
1123 make_item_iter(view_details
, iter
, i
);
1126 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
)
1132 /* XXX: How do we get rid of the cursor? */
1133 g_print("FIXME: Remove cursor\n");
1137 path
= gtk_tree_path_new();
1139 gtk_tree_path_append_index(path
, iter
->i
);
1140 gtk_tree_view_set_cursor((GtkTreeView
*) view
, path
, NULL
, FALSE
);
1141 gtk_tree_path_free(path
);
1144 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
)
1146 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
1149 GPtrArray
*items
= view_details
->items
;
1150 ViewItem
*view_item
;
1152 g_return_if_fail(i
>= 0 && i
< items
->len
);
1153 view_item
= (ViewItem
*) items
->pdata
[i
];
1155 if (view_item
->selected
== selected
)
1158 view_item
->selected
= selected
;
1160 path
= gtk_tree_path_new();
1161 gtk_tree_path_append_index(path
, i
);
1162 t_iter
.user_data
= GINT_TO_POINTER(i
);
1163 gtk_tree_model_row_changed(model
, path
, &t_iter
);
1164 gtk_tree_path_free(path
);
1167 static void view_details_set_selected(ViewIface
*view
,
1171 set_selected((ViewDetails
*) view
, iter
->i
, selected
);
1174 static gboolean
get_selected(ViewDetails
*view_details
, int i
)
1176 GPtrArray
*items
= view_details
->items
;
1178 g_return_val_if_fail(i
>= 0 && i
< items
->len
, FALSE
);
1180 return ((ViewItem
*) items
->pdata
[i
])->selected
;
1183 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
)
1185 return get_selected((ViewDetails
*) view
, iter
->i
);
1188 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
)
1190 ViewDetails
*view_details
= (ViewDetails
*) view
;
1192 int n
= view_details
->items
->len
;
1194 set_selected(view_details
, i
, TRUE
);
1201 set_selected(view_details
, n
, FALSE
);
1205 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
)
1209 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
)
1213 static void view_details_autosize(ViewIface
*view
)
1217 static gboolean
view_details_cursor_visible(ViewIface
*view
)
1222 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
)
1224 ViewDetails
*view_details
= (ViewDetails
*) view
;
1226 view_details
->cursor_base
= iter
->i
;
1229 static void view_details_start_lasso_box(ViewIface
*view
, GdkEventButton
*event
)
1231 g_print("TODO: lasso drag\n");
1234 static void view_details_extend_tip(ViewIface
*view
,
1235 ViewIter
*iter
, GString
*tip
)
1239 static DirItem
*iter_init(ViewIter
*iter
)
1241 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1243 int n
= view_details
->items
->len
;
1244 int flags
= iter
->flags
;
1246 iter
->peek
= iter_peek
;
1248 if (iter
->n_remaining
== 0)
1251 if (flags
& VIEW_ITER_FROM_CURSOR
)
1254 gtk_tree_view_get_cursor((GtkTreeView
*) view_details
,
1257 return NULL
; /* No cursor */
1258 i
= gtk_tree_path_get_indices(path
)[0];
1259 gtk_tree_path_free(path
);
1261 else if (flags
& VIEW_ITER_FROM_BASE
)
1262 i
= view_details
->cursor_base
;
1264 if (i
< 0 || i
>= n
)
1266 /* Either a normal iteration, or an iteration from an
1267 * invalid starting point.
1269 if (flags
& VIEW_ITER_BACKWARDS
)
1275 if (i
< 0 || i
>= n
)
1276 return NULL
; /* No items at all! */
1278 iter
->next
= flags
& VIEW_ITER_BACKWARDS
? iter_prev
: iter_next
;
1279 iter
->n_remaining
--;
1282 if (flags
& VIEW_ITER_SELECTED
&& !is_selected(view_details
, i
))
1283 return iter
->next(iter
);
1284 return iter
->peek(iter
);
1287 static DirItem
*iter_prev(ViewIter
*iter
)
1289 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1290 int n
= view_details
->items
->len
;
1293 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1295 /* i is the last item returned (always valid) */
1297 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1299 while (iter
->n_remaining
)
1302 iter
->n_remaining
--;
1307 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1309 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1310 !is_selected(view_details
, i
))
1314 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1321 static DirItem
*iter_next(ViewIter
*iter
)
1323 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1324 int n
= view_details
->items
->len
;
1327 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1329 /* i is the last item returned (always valid) */
1331 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1333 while (iter
->n_remaining
)
1336 iter
->n_remaining
--;
1341 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1343 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1344 !is_selected(view_details
, i
))
1348 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1355 static DirItem
*iter_peek(ViewIter
*iter
)
1357 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1358 int n
= view_details
->items
->len
;
1364 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1366 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1369 /* Set the iterator to return 'i' on the next peek().
1370 * If i is -1, returns NULL on next peek().
1372 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
)
1374 make_iter(view_details
, iter
, 0);
1376 g_return_if_fail(i
>= -1 && i
< (int) view_details
->items
->len
);
1379 iter
->next
= iter_next
;
1380 iter
->peek
= iter_peek
;
1381 iter
->n_remaining
= 0;
1384 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
1387 iter
->view
= (ViewIface
*) view_details
;
1388 iter
->next
= iter_init
;
1392 iter
->flags
= flags
;
1394 if (flags
& VIEW_ITER_ONE_ONLY
)
1396 iter
->n_remaining
= 1;
1400 iter
->n_remaining
= view_details
->items
->len
;