4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2003, 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 */
57 #define COL_BG_COLOUR 9
59 #define COL_VIEW_ITEM 11
62 static gpointer parent_class
= NULL
;
64 struct _ViewDetailsClass
{
65 GtkTreeViewClass parent
;
68 /* Static prototypes */
69 static void view_details_finialize(GObject
*object
);
70 static void view_details_class_init(gpointer gclass
, gpointer data
);
71 static void view_details_init(GTypeInstance
*object
, gpointer gclass
);
73 static void view_details_iface_init(gpointer giface
, gpointer iface_data
);
75 static void view_details_sort(ViewIface
*view
);
76 static void view_details_style_changed(ViewIface
*view
, int flags
);
77 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
);
78 static void view_details_add_items(ViewIface
*view
, GPtrArray
*items
);
79 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
);
80 static void view_details_delete_if(ViewIface
*view
,
81 gboolean (*test
)(gpointer item
, gpointer data
),
83 static void view_details_clear(ViewIface
*view
);
84 static void view_details_select_all(ViewIface
*view
);
85 static void view_details_clear_selection(ViewIface
*view
);
86 static int view_details_count_items(ViewIface
*view
);
87 static int view_details_count_selected(ViewIface
*view
);
88 static void view_details_show_cursor(ViewIface
*view
);
89 static void view_details_get_iter(ViewIface
*view
,
90 ViewIter
*iter
, IterFlags flags
);
91 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
92 GdkWindow
*src
, int x
, int y
);
93 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
94 static void view_details_set_selected(ViewIface
*view
,
97 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
);
98 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
);
99 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
);
100 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
);
101 static void view_details_autosize(ViewIface
*view
);
102 static gboolean
view_details_cursor_visible(ViewIface
*view
);
103 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
);
104 static void view_details_start_lasso_box(ViewIface
*view
,
105 GdkEventButton
*event
);
106 static void view_details_extend_tip(ViewIface
*view
,
107 ViewIter
*iter
, GString
*tip
);
108 static gboolean
view_details_auto_scroll_callback(ViewIface
*view
);
110 static DirItem
*iter_peek(ViewIter
*iter
);
111 static DirItem
*iter_prev(ViewIter
*iter
);
112 static DirItem
*iter_next(ViewIter
*iter
);
113 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
115 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
);
116 static void view_details_tree_model_init(GtkTreeModelIface
*iface
);
117 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
118 gint
*sort_column_id
,
120 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
123 static void details_set_sort_func(GtkTreeSortable
*sortable
,
125 GtkTreeIterCompareFunc func
,
127 GtkDestroyNotify destroy
);
128 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
129 GtkTreeIterCompareFunc func
,
131 GtkDestroyNotify destroy
);
132 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
);
133 static void view_details_sortable_init(GtkTreeSortableIface
*iface
);
134 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
);
135 static gboolean
get_selected(ViewDetails
*view_details
, int i
);
136 static void free_view_item(ViewItem
*view_item
);
137 static void details_update_header_visibility(ViewDetails
*view_details
);
140 /****************************************************************
141 * EXTERNAL INTERFACE *
142 ****************************************************************/
144 GtkWidget
*view_details_new(FilerWindow
*filer_window
)
146 ViewDetails
*view_details
;
148 view_details
= g_object_new(view_details_get_type(), NULL
);
149 view_details
->filer_window
= filer_window
;
151 gtk_range_set_adjustment(GTK_RANGE(filer_window
->scrollbar
),
152 gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(view_details
)));
154 if (filer_window
->sort_type
!= -1)
155 view_details_sort((ViewIface
*) view_details
);
157 details_update_header_visibility(view_details
);
159 return GTK_WIDGET(view_details
);
162 GType
view_details_get_type(void)
164 static GType type
= 0;
168 static const GTypeInfo info
=
170 sizeof (ViewDetailsClass
),
171 NULL
, /* base_init */
172 NULL
, /* base_finalise */
173 view_details_class_init
,
174 NULL
, /* class_finalise */
175 NULL
, /* class_data */
180 static const GInterfaceInfo view_iface_info
= {
181 view_details_iface_init
,
184 static const GInterfaceInfo tree_model_info
= {
185 (GInterfaceInitFunc
) view_details_tree_model_init
,
188 static const GInterfaceInfo sortable_info
= {
189 (GInterfaceInitFunc
) view_details_sortable_init
,
194 type
= g_type_register_static(gtk_tree_view_get_type(),
195 "ViewDetails", &info
, 0);
197 g_type_add_interface_static(type
, VIEW_TYPE_IFACE
,
199 g_type_add_interface_static(type
, GTK_TYPE_TREE_MODEL
,
201 g_type_add_interface_static(type
, GTK_TYPE_TREE_SORTABLE
,
208 /****************************************************************
209 * INTERNAL FUNCTIONS *
210 ****************************************************************/
212 /* Update the visibility of the list headers */
213 static void details_update_header_visibility(ViewDetails
*view_details
)
215 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view_details
),
216 o_display_show_headers
.int_value
);
219 /* Fulfill the GtkTreeModel requirements */
220 static guint
details_get_flags(GtkTreeModel
*tree_model
)
222 return GTK_TREE_MODEL_LIST_ONLY
;
225 static gint
details_get_n_columns(GtkTreeModel
*tree_model
)
230 static GType
details_get_column_type(GtkTreeModel
*tree_model
, gint index
)
232 g_return_val_if_fail(index
< N_COLUMNS
&& index
>= 0, G_TYPE_INVALID
);
234 if (index
== COL_COLOUR
|| index
== COL_BG_COLOUR
)
235 return GDK_TYPE_COLOR
;
236 else if (index
== COL_ITEM
|| index
== COL_VIEW_ITEM
)
237 return G_TYPE_POINTER
;
238 else if (index
== COL_WEIGHT
)
240 return G_TYPE_STRING
;
243 static gboolean
details_get_iter(GtkTreeModel
*tree_model
,
247 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
250 g_return_val_if_fail(gtk_tree_path_get_depth (path
) > 0, FALSE
);
252 i
= gtk_tree_path_get_indices(path
)[0];
254 if (i
>= view_details
->items
->len
)
257 iter
->user_data
= GINT_TO_POINTER(i
);
262 static GtkTreePath
*details_get_path(GtkTreeModel
*tree_model
,
267 retval
= gtk_tree_path_new();
268 gtk_tree_path_append_index(retval
, GPOINTER_TO_INT(iter
->user_data
));
273 static void details_get_value(GtkTreeModel
*tree_model
,
278 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
279 GtkStyle
*style
= ((GtkWidget
*) tree_model
)->style
;
281 GPtrArray
*items
= view_details
->items
;
286 g_return_if_fail(column
>= 0 && column
< N_COLUMNS
);
288 i
= GPOINTER_TO_INT(iter
->user_data
);
289 g_return_if_fail(i
>= 0 && i
< items
->len
);
290 view_item
= (ViewItem
*) items
->pdata
[i
];
291 item
= view_item
->item
;
293 if (column
== COL_LEAF
)
295 g_value_init(value
, G_TYPE_STRING
);
296 g_value_set_string(value
,
297 view_item
->utf8_name
? view_item
->utf8_name
301 else if (column
== COL_VIEW_ITEM
)
303 g_value_init(value
, G_TYPE_POINTER
);
304 g_value_set_pointer(value
, view_item
);
307 else if (column
== COL_ITEM
)
309 g_value_init(value
, G_TYPE_POINTER
);
310 g_value_set_pointer(value
, item
);
314 if (item
->base_type
== TYPE_UNKNOWN
)
317 type
= details_get_column_type(tree_model
, column
);
318 g_value_init(value
, type
);
319 if (type
== G_TYPE_STRING
)
320 g_value_set_string(value
, "");
321 else if (type
== GDK_TYPE_COLOR
)
322 g_value_set_boxed(value
, NULL
);
323 else if (type
== G_TYPE_INT
)
324 g_value_set_int(value
, PANGO_WEIGHT_NORMAL
);
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_COLOR
);
340 if (view_item
->utf8_name
)
346 g_value_set_boxed(value
, &red
);
349 g_value_set_boxed(value
,
350 type_get_colour(item
, NULL
));
353 g_value_init(value
, GDK_TYPE_COLOR
);
354 if (view_item
->selected
)
356 GtkStateType state
= view_details
->
357 filer_window
->selection_state
;
358 g_value_set_boxed(value
, &style
->base
[state
]);
361 g_value_set_boxed(value
, NULL
);
364 g_value_init(value
, G_TYPE_STRING
);
365 g_value_set_string(value
, user_name(item
->uid
));
368 g_value_init(value
, G_TYPE_STRING
);
369 g_value_set_string(value
, group_name(item
->gid
));
374 time
= pretty_time(&item
->mtime
);
375 g_value_init(value
, G_TYPE_STRING
);
376 g_value_set_string(value
, time
);
381 g_value_init(value
, G_TYPE_STRING
);
382 g_value_set_string(value
, pretty_permissions(m
));
385 g_value_init(value
, G_TYPE_STRING
);
386 if (item
->base_type
!= TYPE_DIRECTORY
)
387 g_value_set_string(value
,
388 format_size(item
->size
));
391 g_value_init(value
, G_TYPE_STRING
);
392 g_value_set_string(value
,
393 item
->flags
& ITEM_FLAG_APPDIR
? "App" :
395 S_ISCHR(m
) ? "Char" :
396 S_ISBLK(m
) ? "Blck" :
397 S_ISLNK(m
) ? "Link" :
398 S_ISSOCK(m
) ? "Sock" :
399 S_ISFIFO(m
) ? "Pipe" :
400 S_ISDOOR(m
) ? "Door" :
404 g_value_init(value
, G_TYPE_INT
);
405 if (item
->flags
& ITEM_FLAG_RECENT
)
406 g_value_set_int(value
, PANGO_WEIGHT_BOLD
);
408 g_value_set_int(value
, PANGO_WEIGHT_NORMAL
);
411 g_value_init(value
, G_TYPE_STRING
);
412 g_value_set_string(value
, "Hello");
417 static gboolean
details_iter_next(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
419 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
422 i
= GPOINTER_TO_INT(iter
->user_data
) + 1;
423 iter
->user_data
= GINT_TO_POINTER(i
);
425 return i
< view_details
->items
->len
;
428 static gboolean
details_iter_children(GtkTreeModel
*tree_model
,
432 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
434 /* this is a list, nodes have no children */
438 /* but if parent == NULL we return the list itself as children of the
442 if (view_details
->items
->len
)
444 iter
->user_data
= GINT_TO_POINTER(0);
451 static gboolean
details_iter_has_child(GtkTreeModel
*tree_model
,
457 static gint
details_iter_n_children(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
459 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
462 return view_details
->items
->len
;
467 static gboolean
details_iter_nth_child(GtkTreeModel
*tree_model
,
472 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
477 if (n
>= 0 && n
< view_details
->items
->len
)
479 iter
->user_data
= GINT_TO_POINTER(n
);
486 static gboolean
details_iter_parent(GtkTreeModel
*tree_model
,
493 /* A ViewDetails is both a GtkTreeView and a GtkTreeModel.
494 * The following functions implement the model interface...
497 static void view_details_tree_model_init(GtkTreeModelIface
*iface
)
499 iface
->get_flags
= details_get_flags
;
500 iface
->get_n_columns
= details_get_n_columns
;
501 iface
->get_column_type
= details_get_column_type
;
502 iface
->get_iter
= details_get_iter
;
503 iface
->get_path
= details_get_path
;
504 iface
->get_value
= details_get_value
;
505 iface
->iter_next
= details_iter_next
;
506 iface
->iter_children
= details_iter_children
;
507 iface
->iter_has_child
= details_iter_has_child
;
508 iface
->iter_n_children
= details_iter_n_children
;
509 iface
->iter_nth_child
= details_iter_nth_child
;
510 iface
->iter_parent
= details_iter_parent
;
513 static void view_details_sortable_init(GtkTreeSortableIface
*iface
)
515 iface
->get_sort_column_id
= details_get_sort_column_id
;
516 iface
->set_sort_column_id
= details_set_sort_column_id
;
517 iface
->set_sort_func
= details_set_sort_func
;
518 iface
->set_default_sort_func
= details_set_default_sort_func
;
519 iface
->has_default_sort_func
= details_has_default_sort_func
;
522 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
523 gint
*sort_column_id
,
526 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
527 FilerWindow
*filer_window
= view_details
->filer_window
;
531 return FALSE
; /* Not yet initialised */
533 switch (filer_window
->sort_type
)
535 case SORT_NAME
: col
= COL_LEAF
; break;
536 case SORT_TYPE
: col
= COL_TYPE
; break;
537 case SORT_DATE
: col
= COL_MTIME
; break;
538 case SORT_SIZE
: col
= COL_SIZE
; break;
539 case SORT_OWNER
: col
= COL_OWNER
; break;
540 case SORT_GROUP
: col
= COL_GROUP
; break;
542 g_warning("details_get_sort_column_id(): error!");
546 *sort_column_id
= col
;
548 *order
= filer_window
->sort_order
;
552 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
556 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
557 FilerWindow
*filer_window
= view_details
->filer_window
;
560 return; /* Not yet initialised */
562 switch (sort_column_id
)
565 display_set_sort_type(filer_window
, SORT_NAME
, order
);
568 display_set_sort_type(filer_window
, SORT_SIZE
, order
);
571 display_set_sort_type(filer_window
, SORT_DATE
, order
);
574 display_set_sort_type(filer_window
, SORT_TYPE
, order
);
577 display_set_sort_type(filer_window
, SORT_OWNER
, order
);
580 display_set_sort_type(filer_window
, SORT_GROUP
, order
);
583 g_assert_not_reached();
587 static void details_set_sort_func(GtkTreeSortable
*sortable
,
589 GtkTreeIterCompareFunc func
,
591 GtkDestroyNotify destroy
)
593 g_assert_not_reached();
596 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
597 GtkTreeIterCompareFunc func
,
599 GtkDestroyNotify destroy
)
601 g_assert_not_reached();
604 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
)
610 /* End of model implementation */
612 static gboolean
is_selected(ViewDetails
*view_details
, int i
)
616 return view_details_get_selected((ViewIface
*) view_details
, &iter
);
619 static gboolean
view_details_scroll(GtkWidget
*widget
, GdkEventScroll
*event
)
621 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
622 GtkTreePath
*path
= NULL
;
624 if (!gtk_tree_view_get_path_at_pos(tree
, 0, 1, &path
, NULL
, NULL
, NULL
))
625 return TRUE
; /* Empty? */
627 if (event
->direction
== GDK_SCROLL_UP
)
628 gtk_tree_path_prev(path
);
629 else if (event
->direction
== GDK_SCROLL_DOWN
)
630 gtk_tree_path_next(path
);
634 gtk_tree_view_scroll_to_cell(tree
, path
, NULL
, TRUE
, 0, 0);
636 gtk_tree_path_free(path
);
640 static gboolean
view_details_button_press(GtkWidget
*widget
,
643 FilerWindow
*filer_window
= ((ViewDetails
*) widget
)->filer_window
;
644 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
646 if (bev
->window
!= gtk_tree_view_get_bin_window(tree
))
647 return GTK_WIDGET_CLASS(parent_class
)->button_press_event(
650 if (dnd_motion_press(widget
, bev
))
651 filer_perform_action(filer_window
, bev
);
656 static gboolean
view_details_button_release(GtkWidget
*widget
,
659 FilerWindow
*filer_window
= ((ViewDetails
*) widget
)->filer_window
;
660 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
662 if (bev
->window
!= gtk_tree_view_get_bin_window(tree
))
663 return GTK_WIDGET_CLASS(parent_class
)->button_release_event(
666 if (!dnd_motion_release(bev
))
667 filer_perform_action(filer_window
, bev
);
672 static gint
view_details_motion_notify(GtkWidget
*widget
, GdkEventMotion
*event
)
674 ViewDetails
*view_details
= (ViewDetails
*) widget
;
675 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
677 if (event
->window
!= gtk_tree_view_get_bin_window(tree
))
678 return GTK_WIDGET_CLASS(parent_class
)->motion_notify_event(
681 return filer_motion_notify(view_details
->filer_window
, event
);
684 static gboolean
view_details_expose(GtkWidget
*widget
, GdkEventExpose
*event
)
686 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
687 GtkTreePath
*path
= NULL
;
688 GdkRectangle focus_rectangle
;
691 had_cursor
= (GTK_WIDGET_FLAGS(widget
) & GTK_HAS_FOCUS
) != 0;
694 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_HAS_FOCUS
);
695 GTK_WIDGET_CLASS(parent_class
)->expose_event(widget
, event
);
697 GTK_WIDGET_SET_FLAGS(widget
, GTK_HAS_FOCUS
);
699 if (event
->window
!= gtk_tree_view_get_bin_window(tree
))
700 return FALSE
; /* Not the main area */
702 gtk_tree_view_get_cursor(tree
, &path
, NULL
);
704 return FALSE
; /* No cursor */
705 gtk_tree_view_get_background_area(tree
, path
, NULL
, &focus_rectangle
);
706 gtk_tree_path_free(path
);
708 if (!focus_rectangle
.height
)
709 return FALSE
; /* Off screen */
711 focus_rectangle
.width
= widget
->allocation
.width
;
713 gtk_paint_focus(widget
->style
,
721 focus_rectangle
.width
,
722 focus_rectangle
.height
);
727 static void view_details_size_request(GtkWidget
*widget
,
728 GtkRequisition
*requisition
)
730 ViewDetails
*view_details
= (ViewDetails
*) widget
;
732 (*GTK_WIDGET_CLASS(parent_class
)->size_request
)(widget
, requisition
);
734 view_details
->desired_size
= *requisition
;
736 requisition
->height
= 50;
737 requisition
->width
= 50;
740 static void view_details_drag_data_received(GtkWidget
*widget
,
741 GdkDragContext
*drag_context
,
742 gint x
, gint y
, GtkSelectionData
*data
, guint info
, guint time
)
744 /* Just here to override annoying default handler */
747 static void view_details_destroy(GtkObject
*view_details
)
749 VIEW_DETAILS(view_details
)->filer_window
= NULL
;
752 static void view_details_finialize(GObject
*object
)
754 ViewDetails
*view_details
= (ViewDetails
*) object
;
756 g_ptr_array_free(view_details
->items
, TRUE
);
757 view_details
->items
= NULL
;
759 G_OBJECT_CLASS(parent_class
)->finalize(object
);
762 static void view_details_class_init(gpointer gclass
, gpointer data
)
764 GObjectClass
*object
= (GObjectClass
*) gclass
;
765 GtkWidgetClass
*widget
= (GtkWidgetClass
*) gclass
;
767 parent_class
= g_type_class_peek_parent(gclass
);
769 object
->finalize
= view_details_finialize
;
770 GTK_OBJECT_CLASS(object
)->destroy
= view_details_destroy
;
772 widget
->scroll_event
= view_details_scroll
;
773 widget
->button_press_event
= view_details_button_press
;
774 widget
->button_release_event
= view_details_button_release
;
775 widget
->motion_notify_event
= view_details_motion_notify
;
776 widget
->expose_event
= view_details_expose
;
777 widget
->size_request
= view_details_size_request
;
778 widget
->drag_data_received
= view_details_drag_data_received
;
781 static gboolean
block_focus(GtkWidget
*button
, GtkDirectionType dir
,
782 ViewDetails
*view_details
)
784 GTK_WIDGET_UNSET_FLAGS(button
, GTK_CAN_FOCUS
);
788 #define ADD_TEXT_COLUMN(name, model_column) \
789 cell = gtk_cell_renderer_text_new(); \
790 column = gtk_tree_view_column_new_with_attributes(name, cell, \
791 "text", model_column, \
792 "foreground-gdk", COL_COLOUR, \
793 "background-gdk", COL_BG_COLOUR, \
794 "weight", COL_WEIGHT, \
796 gtk_tree_view_append_column(treeview, column); \
797 g_signal_connect(column->button, "grab-focus", \
798 G_CALLBACK(block_focus), view_details);
800 static void view_details_init(GTypeInstance
*object
, gpointer gclass
)
802 GtkTreeView
*treeview
= (GtkTreeView
*) object
;
803 GtkTreeViewColumn
*column
;
804 GtkCellRenderer
*cell
;
805 GtkTreeSortable
*sortable_list
;
806 GtkTreeSelection
*selection
;
807 ViewDetails
*view_details
= (ViewDetails
*) object
;
809 view_details
->items
= g_ptr_array_new();
810 view_details
->cursor_base
= -1;
811 view_details
->desired_size
.width
= -1;
812 view_details
->desired_size
.height
= -1;
814 selection
= gtk_tree_view_get_selection(treeview
);
815 gtk_tree_selection_set_mode(selection
, GTK_SELECTION_NONE
);
818 view_details
->sort_fn
= NULL
;
819 sortable_list
= GTK_TREE_SORTABLE(object
);
821 gtk_tree_view_set_model(treeview
, GTK_TREE_MODEL(view_details
));
824 cell
= cell_icon_new(view_details
);
825 column
= gtk_tree_view_column_new_with_attributes(NULL
, cell
,
826 "item", COL_VIEW_ITEM
,
827 "background-gdk", COL_BG_COLOUR
,
829 gtk_tree_view_append_column(treeview
, column
);
831 ADD_TEXT_COLUMN(_("_Name"), COL_LEAF
);
832 gtk_tree_view_column_set_sort_column_id(column
, COL_LEAF
);
833 gtk_tree_view_column_set_resizable(column
, TRUE
);
834 ADD_TEXT_COLUMN(_("_Type"), COL_TYPE
);
835 gtk_tree_view_column_set_sort_column_id(column
, COL_TYPE
);
836 ADD_TEXT_COLUMN(_("_Permissions"), COL_PERM
);
837 ADD_TEXT_COLUMN(_("_Owner"), COL_OWNER
);
838 gtk_tree_view_column_set_sort_column_id(column
, COL_OWNER
);
839 ADD_TEXT_COLUMN(_("_Group"), COL_GROUP
);
840 gtk_tree_view_column_set_sort_column_id(column
, COL_GROUP
);
841 ADD_TEXT_COLUMN(_("_Size"), COL_SIZE
);
842 gtk_tree_view_column_set_sort_column_id(column
, COL_SIZE
);
843 ADD_TEXT_COLUMN(_("Last _Modified"), COL_MTIME
);
844 gtk_tree_view_column_set_sort_column_id(column
, COL_MTIME
);
847 /* Create the handers for the View interface */
848 static void view_details_iface_init(gpointer giface
, gpointer iface_data
)
850 ViewIfaceClass
*iface
= giface
;
852 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
855 iface
->sort
= view_details_sort
;
856 iface
->style_changed
= view_details_style_changed
;
857 iface
->autoselect
= view_details_autoselect
;
858 iface
->add_items
= view_details_add_items
;
859 iface
->update_items
= view_details_update_items
;
860 iface
->delete_if
= view_details_delete_if
;
861 iface
->clear
= view_details_clear
;
862 iface
->select_all
= view_details_select_all
;
863 iface
->clear_selection
= view_details_clear_selection
;
864 iface
->count_items
= view_details_count_items
;
865 iface
->count_selected
= view_details_count_selected
;
866 iface
->show_cursor
= view_details_show_cursor
;
867 iface
->get_iter
= view_details_get_iter
;
868 iface
->get_iter_at_point
= view_details_get_iter_at_point
;
869 iface
->cursor_to_iter
= view_details_cursor_to_iter
;
870 iface
->set_selected
= view_details_set_selected
;
871 iface
->get_selected
= view_details_get_selected
;
872 iface
->set_frozen
= view_details_set_frozen
;
873 iface
->select_only
= view_details_select_only
;
874 iface
->wink_item
= view_details_wink_item
;
875 iface
->autosize
= view_details_autosize
;
876 iface
->cursor_visible
= view_details_cursor_visible
;
877 iface
->set_base
= view_details_set_base
;
878 iface
->start_lasso_box
= view_details_start_lasso_box
;
879 iface
->extend_tip
= view_details_extend_tip
;
880 iface
->auto_scroll_callback
= view_details_auto_scroll_callback
;
883 /* Implementations of the View interface. See view_iface.c for comments. */
885 static void view_details_style_changed(ViewIface
*view
, int flags
)
887 ViewDetails
*view_details
= (ViewDetails
*) view
;
888 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
890 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
892 int n
= view_details
->items
->len
;
894 path
= gtk_tree_path_new();
895 gtk_tree_path_append_index(path
, 0);
897 for (i
= 0; i
< n
; i
++)
900 ViewItem
*item
= items
[i
];
902 iter
.user_data
= GINT_TO_POINTER(i
);
905 g_object_unref(G_OBJECT(item
->image
));
908 gtk_tree_model_row_changed(model
, path
, &iter
);
909 gtk_tree_path_next(path
);
912 gtk_tree_path_free(path
);
914 gtk_tree_view_columns_autosize((GtkTreeView
*) view
);
916 if (flags
& VIEW_UPDATE_HEADERS
)
917 details_update_header_visibility(view_details
);
920 static gint
wrap_sort(gconstpointer a
, gconstpointer b
,
921 ViewDetails
*view_details
)
923 ViewItem
*ia
= *(ViewItem
**) a
;
924 ViewItem
*ib
= *(ViewItem
**) b
;
926 if (view_details
->filer_window
->sort_order
== GTK_SORT_ASCENDING
)
927 return view_details
->sort_fn(ia
->item
, ib
->item
);
929 return -view_details
->sort_fn(ia
->item
, ib
->item
);
932 static void resort(ViewDetails
*view_details
)
934 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
935 gint i
, len
= view_details
->items
->len
;
942 for (i
= len
- 1; i
>= 0; i
--)
943 items
[i
]->old_pos
= i
;
945 switch (view_details
->filer_window
->sort_type
)
947 case SORT_NAME
: view_details
->sort_fn
= sort_by_name
; break;
948 case SORT_TYPE
: view_details
->sort_fn
= sort_by_type
; break;
949 case SORT_DATE
: view_details
->sort_fn
= sort_by_date
; break;
950 case SORT_SIZE
: view_details
->sort_fn
= sort_by_size
; break;
951 case SORT_OWNER
: view_details
->sort_fn
= sort_by_owner
; break;
952 case SORT_GROUP
: view_details
->sort_fn
= sort_by_group
; break;
954 g_assert_not_reached();
957 g_ptr_array_sort_with_data(view_details
->items
,
958 (GCompareDataFunc
) wrap_sort
,
961 new_order
= g_new(guint
, len
);
962 for (i
= len
- 1; i
>= 0; i
--)
963 new_order
[i
] = items
[i
]->old_pos
;
965 path
= gtk_tree_path_new();
966 gtk_tree_model_rows_reordered((GtkTreeModel
*) view_details
,
967 path
, NULL
, new_order
);
968 gtk_tree_path_free(path
);
972 static void view_details_sort(ViewIface
*view
)
974 resort((ViewDetails
*) view
);
975 gtk_tree_sortable_sort_column_changed((GtkTreeSortable
*) view
);
978 static gboolean
view_details_autoselect(ViewIface
*view
, const gchar
*leaf
)
983 static void view_details_add_items(ViewIface
*view
, GPtrArray
*new_items
)
985 ViewDetails
*view_details
= (ViewDetails
*) view
;
986 FilerWindow
*filer_window
= view_details
->filer_window
;
987 gboolean show_hidden
= filer_window
->show_hidden
;
988 GPtrArray
*items
= view_details
->items
;
992 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
994 iter
.user_data
= GINT_TO_POINTER(items
->len
);
995 path
= details_get_path(model
, &iter
);
997 for (i
= 0; i
< new_items
->len
; i
++)
999 DirItem
*item
= (DirItem
*) new_items
->pdata
[i
];
1000 char *leafname
= item
->leafname
;
1003 if (leafname
[0] == '.')
1008 if (leafname
[1] == '\0')
1009 continue; /* Never show '.' */
1011 if (leafname
[1] == '.' &&
1012 leafname
[2] == '\0')
1013 continue; /* Never show '..' */
1016 vitem
= g_new(ViewItem
, 1);
1018 vitem
->image
= NULL
;
1019 vitem
->selected
= FALSE
;
1020 if (!g_utf8_validate(leafname
, -1, NULL
))
1021 vitem
->utf8_name
= to_utf8(leafname
);
1023 vitem
->utf8_name
= NULL
;
1025 g_ptr_array_add(items
, vitem
);
1027 iter
.user_data
= GINT_TO_POINTER(items
->len
- 1);
1028 gtk_tree_model_row_inserted(model
, path
, &iter
);
1029 gtk_tree_path_next(path
);
1032 gtk_tree_path_free(path
);
1034 resort(view_details
);
1037 /* Find an item in the sorted array.
1038 * Returns the item number, or -1 if not found.
1040 static int details_find_item(ViewDetails
*view_details
, DirItem
*item
)
1042 ViewItem
**items
, tmp
, *tmpp
;
1045 g_return_val_if_fail(view_details
!= NULL
, -1);
1046 g_return_val_if_fail(item
!= NULL
, -1);
1051 items
= (ViewItem
**) view_details
->items
->pdata
;
1053 /* If item is here, then: lower <= i < upper */
1055 upper
= view_details
->items
->len
;
1057 while (lower
< upper
)
1061 i
= (lower
+ upper
) >> 1;
1063 cmp
= wrap_sort(&items
[i
], &tmpp
, view_details
);
1076 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
)
1078 ViewDetails
*view_details
= (ViewDetails
*) view
;
1079 FilerWindow
*filer_window
= view_details
->filer_window
;
1081 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
1083 g_return_if_fail(items
->len
> 0);
1085 /* The item data has already been modified, so this gives the
1086 * final sort order...
1088 resort(view_details
);
1090 for (i
= 0; i
< items
->len
; i
++)
1092 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1093 const gchar
*leafname
= item
->leafname
;
1096 if (leafname
[0] == '.' && filer_window
->show_hidden
== FALSE
)
1099 j
= details_find_item(view_details
, item
);
1102 g_warning("Failed to find '%s'\n", leafname
);
1107 ViewItem
*view_item
= view_details
->items
->pdata
[j
];
1108 if (view_item
->image
)
1110 g_object_unref(G_OBJECT(view_item
->image
));
1111 view_item
->image
= NULL
;
1113 path
= gtk_tree_path_new();
1114 gtk_tree_path_append_index(path
, j
);
1115 iter
.user_data
= GINT_TO_POINTER(j
);
1116 gtk_tree_model_row_changed(model
, path
, &iter
);
1121 static void view_details_delete_if(ViewIface
*view
,
1122 gboolean (*test
)(gpointer item
, gpointer data
),
1126 ViewDetails
*view_details
= (ViewDetails
*) view
;
1128 GPtrArray
*items
= view_details
->items
;
1129 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1131 path
= gtk_tree_path_new();
1133 gtk_tree_path_append_index(path
, i
);
1135 while (i
< items
->len
)
1137 ViewItem
*item
= items
->pdata
[i
];
1139 if (test(item
->item
, data
))
1141 free_view_item(items
->pdata
[i
]);
1142 g_ptr_array_remove_index(items
, i
);
1143 gtk_tree_model_row_deleted(model
, path
);
1148 gtk_tree_path_next(path
);
1152 gtk_tree_path_free(path
);
1155 static void view_details_clear(ViewIface
*view
)
1158 GPtrArray
*items
= ((ViewDetails
*) view
)->items
;
1159 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1161 path
= gtk_tree_path_new();
1162 gtk_tree_path_append_index(path
, items
->len
);
1164 while (gtk_tree_path_prev(path
))
1165 gtk_tree_model_row_deleted(model
, path
);
1167 g_ptr_array_set_size(items
, 0);
1168 gtk_tree_path_free(path
);
1171 static void view_details_select_all(ViewIface
*view
)
1174 int n
= ((ViewDetails
*) view
)->items
->len
;
1176 for (i
= 0; i
< n
; i
++)
1180 view_details_set_selected(view
, &iter
, TRUE
);
1184 static void view_details_clear_selection(ViewIface
*view
)
1187 int n
= ((ViewDetails
*) view
)->items
->len
;
1189 for (i
= 0; i
< n
; i
++)
1193 view_details_set_selected(view
, &iter
, FALSE
);
1197 static int view_details_count_items(ViewIface
*view
)
1199 ViewDetails
*view_details
= (ViewDetails
*) view
;
1201 return view_details
->items
->len
;
1204 static int view_details_count_selected(ViewIface
*view
)
1206 ViewDetails
*view_details
= (ViewDetails
*) view
;
1207 int n
= view_details
->items
->len
;
1208 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
1212 for (i
= 0; i
< n
; i
++)
1213 if (items
[i
]->selected
)
1219 static void view_details_show_cursor(ViewIface
*view
)
1223 static void view_details_get_iter(ViewIface
*view
,
1224 ViewIter
*iter
, IterFlags flags
)
1226 make_iter((ViewDetails
*) view
, iter
, flags
);
1229 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
1230 GdkWindow
*src
, int x
, int y
)
1232 ViewDetails
*view_details
= (ViewDetails
*) view
;
1233 GtkTreeModel
*model
;
1234 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1235 GtkTreePath
*path
= NULL
;
1238 model
= gtk_tree_view_get_model(tree
);
1240 if (gtk_tree_view_get_path_at_pos(tree
, x
, y
, &path
, NULL
, NULL
, NULL
))
1242 g_return_if_fail(path
!= NULL
);
1244 i
= gtk_tree_path_get_indices(path
)[0];
1245 gtk_tree_path_free(path
);
1248 make_item_iter(view_details
, iter
, i
);
1251 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
)
1254 ViewDetails
*view_details
= (ViewDetails
*) view
;
1256 path
= gtk_tree_path_new();
1259 gtk_tree_path_append_index(path
, iter
->i
);
1262 /* Using depth zero or index -1 gives an error, but this
1265 gtk_tree_path_append_index(path
, view_details
->items
->len
);
1268 gtk_tree_view_set_cursor((GtkTreeView
*) view
, path
, NULL
, FALSE
);
1269 gtk_tree_path_free(path
);
1272 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
)
1274 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
1277 GPtrArray
*items
= view_details
->items
;
1278 ViewItem
*view_item
;
1280 g_return_if_fail(i
>= 0 && i
< items
->len
);
1281 view_item
= (ViewItem
*) items
->pdata
[i
];
1283 if (view_item
->selected
== selected
)
1286 view_item
->selected
= selected
;
1288 path
= gtk_tree_path_new();
1289 gtk_tree_path_append_index(path
, i
);
1290 t_iter
.user_data
= GINT_TO_POINTER(i
);
1291 gtk_tree_model_row_changed(model
, path
, &t_iter
);
1292 gtk_tree_path_free(path
);
1295 static void view_details_set_selected(ViewIface
*view
,
1299 set_selected((ViewDetails
*) view
, iter
->i
, selected
);
1302 static gboolean
get_selected(ViewDetails
*view_details
, int i
)
1304 GPtrArray
*items
= view_details
->items
;
1306 g_return_val_if_fail(i
>= 0 && i
< items
->len
, FALSE
);
1308 return ((ViewItem
*) items
->pdata
[i
])->selected
;
1311 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
)
1313 return get_selected((ViewDetails
*) view
, iter
->i
);
1316 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
)
1318 ViewDetails
*view_details
= (ViewDetails
*) view
;
1320 int n
= view_details
->items
->len
;
1322 set_selected(view_details
, i
, TRUE
);
1329 set_selected(view_details
, n
, FALSE
);
1333 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
)
1337 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
)
1342 static void view_details_autosize(ViewIface
*view
)
1344 ViewDetails
*view_details
= (ViewDetails
*) view
;
1345 FilerWindow
*filer_window
= view_details
->filer_window
;
1346 int max_width
= (o_filer_size_limit
.int_value
* screen_width
) / 100;
1347 int max_height
= (o_filer_size_limit
.int_value
* screen_height
) / 100;
1351 gtk_widget_queue_resize(GTK_WIDGET(view
));
1352 gtk_widget_size_request(GTK_WIDGET(view
), &req
);
1354 h
= MAX(view_details
->desired_size
.height
, SMALL_HEIGHT
);
1356 filer_window_set_size(filer_window
,
1357 MIN(view_details
->desired_size
.width
, max_width
),
1358 MIN(h
, max_height
));
1361 static gboolean
view_details_cursor_visible(ViewIface
*view
)
1366 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
)
1368 ViewDetails
*view_details
= (ViewDetails
*) view
;
1370 view_details
->cursor_base
= iter
->i
;
1373 static void view_details_start_lasso_box(ViewIface
*view
, GdkEventButton
*event
)
1377 static void view_details_extend_tip(ViewIface
*view
,
1378 ViewIter
*iter
, GString
*tip
)
1382 static DirItem
*iter_init(ViewIter
*iter
)
1384 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1386 int n
= view_details
->items
->len
;
1387 int flags
= iter
->flags
;
1389 iter
->peek
= iter_peek
;
1391 if (iter
->n_remaining
== 0)
1394 if (flags
& VIEW_ITER_FROM_CURSOR
)
1397 gtk_tree_view_get_cursor((GtkTreeView
*) view_details
,
1400 return NULL
; /* No cursor */
1401 i
= gtk_tree_path_get_indices(path
)[0];
1402 gtk_tree_path_free(path
);
1404 else if (flags
& VIEW_ITER_FROM_BASE
)
1405 i
= view_details
->cursor_base
;
1407 if (i
< 0 || i
>= n
)
1409 /* Either a normal iteration, or an iteration from an
1410 * invalid starting point.
1412 if (flags
& VIEW_ITER_BACKWARDS
)
1418 if (i
< 0 || i
>= n
)
1419 return NULL
; /* No items at all! */
1421 iter
->next
= flags
& VIEW_ITER_BACKWARDS
? iter_prev
: iter_next
;
1422 iter
->n_remaining
--;
1425 if (flags
& VIEW_ITER_SELECTED
&& !is_selected(view_details
, i
))
1426 return iter
->next(iter
);
1427 return iter
->peek(iter
);
1430 static DirItem
*iter_prev(ViewIter
*iter
)
1432 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1433 int n
= view_details
->items
->len
;
1436 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1438 /* i is the last item returned (always valid) */
1440 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1442 while (iter
->n_remaining
)
1445 iter
->n_remaining
--;
1450 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1452 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1453 !is_selected(view_details
, i
))
1457 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1464 static DirItem
*iter_next(ViewIter
*iter
)
1466 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1467 int n
= view_details
->items
->len
;
1470 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1472 /* i is the last item returned (always valid) */
1474 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1476 while (iter
->n_remaining
)
1479 iter
->n_remaining
--;
1484 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1486 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1487 !is_selected(view_details
, i
))
1491 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1498 static DirItem
*iter_peek(ViewIter
*iter
)
1500 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1501 int n
= view_details
->items
->len
;
1507 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1509 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1512 /* Set the iterator to return 'i' on the next peek().
1513 * If i is -1, returns NULL on next peek().
1515 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
)
1517 make_iter(view_details
, iter
, 0);
1519 g_return_if_fail(i
>= -1 && i
< (int) view_details
->items
->len
);
1522 iter
->next
= iter_next
;
1523 iter
->peek
= iter_peek
;
1524 iter
->n_remaining
= 0;
1527 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
1530 iter
->view
= (ViewIface
*) view_details
;
1531 iter
->next
= iter_init
;
1535 iter
->flags
= flags
;
1537 if (flags
& VIEW_ITER_ONE_ONLY
)
1539 iter
->n_remaining
= 1;
1543 iter
->n_remaining
= view_details
->items
->len
;
1546 static void free_view_item(ViewItem
*view_item
)
1548 if (view_item
->image
)
1549 g_object_unref(G_OBJECT(view_item
->image
));
1550 g_free(view_item
->utf8_name
);
1554 static gboolean
view_details_auto_scroll_callback(ViewIface
*view
)
1556 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1557 ViewDetails
*view_details
= (ViewDetails
*) view
;
1558 FilerWindow
*filer_window
= view_details
->filer_window
;
1559 GtkRange
*scrollbar
= (GtkRange
*) filer_window
->scrollbar
;
1563 GdkModifierType mask
;
1566 window
= gtk_tree_view_get_bin_window(tree
);
1568 gdk_window_get_pointer(window
, &x
, &y
, &mask
);
1569 gdk_drawable_get_size(window
, &w
, NULL
);
1571 adj
= gtk_range_get_adjustment(scrollbar
);
1574 if ((x
< 0 || x
> w
|| y
< 0 || y
> h
)) /* && !view->lasso_box) */
1575 return FALSE
; /* Out of window - stop */
1577 if (y
< AUTOSCROLL_STEP
)
1578 diff
= y
- AUTOSCROLL_STEP
;
1579 else if (y
> h
- AUTOSCROLL_STEP
)
1580 diff
= AUTOSCROLL_STEP
+ y
- h
;
1584 int old
= adj
->value
;
1585 int value
= old
+ diff
;
1587 value
= CLAMP(value
, 0, adj
->upper
- adj
->page_size
);
1588 gtk_adjustment_set_value(adj
, value
);
1590 if (adj
->value
!= old
)