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 */
74 gchar
*utf8_name
; /* NULL => leafname is valid */
77 typedef struct _ViewDetails ViewDetails
;
82 FilerWindow
*filer_window
; /* Used for styles, etc */
84 GPtrArray
*items
; /* ViewItem */
88 int (*sort_fn
)(const void *, const void *);
90 int cursor_base
; /* Cursor when minibuffer opened */
93 /* Static prototypes */
94 static void view_details_finialize(GObject
*object
);
95 static void view_details_class_init(gpointer gclass
, gpointer data
);
96 static void view_details_init(GTypeInstance
*object
, gpointer gclass
);
98 static void view_details_iface_init(gpointer giface
, gpointer iface_data
);
100 static void view_details_sort(ViewIface
*view
);
101 static void view_details_style_changed(ViewIface
*view
, int flags
);
102 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
);
103 static void view_details_add_items(ViewIface
*view
, GPtrArray
*items
);
104 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
);
105 static void view_details_delete_if(ViewIface
*view
,
106 gboolean (*test
)(gpointer item
, gpointer data
),
108 static void view_details_clear(ViewIface
*view
);
109 static void view_details_select_all(ViewIface
*view
);
110 static void view_details_clear_selection(ViewIface
*view
);
111 static int view_details_count_items(ViewIface
*view
);
112 static int view_details_count_selected(ViewIface
*view
);
113 static void view_details_show_cursor(ViewIface
*view
);
114 static void view_details_get_iter(ViewIface
*view
,
115 ViewIter
*iter
, IterFlags flags
);
116 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
118 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
119 static void view_details_set_selected(ViewIface
*view
,
122 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
);
123 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
);
124 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
);
125 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
);
126 static void view_details_autosize(ViewIface
*view
);
127 static gboolean
view_details_cursor_visible(ViewIface
*view
);
128 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
);
129 static void view_details_start_lasso_box(ViewIface
*view
,
130 GdkEventButton
*event
);
131 static void view_details_extend_tip(ViewIface
*view
,
132 ViewIter
*iter
, GString
*tip
);
134 static DirItem
*iter_peek(ViewIter
*iter
);
135 static DirItem
*iter_prev(ViewIter
*iter
);
136 static DirItem
*iter_next(ViewIter
*iter
);
137 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
139 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
);
140 static void view_details_tree_model_init(GtkTreeModelIface
*iface
);
141 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
142 gint
*sort_column_id
,
144 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
147 static void details_set_sort_func(GtkTreeSortable
*sortable
,
149 GtkTreeIterCompareFunc func
,
151 GtkDestroyNotify destroy
);
152 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
153 GtkTreeIterCompareFunc func
,
155 GtkDestroyNotify destroy
);
156 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
);
157 static void view_details_sortable_init(GtkTreeSortableIface
*iface
);
158 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
);
159 static gboolean
get_selected(ViewDetails
*view_details
, int i
);
160 static void free_view_item(ViewItem
*view_item
);
163 /****************************************************************
164 * EXTERNAL INTERFACE *
165 ****************************************************************/
167 GtkWidget
*view_details_new(FilerWindow
*filer_window
)
169 ViewDetails
*view_details
;
171 view_details
= g_object_new(view_details_get_type(), NULL
);
172 view_details
->filer_window
= filer_window
;
174 gtk_range_set_adjustment(GTK_RANGE(filer_window
->scrollbar
),
175 gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(view_details
)));
177 return GTK_WIDGET(view_details
);
180 GType
view_details_get_type(void)
182 static GType type
= 0;
186 static const GTypeInfo info
=
188 sizeof (ViewDetailsClass
),
189 NULL
, /* base_init */
190 NULL
, /* base_finalise */
191 view_details_class_init
,
192 NULL
, /* class_finalise */
193 NULL
, /* class_data */
198 static const GInterfaceInfo view_iface_info
= {
199 view_details_iface_init
,
202 static const GInterfaceInfo tree_model_info
= {
203 (GInterfaceInitFunc
) view_details_tree_model_init
,
206 static const GInterfaceInfo sortable_info
= {
207 (GInterfaceInitFunc
) view_details_sortable_init
,
212 type
= g_type_register_static(gtk_tree_view_get_type(),
213 "ViewDetails", &info
, 0);
215 g_type_add_interface_static(type
, VIEW_TYPE_IFACE
,
217 g_type_add_interface_static(type
, GTK_TYPE_TREE_MODEL
,
219 g_type_add_interface_static(type
, GTK_TYPE_TREE_SORTABLE
,
226 /****************************************************************
227 * INTERNAL FUNCTIONS *
228 ****************************************************************/
230 /* Fulfill the GtkTreeModel requirements */
231 static guint
details_get_flags(GtkTreeModel
*tree_model
)
233 return GTK_TREE_MODEL_LIST_ONLY
;
236 static gint
details_get_n_columns(GtkTreeModel
*tree_model
)
241 static GType
details_get_column_type(GtkTreeModel
*tree_model
, gint index
)
243 g_return_val_if_fail(index
< N_COLUMNS
&& index
>= 0, G_TYPE_INVALID
);
245 if (index
== COL_COLOUR
|| index
== COL_BG_COLOUR
)
246 return GDK_TYPE_COLOR
;
247 else if (index
== COL_ITEM
)
248 return G_TYPE_POINTER
;
249 else if (index
== COL_ICON
)
250 return GDK_TYPE_PIXBUF
;
251 return G_TYPE_STRING
;
254 static gboolean
details_get_iter(GtkTreeModel
*tree_model
,
258 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
261 g_return_val_if_fail(gtk_tree_path_get_depth (path
) > 0, FALSE
);
263 i
= gtk_tree_path_get_indices(path
)[0];
265 if (i
>= view_details
->items
->len
)
268 iter
->user_data
= GINT_TO_POINTER(i
);
273 static GtkTreePath
*details_get_path(GtkTreeModel
*tree_model
,
278 retval
= gtk_tree_path_new();
279 gtk_tree_path_append_index(retval
, GPOINTER_TO_INT(iter
->user_data
));
284 static void details_get_value(GtkTreeModel
*tree_model
,
289 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
290 GtkStyle
*style
= ((GtkWidget
*) tree_model
)->style
;
292 GPtrArray
*items
= view_details
->items
;
297 g_return_if_fail(column
>= 0 && column
< N_COLUMNS
);
299 i
= GPOINTER_TO_INT(iter
->user_data
);
300 g_return_if_fail(i
>= 0 && i
< items
->len
);
301 view_item
= (ViewItem
*) items
->pdata
[i
];
302 item
= view_item
->item
;
304 if (column
== COL_LEAF
)
306 g_value_init(value
, G_TYPE_STRING
);
307 g_value_set_string(value
,
308 view_item
->utf8_name
? view_item
->utf8_name
312 else if (column
== COL_ITEM
)
314 g_value_init(value
, G_TYPE_POINTER
);
315 g_value_set_pointer(value
, item
);
319 if (item
->base_type
== TYPE_UNKNOWN
)
322 type
= details_get_column_type(tree_model
, column
);
323 g_value_init(value
, type
);
324 if (type
== G_TYPE_STRING
)
325 g_value_set_string(value
, "");
326 else if (type
== GDK_TYPE_COLOR
)
327 g_value_set_boxed(value
, NULL
);
329 g_value_set_object(value
, NULL
);
338 g_value_init(value
, G_TYPE_STRING
);
339 g_value_set_string(value
, item
->leafname
);
342 g_value_init(value
, GDK_TYPE_PIXBUF
);
343 if (!item
->image
->sm_pixbuf
)
344 pixmap_make_small(item
->image
);
345 g_value_set_object(value
, item
->image
->sm_pixbuf
);
348 g_value_init(value
, GDK_TYPE_COLOR
);
349 if (view_item
->utf8_name
)
355 g_value_set_boxed(value
, &red
);
358 g_value_set_boxed(value
,
359 type_get_colour(item
, NULL
));
362 g_value_init(value
, GDK_TYPE_COLOR
);
363 g_value_set_boxed(value
, view_item
->selected
364 ? &style
->base
[GTK_STATE_SELECTED
]
368 g_value_init(value
, G_TYPE_STRING
);
369 g_value_set_string(value
, user_name(item
->uid
));
372 g_value_init(value
, G_TYPE_STRING
);
373 g_value_set_string(value
, group_name(item
->gid
));
378 time
= pretty_time(&item
->mtime
);
379 g_value_init(value
, G_TYPE_STRING
);
380 g_value_set_string(value
, time
);
385 g_value_init(value
, G_TYPE_STRING
);
386 g_value_set_string(value
, pretty_permissions(m
));
389 g_value_init(value
, G_TYPE_STRING
);
390 if (item
->base_type
!= TYPE_DIRECTORY
)
391 g_value_set_string(value
,
392 format_size(item
->size
));
395 g_value_init(value
, G_TYPE_STRING
);
396 g_value_set_string(value
,
397 item
->flags
& ITEM_FLAG_APPDIR
? "App" :
399 S_ISCHR(m
) ? "Char" :
400 S_ISBLK(m
) ? "Blck" :
401 S_ISLNK(m
) ? "Link" :
402 S_ISSOCK(m
) ? "Sock" :
403 S_ISFIFO(m
) ? "Pipe" :
404 S_ISDOOR(m
) ? "Door" :
408 g_value_init(value
, G_TYPE_STRING
);
409 g_value_set_string(value
, "Hello");
414 static gboolean
details_iter_next(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
416 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
419 i
= GPOINTER_TO_INT(iter
->user_data
) + 1;
420 iter
->user_data
= GINT_TO_POINTER(i
);
422 return i
< view_details
->items
->len
;
425 static gboolean
details_iter_children(GtkTreeModel
*tree_model
,
429 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
431 /* this is a list, nodes have no children */
435 /* but if parent == NULL we return the list itself as children of the
439 if (view_details
->items
->len
)
441 iter
->user_data
= GINT_TO_POINTER(0);
448 static gboolean
details_iter_has_child(GtkTreeModel
*tree_model
,
454 static gint
details_iter_n_children(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
456 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
459 return view_details
->items
->len
;
464 static gboolean
details_iter_nth_child(GtkTreeModel
*tree_model
,
469 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
474 if (n
>= 0 && n
< view_details
->items
->len
)
476 iter
->user_data
= GINT_TO_POINTER(n
);
483 static gboolean
details_iter_parent(GtkTreeModel
*tree_model
,
490 /* A ViewDetails is both a GtkTreeView and a GtkTreeModel.
491 * The following functions implement the model interface...
494 static void view_details_tree_model_init(GtkTreeModelIface
*iface
)
496 iface
->get_flags
= details_get_flags
;
497 iface
->get_n_columns
= details_get_n_columns
;
498 iface
->get_column_type
= details_get_column_type
;
499 iface
->get_iter
= details_get_iter
;
500 iface
->get_path
= details_get_path
;
501 iface
->get_value
= details_get_value
;
502 iface
->iter_next
= details_iter_next
;
503 iface
->iter_children
= details_iter_children
;
504 iface
->iter_has_child
= details_iter_has_child
;
505 iface
->iter_n_children
= details_iter_n_children
;
506 iface
->iter_nth_child
= details_iter_nth_child
;
507 iface
->iter_parent
= details_iter_parent
;
510 static void view_details_sortable_init(GtkTreeSortableIface
*iface
)
512 iface
->get_sort_column_id
= details_get_sort_column_id
;
513 iface
->set_sort_column_id
= details_set_sort_column_id
;
514 iface
->set_sort_func
= details_set_sort_func
;
515 iface
->set_default_sort_func
= details_set_default_sort_func
;
516 iface
->has_default_sort_func
= details_has_default_sort_func
;
519 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
520 gint
*sort_column_id
,
523 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
525 if (view_details
->sort_column_id
== -1)
529 *sort_column_id
= view_details
->sort_column_id
;
531 *order
= view_details
->order
;
535 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
539 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
541 if (view_details
->sort_column_id
== sort_column_id
&&
542 view_details
->order
== order
)
545 view_details
->sort_column_id
= sort_column_id
;
546 view_details
->order
= order
;
548 switch (sort_column_id
)
551 view_details
->sort_fn
= sort_by_name
;
554 view_details
->sort_fn
= sort_by_size
;
557 view_details
->sort_fn
= sort_by_date
;
560 view_details
->sort_fn
= sort_by_type
;
563 view_details
->sort_fn
= sort_by_owner
;
566 view_details
->sort_fn
= sort_by_group
;
569 g_assert_not_reached();
572 view_details_sort((ViewIface
*) view_details
);
574 gtk_tree_sortable_sort_column_changed(sortable
);
577 static void details_set_sort_func(GtkTreeSortable
*sortable
,
579 GtkTreeIterCompareFunc func
,
581 GtkDestroyNotify destroy
)
583 g_assert_not_reached();
586 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
587 GtkTreeIterCompareFunc func
,
589 GtkDestroyNotify destroy
)
591 g_assert_not_reached();
594 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
)
600 /* End of model implementation */
602 static gboolean
is_selected(ViewDetails
*view_details
, int i
)
606 return view_details_get_selected((ViewIface
*) view_details
, &iter
);
609 static gboolean
view_details_button_press(GtkWidget
*widget
,
612 FilerWindow
*filer_window
= ((ViewDetails
*) widget
)->filer_window
;
614 if (dnd_motion_press(widget
, bev
))
615 filer_perform_action(filer_window
, bev
);
620 static gboolean
view_details_button_release(GtkWidget
*widget
,
623 FilerWindow
*filer_window
= ((ViewDetails
*) widget
)->filer_window
;
625 if (!dnd_motion_release(bev
))
626 filer_perform_action(filer_window
, bev
);
631 static gint
view_details_key_press_event(GtkWidget
*widget
, GdkEventKey
*event
)
633 ViewDetails
*view_details
= (ViewDetails
*) widget
;
634 FilerWindow
*filer_window
= view_details
->filer_window
;
636 switch (event
->keyval
)
639 filer_window_toggle_cursor_item_selected(filer_window
);
642 change_to_parent(filer_window
);
646 return GTK_WIDGET_CLASS(parent_class
)->key_press_event(widget
, event
);
649 static gint
view_details_motion_notify(GtkWidget
*widget
, GdkEventMotion
*event
)
651 ViewDetails
*view_details
= (ViewDetails
*) widget
;
653 return filer_motion_notify(view_details
->filer_window
, event
);
656 static gboolean
view_details_expose(GtkWidget
*widget
, GdkEventExpose
*event
)
658 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
659 GtkTreePath
*path
= NULL
;
660 GdkRectangle focus_rectangle
;
663 had_cursor
= (GTK_WIDGET_FLAGS(widget
) & GTK_HAS_FOCUS
) != 0;
666 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_HAS_FOCUS
);
667 GTK_WIDGET_CLASS(parent_class
)->expose_event(widget
, event
);
669 GTK_WIDGET_SET_FLAGS(widget
, GTK_HAS_FOCUS
);
671 if (event
->window
!= gtk_tree_view_get_bin_window(tree
))
672 return FALSE
; /* Not the main area */
674 gtk_tree_view_get_cursor(tree
, &path
, NULL
);
676 return FALSE
; /* No cursor */
677 gtk_tree_view_get_background_area(tree
, path
, NULL
, &focus_rectangle
);
678 gtk_tree_path_free(path
);
680 if (!focus_rectangle
.height
)
681 return FALSE
; /* Off screen */
683 focus_rectangle
.width
= widget
->allocation
.width
;
685 gtk_paint_focus(widget
->style
,
693 focus_rectangle
.width
,
694 focus_rectangle
.height
);
699 static void view_details_destroy(GtkObject
*view_details
)
701 VIEW_DETAILS(view_details
)->filer_window
= NULL
;
704 static void view_details_finialize(GObject
*object
)
706 ViewDetails
*view_details
= (ViewDetails
*) object
;
708 g_ptr_array_free(view_details
->items
, TRUE
);
709 view_details
->items
= NULL
;
711 G_OBJECT_CLASS(parent_class
)->finalize(object
);
714 static void view_details_class_init(gpointer gclass
, gpointer data
)
716 GObjectClass
*object
= (GObjectClass
*) gclass
;
717 GtkWidgetClass
*widget
= (GtkWidgetClass
*) gclass
;
719 parent_class
= g_type_class_peek_parent(gclass
);
721 object
->finalize
= view_details_finialize
;
722 GTK_OBJECT_CLASS(object
)->destroy
= view_details_destroy
;
724 widget
->button_press_event
= view_details_button_press
;
725 widget
->button_release_event
= view_details_button_release
;
726 widget
->key_press_event
= view_details_key_press_event
;
727 widget
->motion_notify_event
= view_details_motion_notify
;
728 widget
->expose_event
= view_details_expose
;
731 static gboolean
block_focus(GtkWidget
*button
, GtkDirectionType dir
,
732 ViewDetails
*view_details
)
734 GTK_WIDGET_UNSET_FLAGS(button
, GTK_CAN_FOCUS
);
738 #define ADD_TEXT_COLUMN(name, model_column) \
739 cell = gtk_cell_renderer_text_new(); \
740 column = gtk_tree_view_column_new_with_attributes(name, cell, \
741 "text", model_column, \
742 "foreground-gdk", COL_COLOUR, \
743 "background-gdk", COL_BG_COLOUR, \
745 gtk_tree_view_append_column(treeview, column); \
746 g_signal_connect(column->button, "grab-focus", \
747 G_CALLBACK(block_focus), view_details);
749 static void view_details_init(GTypeInstance
*object
, gpointer gclass
)
751 GtkTreeView
*treeview
= (GtkTreeView
*) object
;
752 GtkTreeViewColumn
*column
;
753 GtkCellRenderer
*cell
;
754 GtkTreeSortable
*sortable_list
;
755 GtkTreeSelection
*selection
;
756 ViewDetails
*view_details
= (ViewDetails
*) object
;
758 view_details
->items
= g_ptr_array_new();
759 view_details
->cursor_base
= -1;
761 selection
= gtk_tree_view_get_selection(treeview
);
762 gtk_tree_selection_set_mode(selection
, GTK_SELECTION_NONE
);
765 view_details
->sort_column_id
= -1;
766 view_details
->sort_fn
= NULL
;
767 sortable_list
= GTK_TREE_SORTABLE(object
);
768 gtk_tree_sortable_set_sort_column_id(sortable_list
, COL_LEAF
,
771 gtk_tree_view_set_model(treeview
, GTK_TREE_MODEL(view_details
));
774 cell
= cell_icon_new();
775 column
= gtk_tree_view_column_new_with_attributes(NULL
, cell
,
777 "background-gdk", COL_BG_COLOUR
,
779 gtk_tree_view_append_column(treeview
, column
);
781 ADD_TEXT_COLUMN(_("_Name"), COL_LEAF
);
782 gtk_tree_view_column_set_sort_column_id(column
, COL_LEAF
);
783 ADD_TEXT_COLUMN(_("_Type"), COL_TYPE
);
784 gtk_tree_view_column_set_sort_column_id(column
, COL_TYPE
);
785 ADD_TEXT_COLUMN(_("_Permissions"), COL_PERM
);
786 ADD_TEXT_COLUMN(_("_Owner"), COL_OWNER
);
787 gtk_tree_view_column_set_sort_column_id(column
, COL_OWNER
);
788 ADD_TEXT_COLUMN(_("_Group"), COL_GROUP
);
789 gtk_tree_view_column_set_sort_column_id(column
, COL_GROUP
);
790 ADD_TEXT_COLUMN(_("_Size"), COL_SIZE
);
791 gtk_tree_view_column_set_sort_column_id(column
, COL_SIZE
);
792 ADD_TEXT_COLUMN(_("Last _Modified"), COL_MTIME
);
793 gtk_tree_view_column_set_sort_column_id(column
, COL_MTIME
);
795 gtk_widget_set_size_request(GTK_WIDGET(treeview
), -1, 50);
798 /* Create the handers for the View interface */
799 static void view_details_iface_init(gpointer giface
, gpointer iface_data
)
801 ViewIfaceClass
*iface
= giface
;
803 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
806 iface
->sort
= view_details_sort
;
807 iface
->style_changed
= view_details_style_changed
;
808 iface
->autoselect
= view_details_autoselect
;
809 iface
->add_items
= view_details_add_items
;
810 iface
->update_items
= view_details_update_items
;
811 iface
->delete_if
= view_details_delete_if
;
812 iface
->clear
= view_details_clear
;
813 iface
->select_all
= view_details_select_all
;
814 iface
->clear_selection
= view_details_clear_selection
;
815 iface
->count_items
= view_details_count_items
;
816 iface
->count_selected
= view_details_count_selected
;
817 iface
->show_cursor
= view_details_show_cursor
;
818 iface
->get_iter
= view_details_get_iter
;
819 iface
->get_iter_at_point
= view_details_get_iter_at_point
;
820 iface
->cursor_to_iter
= view_details_cursor_to_iter
;
821 iface
->set_selected
= view_details_set_selected
;
822 iface
->get_selected
= view_details_get_selected
;
823 iface
->set_frozen
= view_details_set_frozen
;
824 iface
->select_only
= view_details_select_only
;
825 iface
->wink_item
= view_details_wink_item
;
826 iface
->autosize
= view_details_autosize
;
827 iface
->cursor_visible
= view_details_cursor_visible
;
828 iface
->set_base
= view_details_set_base
;
829 iface
->start_lasso_box
= view_details_start_lasso_box
;
830 iface
->extend_tip
= view_details_extend_tip
;
833 /* Implementations of the View interface. See view_iface.c for comments. */
835 static void view_details_style_changed(ViewIface
*view
, int flags
)
839 static gint
wrap_sort(gconstpointer a
, gconstpointer b
,
840 ViewDetails
*view_details
)
842 ViewItem
*ia
= *(ViewItem
**) a
;
843 ViewItem
*ib
= *(ViewItem
**) b
;
845 if (view_details
->order
== GTK_SORT_ASCENDING
)
846 return view_details
->sort_fn(ia
->item
, ib
->item
);
848 return -view_details
->sort_fn(ia
->item
, ib
->item
);
851 static void view_details_sort(ViewIface
*view
)
853 ViewDetails
*view_details
= (ViewDetails
*) view
;
854 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
856 gint i
, len
= view_details
->items
->len
;
859 g_return_if_fail(view_details
->sort_fn
!= NULL
);
864 for (i
= len
- 1; i
>= 0; i
--)
865 items
[i
]->old_pos
= i
;
867 g_ptr_array_sort_with_data(view_details
->items
,
868 (GCompareDataFunc
) wrap_sort
,
871 new_order
= g_array_sized_new(FALSE
, FALSE
, sizeof(gint
), len
);
872 g_array_set_size(new_order
, len
);
874 for (i
= len
- 1; i
>= 0; i
--)
875 g_array_insert_val(new_order
, items
[i
]->old_pos
, i
);
877 path
= gtk_tree_path_new();
878 gtk_tree_model_rows_reordered((GtkTreeModel
*) view
,
880 (gint
*) new_order
->data
);
881 gtk_tree_path_free(path
);
882 g_array_free(new_order
, TRUE
);
885 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
)
890 static void view_details_add_items(ViewIface
*view
, GPtrArray
*new_items
)
892 ViewDetails
*view_details
= (ViewDetails
*) view
;
893 FilerWindow
*filer_window
= view_details
->filer_window
;
894 gboolean show_hidden
= filer_window
->show_hidden
;
895 GPtrArray
*items
= view_details
->items
;
899 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
901 iter
.user_data
= GINT_TO_POINTER(items
->len
);
902 path
= details_get_path(model
, &iter
);
904 for (i
= 0; i
< new_items
->len
; i
++)
906 DirItem
*item
= (DirItem
*) new_items
->pdata
[i
];
907 char *leafname
= item
->leafname
;
910 if (leafname
[0] == '.')
915 if (leafname
[1] == '\0')
916 continue; /* Never show '.' */
918 if (leafname
[1] == '.' &&
920 continue; /* Never show '..' */
923 vitem
= g_new(ViewItem
, 1);
926 vitem
->selected
= FALSE
;
927 if (!g_utf8_validate(leafname
, -1, NULL
))
928 vitem
->utf8_name
= to_utf8(leafname
);
930 vitem
->utf8_name
= NULL
;
932 g_ptr_array_add(items
, vitem
);
934 iter
.user_data
= GINT_TO_POINTER(items
->len
- 1);
935 gtk_tree_model_row_inserted(model
, path
, &iter
);
936 gtk_tree_path_next(path
);
939 gtk_tree_path_free(path
);
941 view_details_sort(view
);
944 /* Find an item in the sorted array.
945 * Returns the item number, or -1 if not found.
947 static int details_find_item(ViewDetails
*view_details
, DirItem
*item
)
949 ViewItem
**items
, tmp
, *tmpp
;
951 int (*compar
)(const void *, const void *);
953 g_return_val_if_fail(view_details
!= NULL
, -1);
954 g_return_val_if_fail(item
!= NULL
, -1);
959 items
= (ViewItem
**) view_details
->items
->pdata
;
960 compar
= view_details
->sort_fn
;
962 g_return_val_if_fail(compar
!= NULL
, -1);
964 /* If item is here, then: lower <= i < upper */
966 upper
= view_details
->items
->len
;
968 while (lower
< upper
)
972 i
= (lower
+ upper
) >> 1;
974 cmp
= wrap_sort(&items
[i
], &tmpp
, view_details
);
987 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
)
989 ViewDetails
*view_details
= (ViewDetails
*) view
;
990 FilerWindow
*filer_window
= view_details
->filer_window
;
992 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
994 g_return_if_fail(items
->len
> 0);
996 /* The item data has already been modified, so this gives the
997 * final sort order...
999 view_details_sort(view
);
1001 for (i
= 0; i
< items
->len
; i
++)
1003 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1004 const gchar
*leafname
= item
->leafname
;
1007 if (leafname
[0] == '.' && filer_window
->show_hidden
== FALSE
)
1010 j
= details_find_item(view_details
, item
);
1013 g_warning("Failed to find '%s'\n", leafname
);
1018 path
= gtk_tree_path_new();
1019 gtk_tree_path_append_index(path
, j
);
1020 iter
.user_data
= GINT_TO_POINTER(j
);
1021 gtk_tree_model_row_changed(model
, path
, &iter
);
1026 static void view_details_delete_if(ViewIface
*view
,
1027 gboolean (*test
)(gpointer item
, gpointer data
),
1031 ViewDetails
*view_details
= (ViewDetails
*) view
;
1033 GPtrArray
*items
= view_details
->items
;
1034 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1036 path
= gtk_tree_path_new();
1038 gtk_tree_path_append_index(path
, i
);
1040 while (i
< items
->len
)
1042 ViewItem
*item
= items
->pdata
[i
];
1044 if (test(item
->item
, data
))
1046 free_view_item(items
->pdata
[i
]);
1047 g_ptr_array_remove_index(items
, i
);
1048 gtk_tree_model_row_deleted(model
, path
);
1053 gtk_tree_path_next(path
);
1057 gtk_tree_path_free(path
);
1060 static void view_details_clear(ViewIface
*view
)
1063 GPtrArray
*items
= ((ViewDetails
*) view
)->items
;
1064 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1066 path
= gtk_tree_path_new();
1067 gtk_tree_path_append_index(path
, items
->len
);
1069 while (gtk_tree_path_prev(path
))
1070 gtk_tree_model_row_deleted(model
, path
);
1072 g_ptr_array_set_size(items
, 0);
1073 gtk_tree_path_free(path
);
1076 static void view_details_select_all(ViewIface
*view
)
1079 int n
= ((ViewDetails
*) view
)->items
->len
;
1081 for (i
= 0; i
< n
; i
++)
1085 view_details_set_selected(view
, &iter
, TRUE
);
1089 static void view_details_clear_selection(ViewIface
*view
)
1092 int n
= ((ViewDetails
*) view
)->items
->len
;
1094 for (i
= 0; i
< n
; i
++)
1098 view_details_set_selected(view
, &iter
, FALSE
);
1102 static int view_details_count_items(ViewIface
*view
)
1104 ViewDetails
*view_details
= (ViewDetails
*) view
;
1106 return view_details
->items
->len
;
1109 static int view_details_count_selected(ViewIface
*view
)
1111 ViewDetails
*view_details
= (ViewDetails
*) view
;
1112 int n
= view_details
->items
->len
;
1113 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
1117 for (i
= 0; i
< n
; i
++)
1118 if (items
[i
]->selected
)
1124 static void view_details_show_cursor(ViewIface
*view
)
1128 static void view_details_get_iter(ViewIface
*view
,
1129 ViewIter
*iter
, IterFlags flags
)
1131 make_iter((ViewDetails
*) view
, iter
, flags
);
1134 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
1137 ViewDetails
*view_details
= (ViewDetails
*) view
;
1138 GtkTreeModel
*model
;
1139 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1140 GtkTreePath
*path
= NULL
;
1143 model
= gtk_tree_view_get_model(tree
);
1145 if (gtk_tree_view_get_path_at_pos(tree
, x
, y
, &path
, NULL
, NULL
, NULL
))
1147 g_return_if_fail(path
!= NULL
);
1149 i
= gtk_tree_path_get_indices(path
)[0];
1150 gtk_tree_path_free(path
);
1153 make_item_iter(view_details
, iter
, i
);
1156 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
)
1159 ViewDetails
*view_details
= (ViewDetails
*) view
;
1161 path
= gtk_tree_path_new();
1164 gtk_tree_path_append_index(path
, iter
->i
);
1167 /* Using depth zero or index -1 gives an error, but this
1170 gtk_tree_path_append_index(path
, view_details
->items
->len
);
1173 gtk_tree_view_set_cursor((GtkTreeView
*) view
, path
, NULL
, FALSE
);
1174 gtk_tree_path_free(path
);
1177 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
)
1179 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
1182 GPtrArray
*items
= view_details
->items
;
1183 ViewItem
*view_item
;
1185 g_return_if_fail(i
>= 0 && i
< items
->len
);
1186 view_item
= (ViewItem
*) items
->pdata
[i
];
1188 if (view_item
->selected
== selected
)
1191 view_item
->selected
= selected
;
1193 path
= gtk_tree_path_new();
1194 gtk_tree_path_append_index(path
, i
);
1195 t_iter
.user_data
= GINT_TO_POINTER(i
);
1196 gtk_tree_model_row_changed(model
, path
, &t_iter
);
1197 gtk_tree_path_free(path
);
1200 static void view_details_set_selected(ViewIface
*view
,
1204 set_selected((ViewDetails
*) view
, iter
->i
, selected
);
1207 static gboolean
get_selected(ViewDetails
*view_details
, int i
)
1209 GPtrArray
*items
= view_details
->items
;
1211 g_return_val_if_fail(i
>= 0 && i
< items
->len
, FALSE
);
1213 return ((ViewItem
*) items
->pdata
[i
])->selected
;
1216 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
)
1218 return get_selected((ViewDetails
*) view
, iter
->i
);
1221 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
)
1223 ViewDetails
*view_details
= (ViewDetails
*) view
;
1225 int n
= view_details
->items
->len
;
1227 set_selected(view_details
, i
, TRUE
);
1234 set_selected(view_details
, n
, FALSE
);
1238 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
)
1242 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
)
1246 static void view_details_autosize(ViewIface
*view
)
1248 ViewDetails
*view_details
= (ViewDetails
*) view
;
1249 FilerWindow
*filer_window
= view_details
->filer_window
;
1251 int max_height
= (o_filer_size_limit
.int_value
* screen_height
) / 100;
1253 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1254 GtkTreeViewColumn
*column
;
1257 gtk_widget_size_request(GTK_WIDGET(view
), &req
);
1258 column
= gtk_tree_view_get_column(tree
, 1);
1259 gtk_tree_view_column_cell_get_size(column
, NULL
, NULL
, NULL
, NULL
, &h
);
1261 bin
= gtk_tree_view_get_bin_window(GTK_TREE_VIEW(view
));
1263 gdk_window_get_position(bin
, NULL
, &y
);
1265 h
= MAX(h
, SMALL_HEIGHT
);
1267 h
= (view_details
->items
->len
+ 2) * h
+ y
;
1269 h
= MIN(h
, max_height
);
1271 filer_window_set_size(filer_window
, 5, h
);
1274 static gboolean
view_details_cursor_visible(ViewIface
*view
)
1279 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
)
1281 ViewDetails
*view_details
= (ViewDetails
*) view
;
1283 view_details
->cursor_base
= iter
->i
;
1286 static void view_details_start_lasso_box(ViewIface
*view
, GdkEventButton
*event
)
1290 static void view_details_extend_tip(ViewIface
*view
,
1291 ViewIter
*iter
, GString
*tip
)
1295 static DirItem
*iter_init(ViewIter
*iter
)
1297 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1299 int n
= view_details
->items
->len
;
1300 int flags
= iter
->flags
;
1302 iter
->peek
= iter_peek
;
1304 if (iter
->n_remaining
== 0)
1307 if (flags
& VIEW_ITER_FROM_CURSOR
)
1310 gtk_tree_view_get_cursor((GtkTreeView
*) view_details
,
1313 return NULL
; /* No cursor */
1314 i
= gtk_tree_path_get_indices(path
)[0];
1315 gtk_tree_path_free(path
);
1317 else if (flags
& VIEW_ITER_FROM_BASE
)
1318 i
= view_details
->cursor_base
;
1320 if (i
< 0 || i
>= n
)
1322 /* Either a normal iteration, or an iteration from an
1323 * invalid starting point.
1325 if (flags
& VIEW_ITER_BACKWARDS
)
1331 if (i
< 0 || i
>= n
)
1332 return NULL
; /* No items at all! */
1334 iter
->next
= flags
& VIEW_ITER_BACKWARDS
? iter_prev
: iter_next
;
1335 iter
->n_remaining
--;
1338 if (flags
& VIEW_ITER_SELECTED
&& !is_selected(view_details
, i
))
1339 return iter
->next(iter
);
1340 return iter
->peek(iter
);
1343 static DirItem
*iter_prev(ViewIter
*iter
)
1345 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1346 int n
= view_details
->items
->len
;
1349 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1351 /* i is the last item returned (always valid) */
1353 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1355 while (iter
->n_remaining
)
1358 iter
->n_remaining
--;
1363 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1365 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1366 !is_selected(view_details
, i
))
1370 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1377 static DirItem
*iter_next(ViewIter
*iter
)
1379 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1380 int n
= view_details
->items
->len
;
1383 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1385 /* i is the last item returned (always valid) */
1387 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1389 while (iter
->n_remaining
)
1392 iter
->n_remaining
--;
1397 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1399 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1400 !is_selected(view_details
, i
))
1404 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1411 static DirItem
*iter_peek(ViewIter
*iter
)
1413 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1414 int n
= view_details
->items
->len
;
1420 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1422 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1425 /* Set the iterator to return 'i' on the next peek().
1426 * If i is -1, returns NULL on next peek().
1428 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
)
1430 make_iter(view_details
, iter
, 0);
1432 g_return_if_fail(i
>= -1 && i
< (int) view_details
->items
->len
);
1435 iter
->next
= iter_next
;
1436 iter
->peek
= iter_peek
;
1437 iter
->n_remaining
= 0;
1440 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
1443 iter
->view
= (ViewIface
*) view_details
;
1444 iter
->next
= iter_init
;
1448 iter
->flags
= flags
;
1450 if (flags
& VIEW_ITER_ONE_ONLY
)
1452 iter
->n_remaining
= 1;
1456 iter
->n_remaining
= view_details
->items
->len
;
1459 static void free_view_item(ViewItem
*view_item
)
1461 g_free(view_item
->utf8_name
);