2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
20 /* view_details.c - display a list of files in a TreeView */
25 #include <gdk/gdkkeysyms.h>
29 #include "view_iface.h"
30 #include "view_details.h"
40 #include "gui_support.h"
43 #include "cell_icon.h"
45 /* These are the column numbers in the ListStore */
56 #define COL_VIEW_ITEM 10
59 static gpointer parent_class
= NULL
;
61 struct _ViewDetailsClass
{
62 GtkTreeViewClass parent
;
65 /* Static prototypes */
66 static void view_details_finialize(GObject
*object
);
67 static void view_details_class_init(gpointer gclass
, gpointer data
);
68 static void view_details_init(GTypeInstance
*object
, gpointer gclass
);
70 static void view_details_iface_init(gpointer giface
, gpointer iface_data
);
72 static void view_details_sort(ViewIface
*view
);
73 static void view_details_style_changed(ViewIface
*view
, int flags
);
74 static void view_details_add_items(ViewIface
*view
, GPtrArray
*items
);
75 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
);
76 static void view_details_delete_if(ViewIface
*view
,
77 gboolean (*test
)(gpointer item
, gpointer data
),
79 static void view_details_clear(ViewIface
*view
);
80 static void view_details_select_all(ViewIface
*view
);
81 static void view_details_clear_selection(ViewIface
*view
);
82 static int view_details_count_items(ViewIface
*view
);
83 static int view_details_count_selected(ViewIface
*view
);
84 static void view_details_show_cursor(ViewIface
*view
);
85 static void view_details_get_iter(ViewIface
*view
,
86 ViewIter
*iter
, IterFlags flags
);
87 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
88 GdkWindow
*src
, int x
, int y
);
89 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
90 static void view_details_set_selected(ViewIface
*view
,
93 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
);
94 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
);
95 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
);
96 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
);
97 static void view_details_autosize(ViewIface
*view
);
98 static gboolean
view_details_cursor_visible(ViewIface
*view
);
99 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
);
100 static void view_details_start_lasso_box(ViewIface
*view
,
101 GdkEventButton
*event
);
102 static void view_details_extend_tip(ViewIface
*view
,
103 ViewIter
*iter
, GString
*tip
);
104 static gboolean
view_details_auto_scroll_callback(ViewIface
*view
);
106 static DirItem
*iter_peek(ViewIter
*iter
);
107 static DirItem
*iter_prev(ViewIter
*iter
);
108 static DirItem
*iter_next(ViewIter
*iter
);
109 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
111 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
);
112 static void view_details_tree_model_init(GtkTreeModelIface
*iface
);
113 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
114 gint
*sort_column_id
,
116 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
119 static void details_set_sort_func(GtkTreeSortable
*sortable
,
121 GtkTreeIterCompareFunc func
,
123 GtkDestroyNotify destroy
);
124 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
125 GtkTreeIterCompareFunc func
,
127 GtkDestroyNotify destroy
);
128 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
);
129 static void view_details_sortable_init(GtkTreeSortableIface
*iface
);
130 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
);
131 static gboolean
get_selected(ViewDetails
*view_details
, int i
);
132 static void free_view_item(ViewItem
*view_item
);
133 static void details_update_header_visibility(ViewDetails
*view_details
);
134 static void set_lasso(ViewDetails
*view_details
, int x
, int y
);
135 static void cancel_wink(ViewDetails
*view_details
);
138 /****************************************************************
139 * EXTERNAL INTERFACE *
140 ****************************************************************/
142 GtkWidget
*view_details_new(FilerWindow
*filer_window
)
144 ViewDetails
*view_details
;
146 view_details
= g_object_new(view_details_get_type(), NULL
);
147 view_details
->filer_window
= filer_window
;
149 gtk_range_set_adjustment(GTK_RANGE(filer_window
->scrollbar
),
150 gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(view_details
)));
152 if (filer_window
->sort_type
!= -1)
153 view_details_sort((ViewIface
*) view_details
);
155 details_update_header_visibility(view_details
);
157 return GTK_WIDGET(view_details
);
160 GType
view_details_get_type(void)
162 static GType type
= 0;
166 static const GTypeInfo info
=
168 sizeof (ViewDetailsClass
),
169 NULL
, /* base_init */
170 NULL
, /* base_finalise */
171 view_details_class_init
,
172 NULL
, /* class_finalise */
173 NULL
, /* class_data */
178 static const GInterfaceInfo view_iface_info
= {
179 view_details_iface_init
,
182 static const GInterfaceInfo tree_model_info
= {
183 (GInterfaceInitFunc
) view_details_tree_model_init
,
186 static const GInterfaceInfo sortable_info
= {
187 (GInterfaceInitFunc
) view_details_sortable_init
,
192 type
= g_type_register_static(gtk_tree_view_get_type(),
193 "ViewDetails", &info
, 0);
195 g_type_add_interface_static(type
, VIEW_TYPE_IFACE
,
197 g_type_add_interface_static(type
, GTK_TYPE_TREE_MODEL
,
199 g_type_add_interface_static(type
, GTK_TYPE_TREE_SORTABLE
,
206 /****************************************************************
207 * INTERNAL FUNCTIONS *
208 ****************************************************************/
210 /* Update the visibility of the list headers */
211 static void details_update_header_visibility(ViewDetails
*view_details
)
213 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view_details
),
214 o_display_show_headers
.int_value
);
217 /* Fulfill the GtkTreeModel requirements */
218 static guint
details_get_flags(GtkTreeModel
*tree_model
)
220 return GTK_TREE_MODEL_LIST_ONLY
;
223 static gint
details_get_n_columns(GtkTreeModel
*tree_model
)
228 static GType
details_get_column_type(GtkTreeModel
*tree_model
, gint index
)
230 g_return_val_if_fail(index
< N_COLUMNS
&& index
>= 0, G_TYPE_INVALID
);
232 if (index
== COL_COLOUR
)
233 return GDK_TYPE_COLOR
;
234 else if (index
== COL_ITEM
|| index
== COL_VIEW_ITEM
)
235 return G_TYPE_POINTER
;
236 else if (index
== COL_WEIGHT
)
238 return G_TYPE_STRING
;
241 static gboolean
details_get_iter(GtkTreeModel
*tree_model
,
245 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
248 g_return_val_if_fail(gtk_tree_path_get_depth (path
) > 0, FALSE
);
250 i
= gtk_tree_path_get_indices(path
)[0];
252 if (i
>= view_details
->items
->len
)
255 iter
->user_data
= GINT_TO_POINTER(i
);
260 static GtkTreePath
*details_get_path(GtkTreeModel
*tree_model
,
265 retval
= gtk_tree_path_new();
266 gtk_tree_path_append_index(retval
, GPOINTER_TO_INT(iter
->user_data
));
271 static void details_get_value(GtkTreeModel
*tree_model
,
276 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
278 GPtrArray
*items
= view_details
->items
;
283 g_return_if_fail(column
>= 0 && column
< N_COLUMNS
);
285 i
= GPOINTER_TO_INT(iter
->user_data
);
286 g_return_if_fail(i
>= 0 && i
< items
->len
);
287 view_item
= (ViewItem
*) items
->pdata
[i
];
288 item
= view_item
->item
;
290 if (column
== COL_LEAF
)
292 g_value_init(value
, G_TYPE_STRING
);
293 g_value_set_string(value
,
294 view_item
->utf8_name
? view_item
->utf8_name
298 else if (column
== COL_VIEW_ITEM
)
300 g_value_init(value
, G_TYPE_POINTER
);
301 g_value_set_pointer(value
, view_item
);
304 else if (column
== COL_ITEM
)
306 g_value_init(value
, G_TYPE_POINTER
);
307 g_value_set_pointer(value
, item
);
311 if (item
->base_type
== TYPE_UNKNOWN
)
314 type
= details_get_column_type(tree_model
, column
);
315 g_value_init(value
, type
);
316 if (type
== G_TYPE_STRING
)
317 g_value_set_string(value
, "");
318 else if (type
== GDK_TYPE_COLOR
)
319 g_value_set_boxed(value
, NULL
);
320 else if (type
== G_TYPE_INT
)
321 g_value_set_int(value
, PANGO_WEIGHT_NORMAL
);
323 g_value_set_object(value
, NULL
);
332 g_value_init(value
, G_TYPE_STRING
);
333 g_value_set_string(value
, item
->leafname
);
336 g_value_init(value
, GDK_TYPE_COLOR
);
337 if (view_item
->utf8_name
)
343 g_value_set_boxed(value
, &red
);
346 g_value_set_boxed(value
,
347 type_get_colour(item
, NULL
));
350 g_value_init(value
, G_TYPE_STRING
);
351 g_value_set_string(value
, user_name(item
->uid
));
354 g_value_init(value
, G_TYPE_STRING
);
355 g_value_set_string(value
, group_name(item
->gid
));
360 time
= pretty_time(&item
->mtime
);
361 g_value_init(value
, G_TYPE_STRING
);
362 g_value_set_string(value
, time
);
367 g_value_init(value
, G_TYPE_STRING
);
368 g_value_set_string(value
, pretty_permissions(m
));
371 g_value_init(value
, G_TYPE_STRING
);
372 if (item
->base_type
!= TYPE_DIRECTORY
)
373 g_value_set_string(value
,
374 format_size(item
->size
));
377 g_value_init(value
, G_TYPE_STRING
);
378 if(o_display_show_full_type
.int_value
)
379 g_value_set_string(value
,
380 item
->flags
& ITEM_FLAG_APPDIR
? "Application" :
381 mime_type_comment(item
->mime_type
));
383 g_value_set_string(value
,
384 item
->flags
& ITEM_FLAG_APPDIR
? "App" :
386 S_ISCHR(m
) ? "Char" :
387 S_ISBLK(m
) ? "Blck" :
388 S_ISLNK(m
) ? "Link" :
389 S_ISSOCK(m
) ? "Sock" :
390 S_ISFIFO(m
) ? "Pipe" :
391 S_ISDOOR(m
) ? "Door" :
396 g_value_init(value
, G_TYPE_INT
);
397 if (item
->flags
& ITEM_FLAG_RECENT
)
398 g_value_set_int(value
, PANGO_WEIGHT_BOLD
);
400 g_value_set_int(value
, PANGO_WEIGHT_NORMAL
);
403 g_value_init(value
, G_TYPE_STRING
);
404 g_value_set_string(value
, "Hello");
409 static gboolean
details_iter_next(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
411 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
414 i
= GPOINTER_TO_INT(iter
->user_data
) + 1;
415 iter
->user_data
= GINT_TO_POINTER(i
);
417 return i
< view_details
->items
->len
;
420 static gboolean
details_iter_children(GtkTreeModel
*tree_model
,
424 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
426 /* this is a list, nodes have no children */
430 /* but if parent == NULL we return the list itself as children of the
434 if (view_details
->items
->len
)
436 iter
->user_data
= GINT_TO_POINTER(0);
443 static gboolean
details_iter_has_child(GtkTreeModel
*tree_model
,
449 static gint
details_iter_n_children(GtkTreeModel
*tree_model
, GtkTreeIter
*iter
)
451 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
454 return view_details
->items
->len
;
459 static gboolean
details_iter_nth_child(GtkTreeModel
*tree_model
,
464 ViewDetails
*view_details
= (ViewDetails
*) tree_model
;
469 if (n
>= 0 && n
< view_details
->items
->len
)
471 iter
->user_data
= GINT_TO_POINTER(n
);
478 static gboolean
details_iter_parent(GtkTreeModel
*tree_model
,
485 /* A ViewDetails is both a GtkTreeView and a GtkTreeModel.
486 * The following functions implement the model interface...
489 static void view_details_tree_model_init(GtkTreeModelIface
*iface
)
491 iface
->get_flags
= details_get_flags
;
492 iface
->get_n_columns
= details_get_n_columns
;
493 iface
->get_column_type
= details_get_column_type
;
494 iface
->get_iter
= details_get_iter
;
495 iface
->get_path
= details_get_path
;
496 iface
->get_value
= details_get_value
;
497 iface
->iter_next
= details_iter_next
;
498 iface
->iter_children
= details_iter_children
;
499 iface
->iter_has_child
= details_iter_has_child
;
500 iface
->iter_n_children
= details_iter_n_children
;
501 iface
->iter_nth_child
= details_iter_nth_child
;
502 iface
->iter_parent
= details_iter_parent
;
505 static void view_details_sortable_init(GtkTreeSortableIface
*iface
)
507 iface
->get_sort_column_id
= details_get_sort_column_id
;
508 iface
->set_sort_column_id
= details_set_sort_column_id
;
509 iface
->set_sort_func
= details_set_sort_func
;
510 iface
->set_default_sort_func
= details_set_default_sort_func
;
511 iface
->has_default_sort_func
= details_has_default_sort_func
;
514 static gboolean
details_get_sort_column_id(GtkTreeSortable
*sortable
,
515 gint
*sort_column_id
,
518 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
519 FilerWindow
*filer_window
= view_details
->filer_window
;
523 return FALSE
; /* Not yet initialised */
525 switch (filer_window
->sort_type
)
527 case SORT_NAME
: col
= COL_LEAF
; break;
528 case SORT_TYPE
: col
= COL_TYPE
; break;
529 case SORT_DATE
: col
= COL_MTIME
; break;
530 case SORT_SIZE
: col
= COL_SIZE
; break;
531 case SORT_OWNER
: col
= COL_OWNER
; break;
532 case SORT_GROUP
: col
= COL_GROUP
; break;
534 g_warning("details_get_sort_column_id(): error!");
538 *sort_column_id
= col
;
540 *order
= filer_window
->sort_order
;
544 static void details_set_sort_column_id(GtkTreeSortable
*sortable
,
548 ViewDetails
*view_details
= (ViewDetails
*) sortable
;
549 FilerWindow
*filer_window
= view_details
->filer_window
;
552 return; /* Not yet initialised */
554 switch (sort_column_id
)
557 display_set_sort_type(filer_window
, SORT_NAME
, order
);
560 display_set_sort_type(filer_window
, SORT_SIZE
, order
);
563 display_set_sort_type(filer_window
, SORT_DATE
, order
);
566 display_set_sort_type(filer_window
, SORT_TYPE
, order
);
569 display_set_sort_type(filer_window
, SORT_OWNER
, order
);
572 display_set_sort_type(filer_window
, SORT_GROUP
, order
);
575 g_assert_not_reached();
579 static void details_set_sort_func(GtkTreeSortable
*sortable
,
581 GtkTreeIterCompareFunc func
,
583 GtkDestroyNotify destroy
)
585 g_assert_not_reached();
588 static void details_set_default_sort_func(GtkTreeSortable
*sortable
,
589 GtkTreeIterCompareFunc func
,
591 GtkDestroyNotify destroy
)
593 g_assert_not_reached();
596 static gboolean
details_has_default_sort_func(GtkTreeSortable
*sortable
)
602 /* End of model implementation */
604 static gboolean
is_selected(ViewDetails
*view_details
, int i
)
608 return view_details_get_selected((ViewIface
*) view_details
, &iter
);
611 static gboolean
view_details_scroll(GtkWidget
*widget
, GdkEventScroll
*event
)
613 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
614 GtkTreePath
*path
= NULL
;
616 if (!gtk_tree_view_get_path_at_pos(tree
, 0, 1, &path
, NULL
, NULL
, NULL
))
617 return TRUE
; /* Empty? */
619 if (event
->direction
== GDK_SCROLL_UP
)
620 gtk_tree_path_prev(path
);
621 else if (event
->direction
== GDK_SCROLL_DOWN
)
622 gtk_tree_path_next(path
);
626 gtk_tree_view_scroll_to_cell(tree
, path
, NULL
, TRUE
, 0, 0);
628 gtk_tree_path_free(path
);
632 static gint
view_details_key_press(GtkWidget
*widget
, GdkEventKey
*event
)
634 if (event
->keyval
== GDK_Up
|| event
->keyval
== GDK_Down
||
635 event
->keyval
== GDK_Prior
|| event
->keyval
== GDK_Next
||
636 event
->keyval
== GDK_Home
|| event
->keyval
== GDK_End
) {
637 /* Work around a strange GTK bug that prevents you from moving the cursor
638 * if nothing is selected.
640 if (event
->state
& GDK_CONTROL_MASK
)
642 return GTK_WIDGET_CLASS(parent_class
)->key_press_event(widget
, event
);
646 /* GTK hard-codes the test for CTRL, and won't move the cursor
649 event
->state
|= GDK_CONTROL_MASK
;
650 gtk_propagate_event(widget
, (GdkEvent
*) event
);
657 static gboolean
view_details_button_press(GtkWidget
*widget
,
660 FilerWindow
*filer_window
= ((ViewDetails
*) widget
)->filer_window
;
661 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
663 if (bev
->window
!= gtk_tree_view_get_bin_window(tree
))
664 return GTK_WIDGET_CLASS(parent_class
)->button_press_event(
667 if (dnd_motion_press(widget
, bev
))
668 filer_perform_action(filer_window
, bev
);
673 static int get_lasso_index(ViewDetails
*view_details
, int y
)
675 GtkTreeViewColumn
*column
= NULL
;
676 GtkTreePath
*path
= NULL
;
677 GtkTreeView
*tree
= (GtkTreeView
*) view_details
;
682 y
= 0; /* gtk_tree_view_get_path_at_pos can't handle negatives */
684 if (gtk_tree_view_get_path_at_pos(tree
, 4, y
, &path
,
685 &column
, NULL
, &cell_y
))
688 i
= gtk_tree_path_get_indices(path
)[0];
689 gtk_tree_view_get_cell_area(tree
, path
, column
, &rect
);
690 gtk_tree_path_free(path
);
692 if (2 * cell_y
> rect
.height
)
696 i
= view_details
->items
->len
;
701 static gboolean
select_lasso_cb(ViewIter
*iter
, gpointer data
)
703 int start
= ((int *) data
)[0];
704 int end
= ((int *) data
)[1];
705 GdkFunction fn
= ((int *) data
)[2];
706 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
709 titer
.user_data
= GINT_TO_POINTER(iter
->i
);
711 if (iter
->i
< start
|| iter
->i
>= end
)
712 return gtk_tree_selection_iter_is_selected(
713 view_details
->selection
, &titer
);
718 return !gtk_tree_selection_iter_is_selected(view_details
->selection
,
722 static void select_lasso(ViewDetails
*view_details
, GdkFunction fn
)
727 adj
= gtk_tree_view_get_vadjustment((GtkTreeView
*) view_details
);
729 range
[0] = view_details
->lasso_start_index
;
730 range
[1] = get_lasso_index(view_details
,
731 view_details
->drag_box_y
[1] - adj
->value
);
734 if (range
[0] == range
[1])
736 if (range
[0] > range
[1])
743 view_select_if((ViewIface
*) view_details
, select_lasso_cb
, &range
);
746 static gboolean
view_details_button_release(GtkWidget
*widget
,
749 ViewDetails
*view_details
= (ViewDetails
*) widget
;
750 FilerWindow
*filer_window
= view_details
->filer_window
;
751 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
753 if (bev
->window
!= gtk_tree_view_get_bin_window(tree
))
754 return GTK_WIDGET_CLASS(parent_class
)->button_release_event(
757 if (!dnd_motion_release(bev
))
758 filer_perform_action(filer_window
, bev
);
760 if (motion_buttons_pressed
== 0 && view_details
->lasso_box
)
762 select_lasso(view_details
,
763 bev
->button
== 1 ? GDK_SET
: GDK_INVERT
);
764 filer_set_autoscroll(filer_window
, FALSE
);
765 set_lasso(view_details
,
766 view_details
->drag_box_x
[0],
767 view_details
->drag_box_y
[0]);
768 view_details
->lasso_box
= FALSE
;
774 static gint
view_details_motion_notify(GtkWidget
*widget
, GdkEventMotion
*event
)
776 ViewDetails
*view_details
= (ViewDetails
*) widget
;
777 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
779 if (event
->window
!= gtk_tree_view_get_bin_window(tree
))
780 return GTK_WIDGET_CLASS(parent_class
)->motion_notify_event(
783 if (view_details
->lasso_box
)
786 adj
= gtk_tree_view_get_vadjustment(tree
);
787 set_lasso(view_details
, event
->x
, event
->y
+ adj
->value
);
791 return filer_motion_notify(view_details
->filer_window
, event
);
794 static gboolean
view_details_expose(GtkWidget
*widget
, GdkEventExpose
*event
)
796 GtkTreeView
*tree
= (GtkTreeView
*) widget
;
797 GtkTreePath
*path
= NULL
;
798 GdkRectangle focus_rectangle
;
799 ViewDetails
*view_details
= (ViewDetails
*) widget
;
802 had_cursor
= (GTK_WIDGET_FLAGS(widget
) & GTK_HAS_FOCUS
) != 0;
804 if (view_details
->filer_window
->selection_state
== GTK_STATE_SELECTED
)
805 GTK_WIDGET_SET_FLAGS(widget
, GTK_HAS_FOCUS
);
807 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_HAS_FOCUS
);
808 GTK_WIDGET_CLASS(parent_class
)->expose_event(widget
, event
);
810 GTK_WIDGET_SET_FLAGS(widget
, GTK_HAS_FOCUS
);
812 if (event
->window
!= gtk_tree_view_get_bin_window(tree
))
813 return FALSE
; /* Not the main area */
815 if (view_details
->lasso_box
)
817 int x
, y
, width
, height
;
820 adj
= gtk_tree_view_get_vadjustment(tree
);
821 x
= MIN(view_details
->drag_box_x
[0],
822 view_details
->drag_box_x
[1]);
823 y
= MIN(view_details
->drag_box_y
[0],
824 view_details
->drag_box_y
[1]);
825 width
= abs(view_details
->drag_box_x
[1] -
826 view_details
->drag_box_x
[0]);
827 height
= abs(view_details
->drag_box_y
[1] -
828 view_details
->drag_box_y
[0]);
832 gdk_draw_rectangle(event
->window
,
833 widget
->style
->fg_gc
[GTK_STATE_NORMAL
],
834 FALSE
, x
, y
, width
- 1, height
- 1);
837 if (view_details
->wink_item
!= -1 && view_details
->wink_step
& 1)
839 GtkTreePath
*wink_path
;
840 GdkRectangle wink_area
;
842 wink_path
= gtk_tree_path_new();
843 gtk_tree_path_append_index(wink_path
, view_details
->wink_item
);
844 gtk_tree_view_get_background_area(tree
, wink_path
,
846 gtk_tree_path_free(wink_path
);
848 if (wink_area
.height
)
851 wink_area
.width
= widget
->allocation
.width
;
852 gdk_draw_rectangle(event
->window
,
853 widget
->style
->fg_gc
[GTK_STATE_NORMAL
],
858 wink_area
.height
- 3);
862 gtk_tree_view_get_cursor(tree
, &path
, NULL
);
864 return FALSE
; /* No cursor */
865 gtk_tree_view_get_background_area(tree
, path
, NULL
, &focus_rectangle
);
866 gtk_tree_path_free(path
);
868 if (!focus_rectangle
.height
)
869 return FALSE
; /* Off screen */
871 focus_rectangle
.width
= widget
->allocation
.width
;
873 gtk_paint_focus(widget
->style
,
881 focus_rectangle
.width
,
882 focus_rectangle
.height
);
887 static void view_details_size_request(GtkWidget
*widget
,
888 GtkRequisition
*requisition
)
890 ViewDetails
*view_details
= (ViewDetails
*) widget
;
892 (*GTK_WIDGET_CLASS(parent_class
)->size_request
)(widget
, requisition
);
894 view_details
->desired_size
= *requisition
;
896 requisition
->height
= 50;
897 requisition
->width
= 50;
900 static void view_details_drag_data_received(GtkWidget
*widget
,
901 GdkDragContext
*drag_context
,
902 gint x
, gint y
, GtkSelectionData
*data
, guint info
, guint time
)
904 /* Just here to override annoying default handler */
907 static void view_details_destroy(GtkObject
*obj
)
909 ViewDetails
*view_details
= VIEW_DETAILS(obj
);
911 view_details
->filer_window
= NULL
;
912 cancel_wink(view_details
);
915 static void view_details_finialize(GObject
*object
)
917 ViewDetails
*view_details
= (ViewDetails
*) object
;
919 g_ptr_array_free(view_details
->items
, TRUE
);
920 view_details
->items
= NULL
;
922 G_OBJECT_CLASS(parent_class
)->finalize(object
);
925 static void view_details_class_init(gpointer gclass
, gpointer data
)
927 GObjectClass
*object
= (GObjectClass
*) gclass
;
928 GtkWidgetClass
*widget
= (GtkWidgetClass
*) gclass
;
930 parent_class
= g_type_class_peek_parent(gclass
);
932 object
->finalize
= view_details_finialize
;
933 GTK_OBJECT_CLASS(object
)->destroy
= view_details_destroy
;
935 widget
->scroll_event
= view_details_scroll
;
936 widget
->key_press_event
= view_details_key_press
;
937 widget
->button_press_event
= view_details_button_press
;
938 widget
->button_release_event
= view_details_button_release
;
939 widget
->motion_notify_event
= view_details_motion_notify
;
940 widget
->expose_event
= view_details_expose
;
941 widget
->size_request
= view_details_size_request
;
942 widget
->drag_data_received
= view_details_drag_data_received
;
945 * Add the ViewDetails::mono-font style property.
946 * To use this add something like
949 * ViewDetails::mono-font = "Courier 8"
951 * class "ViewDetails" style "details"
953 * to your ~/.gtkrc-2.0
955 gtk_widget_class_install_style_property(widget
,
956 g_param_spec_string("mono-font",
958 _("Font for displaying mono-spaced text"),
964 static gboolean
block_focus(GtkWidget
*button
, GtkDirectionType dir
,
965 ViewDetails
*view_details
)
967 GTK_WIDGET_UNSET_FLAGS(button
, GTK_CAN_FOCUS
);
971 static gboolean
test_can_change_selection(GtkTreeSelection
*sel
,
974 gboolean path_currently_selected
,
977 ViewDetails
*view_details
;
979 view_details
= VIEW_DETAILS(gtk_tree_selection_get_tree_view(sel
));
981 return view_details
->can_change_selection
!= 0;
984 static void selection_changed(GtkTreeSelection
*selection
,
987 ViewDetails
*view_details
= VIEW_DETAILS(user_data
);
989 filer_selection_changed(view_details
->filer_window
,
990 gtk_get_current_event_time());
994 * Set the font used for a treeview column to that given for the
995 * "mono-font" style property of a widget. This has to be done _after_ the
996 * widget has been realized, because that is when the style information is
997 * set up. This is done by connecting this function to run after the
1000 static void set_column_mono_font(GtkWidget
*widget
, GObject
*object
)
1002 const gchar
*font_name
;
1004 gtk_widget_style_get(widget
, "mono-font", &font_name
, NULL
);
1005 g_object_set(object
, "font", font_name
, NULL
);
1008 #define ADD_TEXT_COLUMN(name, model_column) \
1009 cell = gtk_cell_renderer_text_new(); \
1010 column = gtk_tree_view_column_new_with_attributes(name, cell, \
1011 "text", model_column, \
1012 "foreground-gdk", COL_COLOUR, \
1013 "weight", COL_WEIGHT, \
1015 gtk_tree_view_append_column(treeview, column); \
1016 g_signal_connect(column->button, "grab-focus", \
1017 G_CALLBACK(block_focus), view_details);
1019 static void view_details_init(GTypeInstance
*object
, gpointer gclass
)
1021 GtkTreeView
*treeview
= (GtkTreeView
*) object
;
1022 GtkTreeViewColumn
*column
;
1023 GtkCellRenderer
*cell
;
1024 GtkTreeSortable
*sortable_list
;
1025 ViewDetails
*view_details
= (ViewDetails
*) object
;
1027 view_details
->items
= g_ptr_array_new();
1028 view_details
->cursor_base
= -1;
1029 view_details
->wink_item
= -1;
1030 view_details
->desired_size
.width
= -1;
1031 view_details
->desired_size
.height
= -1;
1032 view_details
->can_change_selection
= 0;
1033 view_details
->lasso_box
= FALSE
;
1035 view_details
->selection
= gtk_tree_view_get_selection(treeview
);
1036 gtk_tree_selection_set_mode(view_details
->selection
,
1037 GTK_SELECTION_MULTIPLE
);
1038 gtk_tree_selection_set_select_function(view_details
->selection
,
1039 test_can_change_selection
, view_details
, NULL
);
1042 view_details
->sort_fn
= NULL
;
1043 sortable_list
= GTK_TREE_SORTABLE(object
);
1045 gtk_tree_view_set_model(treeview
, GTK_TREE_MODEL(view_details
));
1046 /* Do this after set_model, because that can generate this
1049 g_signal_connect(view_details
->selection
, "changed",
1050 G_CALLBACK(selection_changed
), view_details
);
1053 cell
= cell_icon_new(view_details
);
1054 column
= gtk_tree_view_column_new_with_attributes(NULL
, cell
,
1055 "item", COL_VIEW_ITEM
,
1057 gtk_tree_view_append_column(treeview
, column
);
1059 ADD_TEXT_COLUMN(_("_Name"), COL_LEAF
);
1060 gtk_tree_view_column_set_sort_column_id(column
, COL_LEAF
);
1061 gtk_tree_view_column_set_resizable(column
, TRUE
);
1062 ADD_TEXT_COLUMN(_("_Type"), COL_TYPE
);
1063 gtk_tree_view_column_set_sort_column_id(column
, COL_TYPE
);
1064 gtk_tree_view_column_set_resizable(column
, TRUE
);
1065 ADD_TEXT_COLUMN(_("_Permissions"), COL_PERM
);
1066 g_object_set(G_OBJECT(cell
), "font", "monospace", NULL
);
1067 g_signal_connect_after(object
, "realize",
1068 G_CALLBACK(set_column_mono_font
),
1070 ADD_TEXT_COLUMN(_("_Owner"), COL_OWNER
);
1071 gtk_tree_view_column_set_sort_column_id(column
, COL_OWNER
);
1072 ADD_TEXT_COLUMN(_("_Group"), COL_GROUP
);
1073 gtk_tree_view_column_set_sort_column_id(column
, COL_GROUP
);
1074 ADD_TEXT_COLUMN(_("_Size"), COL_SIZE
);
1075 g_object_set(G_OBJECT(cell
), "xalign", 1.0, "font", "monospace", NULL
);
1076 g_signal_connect_after(object
, "realize",
1077 G_CALLBACK(set_column_mono_font
),
1079 gtk_tree_view_column_set_sort_column_id(column
, COL_SIZE
);
1080 ADD_TEXT_COLUMN(_("Last _Modified"), COL_MTIME
);
1081 gtk_tree_view_column_set_sort_column_id(column
, COL_MTIME
);
1084 /* Create the handers for the View interface */
1085 static void view_details_iface_init(gpointer giface
, gpointer iface_data
)
1087 ViewIfaceClass
*iface
= giface
;
1089 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
1091 /* override stuff */
1092 iface
->sort
= view_details_sort
;
1093 iface
->style_changed
= view_details_style_changed
;
1094 iface
->add_items
= view_details_add_items
;
1095 iface
->update_items
= view_details_update_items
;
1096 iface
->delete_if
= view_details_delete_if
;
1097 iface
->clear
= view_details_clear
;
1098 iface
->select_all
= view_details_select_all
;
1099 iface
->clear_selection
= view_details_clear_selection
;
1100 iface
->count_items
= view_details_count_items
;
1101 iface
->count_selected
= view_details_count_selected
;
1102 iface
->show_cursor
= view_details_show_cursor
;
1103 iface
->get_iter
= view_details_get_iter
;
1104 iface
->get_iter_at_point
= view_details_get_iter_at_point
;
1105 iface
->cursor_to_iter
= view_details_cursor_to_iter
;
1106 iface
->set_selected
= view_details_set_selected
;
1107 iface
->get_selected
= view_details_get_selected
;
1108 iface
->set_frozen
= view_details_set_frozen
;
1109 iface
->select_only
= view_details_select_only
;
1110 iface
->wink_item
= view_details_wink_item
;
1111 iface
->autosize
= view_details_autosize
;
1112 iface
->cursor_visible
= view_details_cursor_visible
;
1113 iface
->set_base
= view_details_set_base
;
1114 iface
->start_lasso_box
= view_details_start_lasso_box
;
1115 iface
->extend_tip
= view_details_extend_tip
;
1116 iface
->auto_scroll_callback
= view_details_auto_scroll_callback
;
1119 /* Implementations of the View interface. See view_iface.c for comments. */
1121 static void view_details_style_changed(ViewIface
*view
, int flags
)
1123 ViewDetails
*view_details
= (ViewDetails
*) view
;
1124 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1126 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
1128 int n
= view_details
->items
->len
;
1130 path
= gtk_tree_path_new();
1131 gtk_tree_path_append_index(path
, 0);
1133 for (i
= 0; i
< n
; i
++)
1136 ViewItem
*item
= items
[i
];
1138 iter
.user_data
= GINT_TO_POINTER(i
);
1141 g_object_unref(G_OBJECT(item
->image
));
1144 gtk_tree_model_row_changed(model
, path
, &iter
);
1145 gtk_tree_path_next(path
);
1148 gtk_tree_path_free(path
);
1150 gtk_tree_view_columns_autosize((GtkTreeView
*) view
);
1152 if (flags
& VIEW_UPDATE_HEADERS
)
1153 details_update_header_visibility(view_details
);
1156 static gint
wrap_sort(gconstpointer a
, gconstpointer b
,
1157 ViewDetails
*view_details
)
1159 ViewItem
*ia
= *(ViewItem
**) a
;
1160 ViewItem
*ib
= *(ViewItem
**) b
;
1162 if (view_details
->filer_window
->sort_order
== GTK_SORT_ASCENDING
)
1163 return view_details
->sort_fn(ia
->item
, ib
->item
);
1165 return -view_details
->sort_fn(ia
->item
, ib
->item
);
1168 static void resort(ViewDetails
*view_details
)
1170 ViewItem
**items
= (ViewItem
**) view_details
->items
->pdata
;
1171 gint i
, len
= view_details
->items
->len
;
1174 int wink_item
= view_details
->wink_item
;
1179 for (i
= len
- 1; i
>= 0; i
--)
1180 items
[i
]->old_pos
= i
;
1182 switch (view_details
->filer_window
->sort_type
)
1184 case SORT_NAME
: view_details
->sort_fn
= sort_by_name
; break;
1185 case SORT_TYPE
: view_details
->sort_fn
= sort_by_type
; break;
1186 case SORT_DATE
: view_details
->sort_fn
= sort_by_date
; break;
1187 case SORT_SIZE
: view_details
->sort_fn
= sort_by_size
; break;
1188 case SORT_OWNER
: view_details
->sort_fn
= sort_by_owner
; break;
1189 case SORT_GROUP
: view_details
->sort_fn
= sort_by_group
; break;
1191 g_assert_not_reached();
1194 g_ptr_array_sort_with_data(view_details
->items
,
1195 (GCompareDataFunc
) wrap_sort
,
1198 new_order
= g_new(guint
, len
);
1199 for (i
= len
- 1; i
>= 0; i
--)
1201 new_order
[i
] = items
[i
]->old_pos
;
1202 if (wink_item
== items
[i
]->old_pos
)
1206 view_details
->wink_item
= wink_item
;
1208 path
= gtk_tree_path_new();
1209 gtk_tree_model_rows_reordered((GtkTreeModel
*) view_details
,
1210 path
, NULL
, new_order
);
1211 gtk_tree_path_free(path
);
1215 static void view_details_sort(ViewIface
*view
)
1217 resort((ViewDetails
*) view
);
1218 gtk_tree_sortable_sort_column_changed((GtkTreeSortable
*) view
);
1221 static void view_details_add_items(ViewIface
*view
, GPtrArray
*new_items
)
1223 ViewDetails
*view_details
= (ViewDetails
*) view
;
1224 FilerWindow
*filer_window
= view_details
->filer_window
;
1225 GPtrArray
*items
= view_details
->items
;
1229 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1231 iter
.user_data
= GINT_TO_POINTER(items
->len
);
1232 path
= details_get_path(model
, &iter
);
1234 for (i
= 0; i
< new_items
->len
; i
++)
1236 DirItem
*item
= (DirItem
*) new_items
->pdata
[i
];
1237 char *leafname
= item
->leafname
;
1240 if(!filer_match_filter(filer_window
, item
))
1242 if (leafname
[0] == '.')
1244 if (leafname
[1] == '\0')
1245 continue; /* Never show '.' */
1247 if (leafname
[1] == '.' &&
1248 leafname
[2] == '\0')
1249 continue; /* Never show '..' */
1252 vitem
= g_new(ViewItem
, 1);
1254 vitem
->image
= NULL
;
1255 if (!g_utf8_validate(leafname
, -1, NULL
))
1256 vitem
->utf8_name
= to_utf8(leafname
);
1258 vitem
->utf8_name
= NULL
;
1260 g_ptr_array_add(items
, vitem
);
1262 iter
.user_data
= GINT_TO_POINTER(items
->len
- 1);
1263 gtk_tree_model_row_inserted(model
, path
, &iter
);
1264 gtk_tree_path_next(path
);
1267 gtk_tree_path_free(path
);
1269 resort(view_details
);
1272 /* Find an item in the sorted array.
1273 * Returns the item number, or -1 if not found.
1275 static int details_find_item(ViewDetails
*view_details
, DirItem
*item
)
1277 ViewItem
**items
, tmp
, *tmpp
;
1280 g_return_val_if_fail(view_details
!= NULL
, -1);
1281 g_return_val_if_fail(item
!= NULL
, -1);
1286 items
= (ViewItem
**) view_details
->items
->pdata
;
1288 /* If item is here, then: lower <= i < upper */
1290 upper
= view_details
->items
->len
;
1292 while (lower
< upper
)
1296 i
= (lower
+ upper
) >> 1;
1298 cmp
= wrap_sort(&items
[i
], &tmpp
, view_details
);
1311 static void view_details_update_items(ViewIface
*view
, GPtrArray
*items
)
1313 ViewDetails
*view_details
= (ViewDetails
*) view
;
1314 FilerWindow
*filer_window
= view_details
->filer_window
;
1316 GtkTreeModel
*model
= (GtkTreeModel
*) view_details
;
1318 g_return_if_fail(items
->len
> 0);
1320 /* The item data has already been modified, so this gives the
1321 * final sort order...
1323 resort(view_details
);
1325 for (i
= 0; i
< items
->len
; i
++)
1327 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1328 const gchar
*leafname
= item
->leafname
;
1331 if (!filer_match_filter(filer_window
, item
))
1334 j
= details_find_item(view_details
, item
);
1337 g_warning("Failed to find '%s'\n", leafname
);
1342 ViewItem
*view_item
= view_details
->items
->pdata
[j
];
1343 if (view_item
->image
)
1345 g_object_unref(G_OBJECT(view_item
->image
));
1346 view_item
->image
= NULL
;
1348 path
= gtk_tree_path_new();
1349 gtk_tree_path_append_index(path
, j
);
1350 iter
.user_data
= GINT_TO_POINTER(j
);
1351 gtk_tree_model_row_changed(model
, path
, &iter
);
1356 static void view_details_delete_if(ViewIface
*view
,
1357 gboolean (*test
)(gpointer item
, gpointer data
),
1361 ViewDetails
*view_details
= (ViewDetails
*) view
;
1363 GPtrArray
*items
= view_details
->items
;
1364 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1366 path
= gtk_tree_path_new();
1368 gtk_tree_path_append_index(path
, i
);
1370 while (i
< items
->len
)
1372 ViewItem
*item
= items
->pdata
[i
];
1374 if (test(item
->item
, data
))
1376 free_view_item(items
->pdata
[i
]);
1377 g_ptr_array_remove_index(items
, i
);
1378 gtk_tree_model_row_deleted(model
, path
);
1383 gtk_tree_path_next(path
);
1387 gtk_tree_path_free(path
);
1390 static void view_details_clear(ViewIface
*view
)
1393 GPtrArray
*items
= ((ViewDetails
*) view
)->items
;
1394 GtkTreeModel
*model
= (GtkTreeModel
*) view
;
1396 path
= gtk_tree_path_new();
1397 gtk_tree_path_append_index(path
, items
->len
);
1399 while (gtk_tree_path_prev(path
))
1400 gtk_tree_model_row_deleted(model
, path
);
1402 g_ptr_array_set_size(items
, 0);
1403 gtk_tree_path_free(path
);
1406 static void view_details_select_all(ViewIface
*view
)
1408 ViewDetails
*view_details
= (ViewDetails
*) view
;
1410 view_details
->can_change_selection
++;
1411 gtk_tree_selection_select_all(view_details
->selection
);
1412 view_details
->can_change_selection
--;
1415 static void view_details_clear_selection(ViewIface
*view
)
1417 ViewDetails
*view_details
= (ViewDetails
*) view
;
1419 view_details
->can_change_selection
++;
1420 gtk_tree_selection_unselect_all(view_details
->selection
);
1421 view_details
->can_change_selection
--;
1424 static int view_details_count_items(ViewIface
*view
)
1426 ViewDetails
*view_details
= (ViewDetails
*) view
;
1428 return view_details
->items
->len
;
1431 #if GTK_MINOR_VERSION < 2
1432 static void view_details_count_inc(GtkTreeModel
*model
, GtkTreePath
*path
,
1433 GtkTreeIter
*iter
, gpointer data
)
1435 int *count
= (int *) data
;
1440 static int view_details_count_selected(ViewIface
*view
)
1442 ViewDetails
*view_details
= (ViewDetails
*) view
;
1444 #if GTK_MINOR_VERSION >= 2
1445 return gtk_tree_selection_count_selected_rows(view_details
->selection
);
1449 gtk_tree_selection_selected_foreach(view_details
->selection
,
1450 view_details_count_inc
, &count
);
1455 static void view_details_show_cursor(ViewIface
*view
)
1459 static void view_details_get_iter(ViewIface
*view
,
1460 ViewIter
*iter
, IterFlags flags
)
1462 make_iter((ViewDetails
*) view
, iter
, flags
);
1465 static void view_details_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
1466 GdkWindow
*src
, int x
, int y
)
1468 ViewDetails
*view_details
= (ViewDetails
*) view
;
1469 GtkTreeModel
*model
;
1470 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1471 GtkTreePath
*path
= NULL
;
1475 model
= gtk_tree_view_get_model(tree
);
1477 if (gtk_tree_view_get_path_at_pos(tree
, x
, y
+ 4, &path
, NULL
,
1480 g_return_if_fail(path
!= NULL
);
1483 i
= gtk_tree_path_get_indices(path
)[0];
1484 gtk_tree_path_free(path
);
1487 make_item_iter(view_details
, iter
, i
);
1490 static void view_details_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
)
1493 ViewDetails
*view_details
= (ViewDetails
*) view
;
1495 path
= gtk_tree_path_new();
1498 gtk_tree_path_append_index(path
, iter
->i
);
1501 /* Using depth zero or index -1 gives an error, but this
1504 gtk_tree_path_append_index(path
, view_details
->items
->len
);
1507 gtk_tree_view_set_cursor((GtkTreeView
*) view
, path
, NULL
, FALSE
);
1508 gtk_tree_path_free(path
);
1511 static void set_selected(ViewDetails
*view_details
, int i
, gboolean selected
)
1515 iter
.user_data
= GINT_TO_POINTER(i
);
1516 view_details
->can_change_selection
++;
1518 gtk_tree_selection_select_iter(view_details
->selection
, &iter
);
1520 gtk_tree_selection_unselect_iter(view_details
->selection
,
1522 view_details
->can_change_selection
--;
1525 static void view_details_set_selected(ViewIface
*view
,
1529 set_selected((ViewDetails
*) view
, iter
->i
, selected
);
1532 static gboolean
get_selected(ViewDetails
*view_details
, int i
)
1536 iter
.user_data
= GINT_TO_POINTER(i
);
1538 return gtk_tree_selection_iter_is_selected(view_details
->selection
,
1542 static gboolean
view_details_get_selected(ViewIface
*view
, ViewIter
*iter
)
1544 return get_selected((ViewDetails
*) view
, iter
->i
);
1547 static void view_details_select_only(ViewIface
*view
, ViewIter
*iter
)
1549 ViewDetails
*view_details
= (ViewDetails
*) view
;
1552 path
= gtk_tree_path_new();
1553 gtk_tree_path_append_index(path
, iter
->i
);
1554 view_details
->can_change_selection
++;
1555 gtk_tree_selection_unselect_all(view_details
->selection
);
1556 gtk_tree_selection_select_range(view_details
->selection
, path
, path
);
1557 view_details
->can_change_selection
--;
1558 gtk_tree_path_free(path
);
1561 static void view_details_set_frozen(ViewIface
*view
, gboolean frozen
)
1565 static void redraw_wink_area(ViewDetails
*view_details
)
1567 GtkTreePath
*wink_path
;
1568 GdkRectangle wink_area
;
1569 GtkTreeView
*tree
= (GtkTreeView
*) view_details
;
1571 g_return_if_fail(view_details
->wink_item
>= 0);
1573 wink_path
= gtk_tree_path_new();
1574 gtk_tree_path_append_index(wink_path
, view_details
->wink_item
);
1575 gtk_tree_view_get_background_area(tree
, wink_path
, NULL
, &wink_area
);
1576 gtk_tree_path_free(wink_path
);
1578 if (wink_area
.height
)
1581 window
= gtk_tree_view_get_bin_window(tree
);
1583 wink_area
.width
= GTK_WIDGET(tree
)->allocation
.width
;
1584 gdk_window_invalidate_rect(window
, &wink_area
, FALSE
);
1588 static void cancel_wink(ViewDetails
*view_details
)
1590 if (view_details
->wink_item
== -1)
1593 if (view_details
->filer_window
)
1594 redraw_wink_area(view_details
);
1596 view_details
->wink_item
= -1;
1597 g_source_remove(view_details
->wink_timeout
);
1600 static gboolean
wink_timeout(ViewDetails
*view_details
)
1602 view_details
->wink_step
--;
1603 if (view_details
->wink_step
< 1)
1605 cancel_wink(view_details
);
1609 redraw_wink_area(view_details
);
1614 static void view_details_wink_item(ViewIface
*view
, ViewIter
*iter
)
1616 ViewDetails
*view_details
= (ViewDetails
*) view
;
1619 cancel_wink(view_details
);
1623 view_details
->wink_item
= iter
->i
;
1624 view_details
->wink_timeout
= g_timeout_add(70,
1625 (GSourceFunc
) wink_timeout
, view_details
);
1626 view_details
->wink_step
= 7;
1627 redraw_wink_area(view_details
);
1629 path
= gtk_tree_path_new();
1630 gtk_tree_path_append_index(path
, iter
->i
);
1631 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view
),
1632 path
, NULL
, FALSE
, 0, 0);
1633 gtk_tree_path_free(path
);
1636 static void view_details_autosize(ViewIface
*view
)
1638 ViewDetails
*view_details
= (ViewDetails
*) view
;
1639 FilerWindow
*filer_window
= view_details
->filer_window
;
1640 int max_width
= (o_filer_size_limit
.int_value
* monitor_width
) / 100;
1641 int max_height
= (o_filer_size_limit
.int_value
* monitor_height
) / 100;
1645 gtk_widget_queue_resize(GTK_WIDGET(view
));
1646 gtk_widget_size_request(GTK_WIDGET(view
), &req
);
1648 h
= MAX(view_details
->desired_size
.height
, SMALL_HEIGHT
);
1650 filer_window_set_size(filer_window
,
1651 MIN(view_details
->desired_size
.width
, max_width
),
1652 MIN(h
, max_height
));
1655 static gboolean
view_details_cursor_visible(ViewIface
*view
)
1657 GtkTreePath
*path
= NULL
;
1659 gtk_tree_view_get_cursor((GtkTreeView
*) view
, &path
, NULL
);
1662 gtk_tree_path_free(path
);
1664 return path
!= NULL
;
1667 static void view_details_set_base(ViewIface
*view
, ViewIter
*iter
)
1669 ViewDetails
*view_details
= (ViewDetails
*) view
;
1671 view_details
->cursor_base
= iter
->i
;
1674 /* Change the dynamic corner of the lasso box and trigger a redraw */
1675 static void set_lasso(ViewDetails
*view_details
, int x
, int y
)
1679 int minx
, miny
, maxx
, maxy
;
1681 if (x
== view_details
->drag_box_x
[1] &&
1682 y
== view_details
->drag_box_y
[1])
1685 /* Get old region */
1686 minx
= MIN(view_details
->drag_box_x
[0], view_details
->drag_box_x
[1]);
1687 miny
= MIN(view_details
->drag_box_y
[0], view_details
->drag_box_y
[1]);
1688 maxx
= MAX(view_details
->drag_box_x
[0], view_details
->drag_box_x
[1]);
1689 maxy
= MAX(view_details
->drag_box_y
[0], view_details
->drag_box_y
[1]);
1691 /* Enlarge to cover new point */
1692 minx
= MIN(minx
, x
);
1693 miny
= MIN(miny
, y
);
1694 maxx
= MAX(maxx
, x
);
1695 maxy
= MAX(maxy
, y
);
1699 area
.width
= maxx
- minx
;
1700 area
.height
= maxy
- miny
;
1702 view_details
->drag_box_x
[1] = x
;
1703 view_details
->drag_box_y
[1] = y
;
1705 window
= gtk_tree_view_get_bin_window((GtkTreeView
*) view_details
);
1706 if (area
.width
&& area
.height
)
1710 adj
= gtk_tree_view_get_vadjustment((GtkTreeView
*)
1712 area
.y
-= adj
->value
;
1713 gdk_window_invalidate_rect(window
, &area
, FALSE
);
1717 static void view_details_start_lasso_box(ViewIface
*view
, GdkEventButton
*event
)
1719 ViewDetails
*view_details
= (ViewDetails
*) view
;
1722 adj
= gtk_tree_view_get_vadjustment((GtkTreeView
*) view_details
);
1724 view_details
->lasso_start_index
= get_lasso_index(view_details
,
1727 filer_set_autoscroll(view_details
->filer_window
, TRUE
);
1729 view_details
->drag_box_x
[0] = view_details
->drag_box_x
[1] = event
->x
;
1730 view_details
->drag_box_y
[0] = view_details
->drag_box_y
[1] = event
->y
+
1732 view_details
->lasso_box
= TRUE
;
1735 static void view_details_extend_tip(ViewIface
*view
,
1736 ViewIter
*iter
, GString
*tip
)
1740 static DirItem
*iter_init(ViewIter
*iter
)
1742 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1744 int n
= view_details
->items
->len
;
1745 int flags
= iter
->flags
;
1747 iter
->peek
= iter_peek
;
1749 if (iter
->n_remaining
== 0)
1752 if (flags
& VIEW_ITER_FROM_CURSOR
)
1755 gtk_tree_view_get_cursor((GtkTreeView
*) view_details
,
1758 return NULL
; /* No cursor */
1759 i
= gtk_tree_path_get_indices(path
)[0];
1760 gtk_tree_path_free(path
);
1762 else if (flags
& VIEW_ITER_FROM_BASE
)
1763 i
= view_details
->cursor_base
;
1765 if (i
< 0 || i
>= n
)
1767 /* Either a normal iteration, or an iteration from an
1768 * invalid starting point.
1770 if (flags
& VIEW_ITER_BACKWARDS
)
1776 if (i
< 0 || i
>= n
)
1777 return NULL
; /* No items at all! */
1779 iter
->next
= flags
& VIEW_ITER_BACKWARDS
? iter_prev
: iter_next
;
1780 iter
->n_remaining
--;
1783 if (flags
& VIEW_ITER_SELECTED
&& !is_selected(view_details
, i
))
1784 return iter
->next(iter
);
1785 return iter
->peek(iter
);
1788 static DirItem
*iter_prev(ViewIter
*iter
)
1790 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1791 int n
= view_details
->items
->len
;
1794 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1796 /* i is the last item returned (always valid) */
1798 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1800 while (iter
->n_remaining
)
1803 iter
->n_remaining
--;
1808 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1810 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1811 !is_selected(view_details
, i
))
1815 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1822 static DirItem
*iter_next(ViewIter
*iter
)
1824 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1825 int n
= view_details
->items
->len
;
1828 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1830 /* i is the last item returned (always valid) */
1832 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1834 while (iter
->n_remaining
)
1837 iter
->n_remaining
--;
1842 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1844 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1845 !is_selected(view_details
, i
))
1849 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1856 static DirItem
*iter_peek(ViewIter
*iter
)
1858 ViewDetails
*view_details
= (ViewDetails
*) iter
->view
;
1859 int n
= view_details
->items
->len
;
1865 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1867 return ((ViewItem
*) view_details
->items
->pdata
[i
])->item
;
1870 /* Set the iterator to return 'i' on the next peek().
1871 * If i is -1, returns NULL on next peek().
1873 static void make_item_iter(ViewDetails
*view_details
, ViewIter
*iter
, int i
)
1875 make_iter(view_details
, iter
, 0);
1877 g_return_if_fail(i
>= -1 && i
< (int) view_details
->items
->len
);
1880 iter
->next
= iter_next
;
1881 iter
->peek
= iter_peek
;
1882 iter
->n_remaining
= 0;
1885 static void make_iter(ViewDetails
*view_details
, ViewIter
*iter
,
1888 iter
->view
= (ViewIface
*) view_details
;
1889 iter
->next
= iter_init
;
1893 iter
->flags
= flags
;
1895 if (flags
& VIEW_ITER_ONE_ONLY
)
1897 iter
->n_remaining
= 1;
1901 iter
->n_remaining
= view_details
->items
->len
;
1904 static void free_view_item(ViewItem
*view_item
)
1906 if (view_item
->image
)
1907 g_object_unref(G_OBJECT(view_item
->image
));
1908 g_free(view_item
->utf8_name
);
1912 static gboolean
view_details_auto_scroll_callback(ViewIface
*view
)
1914 GtkTreeView
*tree
= (GtkTreeView
*) view
;
1915 ViewDetails
*view_details
= (ViewDetails
*) view
;
1916 FilerWindow
*filer_window
= view_details
->filer_window
;
1917 GtkRange
*scrollbar
= (GtkRange
*) filer_window
->scrollbar
;
1921 GdkModifierType mask
;
1924 window
= gtk_tree_view_get_bin_window(tree
);
1926 gdk_window_get_pointer(window
, &x
, &y
, &mask
);
1927 gdk_drawable_get_size(window
, &w
, NULL
);
1929 adj
= gtk_range_get_adjustment(scrollbar
);
1932 if ((x
< 0 || x
> w
|| y
< 0 || y
> h
) && !view_details
->lasso_box
)
1933 return FALSE
; /* Out of window - stop */
1935 if (y
< AUTOSCROLL_STEP
)
1936 diff
= y
- AUTOSCROLL_STEP
;
1937 else if (y
> h
- AUTOSCROLL_STEP
)
1938 diff
= AUTOSCROLL_STEP
+ y
- h
;
1942 int old
= adj
->value
;
1943 int value
= old
+ diff
;
1945 value
= CLAMP(value
, 0, adj
->upper
- adj
->page_size
);
1946 gtk_adjustment_set_value(adj
, value
);
1948 if (adj
->value
!= old
)