4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2005, 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_iface.c - operations supported by all views */
30 #include "view_iface.h"
33 /* A word about interfaces:
35 * gobject's documentation's explanation of interfaces leaves something[1] to
36 * be desired, so I'd better explain here...
38 * [1] Like, eg, an explanation.
40 * A ViewIfaceClass is a struct which contains a number of function
41 * pointers. Each class that implements the View interface creates its
42 * own ViewIfaceClass with pointers to its implementation. This is stored
45 * When you want to call a method (eg, sort()) on a View, you call
46 * view_sort(object) here, which gets the class of object and then looks
47 * for that class's implementation of the View interface, and then calls
48 * the actual function through that.
53 * A ViewIter is used to index items. They are usually allocated
54 * on the stack and then initialised using view_get_iter().
56 * Normally, an iterator starts off not pointing at any item, but
57 * each call to iter->next(iter) returns the next item, and leaves
58 * the iterator pointing at the returned item. If you like the item,
59 * you can then pass the iterator to view_cursor_to_iter(), etc.
61 * Using flags passed to view_get_iter, you can start the sequence from the
62 * beginning, end, cursor or 'base' (a saved cursor position). You can
63 * go forwards or backwards. You can opt to only get selected items returned.
65 * You can also have one-shot iterators which already point to an item, and
66 * you never call the next method (view_get_cursor, for example). In fact,
67 * these iterators return a sequence of one item, but next() gets called
68 * automatically for you.
70 * You don't need to free iterators, and they become invalid if the
71 * View changes (items added, removed or altered), so don't hang on to
75 /****************************************************************
76 * EXTERNAL INTERFACE *
77 ****************************************************************/
79 GType
view_iface_get_type(void)
81 static GType iface_type
= 0;
85 static const GTypeInfo iface_info
=
87 sizeof (ViewIfaceClass
),
89 NULL
, /* base_finalize */
92 iface_type
= g_type_register_static(G_TYPE_INTERFACE
,
93 "ViewIface", &iface_info
, 0);
95 /* Actually, all Views should be GTK_TYPE_WIDGETs, to be more
96 * accurate, but including gtk.h takes so long, and noone's
97 * going to get this wrong ;-)
99 g_type_interface_add_prerequisite(iface_type
, G_TYPE_OBJECT
);
105 /* The sort function has changed -- resort */
106 void view_sort(ViewIface
*obj
)
108 g_return_if_fail(VIEW_IS_IFACE(obj
));
109 VIEW_IFACE_GET_CLASS(obj
)->sort(obj
);
112 /* The style has changed -- shrink the grid and redraw.
113 * Also update ViewData (and name layout too) if appropriate
116 void view_style_changed(ViewIface
*obj
, int flags
)
118 g_return_if_fail(VIEW_IS_IFACE(obj
));
120 VIEW_IFACE_GET_CLASS(obj
)->style_changed(obj
, flags
);
123 /* Wink or move the cursor to this item, if present. Return TRUE on
124 * success (iff leaf was present).
126 gboolean
view_autoselect(ViewIface
*obj
, const gchar
*leaf
)
131 g_return_val_if_fail(VIEW_IS_IFACE(obj
), FALSE
);
132 g_return_val_if_fail(leaf
!= NULL
, FALSE
);
134 view_get_iter(obj
, &iter
, 0);
135 while ((item
= iter
.next(&iter
)))
137 if (strcmp(item
->leafname
, leaf
) != 0)
140 if (view_cursor_visible(obj
))
141 view_cursor_to_iter(obj
, &iter
);
143 view_wink_item(obj
, &iter
);
151 /* Scanning has turned up some new items... */
152 void view_add_items(ViewIface
*obj
, GPtrArray
*items
)
154 VIEW_IFACE_GET_CLASS(obj
)->add_items(obj
, items
);
157 /* These items are already known, but have changed... */
158 void view_update_items(ViewIface
*obj
, GPtrArray
*items
)
160 VIEW_IFACE_GET_CLASS(obj
)->update_items(obj
, items
);
163 /* Call test(item) for each item in the view and delete all those for
164 * which it returns TRUE.
166 void view_delete_if(ViewIface
*obj
,
167 gboolean (*test
)(gpointer item
, gpointer data
),
170 g_return_if_fail(VIEW_IS_IFACE(obj
));
172 VIEW_IFACE_GET_CLASS(obj
)->delete_if(obj
, test
, data
);
175 /* Remove all items from the view (used when changing directory) */
176 void view_clear(ViewIface
*obj
)
178 g_return_if_fail(VIEW_IS_IFACE(obj
));
180 VIEW_IFACE_GET_CLASS(obj
)->clear(obj
);
183 /* Select all items */
184 void view_select_all(ViewIface
*obj
)
186 g_return_if_fail(VIEW_IS_IFACE(obj
));
188 VIEW_IFACE_GET_CLASS(obj
)->select_all(obj
);
191 /* Unselect all items */
192 void view_clear_selection(ViewIface
*obj
)
194 g_return_if_fail(VIEW_IS_IFACE(obj
));
196 VIEW_IFACE_GET_CLASS(obj
)->clear_selection(obj
);
199 /* Return the total number of items */
200 int view_count_items(ViewIface
*obj
)
202 g_return_val_if_fail(VIEW_IS_IFACE(obj
), 0);
204 return VIEW_IFACE_GET_CLASS(obj
)->count_items(obj
);
207 /* Return the number of selected items */
208 int view_count_selected(ViewIface
*obj
)
210 g_return_val_if_fail(VIEW_IS_IFACE(obj
), 0);
212 return VIEW_IFACE_GET_CLASS(obj
)->count_selected(obj
);
215 void view_show_cursor(ViewIface
*obj
)
217 g_return_if_fail(VIEW_IS_IFACE(obj
));
219 VIEW_IFACE_GET_CLASS(obj
)->show_cursor(obj
);
222 /* Create an iterator which will return each element selected by 'flags'
223 * from successive calls to iter.next(&iter). NULL indicates the end
226 * The iterator does not need to be freed. It becomes invalid if the
227 * view is changed in any way.
229 void view_get_iter(ViewIface
*obj
, ViewIter
*iter
, IterFlags flags
)
231 g_return_if_fail(VIEW_IS_IFACE(obj
));
232 g_return_if_fail(iter
!= NULL
);
234 VIEW_IFACE_GET_CLASS(obj
)->get_iter(obj
, iter
, flags
);
237 /* Make an 'iter' for the cursor item, if any. Use iter->peek() to get
238 * the DirItem (will be NULL if the cursor isn't on an item).
240 void view_get_cursor(ViewIface
*obj
, ViewIter
*iter
)
242 g_return_if_fail(VIEW_IS_IFACE(obj
));
243 g_return_if_fail(iter
!= NULL
);
245 VIEW_IFACE_GET_CLASS(obj
)->get_iter(obj
, iter
,
246 VIEW_ITER_FROM_CURSOR
| VIEW_ITER_ONE_ONLY
);
249 /* Position cursor on the last item returned by iter.next().
250 * If iter is NULL, remove the cursor.
252 void view_cursor_to_iter(ViewIface
*obj
, ViewIter
*iter
)
254 g_return_if_fail(VIEW_IS_IFACE(obj
));
256 VIEW_IFACE_GET_CLASS(obj
)->cursor_to_iter(obj
, iter
);
259 /* Select the item at this iter */
260 void view_set_selected(ViewIface
*obj
, ViewIter
*iter
, gboolean selected
)
262 g_return_if_fail(VIEW_IS_IFACE(obj
));
264 VIEW_IFACE_GET_CLASS(obj
)->set_selected(obj
, iter
, selected
);
267 /* TRUE if this item is selected */
268 gboolean
view_get_selected(ViewIface
*obj
, ViewIter
*iter
)
270 g_return_val_if_fail(VIEW_IS_IFACE(obj
), FALSE
);
272 return VIEW_IFACE_GET_CLASS(obj
)->get_selected(obj
, iter
);
275 /* Flash / draw attention to this item */
276 void view_wink_item(ViewIface
*obj
, ViewIter
*iter
)
278 g_return_if_fail(VIEW_IS_IFACE(obj
));
280 VIEW_IFACE_GET_CLASS(obj
)->wink_item(obj
, iter
);
283 /* Clear the selection, then select this item. Does it atomically to avoid
284 * problems with giving up and quickly reclaiming the primary selection.
286 void view_select_only(ViewIface
*obj
, ViewIter
*iter
)
288 g_return_if_fail(VIEW_IS_IFACE(obj
));
290 VIEW_IFACE_GET_CLASS(obj
)->select_only(obj
, iter
);
293 void view_select_if(ViewIface
*obj
,
294 gboolean (*test
)(ViewIter
*iter
, gpointer data
),
298 gboolean should_select_first
;
300 g_return_if_fail(VIEW_IS_IFACE(obj
));
302 view_get_iter(obj
, &iter
, 0);
304 if (!iter
.next(&iter
))
305 return; /* No items */
309 /* If anything is currently selected then select the first item now
310 * and set it to its correct value at the end (avoids losing the
311 * primary and regaining it quickly). Do the test first in case it
312 * relies on the selected state!
314 should_select_first
= test(&iter
, data
);
315 if (view_count_selected(obj
))
316 view_set_selected(obj
, &iter
, TRUE
);
318 while (iter
.next(&iter
))
319 view_set_selected(obj
, &iter
, test(&iter
, data
));
321 view_get_iter(obj
, &iter
, 0);
323 view_set_selected(obj
, &iter
, should_select_first
);
328 /* Prevent selection_changed events from being emitted */
329 void view_freeze(ViewIface
*obj
)
331 g_return_if_fail(VIEW_IS_IFACE(obj
));
333 VIEW_IFACE_GET_CLASS(obj
)->set_frozen(obj
, TRUE
);
336 /* Undo a view_freeze (and emit the changed signal) */
337 void view_thaw(ViewIface
*obj
)
339 g_return_if_fail(VIEW_IS_IFACE(obj
));
341 VIEW_IFACE_GET_CLASS(obj
)->set_frozen(obj
, FALSE
);
344 /* Resize the filer window to a sensible size.
345 * v_border is the height of the toolbar + the minibuffer (if visible).
349 void view_autosize(ViewIface
*obj
)
351 g_return_if_fail(VIEW_IS_IFACE(obj
));
353 VIEW_IFACE_GET_CLASS(obj
)->autosize(obj
);
356 /* Return TRUE if the cursor is shown. Note that the cursor may be visible
357 * even if their are no items (so get_cursor().peek() would return NULL).
359 gboolean
view_cursor_visible(ViewIface
*obj
)
361 g_return_val_if_fail(VIEW_IS_IFACE(obj
), FALSE
);
363 return VIEW_IFACE_GET_CLASS(obj
)->cursor_visible(obj
);
366 /* The 'base' position is used to record the position of the cursor
367 * when the minibuffer is opened, for interactive searching.
369 void view_set_base(ViewIface
*obj
, ViewIter
*iter
)
371 g_return_if_fail(VIEW_IS_IFACE(obj
));
373 VIEW_IFACE_GET_CLASS(obj
)->set_base(obj
, iter
);
376 /* Returns an interator which yields just the item under the pointer.
377 * iter.peek() will return NULL if no item was under the pointer.
378 * x, y is relative to 'window'.
380 void view_get_iter_at_point(ViewIface
*obj
, ViewIter
*iter
,
381 GdkWindow
*window
, int x
, int y
)
383 g_return_if_fail(VIEW_IS_IFACE(obj
));
385 VIEW_IFACE_GET_CLASS(obj
)->get_iter_at_point(obj
, iter
, window
, x
, y
);
388 /* Begin a drag to select a group of icons */
389 void view_start_lasso_box(ViewIface
*obj
, GdkEventButton
*event
)
391 g_return_if_fail(VIEW_IS_IFACE(obj
));
393 VIEW_IFACE_GET_CLASS(obj
)->start_lasso_box(obj
, event
);
396 /* Add anything useful to the tooltip string. Used to include the name of
397 * items where the name is shown truncated.
399 void view_extend_tip(ViewIface
*obj
, ViewIter
*iter
, GString
*tip
)
401 g_return_if_fail(VIEW_IS_IFACE(obj
));
403 VIEW_IFACE_GET_CLASS(obj
)->extend_tip(obj
, iter
, tip
);
406 /* This is called frequently while auto_scroll is on.
407 * Checks the pointer position and scrolls the window if it's
408 * near the top or bottom.
410 gboolean
view_auto_scroll_callback(ViewIface
*obj
)
412 g_return_val_if_fail(VIEW_IS_IFACE(obj
), FALSE
);
414 return VIEW_IFACE_GET_CLASS(obj
)->auto_scroll_callback(obj
);