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 */
58 #define COL_VIEW_ITEM 10
61 static gpointer parent_class
= NULL
;
63 struct _ViewDetailsClass
{
64 GtkTreeViewClass parent
;
67 /* Static prototypes */
68 static void view_details_finialize(GObject
*object
);
69 static void view_details_class_init(gpointer gclass
, gpointer data
);
70 static void view_details_init(GTypeInstance
*object
, gpointer gclass
);
72 static void view_details_iface_init(gpointer giface
, gpointer iface_data
);
74 static void view_details_sort(ViewIface
*view
);
75 static void view_details_style_changed(ViewIface
*view
, int flags
);
76 static void view_details_add_items(ViewIface
*view
, GPtrArray
*items
);
77 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
);
78 static void view_details_delete_if(ViewIface
*view
,
79 gboolean (*test
)(gpointer item
, gpointer data
),
81 static void view_details_clear(ViewIface
*view
);
82 static void view_details_select_all(ViewIface
*view
);
83 static void view_details_clear_selection(ViewIface
*view
);
84 static int view_details_count_items(ViewIface
*view
);
85 static int view_details_count_selected(ViewIface
*view
);
86 static void view_details_show_cursor(ViewIface
*view
);
87 static void view_details_get_iter(ViewIface
*view
,
88 ViewIter
*iter
, IterFlags flags
);
89 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
90 GdkWindow
*src
, int x
, int y
);
91 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
92 static void view_details_set_selected(ViewIface
*view
,
95 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
);
96 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
);
97 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
);
98 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
);
99 static void view_details_autosize(ViewIface
*view
);
100 static gboolean
view_details_cursor_visible(ViewIface
*view
);
101 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
);
102 static void view_details_start_lasso_box(ViewIface
*view
,
103 GdkEventButton
*event
);
104 static void view_details_extend_tip(ViewIface
*view
,
105 ViewIter
*iter
, GString
*tip
);
106 static gboolean
view_details_auto_scroll_callback(ViewIface
*view
);
108 static DirItem
*iter_peek(ViewIter
*iter
);
109 static DirItem
*iter_prev(ViewIter
*iter
);
110 static DirItem
*iter_next(ViewIter
*iter
);
111 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
113 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
);
114 static void view_details_tree_model_init(GtkTreeModelIface
*iface
);
115 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
116 gint
*sort_column_id
,
118 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
121 static void details_set_sort_func(GtkTreeSortable
*sortable
,
123 GtkTreeIterCompareFunc func
,
125 GtkDestroyNotify destroy
);
126 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
127 GtkTreeIterCompareFunc func
,
129 GtkDestroyNotify destroy
);
130 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
);
131 static void view_details_sortable_init(GtkTreeSortableIface
*iface
);
132 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
);
133 static gboolean
get_selected(ViewDetails
*view_details
, int i
);
134 static void free_view_item(ViewItem
*view_item
);
135 static void details_update_header_visibility(ViewDetails
*view_details
);
136 static void set_lasso(ViewDetails
*view_details
, int x
, int y
);
137 static void cancel_wink(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
)
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
;
280 GPtrArray
*items
= view_details
->items
;
285 g_return_if_fail(column
>= 0 && column
< N_COLUMNS
);
287 i
= GPOINTER_TO_INT(iter
->user_data
);
288 g_return_if_fail(i
>= 0 && i
< items
->len
);
289 view_item
= (ViewItem
*) items
->pdata
[i
];
290 item
= view_item
->item
;
292 if (column
== COL_LEAF
)
294 g_value_init(value
, G_TYPE_STRING
);
295 g_value_set_string(value
,
296 view_item
->utf8_name
? view_item
->utf8_name
300 else if (column
== COL_VIEW_ITEM
)
302 g_value_init(value
, G_TYPE_POINTER
);
303 g_value_set_pointer(value
, view_item
);
306 else if (column
== COL_ITEM
)
308 g_value_init(value
, G_TYPE_POINTER
);
309 g_value_set_pointer(value
, item
);
313 if (item
->base_type
== TYPE_UNKNOWN
)
316 type
= details_get_column_type(tree_model
, column
);
317 g_value_init(value
, type
);
318 if (type
== G_TYPE_STRING
)
319 g_value_set_string(value
, "");
320 else if (type
== GDK_TYPE_COLOR
)
321 g_value_set_boxed(value
, NULL
);
322 else if (type
== G_TYPE_INT
)
323 g_value_set_int(value
, PANGO_WEIGHT_NORMAL
);
325 g_value_set_object(value
, NULL
);
334 g_value_init(value
, G_TYPE_STRING
);
335 g_value_set_string(value
, item
->leafname
);
338 g_value_init(value
, GDK_TYPE_COLOR
);
339 if (view_item
->utf8_name
)
345 g_value_set_boxed(value
, &red
);
348 g_value_set_boxed(value
,
349 type_get_colour(item
, NULL
));
352 g_value_init(value
, G_TYPE_STRING
);
353 g_value_set_string(value
, user_name(item
->uid
));
356 g_value_init(value
, G_TYPE_STRING
);
357 g_value_set_string(value
, group_name(item
->gid
));
362 time
= pretty_time(&item
->mtime
);
363 g_value_init(value
, G_TYPE_STRING
);
364 g_value_set_string(value
, time
);
369 g_value_init(value
, G_TYPE_STRING
);
370 g_value_set_string(value
, pretty_permissions(m
));
373 g_value_init(value
, G_TYPE_STRING
);
374 if (item
->base_type
!= TYPE_DIRECTORY
)
375 g_value_set_string(value
,
376 format_size(item
->size
));
379 g_value_init(value
, G_TYPE_STRING
);
380 g_value_set_string(value
,
381 item
->flags
& ITEM_FLAG_APPDIR
? "App" :
383 S_ISCHR(m
) ? "Char" :
384 S_ISBLK(m
) ? "Blck" :
385 S_ISLNK(m
) ? "Link" :
386 S_ISSOCK(m
) ? "Sock" :
387 S_ISFIFO(m
) ? "Pipe" :
388 S_ISDOOR(m
) ? "Door" :
392 g_value_init(value
, G_TYPE_INT
);
393 if (item
->flags
& ITEM_FLAG_RECENT
)
394 g_value_set_int(value
, PANGO_WEIGHT_BOLD
);
396 g_value_set_int(value
, PANGO_WEIGHT_NORMAL
);
399 g_value_init(value
, G_TYPE_STRING
);
400 g_value_set_string(value
, "Hello");
405 static gboolean
details_iter_next(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
407 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
410 i
= GPOINTER_TO_INT(iter
->user_data
) + 1;
411 iter
->user_data
= GINT_TO_POINTER(i
);
413 return i
< view_details
->items
->len
;
416 static gboolean
details_iter_children(GtkTreeModel
*tree_model
,
420 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
422 /* this is a list, nodes have no children */
426 /* but if parent == NULL we return the list itself as children of the
430 if (view_details
->items
->len
)
432 iter
->user_data
= GINT_TO_POINTER(0);
439 static gboolean
details_iter_has_child(GtkTreeModel
*tree_model
,
445 static gint
details_iter_n_children(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
447 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
450 return view_details
->items
->len
;
455 static gboolean
details_iter_nth_child(GtkTreeModel
*tree_model
,
460 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
465 if (n
>= 0 && n
< view_details
->items
->len
)
467 iter
->user_data
= GINT_TO_POINTER(n
);
474 static gboolean
details_iter_parent(GtkTreeModel
*tree_model
,
481 /* A ViewDetails is both a GtkTreeView and a GtkTreeModel.
482 * The following functions implement the model interface...
485 static void view_details_tree_model_init(GtkTreeModelIface
*iface
)
487 iface
->get_flags
= details_get_flags
;
488 iface
->get_n_columns
= details_get_n_columns
;
489 iface
->get_column_type
= details_get_column_type
;
490 iface
->get_iter
= details_get_iter
;
491 iface
->get_path
= details_get_path
;
492 iface
->get_value
= details_get_value
;
493 iface
->iter_next
= details_iter_next
;
494 iface
->iter_children
= details_iter_children
;
495 iface
->iter_has_child
= details_iter_has_child
;
496 iface
->iter_n_children
= details_iter_n_children
;
497 iface
->iter_nth_child
= details_iter_nth_child
;
498 iface
->iter_parent
= details_iter_parent
;
501 static void view_details_sortable_init(GtkTreeSortableIface
*iface
)
503 iface
->get_sort_column_id
= details_get_sort_column_id
;
504 iface
->set_sort_column_id
= details_set_sort_column_id
;
505 iface
->set_sort_func
= details_set_sort_func
;
506 iface
->set_default_sort_func
= details_set_default_sort_func
;
507 iface
->has_default_sort_func
= details_has_default_sort_func
;
510 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
511 gint
*sort_column_id
,
514 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
515 FilerWindow
*filer_window
= view_details
->filer_window
;
519 return FALSE
; /* Not yet initialised */
521 switch (filer_window
->sort_type
)
523 case SORT_NAME
: col
= COL_LEAF
; break;
524 case SORT_TYPE
: col
= COL_TYPE
; break;
525 case SORT_DATE
: col
= COL_MTIME
; break;
526 case SORT_SIZE
: col
= COL_SIZE
; break;
527 case SORT_OWNER
: col
= COL_OWNER
; break;
528 case SORT_GROUP
: col
= COL_GROUP
; break;
530 g_warning("details_get_sort_column_id(): error!");
534 *sort_column_id
= col
;
536 *order
= filer_window
->sort_order
;
540 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
544 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
545 FilerWindow
*filer_window
= view_details
->filer_window
;
548 return; /* Not yet initialised */
550 switch (sort_column_id
)
553 display_set_sort_type(filer_window
, SORT_NAME
, order
);
556 display_set_sort_type(filer_window
, SORT_SIZE
, order
);
559 display_set_sort_type(filer_window
, SORT_DATE
, order
);
562 display_set_sort_type(filer_window
, SORT_TYPE
, order
);
565 display_set_sort_type(filer_window
, SORT_OWNER
, order
);
568 display_set_sort_type(filer_window
, SORT_GROUP
, order
);
571 g_assert_not_reached();
575 static void details_set_sort_func(GtkTreeSortable
*sortable
,
577 GtkTreeIterCompareFunc func
,
579 GtkDestroyNotify destroy
)
581 g_assert_not_reached();
584 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
585 GtkTreeIterCompareFunc func
,
587 GtkDestroyNotify destroy
)
589 g_assert_not_reached();
592 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
)
598 /* End of model implementation */
600 static gboolean
is_selected(ViewDetails
*view_details
, int i
)
604 return view_details_get_selected((ViewIface
*) view_details
, &iter
);
607 static gboolean
view_details_scroll(GtkWidget
*widget
, GdkEventScroll
*event
)
609 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
610 GtkTreePath
*path
= NULL
;
612 if (!gtk_tree_view_get_path_at_pos(tree
, 0, 1, &path
, NULL
, NULL
, NULL
))
613 return TRUE
; /* Empty? */
615 if (event
->direction
== GDK_SCROLL_UP
)
616 gtk_tree_path_prev(path
);
617 else if (event
->direction
== GDK_SCROLL_DOWN
)
618 gtk_tree_path_next(path
);
622 gtk_tree_view_scroll_to_cell(tree
, path
, NULL
, TRUE
, 0, 0);
624 gtk_tree_path_free(path
);
628 static gint
view_details_key_press(GtkWidget
*widget
, GdkEventKey
*event
)
630 if (event
->keyval
== GDK_Up
|| event
->keyval
== GDK_Down
||
631 event
->keyval
== GDK_Prior
|| event
->keyval
== GDK_Next
||
632 event
->keyval
== GDK_Home
|| event
->keyval
== GDK_End
)
633 return GTK_WIDGET_CLASS(parent_class
)->key_press_event(widget
,
638 static gboolean
view_details_button_press(GtkWidget
*widget
,
641 FilerWindow
*filer_window
= ((ViewDetails
*) widget
)->filer_window
;
642 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
644 if (bev
->window
!= gtk_tree_view_get_bin_window(tree
))
645 return GTK_WIDGET_CLASS(parent_class
)->button_press_event(
648 if (dnd_motion_press(widget
, bev
))
649 filer_perform_action(filer_window
, bev
);
654 static int get_lasso_index(ViewDetails
*view_details
, int y
)
656 GtkTreeViewColumn
*column
= NULL
;
657 GtkTreePath
*path
= NULL
;
658 GtkTreeView
*tree
= (GtkTreeView
*) view_details
;
662 if (gtk_tree_view_get_path_at_pos(tree
, 4, y
, &path
,
663 &column
, NULL
, &cell_y
))
666 i
= gtk_tree_path_get_indices(path
)[0];
667 gtk_tree_view_get_cell_area(tree
, path
, column
, &rect
);
668 gtk_tree_path_free(path
);
670 if (2 * cell_y
> rect
.height
)
674 i
= view_details
->items
->len
;
679 static gboolean
select_lasso_cb(ViewIter
*iter
, gpointer data
)
681 int start
= ((int *) data
)[0];
682 int end
= ((int *) data
)[1];
683 GdkFunction fn
= ((int *) data
)[2];
684 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
687 titer
.user_data
= GINT_TO_POINTER(iter
->i
);
689 if (iter
->i
< start
|| iter
->i
>= end
)
690 return gtk_tree_selection_iter_is_selected(
691 view_details
->selection
, &titer
);
696 return !gtk_tree_selection_iter_is_selected(view_details
->selection
,
700 static void select_lasso(ViewDetails
*view_details
, GdkFunction fn
)
705 adj
= gtk_tree_view_get_vadjustment((GtkTreeView
*) view_details
);
707 range
[0] = view_details
->lasso_start_index
;
708 range
[1] = get_lasso_index(view_details
,
709 view_details
->drag_box_y
[1] - adj
->value
);
712 if (range
[0] == range
[1])
714 if (range
[0] > range
[1])
721 view_select_if((ViewIface
*) view_details
, select_lasso_cb
, &range
);
724 static gboolean
view_details_button_release(GtkWidget
*widget
,
727 ViewDetails
*view_details
= (ViewDetails
*) widget
;
728 FilerWindow
*filer_window
= view_details
->filer_window
;
729 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
731 if (bev
->window
!= gtk_tree_view_get_bin_window(tree
))
732 return GTK_WIDGET_CLASS(parent_class
)->button_release_event(
735 if (!dnd_motion_release(bev
))
736 filer_perform_action(filer_window
, bev
);
738 if (motion_buttons_pressed
== 0 && view_details
->lasso_box
)
740 select_lasso(view_details
,
741 bev
->button
== 1 ? GDK_SET
: GDK_INVERT
);
742 filer_set_autoscroll(filer_window
, FALSE
);
743 set_lasso(view_details
,
744 view_details
->drag_box_x
[0],
745 view_details
->drag_box_y
[0]);
746 view_details
->lasso_box
= FALSE
;
752 static gint
view_details_motion_notify(GtkWidget
*widget
, GdkEventMotion
*event
)
754 ViewDetails
*view_details
= (ViewDetails
*) widget
;
755 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
757 if (event
->window
!= gtk_tree_view_get_bin_window(tree
))
758 return GTK_WIDGET_CLASS(parent_class
)->motion_notify_event(
761 if (view_details
->lasso_box
)
764 adj
= gtk_tree_view_get_vadjustment(tree
);
765 set_lasso(view_details
, event
->x
, event
->y
+ adj
->value
);
769 return filer_motion_notify(view_details
->filer_window
, event
);
772 static gboolean
view_details_expose(GtkWidget
*widget
, GdkEventExpose
*event
)
774 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
775 GtkTreePath
*path
= NULL
;
776 GdkRectangle focus_rectangle
;
777 ViewDetails
*view_details
= (ViewDetails
*) widget
;
780 had_cursor
= (GTK_WIDGET_FLAGS(widget
) & GTK_HAS_FOCUS
) != 0;
782 if (view_details
->filer_window
->selection_state
== GTK_STATE_SELECTED
)
783 GTK_WIDGET_SET_FLAGS(widget
, GTK_HAS_FOCUS
);
785 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_HAS_FOCUS
);
786 GTK_WIDGET_CLASS(parent_class
)->expose_event(widget
, event
);
788 GTK_WIDGET_SET_FLAGS(widget
, GTK_HAS_FOCUS
);
790 if (event
->window
!= gtk_tree_view_get_bin_window(tree
))
791 return FALSE
; /* Not the main area */
793 if (view_details
->lasso_box
)
795 int x
, y
, width
, height
;
798 adj
= gtk_tree_view_get_vadjustment(tree
);
799 x
= MIN(view_details
->drag_box_x
[0],
800 view_details
->drag_box_x
[1]);
801 y
= MIN(view_details
->drag_box_y
[0],
802 view_details
->drag_box_y
[1]);
803 width
= abs(view_details
->drag_box_x
[1] -
804 view_details
->drag_box_x
[0]);
805 height
= abs(view_details
->drag_box_y
[1] -
806 view_details
->drag_box_y
[0]);
810 gdk_draw_rectangle(event
->window
,
811 widget
->style
->fg_gc
[GTK_STATE_NORMAL
],
812 FALSE
, x
, y
, width
- 1, height
- 1);
815 if (view_details
->wink_item
!= -1 && view_details
->wink_step
& 1)
817 GtkTreePath
*wink_path
;
818 GdkRectangle wink_area
;
820 wink_path
= gtk_tree_path_new();
821 gtk_tree_path_append_index(wink_path
, view_details
->wink_item
);
822 gtk_tree_view_get_background_area(tree
, wink_path
,
824 gtk_tree_path_free(wink_path
);
826 if (wink_area
.height
)
829 wink_area
.width
= widget
->allocation
.width
;
830 gdk_draw_rectangle(event
->window
,
831 widget
->style
->fg_gc
[GTK_STATE_NORMAL
],
836 wink_area
.height
- 3);
840 gtk_tree_view_get_cursor(tree
, &path
, NULL
);
842 return FALSE
; /* No cursor */
843 gtk_tree_view_get_background_area(tree
, path
, NULL
, &focus_rectangle
);
844 gtk_tree_path_free(path
);
846 if (!focus_rectangle
.height
)
847 return FALSE
; /* Off screen */
849 focus_rectangle
.width
= widget
->allocation
.width
;
851 gtk_paint_focus(widget
->style
,
859 focus_rectangle
.width
,
860 focus_rectangle
.height
);
865 static void view_details_size_request(GtkWidget
*widget
,
866 GtkRequisition
*requisition
)
868 ViewDetails
*view_details
= (ViewDetails
*) widget
;
870 (*GTK_WIDGET_CLASS(parent_class
)->size_request
)(widget
, requisition
);
872 view_details
->desired_size
= *requisition
;
874 requisition
->height
= 50;
875 requisition
->width
= 50;
878 static void view_details_drag_data_received(GtkWidget
*widget
,
879 GdkDragContext
*drag_context
,
880 gint x
, gint y
, GtkSelectionData
*data
, guint info
, guint time
)
882 /* Just here to override annoying default handler */
885 static void view_details_destroy(GtkObject
*obj
)
887 ViewDetails
*view_details
= VIEW_DETAILS(obj
);
889 view_details
->filer_window
= NULL
;
890 cancel_wink(view_details
);
893 static void view_details_finialize(GObject
*object
)
895 ViewDetails
*view_details
= (ViewDetails
*) object
;
897 g_ptr_array_free(view_details
->items
, TRUE
);
898 view_details
->items
= NULL
;
900 G_OBJECT_CLASS(parent_class
)->finalize(object
);
903 static void view_details_class_init(gpointer gclass
, gpointer data
)
905 GObjectClass
*object
= (GObjectClass
*) gclass
;
906 GtkWidgetClass
*widget
= (GtkWidgetClass
*) gclass
;
908 parent_class
= g_type_class_peek_parent(gclass
);
910 object
->finalize
= view_details_finialize
;
911 GTK_OBJECT_CLASS(object
)->destroy
= view_details_destroy
;
913 widget
->scroll_event
= view_details_scroll
;
914 widget
->key_press_event
= view_details_key_press
;
915 widget
->button_press_event
= view_details_button_press
;
916 widget
->button_release_event
= view_details_button_release
;
917 widget
->motion_notify_event
= view_details_motion_notify
;
918 widget
->expose_event
= view_details_expose
;
919 widget
->size_request
= view_details_size_request
;
920 widget
->drag_data_received
= view_details_drag_data_received
;
923 static gboolean
block_focus(GtkWidget
*button
, GtkDirectionType dir
,
924 ViewDetails
*view_details
)
926 GTK_WIDGET_UNSET_FLAGS(button
, GTK_CAN_FOCUS
);
930 static gboolean
test_can_change_selection(GtkTreeSelection
*sel
,
933 gboolean path_currently_selected
,
936 ViewDetails
*view_details
;
938 view_details
= VIEW_DETAILS(gtk_tree_selection_get_tree_view(sel
));
940 return view_details
->can_change_selection
!= 0;
943 static void selection_changed(GtkTreeSelection
*selection
,
946 ViewDetails
*view_details
= VIEW_DETAILS(user_data
);
948 filer_selection_changed(view_details
->filer_window
,
949 gtk_get_current_event_time());
952 #define ADD_TEXT_COLUMN(name, model_column) \
953 cell = gtk_cell_renderer_text_new(); \
954 column = gtk_tree_view_column_new_with_attributes(name, cell, \
955 "text", model_column, \
956 "foreground-gdk", COL_COLOUR, \
957 "weight", COL_WEIGHT, \
959 gtk_tree_view_append_column(treeview, column); \
960 g_signal_connect(column->button, "grab-focus", \
961 G_CALLBACK(block_focus), view_details);
963 static void view_details_init(GTypeInstance
*object
, gpointer gclass
)
965 GtkTreeView
*treeview
= (GtkTreeView
*) object
;
966 GtkTreeViewColumn
*column
;
967 GtkCellRenderer
*cell
;
968 GtkTreeSortable
*sortable_list
;
969 ViewDetails
*view_details
= (ViewDetails
*) object
;
971 view_details
->items
= g_ptr_array_new();
972 view_details
->cursor_base
= -1;
973 view_details
->wink_item
= -1;
974 view_details
->desired_size
.width
= -1;
975 view_details
->desired_size
.height
= -1;
976 view_details
->can_change_selection
= 0;
977 view_details
->lasso_box
= FALSE
;
979 view_details
->selection
= gtk_tree_view_get_selection(treeview
);
980 gtk_tree_selection_set_mode(view_details
->selection
,
981 GTK_SELECTION_MULTIPLE
);
982 gtk_tree_selection_set_select_function(view_details
->selection
,
983 test_can_change_selection
, view_details
, NULL
);
984 g_signal_connect(view_details
->selection
, "changed",
985 G_CALLBACK(selection_changed
), view_details
);
988 view_details
->sort_fn
= NULL
;
989 sortable_list
= GTK_TREE_SORTABLE(object
);
991 gtk_tree_view_set_model(treeview
, GTK_TREE_MODEL(view_details
));
994 cell
= cell_icon_new(view_details
);
995 column
= gtk_tree_view_column_new_with_attributes(NULL
, cell
,
996 "item", COL_VIEW_ITEM
,
998 gtk_tree_view_append_column(treeview
, column
);
1000 ADD_TEXT_COLUMN(_("_Name"), COL_LEAF
);
1001 gtk_tree_view_column_set_sort_column_id(column
, COL_LEAF
);
1002 gtk_tree_view_column_set_resizable(column
, TRUE
);
1003 ADD_TEXT_COLUMN(_("_Type"), COL_TYPE
);
1004 gtk_tree_view_column_set_sort_column_id(column
, COL_TYPE
);
1005 ADD_TEXT_COLUMN(_("_Permissions"), COL_PERM
);
1006 ADD_TEXT_COLUMN(_("_Owner"), COL_OWNER
);
1007 gtk_tree_view_column_set_sort_column_id(column
, COL_OWNER
);
1008 ADD_TEXT_COLUMN(_("_Group"), COL_GROUP
);
1009 gtk_tree_view_column_set_sort_column_id(column
, COL_GROUP
);
1010 ADD_TEXT_COLUMN(_("_Size"), COL_SIZE
);
1011 gtk_tree_view_column_set_sort_column_id(column
, COL_SIZE
);
1012 ADD_TEXT_COLUMN(_("Last _Modified"), COL_MTIME
);
1013 gtk_tree_view_column_set_sort_column_id(column
, COL_MTIME
);
1016 /* Create the handers for the View interface */
1017 static void view_details_iface_init(gpointer giface
, gpointer iface_data
)
1019 ViewIfaceClass
*iface
= giface
;
1021 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
1023 /* override stuff */
1024 iface
->sort
= view_details_sort
;
1025 iface
->style_changed
= view_details_style_changed
;
1026 iface
->add_items
= view_details_add_items
;
1027 iface
->update_items
= view_details_update_items
;
1028 iface
->delete_if
= view_details_delete_if
;
1029 iface
->clear
= view_details_clear
;
1030 iface
->select_all
= view_details_select_all
;
1031 iface
->clear_selection
= view_details_clear_selection
;
1032 iface
->count_items
= view_details_count_items
;
1033 iface
->count_selected
= view_details_count_selected
;
1034 iface
->show_cursor
= view_details_show_cursor
;
1035 iface
->get_iter
= view_details_get_iter
;
1036 iface
->get_iter_at_point
= view_details_get_iter_at_point
;
1037 iface
->cursor_to_iter
= view_details_cursor_to_iter
;
1038 iface
->set_selected
= view_details_set_selected
;
1039 iface
->get_selected
= view_details_get_selected
;
1040 iface
->set_frozen
= view_details_set_frozen
;
1041 iface
->select_only
= view_details_select_only
;
1042 iface
->wink_item
= view_details_wink_item
;
1043 iface
->autosize
= view_details_autosize
;
1044 iface
->cursor_visible
= view_details_cursor_visible
;
1045 iface
->set_base
= view_details_set_base
;
1046 iface
->start_lasso_box
= view_details_start_lasso_box
;
1047 iface
->extend_tip
= view_details_extend_tip
;
1048 iface
->auto_scroll_callback
= view_details_auto_scroll_callback
;
1051 /* Implementations of the View interface. See view_iface.c for comments. */
1053 static void view_details_style_changed(ViewIface
*view
, int flags
)
1055 ViewDetails
*view_details
= (ViewDetails
*) view
;
1056 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1058 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
1060 int n
= view_details
->items
->len
;
1062 path
= gtk_tree_path_new();
1063 gtk_tree_path_append_index(path
, 0);
1065 for (i
= 0; i
< n
; i
++)
1068 ViewItem
*item
= items
[i
];
1070 iter
.user_data
= GINT_TO_POINTER(i
);
1073 g_object_unref(G_OBJECT(item
->image
));
1076 gtk_tree_model_row_changed(model
, path
, &iter
);
1077 gtk_tree_path_next(path
);
1080 gtk_tree_path_free(path
);
1082 gtk_tree_view_columns_autosize((GtkTreeView
*) view
);
1084 if (flags
& VIEW_UPDATE_HEADERS
)
1085 details_update_header_visibility(view_details
);
1088 static gint
wrap_sort(gconstpointer a
, gconstpointer b
,
1089 ViewDetails
*view_details
)
1091 ViewItem
*ia
= *(ViewItem
**) a
;
1092 ViewItem
*ib
= *(ViewItem
**) b
;
1094 if (view_details
->filer_window
->sort_order
== GTK_SORT_ASCENDING
)
1095 return view_details
->sort_fn(ia
->item
, ib
->item
);
1097 return -view_details
->sort_fn(ia
->item
, ib
->item
);
1100 static void resort(ViewDetails
*view_details
)
1102 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
1103 gint i
, len
= view_details
->items
->len
;
1106 int wink_item
= view_details
->wink_item
;
1111 for (i
= len
- 1; i
>= 0; i
--)
1112 items
[i
]->old_pos
= i
;
1114 switch (view_details
->filer_window
->sort_type
)
1116 case SORT_NAME
: view_details
->sort_fn
= sort_by_name
; break;
1117 case SORT_TYPE
: view_details
->sort_fn
= sort_by_type
; break;
1118 case SORT_DATE
: view_details
->sort_fn
= sort_by_date
; break;
1119 case SORT_SIZE
: view_details
->sort_fn
= sort_by_size
; break;
1120 case SORT_OWNER
: view_details
->sort_fn
= sort_by_owner
; break;
1121 case SORT_GROUP
: view_details
->sort_fn
= sort_by_group
; break;
1123 g_assert_not_reached();
1126 g_ptr_array_sort_with_data(view_details
->items
,
1127 (GCompareDataFunc
) wrap_sort
,
1130 new_order
= g_new(guint
, len
);
1131 for (i
= len
- 1; i
>= 0; i
--)
1133 new_order
[i
] = items
[i
]->old_pos
;
1134 if (wink_item
== items
[i
]->old_pos
)
1138 view_details
->wink_item
= wink_item
;
1140 path
= gtk_tree_path_new();
1141 gtk_tree_model_rows_reordered((GtkTreeModel
*) view_details
,
1142 path
, NULL
, new_order
);
1143 gtk_tree_path_free(path
);
1147 static void view_details_sort(ViewIface
*view
)
1149 resort((ViewDetails
*) view
);
1150 gtk_tree_sortable_sort_column_changed((GtkTreeSortable
*) view
);
1153 static void view_details_add_items(ViewIface
*view
, GPtrArray
*new_items
)
1155 ViewDetails
*view_details
= (ViewDetails
*) view
;
1156 FilerWindow
*filer_window
= view_details
->filer_window
;
1157 gboolean show_hidden
= filer_window
->show_hidden
;
1158 GPtrArray
*items
= view_details
->items
;
1162 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1164 iter
.user_data
= GINT_TO_POINTER(items
->len
);
1165 path
= details_get_path(model
, &iter
);
1167 for (i
= 0; i
< new_items
->len
; i
++)
1169 DirItem
*item
= (DirItem
*) new_items
->pdata
[i
];
1170 char *leafname
= item
->leafname
;
1173 if (leafname
[0] == '.')
1178 if (leafname
[1] == '\0')
1179 continue; /* Never show '.' */
1181 if (leafname
[1] == '.' &&
1182 leafname
[2] == '\0')
1183 continue; /* Never show '..' */
1186 vitem
= g_new(ViewItem
, 1);
1188 vitem
->image
= NULL
;
1189 if (!g_utf8_validate(leafname
, -1, NULL
))
1190 vitem
->utf8_name
= to_utf8(leafname
);
1192 vitem
->utf8_name
= NULL
;
1194 g_ptr_array_add(items
, vitem
);
1196 iter
.user_data
= GINT_TO_POINTER(items
->len
- 1);
1197 gtk_tree_model_row_inserted(model
, path
, &iter
);
1198 gtk_tree_path_next(path
);
1201 gtk_tree_path_free(path
);
1203 resort(view_details
);
1206 /* Find an item in the sorted array.
1207 * Returns the item number, or -1 if not found.
1209 static int details_find_item(ViewDetails
*view_details
, DirItem
*item
)
1211 ViewItem
**items
, tmp
, *tmpp
;
1214 g_return_val_if_fail(view_details
!= NULL
, -1);
1215 g_return_val_if_fail(item
!= NULL
, -1);
1220 items
= (ViewItem
**) view_details
->items
->pdata
;
1222 /* If item is here, then: lower <= i < upper */
1224 upper
= view_details
->items
->len
;
1226 while (lower
< upper
)
1230 i
= (lower
+ upper
) >> 1;
1232 cmp
= wrap_sort(&items
[i
], &tmpp
, view_details
);
1245 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
)
1247 ViewDetails
*view_details
= (ViewDetails
*) view
;
1248 FilerWindow
*filer_window
= view_details
->filer_window
;
1250 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
1252 g_return_if_fail(items
->len
> 0);
1254 /* The item data has already been modified, so this gives the
1255 * final sort order...
1257 resort(view_details
);
1259 for (i
= 0; i
< items
->len
; i
++)
1261 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1262 const gchar
*leafname
= item
->leafname
;
1265 if (leafname
[0] == '.' && filer_window
->show_hidden
== FALSE
)
1268 j
= details_find_item(view_details
, item
);
1271 g_warning("Failed to find '%s'\n", leafname
);
1276 ViewItem
*view_item
= view_details
->items
->pdata
[j
];
1277 if (view_item
->image
)
1279 g_object_unref(G_OBJECT(view_item
->image
));
1280 view_item
->image
= NULL
;
1282 path
= gtk_tree_path_new();
1283 gtk_tree_path_append_index(path
, j
);
1284 iter
.user_data
= GINT_TO_POINTER(j
);
1285 gtk_tree_model_row_changed(model
, path
, &iter
);
1290 static void view_details_delete_if(ViewIface
*view
,
1291 gboolean (*test
)(gpointer item
, gpointer data
),
1295 ViewDetails
*view_details
= (ViewDetails
*) view
;
1297 GPtrArray
*items
= view_details
->items
;
1298 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1300 path
= gtk_tree_path_new();
1302 gtk_tree_path_append_index(path
, i
);
1304 while (i
< items
->len
)
1306 ViewItem
*item
= items
->pdata
[i
];
1308 if (test(item
->item
, data
))
1310 free_view_item(items
->pdata
[i
]);
1311 g_ptr_array_remove_index(items
, i
);
1312 gtk_tree_model_row_deleted(model
, path
);
1317 gtk_tree_path_next(path
);
1321 gtk_tree_path_free(path
);
1324 static void view_details_clear(ViewIface
*view
)
1327 GPtrArray
*items
= ((ViewDetails
*) view
)->items
;
1328 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1330 path
= gtk_tree_path_new();
1331 gtk_tree_path_append_index(path
, items
->len
);
1333 while (gtk_tree_path_prev(path
))
1334 gtk_tree_model_row_deleted(model
, path
);
1336 g_ptr_array_set_size(items
, 0);
1337 gtk_tree_path_free(path
);
1340 static void view_details_select_all(ViewIface
*view
)
1342 ViewDetails
*view_details
= (ViewDetails
*) view
;
1344 view_details
->can_change_selection
++;
1345 gtk_tree_selection_select_all(view_details
->selection
);
1346 view_details
->can_change_selection
--;
1349 static void view_details_clear_selection(ViewIface
*view
)
1351 ViewDetails
*view_details
= (ViewDetails
*) view
;
1353 view_details
->can_change_selection
++;
1354 gtk_tree_selection_unselect_all(view_details
->selection
);
1355 view_details
->can_change_selection
--;
1358 static int view_details_count_items(ViewIface
*view
)
1360 ViewDetails
*view_details
= (ViewDetails
*) view
;
1362 return view_details
->items
->len
;
1365 #if GTK_MINOR_VERSION < 2
1366 static void view_details_count_inc(GtkTreeModel
*model
, GtkTreePath
*path
,
1367 GtkTreeIter
*iter
, gpointer data
)
1369 int *count
= (int *) data
;
1374 static int view_details_count_selected(ViewIface
*view
)
1376 ViewDetails
*view_details
= (ViewDetails
*) view
;
1378 #if GTK_MINOR_VERSION >= 2
1379 return gtk_tree_selection_count_selected_rows(view_details
->selection
);
1383 gtk_tree_selection_selected_foreach(view_details
->selection
,
1384 view_details_count_inc
, &count
);
1389 static void view_details_show_cursor(ViewIface
*view
)
1393 static void view_details_get_iter(ViewIface
*view
,
1394 ViewIter
*iter
, IterFlags flags
)
1396 make_iter((ViewDetails
*) view
, iter
, flags
);
1399 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
1400 GdkWindow
*src
, int x
, int y
)
1402 ViewDetails
*view_details
= (ViewDetails
*) view
;
1403 GtkTreeModel
*model
;
1404 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1405 GtkTreePath
*path
= NULL
;
1409 model
= gtk_tree_view_get_model(tree
);
1411 if (gtk_tree_view_get_path_at_pos(tree
, x
, y
+ 4, &path
, NULL
,
1414 g_return_if_fail(path
!= NULL
);
1417 i
= gtk_tree_path_get_indices(path
)[0];
1418 gtk_tree_path_free(path
);
1421 make_item_iter(view_details
, iter
, i
);
1424 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
)
1427 ViewDetails
*view_details
= (ViewDetails
*) view
;
1429 path
= gtk_tree_path_new();
1432 gtk_tree_path_append_index(path
, iter
->i
);
1435 /* Using depth zero or index -1 gives an error, but this
1438 gtk_tree_path_append_index(path
, view_details
->items
->len
);
1441 gtk_tree_view_set_cursor((GtkTreeView
*) view
, path
, NULL
, FALSE
);
1442 gtk_tree_path_free(path
);
1445 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
)
1449 iter
.user_data
= GINT_TO_POINTER(i
);
1450 view_details
->can_change_selection
++;
1452 gtk_tree_selection_select_iter(view_details
->selection
, &iter
);
1454 gtk_tree_selection_unselect_iter(view_details
->selection
,
1456 view_details
->can_change_selection
--;
1459 static void view_details_set_selected(ViewIface
*view
,
1463 set_selected((ViewDetails
*) view
, iter
->i
, selected
);
1466 static gboolean
get_selected(ViewDetails
*view_details
, int i
)
1470 iter
.user_data
= GINT_TO_POINTER(i
);
1472 return gtk_tree_selection_iter_is_selected(view_details
->selection
,
1476 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
)
1478 return get_selected((ViewDetails
*) view
, iter
->i
);
1481 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
)
1483 ViewDetails
*view_details
= (ViewDetails
*) view
;
1486 path
= gtk_tree_path_new();
1487 gtk_tree_path_append_index(path
, iter
->i
);
1488 view_details
->can_change_selection
++;
1489 gtk_tree_selection_unselect_all(view_details
->selection
);
1490 gtk_tree_selection_select_range(view_details
->selection
, path
, path
);
1491 view_details
->can_change_selection
--;
1492 gtk_tree_path_free(path
);
1495 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
)
1499 static void redraw_wink_area(ViewDetails
*view_details
)
1501 GtkTreePath
*wink_path
;
1502 GdkRectangle wink_area
;
1503 GtkTreeView
*tree
= (GtkTreeView
*) view_details
;
1505 g_return_if_fail(view_details
->wink_item
>= 0);
1507 wink_path
= gtk_tree_path_new();
1508 gtk_tree_path_append_index(wink_path
, view_details
->wink_item
);
1509 gtk_tree_view_get_background_area(tree
, wink_path
, NULL
, &wink_area
);
1510 gtk_tree_path_free(wink_path
);
1512 if (wink_area
.height
)
1515 window
= gtk_tree_view_get_bin_window(tree
);
1517 wink_area
.width
= GTK_WIDGET(tree
)->allocation
.width
;
1518 gdk_window_invalidate_rect(window
, &wink_area
, FALSE
);
1522 static void cancel_wink(ViewDetails
*view_details
)
1524 if (view_details
->wink_item
== -1)
1527 if (view_details
->filer_window
)
1528 redraw_wink_area(view_details
);
1530 view_details
->wink_item
= -1;
1531 g_source_remove(view_details
->wink_timeout
);
1534 static gboolean
wink_timeout(ViewDetails
*view_details
)
1536 view_details
->wink_step
--;
1537 if (view_details
->wink_step
< 1)
1539 cancel_wink(view_details
);
1543 redraw_wink_area(view_details
);
1548 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
)
1550 ViewDetails
*view_details
= (ViewDetails
*) view
;
1553 cancel_wink(view_details
);
1557 view_details
->wink_item
= iter
->i
;
1558 view_details
->wink_timeout
= g_timeout_add(70,
1559 (GSourceFunc
) wink_timeout
, view_details
);
1560 view_details
->wink_step
= 7;
1561 redraw_wink_area(view_details
);
1563 path
= gtk_tree_path_new();
1564 gtk_tree_path_append_index(path
, iter
->i
);
1565 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view
),
1566 path
, NULL
, FALSE
, 0, 0);
1567 gtk_tree_path_free(path
);
1570 static void view_details_autosize(ViewIface
*view
)
1572 ViewDetails
*view_details
= (ViewDetails
*) view
;
1573 FilerWindow
*filer_window
= view_details
->filer_window
;
1574 int max_width
= (o_filer_size_limit
.int_value
* screen_width
) / 100;
1575 int max_height
= (o_filer_size_limit
.int_value
* screen_height
) / 100;
1579 gtk_widget_queue_resize(GTK_WIDGET(view
));
1580 gtk_widget_size_request(GTK_WIDGET(view
), &req
);
1582 h
= MAX(view_details
->desired_size
.height
, SMALL_HEIGHT
);
1584 filer_window_set_size(filer_window
,
1585 MIN(view_details
->desired_size
.width
, max_width
),
1586 MIN(h
, max_height
));
1589 static gboolean
view_details_cursor_visible(ViewIface
*view
)
1591 GtkTreePath
*path
= NULL
;
1593 gtk_tree_view_get_cursor((GtkTreeView
*) view
, &path
, NULL
);
1596 gtk_tree_path_free(path
);
1598 return path
!= NULL
;
1601 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
)
1603 ViewDetails
*view_details
= (ViewDetails
*) view
;
1605 view_details
->cursor_base
= iter
->i
;
1608 /* Change the dynamic corner of the lasso box and trigger a redraw */
1609 static void set_lasso(ViewDetails
*view_details
, int x
, int y
)
1613 int minx
, miny
, maxx
, maxy
;
1615 if (x
== view_details
->drag_box_x
[1] &&
1616 y
== view_details
->drag_box_y
[1])
1619 /* Get old region */
1620 minx
= MIN(view_details
->drag_box_x
[0], view_details
->drag_box_x
[1]);
1621 miny
= MIN(view_details
->drag_box_y
[0], view_details
->drag_box_y
[1]);
1622 maxx
= MAX(view_details
->drag_box_x
[0], view_details
->drag_box_x
[1]);
1623 maxy
= MAX(view_details
->drag_box_y
[0], view_details
->drag_box_y
[1]);
1625 /* Enlarge to cover new point */
1626 minx
= MIN(minx
, x
);
1627 miny
= MIN(miny
, y
);
1628 maxx
= MAX(maxx
, x
);
1629 maxy
= MAX(maxy
, y
);
1633 area
.width
= maxx
- minx
;
1634 area
.height
= maxy
- miny
;
1636 view_details
->drag_box_x
[1] = x
;
1637 view_details
->drag_box_y
[1] = y
;
1639 window
= gtk_tree_view_get_bin_window((GtkTreeView
*) view_details
);
1640 if (area
.width
&& area
.height
)
1644 adj
= gtk_tree_view_get_vadjustment((GtkTreeView
*)
1646 area
.y
-= adj
->value
;
1647 gdk_window_invalidate_rect(window
, &area
, FALSE
);
1651 static void view_details_start_lasso_box(ViewIface
*view
, GdkEventButton
*event
)
1653 ViewDetails
*view_details
= (ViewDetails
*) view
;
1656 adj
= gtk_tree_view_get_vadjustment((GtkTreeView
*) view_details
);
1658 view_details
->lasso_start_index
= get_lasso_index(view_details
,
1661 filer_set_autoscroll(view_details
->filer_window
, TRUE
);
1663 view_details
->drag_box_x
[0] = view_details
->drag_box_x
[1] = event
->x
;
1664 view_details
->drag_box_y
[0] = view_details
->drag_box_y
[1] = event
->y
+
1666 view_details
->lasso_box
= TRUE
;
1669 static void view_details_extend_tip(ViewIface
*view
,
1670 ViewIter
*iter
, GString
*tip
)
1674 static DirItem
*iter_init(ViewIter
*iter
)
1676 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1678 int n
= view_details
->items
->len
;
1679 int flags
= iter
->flags
;
1681 iter
->peek
= iter_peek
;
1683 if (iter
->n_remaining
== 0)
1686 if (flags
& VIEW_ITER_FROM_CURSOR
)
1689 gtk_tree_view_get_cursor((GtkTreeView
*) view_details
,
1692 return NULL
; /* No cursor */
1693 i
= gtk_tree_path_get_indices(path
)[0];
1694 gtk_tree_path_free(path
);
1696 else if (flags
& VIEW_ITER_FROM_BASE
)
1697 i
= view_details
->cursor_base
;
1699 if (i
< 0 || i
>= n
)
1701 /* Either a normal iteration, or an iteration from an
1702 * invalid starting point.
1704 if (flags
& VIEW_ITER_BACKWARDS
)
1710 if (i
< 0 || i
>= n
)
1711 return NULL
; /* No items at all! */
1713 iter
->next
= flags
& VIEW_ITER_BACKWARDS
? iter_prev
: iter_next
;
1714 iter
->n_remaining
--;
1717 if (flags
& VIEW_ITER_SELECTED
&& !is_selected(view_details
, i
))
1718 return iter
->next(iter
);
1719 return iter
->peek(iter
);
1722 static DirItem
*iter_prev(ViewIter
*iter
)
1724 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1725 int n
= view_details
->items
->len
;
1728 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1730 /* i is the last item returned (always valid) */
1732 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1734 while (iter
->n_remaining
)
1737 iter
->n_remaining
--;
1742 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1744 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1745 !is_selected(view_details
, i
))
1749 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1756 static DirItem
*iter_next(ViewIter
*iter
)
1758 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1759 int n
= view_details
->items
->len
;
1762 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1764 /* i is the last item returned (always valid) */
1766 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1768 while (iter
->n_remaining
)
1771 iter
->n_remaining
--;
1776 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1778 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1779 !is_selected(view_details
, i
))
1783 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1790 static DirItem
*iter_peek(ViewIter
*iter
)
1792 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1793 int n
= view_details
->items
->len
;
1799 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1801 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1804 /* Set the iterator to return 'i' on the next peek().
1805 * If i is -1, returns NULL on next peek().
1807 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
)
1809 make_iter(view_details
, iter
, 0);
1811 g_return_if_fail(i
>= -1 && i
< (int) view_details
->items
->len
);
1814 iter
->next
= iter_next
;
1815 iter
->peek
= iter_peek
;
1816 iter
->n_remaining
= 0;
1819 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
1822 iter
->view
= (ViewIface
*) view_details
;
1823 iter
->next
= iter_init
;
1827 iter
->flags
= flags
;
1829 if (flags
& VIEW_ITER_ONE_ONLY
)
1831 iter
->n_remaining
= 1;
1835 iter
->n_remaining
= view_details
->items
->len
;
1838 static void free_view_item(ViewItem
*view_item
)
1840 if (view_item
->image
)
1841 g_object_unref(G_OBJECT(view_item
->image
));
1842 g_free(view_item
->utf8_name
);
1846 static gboolean
view_details_auto_scroll_callback(ViewIface
*view
)
1848 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1849 ViewDetails
*view_details
= (ViewDetails
*) view
;
1850 FilerWindow
*filer_window
= view_details
->filer_window
;
1851 GtkRange
*scrollbar
= (GtkRange
*) filer_window
->scrollbar
;
1855 GdkModifierType mask
;
1858 window
= gtk_tree_view_get_bin_window(tree
);
1860 gdk_window_get_pointer(window
, &x
, &y
, &mask
);
1861 gdk_drawable_get_size(window
, &w
, NULL
);
1863 adj
= gtk_range_get_adjustment(scrollbar
);
1866 if ((x
< 0 || x
> w
|| y
< 0 || y
> h
) && !view_details
->lasso_box
)
1867 return FALSE
; /* Out of window - stop */
1869 if (y
< AUTOSCROLL_STEP
)
1870 diff
= y
- AUTOSCROLL_STEP
;
1871 else if (y
> h
- AUTOSCROLL_STEP
)
1872 diff
= AUTOSCROLL_STEP
+ y
- h
;
1876 int old
= adj
->value
;
1877 int value
= old
+ diff
;
1879 value
= CLAMP(value
, 0, adj
->upper
- adj
->page_size
);
1880 gtk_adjustment_set_value(adj
, value
);
1882 if (adj
->value
!= old
)