Avoid Panel Options dialog being destroyed when changing a panel's side.
[rox-filer/th.git] / ROX-Filer / src / view_iface.c
blob5fef374bf9c26e55212e35639b1227e73aea1a99
1 /*
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)
8 * any later version.
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
13 * more details.
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_iface.c - operations supported by all views */
22 #include "config.h"
24 #include <string.h>
26 #include "global.h"
28 #include "view_iface.h"
29 #include "diritem.h"
31 /* A word about interfaces:
33 * gobject's documentation's explanation of interfaces leaves something[1] to
34 * be desired, so I'd better explain here...
36 * [1] Like, eg, an explanation.
38 * A ViewIfaceClass is a struct which contains a number of function
39 * pointers. Each class that implements the View interface creates its
40 * own ViewIfaceClass with pointers to its implementation. This is stored
41 * with the class.
43 * When you want to call a method (eg, sort()) on a View, you call
44 * view_sort(object) here, which gets the class of object and then looks
45 * for that class's implementation of the View interface, and then calls
46 * the actual function through that.
49 /* ViewIters
51 * A ViewIter is used to index items. They are usually allocated
52 * on the stack and then initialised using view_get_iter().
54 * Normally, an iterator starts off not pointing at any item, but
55 * each call to iter->next(iter) returns the next item, and leaves
56 * the iterator pointing at the returned item. If you like the item,
57 * you can then pass the iterator to view_cursor_to_iter(), etc.
59 * Using flags passed to view_get_iter, you can start the sequence from the
60 * beginning, end, cursor or 'base' (a saved cursor position). You can
61 * go forwards or backwards. You can opt to only get selected items returned.
63 * You can also have one-shot iterators which already point to an item, and
64 * you never call the next method (view_get_cursor, for example). In fact,
65 * these iterators return a sequence of one item, but next() gets called
66 * automatically for you.
68 * You don't need to free iterators, and they become invalid if the
69 * View changes (items added, removed or altered), so don't hang on to
70 * them!
73 /****************************************************************
74 * EXTERNAL INTERFACE *
75 ****************************************************************/
77 GType view_iface_get_type(void)
79 static GType iface_type = 0;
81 if (!iface_type)
83 static const GTypeInfo iface_info =
85 sizeof (ViewIfaceClass),
86 NULL, /* base_init */
87 NULL, /* base_finalize */
90 iface_type = g_type_register_static(G_TYPE_INTERFACE,
91 "ViewIface", &iface_info, 0);
93 /* Actually, all Views should be GTK_TYPE_WIDGETs, to be more
94 * accurate, but including gtk.h takes so long, and noone's
95 * going to get this wrong ;-)
97 g_type_interface_add_prerequisite(iface_type, G_TYPE_OBJECT);
100 return iface_type;
103 /* The sort function has changed -- resort */
104 void view_sort(ViewIface *obj)
106 g_return_if_fail(VIEW_IS_IFACE(obj));
107 VIEW_IFACE_GET_CLASS(obj)->sort(obj);
110 /* The style has changed -- shrink the grid and redraw.
111 * Also update ViewData (and name layout too) if appropriate
112 * flags are set.
114 void view_style_changed(ViewIface *obj, int flags)
116 g_return_if_fail(VIEW_IS_IFACE(obj));
118 VIEW_IFACE_GET_CLASS(obj)->style_changed(obj, flags);
121 /* Wink or move the cursor to this item, if present. Return TRUE on
122 * success (iff leaf was present).
124 gboolean view_autoselect(ViewIface *obj, const gchar *leaf)
126 DirItem *item;
127 ViewIter iter;
129 g_return_val_if_fail(VIEW_IS_IFACE(obj), FALSE);
130 g_return_val_if_fail(leaf != NULL, FALSE);
132 view_get_iter(obj, &iter, 0);
133 while ((item = iter.next(&iter)))
135 if (strcmp(item->leafname, leaf) != 0)
136 continue;
138 if (view_cursor_visible(obj))
139 view_cursor_to_iter(obj, &iter);
140 else
141 view_wink_item(obj, &iter);
143 return TRUE;
146 return FALSE;
149 /* Scanning has turned up some new items... */
150 void view_add_items(ViewIface *obj, GPtrArray *items)
152 VIEW_IFACE_GET_CLASS(obj)->add_items(obj, items);
155 /* These items are already known, but have changed... */
156 void view_update_items(ViewIface *obj, GPtrArray *items)
158 VIEW_IFACE_GET_CLASS(obj)->update_items(obj, items);
161 /* Call test(item) for each item in the view and delete all those for
162 * which it returns TRUE.
164 void view_delete_if(ViewIface *obj,
165 gboolean (*test)(gpointer item, gpointer data),
166 gpointer data)
168 g_return_if_fail(VIEW_IS_IFACE(obj));
170 VIEW_IFACE_GET_CLASS(obj)->delete_if(obj, test, data);
173 /* Remove all items from the view (used when changing directory) */
174 void view_clear(ViewIface *obj)
176 g_return_if_fail(VIEW_IS_IFACE(obj));
178 VIEW_IFACE_GET_CLASS(obj)->clear(obj);
181 /* Select all items */
182 void view_select_all(ViewIface *obj)
184 g_return_if_fail(VIEW_IS_IFACE(obj));
186 VIEW_IFACE_GET_CLASS(obj)->select_all(obj);
189 /* Unselect all items */
190 void view_clear_selection(ViewIface *obj)
192 g_return_if_fail(VIEW_IS_IFACE(obj));
194 VIEW_IFACE_GET_CLASS(obj)->clear_selection(obj);
197 /* Return the total number of items */
198 int view_count_items(ViewIface *obj)
200 g_return_val_if_fail(VIEW_IS_IFACE(obj), 0);
202 return VIEW_IFACE_GET_CLASS(obj)->count_items(obj);
205 /* Return the number of selected items */
206 int view_count_selected(ViewIface *obj)
208 g_return_val_if_fail(VIEW_IS_IFACE(obj), 0);
210 return VIEW_IFACE_GET_CLASS(obj)->count_selected(obj);
213 void view_show_cursor(ViewIface *obj)
215 g_return_if_fail(VIEW_IS_IFACE(obj));
217 VIEW_IFACE_GET_CLASS(obj)->show_cursor(obj);
220 /* Create an iterator which will return each element selected by 'flags'
221 * from successive calls to iter.next(&iter). NULL indicates the end
222 * of the sequence.
224 * The iterator does not need to be freed. It becomes invalid if the
225 * view is changed in any way.
227 void view_get_iter(ViewIface *obj, ViewIter *iter, IterFlags flags)
229 g_return_if_fail(VIEW_IS_IFACE(obj));
230 g_return_if_fail(iter != NULL);
232 VIEW_IFACE_GET_CLASS(obj)->get_iter(obj, iter, flags);
235 /* Make an 'iter' for the cursor item, if any. Use iter->peek() to get
236 * the DirItem (will be NULL if the cursor isn't on an item).
238 void view_get_cursor(ViewIface *obj, ViewIter *iter)
240 g_return_if_fail(VIEW_IS_IFACE(obj));
241 g_return_if_fail(iter != NULL);
243 VIEW_IFACE_GET_CLASS(obj)->get_iter(obj, iter,
244 VIEW_ITER_FROM_CURSOR | VIEW_ITER_ONE_ONLY);
247 /* Position cursor on the last item returned by iter.next().
248 * If iter is NULL, remove the cursor.
250 void view_cursor_to_iter(ViewIface *obj, ViewIter *iter)
252 g_return_if_fail(VIEW_IS_IFACE(obj));
254 VIEW_IFACE_GET_CLASS(obj)->cursor_to_iter(obj, iter);
257 /* Select the item at this iter */
258 void view_set_selected(ViewIface *obj, ViewIter *iter, gboolean selected)
260 g_return_if_fail(VIEW_IS_IFACE(obj));
262 VIEW_IFACE_GET_CLASS(obj)->set_selected(obj, iter, selected);
265 /* TRUE if this item is selected */
266 gboolean view_get_selected(ViewIface *obj, ViewIter *iter)
268 g_return_val_if_fail(VIEW_IS_IFACE(obj), FALSE);
270 return VIEW_IFACE_GET_CLASS(obj)->get_selected(obj, iter);
273 /* Flash / draw attention to this item */
274 void view_wink_item(ViewIface *obj, ViewIter *iter)
276 g_return_if_fail(VIEW_IS_IFACE(obj));
278 VIEW_IFACE_GET_CLASS(obj)->wink_item(obj, iter);
281 /* Clear the selection, then select this item. Does it atomically to avoid
282 * problems with giving up and quickly reclaiming the primary selection.
284 void view_select_only(ViewIface *obj, ViewIter *iter)
286 g_return_if_fail(VIEW_IS_IFACE(obj));
288 VIEW_IFACE_GET_CLASS(obj)->select_only(obj, iter);
291 void view_select_if(ViewIface *obj,
292 gboolean (*test)(ViewIter *iter, gpointer data),
293 gpointer data)
295 ViewIter iter;
296 gboolean should_select_first;
298 g_return_if_fail(VIEW_IS_IFACE(obj));
300 view_get_iter(obj, &iter, 0);
302 if (!iter.next(&iter))
303 return; /* No items */
305 view_freeze(obj);
307 /* If anything is currently selected then select the first item now
308 * and set it to its correct value at the end (avoids losing the
309 * primary and regaining it quickly). Do the test first in case it
310 * relies on the selected state!
312 should_select_first = test(&iter, data);
313 if (view_count_selected(obj))
314 view_set_selected(obj, &iter, TRUE);
316 while (iter.next(&iter))
317 view_set_selected(obj, &iter, test(&iter, data));
319 view_get_iter(obj, &iter, 0);
320 iter.next(&iter);
321 view_set_selected(obj, &iter, should_select_first);
323 view_thaw(obj);
326 /* Prevent selection_changed events from being emitted */
327 void view_freeze(ViewIface *obj)
329 g_return_if_fail(VIEW_IS_IFACE(obj));
331 VIEW_IFACE_GET_CLASS(obj)->set_frozen(obj, TRUE);
334 /* Undo a view_freeze (and emit the changed signal) */
335 void view_thaw(ViewIface *obj)
337 g_return_if_fail(VIEW_IS_IFACE(obj));
339 VIEW_IFACE_GET_CLASS(obj)->set_frozen(obj, FALSE);
342 /* Resize the filer window to a sensible size.
343 * v_border is the height of the toolbar + the minibuffer (if visible).
344 * space is
345 * If allow_shrink is
347 void view_autosize(ViewIface *obj)
349 g_return_if_fail(VIEW_IS_IFACE(obj));
351 VIEW_IFACE_GET_CLASS(obj)->autosize(obj);
354 /* Return TRUE if the cursor is shown. Note that the cursor may be visible
355 * even if their are no items (so get_cursor().peek() would return NULL).
357 gboolean view_cursor_visible(ViewIface *obj)
359 g_return_val_if_fail(VIEW_IS_IFACE(obj), FALSE);
361 return VIEW_IFACE_GET_CLASS(obj)->cursor_visible(obj);
364 /* The 'base' position is used to record the position of the cursor
365 * when the minibuffer is opened, for interactive searching.
367 void view_set_base(ViewIface *obj, ViewIter *iter)
369 g_return_if_fail(VIEW_IS_IFACE(obj));
371 VIEW_IFACE_GET_CLASS(obj)->set_base(obj, iter);
374 /* Returns an interator which yields just the item under the pointer.
375 * iter.peek() will return NULL if no item was under the pointer.
376 * x, y is relative to 'window'.
378 void view_get_iter_at_point(ViewIface *obj, ViewIter *iter,
379 GdkWindow *window, int x, int y)
381 g_return_if_fail(VIEW_IS_IFACE(obj));
383 VIEW_IFACE_GET_CLASS(obj)->get_iter_at_point(obj, iter, window, x, y);
386 /* Begin a drag to select a group of icons */
387 void view_start_lasso_box(ViewIface *obj, GdkEventButton *event)
389 g_return_if_fail(VIEW_IS_IFACE(obj));
391 VIEW_IFACE_GET_CLASS(obj)->start_lasso_box(obj, event);
394 /* Add anything useful to the tooltip string. Used to include the name of
395 * items where the name is shown truncated.
397 void view_extend_tip(ViewIface *obj, ViewIter *iter, GString *tip)
399 g_return_if_fail(VIEW_IS_IFACE(obj));
401 VIEW_IFACE_GET_CLASS(obj)->extend_tip(obj, iter, tip);
404 /* This is called frequently while auto_scroll is on.
405 * Checks the pointer position and scrolls the window if it's
406 * near the top or bottom.
408 gboolean view_auto_scroll_callback(ViewIface *obj)
410 g_return_val_if_fail(VIEW_IS_IFACE(obj), FALSE);
412 return VIEW_IFACE_GET_CLASS(obj)->auto_scroll_callback(obj);