1 /* GTK - The GIMP Toolkit
2 * Recent chooser action for GtkUIManager
4 * Copyright (C) 2007, Emmanuele Bassi
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
25 #include "gtkrecentaction.h"
26 #include "gtkimagemenuitem.h"
27 #include "gtkmenutoolbutton.h"
28 #include "gtkrecentchooser.h"
29 #include "gtkrecentchoosermenu.h"
30 #include "gtkrecentchooserutils.h"
31 #include "gtkrecentchooserprivate.h"
32 #include "gtkprivate.h"
35 #define FALLBACK_ITEM_LIMIT 10
37 #define GTK_RECENT_ACTION_GET_PRIVATE(obj) \
38 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
39 GTK_TYPE_RECENT_ACTION, \
40 GtkRecentActionPrivate))
42 struct _GtkRecentActionPrivate
44 GtkRecentManager *manager;
46 guint show_numbers : 1;
48 /* RecentChooser properties */
49 guint show_private : 1;
50 guint show_not_found : 1;
57 GtkRecentSortType sort_type;
58 GtkRecentSortFunc sort_func;
60 GDestroyNotify data_destroy;
62 GtkRecentFilter *current_filter;
65 GtkRecentChooser *current_chooser;
75 static void gtk_recent_chooser_iface_init (GtkRecentChooserIface *iface);
77 G_DEFINE_TYPE_WITH_CODE (GtkRecentAction,
80 G_IMPLEMENT_INTERFACE (GTK_TYPE_RECENT_CHOOSER,
81 gtk_recent_chooser_iface_init));
84 gtk_recent_action_set_current_uri (GtkRecentChooser *chooser,
88 GtkRecentAction *action = GTK_RECENT_ACTION (chooser);
89 GtkRecentActionPrivate *priv = action->priv;
92 for (l = priv->choosers; l; l = l->next)
94 GtkRecentChooser *recent_chooser = l->data;
96 if (!gtk_recent_chooser_set_current_uri (recent_chooser, uri, error))
104 gtk_recent_action_get_current_uri (GtkRecentChooser *chooser)
106 GtkRecentAction *recent_action = GTK_RECENT_ACTION (chooser);
107 GtkRecentActionPrivate *priv = recent_action->priv;
109 if (priv->current_chooser)
110 return gtk_recent_chooser_get_current_uri (priv->current_chooser);
116 gtk_recent_action_select_uri (GtkRecentChooser *chooser,
120 GtkRecentAction *action = GTK_RECENT_ACTION (chooser);
121 GtkRecentActionPrivate *priv = action->priv;
124 for (l = priv->choosers; l; l = l->next)
126 GtkRecentChooser *recent_chooser = l->data;
128 if (!gtk_recent_chooser_select_uri (recent_chooser, uri, error))
136 gtk_recent_action_unselect_uri (GtkRecentChooser *chooser,
139 GtkRecentAction *action = GTK_RECENT_ACTION (chooser);
140 GtkRecentActionPrivate *priv = action->priv;
143 for (l = priv->choosers; l; l = l->next)
145 GtkRecentChooser *chooser = l->data;
147 gtk_recent_chooser_unselect_uri (chooser, uri);
152 gtk_recent_action_select_all (GtkRecentChooser *chooser)
154 g_warning (_("This function is not implemented for "
155 "widgets of class '%s'"),
156 g_type_name (G_OBJECT_TYPE (chooser)));
160 gtk_recent_action_unselect_all (GtkRecentChooser *chooser)
162 g_warning (_("This function is not implemented for "
163 "widgets of class '%s'"),
164 g_type_name (G_OBJECT_TYPE (chooser)));
169 gtk_recent_action_get_items (GtkRecentChooser *chooser)
171 GtkRecentAction *action = GTK_RECENT_ACTION (chooser);
172 GtkRecentActionPrivate *priv = action->priv;
174 return _gtk_recent_chooser_get_items (chooser,
175 priv->current_filter,
180 static GtkRecentManager *
181 gtk_recent_action_get_recent_manager (GtkRecentChooser *chooser)
183 return GTK_RECENT_ACTION_GET_PRIVATE (chooser)->manager;
187 gtk_recent_action_set_sort_func (GtkRecentChooser *chooser,
188 GtkRecentSortFunc sort_func,
190 GDestroyNotify data_destroy)
192 GtkRecentAction *action = GTK_RECENT_ACTION (chooser);
193 GtkRecentActionPrivate *priv = action->priv;
196 if (priv->data_destroy)
198 priv->data_destroy (priv->sort_data);
199 priv->data_destroy = NULL;
202 priv->sort_func = NULL;
203 priv->sort_data = NULL;
207 priv->sort_func = sort_func;
208 priv->sort_data = sort_data;
209 priv->data_destroy = data_destroy;
212 for (l = priv->choosers; l; l = l->next)
214 GtkRecentChooser *chooser_menu = l->data;
216 gtk_recent_chooser_set_sort_func (chooser_menu, priv->sort_func,
223 set_current_filter (GtkRecentAction *action,
224 GtkRecentFilter *filter)
226 GtkRecentActionPrivate *priv = action->priv;
228 g_object_ref (action);
230 if (priv->current_filter)
231 g_object_unref (priv->current_filter);
233 priv->current_filter = filter;
235 if (priv->current_filter)
236 g_object_ref_sink (priv->current_filter);
238 g_object_notify (G_OBJECT (action), "filter");
240 g_object_unref (action);
244 gtk_recent_action_add_filter (GtkRecentChooser *chooser,
245 GtkRecentFilter *filter)
247 GtkRecentActionPrivate *priv = GTK_RECENT_ACTION_GET_PRIVATE (chooser);
249 if (priv->current_filter != filter)
250 set_current_filter (GTK_RECENT_ACTION (chooser), filter);
254 gtk_recent_action_remove_filter (GtkRecentChooser *chooser,
255 GtkRecentFilter *filter)
257 GtkRecentActionPrivate *priv = GTK_RECENT_ACTION_GET_PRIVATE (chooser);
259 if (priv->current_filter == filter)
260 set_current_filter (GTK_RECENT_ACTION (chooser), NULL);
264 gtk_recent_action_list_filters (GtkRecentChooser *chooser)
266 GSList *retval = NULL;
267 GtkRecentFilter *current_filter;
269 current_filter = GTK_RECENT_ACTION_GET_PRIVATE (chooser)->current_filter;
270 retval = g_slist_prepend (retval, current_filter);
277 gtk_recent_chooser_iface_init (GtkRecentChooserIface *iface)
279 iface->set_current_uri = gtk_recent_action_set_current_uri;
280 iface->get_current_uri = gtk_recent_action_get_current_uri;
281 iface->select_uri = gtk_recent_action_select_uri;
282 iface->unselect_uri = gtk_recent_action_unselect_uri;
283 iface->select_all = gtk_recent_action_select_all;
284 iface->unselect_all = gtk_recent_action_unselect_all;
285 iface->get_items = gtk_recent_action_get_items;
286 iface->get_recent_manager = gtk_recent_action_get_recent_manager;
287 iface->set_sort_func = gtk_recent_action_set_sort_func;
288 iface->add_filter = gtk_recent_action_add_filter;
289 iface->remove_filter = gtk_recent_action_remove_filter;
290 iface->list_filters = gtk_recent_action_list_filters;
294 gtk_recent_action_activate (GtkAction *action)
296 /* we have probably been invoked by a menu tool button or by a
297 * direct call of gtk_action_activate(); since no item has been
298 * selected, we must unset the current recent chooser pointer
300 GTK_RECENT_ACTION_GET_PRIVATE (action)->current_chooser = NULL;
304 delegate_selection_changed (GtkRecentAction *action,
305 GtkRecentChooser *chooser)
307 GtkRecentActionPrivate *priv = action->priv;
309 priv->current_chooser = chooser;
311 g_signal_emit_by_name (action, "selection-changed");
315 delegate_item_activated (GtkRecentAction *action,
316 GtkRecentChooser *chooser)
318 GtkRecentActionPrivate *priv = action->priv;
320 priv->current_chooser = chooser;
322 g_signal_emit_by_name (action, "item-activated");
326 gtk_recent_action_connect_proxy (GtkAction *action,
329 GtkRecentAction *recent_action = GTK_RECENT_ACTION (action);
330 GtkRecentActionPrivate *priv = recent_action->priv;
332 /* it can only be a recent chooser implementor anyway... */
333 if (GTK_IS_RECENT_CHOOSER (widget) &&
334 !g_slist_find (priv->choosers, widget))
338 gtk_recent_chooser_set_sort_func (GTK_RECENT_CHOOSER (widget),
344 g_signal_connect_swapped (widget, "selection_changed",
345 G_CALLBACK (delegate_selection_changed),
347 g_signal_connect_swapped (widget, "item-activated",
348 G_CALLBACK (delegate_item_activated),
352 if (GTK_ACTION_CLASS (gtk_recent_action_parent_class)->connect_proxy)
353 GTK_ACTION_CLASS (gtk_recent_action_parent_class)->connect_proxy (action, widget);
357 gtk_recent_action_disconnect_proxy (GtkAction *action,
360 GtkRecentAction *recent_action = GTK_RECENT_ACTION (action);
361 GtkRecentActionPrivate *priv = recent_action->priv;
363 /* if it was one of the recent choosers we created, remove it
366 if (g_slist_find (priv->choosers, widget))
367 priv->choosers = g_slist_remove (priv->choosers, widget);
369 if (GTK_ACTION_CLASS (gtk_recent_action_parent_class)->disconnect_proxy)
370 GTK_ACTION_CLASS (gtk_recent_action_parent_class)->disconnect_proxy (action, widget);
374 gtk_recent_action_create_menu (GtkAction *action)
376 GtkRecentAction *recent_action = GTK_RECENT_ACTION (action);
377 GtkRecentActionPrivate *priv = recent_action->priv;
380 widget = g_object_new (GTK_TYPE_RECENT_CHOOSER_MENU,
381 "show-private", priv->show_private,
382 "show-not-found", priv->show_not_found,
383 "show-tips", priv->show_tips,
384 "show-icons", priv->show_icons,
385 "show-numbers", priv->show_numbers,
386 "limit", priv->limit,
387 "sort-type", priv->sort_type,
388 "recent-manager", priv->manager,
389 "filter", priv->current_filter,
390 "local-only", priv->local_only,
395 gtk_recent_chooser_set_sort_func (GTK_RECENT_CHOOSER (widget),
401 g_signal_connect_swapped (widget, "selection_changed",
402 G_CALLBACK (delegate_selection_changed),
404 g_signal_connect_swapped (widget, "item-activated",
405 G_CALLBACK (delegate_item_activated),
408 /* keep track of the choosers we create */
409 priv->choosers = g_slist_prepend (priv->choosers, widget);
415 gtk_recent_action_create_menu_item (GtkAction *action)
420 menu = gtk_recent_action_create_menu (action);
421 menuitem = g_object_new (GTK_TYPE_IMAGE_MENU_ITEM, NULL);
422 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu);
423 gtk_widget_show (menu);
429 gtk_recent_action_create_tool_item (GtkAction *action)
434 menu = gtk_recent_action_create_menu (action);
435 toolitem = g_object_new (GTK_TYPE_MENU_TOOL_BUTTON, NULL);
436 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (toolitem), menu);
437 gtk_widget_show (menu);
443 set_recent_manager (GtkRecentAction *action,
444 GtkRecentManager *manager)
446 GtkRecentActionPrivate *priv = action->priv;
449 priv->manager = NULL;
451 priv->manager = gtk_recent_manager_get_default ();
455 gtk_recent_action_finalize (GObject *gobject)
457 GtkRecentAction *action = GTK_RECENT_ACTION (gobject);
458 GtkRecentActionPrivate *priv = action->priv;
460 priv->manager = NULL;
462 if (priv->data_destroy)
464 priv->data_destroy (priv->sort_data);
465 priv->data_destroy = NULL;
468 priv->sort_data = NULL;
469 priv->sort_func = NULL;
471 g_slist_free (priv->choosers);
473 G_OBJECT_CLASS (gtk_recent_action_parent_class)->finalize (gobject);
477 gtk_recent_action_dispose (GObject *gobject)
479 GtkRecentAction *action = GTK_RECENT_ACTION (gobject);
480 GtkRecentActionPrivate *priv = action->priv;
482 if (priv->current_filter)
484 g_object_unref (priv->current_filter);
485 priv->current_filter = NULL;
488 G_OBJECT_CLASS (gtk_recent_action_parent_class)->dispose (gobject);
492 gtk_recent_action_set_property (GObject *gobject,
497 GtkRecentAction *action = GTK_RECENT_ACTION (gobject);
498 GtkRecentActionPrivate *priv = action->priv;
502 case PROP_SHOW_NUMBERS:
503 priv->show_numbers = g_value_get_boolean (value);
505 case GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE:
506 priv->show_private = g_value_get_boolean (value);
508 case GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND:
509 priv->show_not_found = g_value_get_boolean (value);
511 case GTK_RECENT_CHOOSER_PROP_SHOW_TIPS:
512 priv->show_tips = g_value_get_boolean (value);
514 case GTK_RECENT_CHOOSER_PROP_SHOW_ICONS:
515 priv->show_icons = g_value_get_boolean (value);
517 case GTK_RECENT_CHOOSER_PROP_LIMIT:
518 priv->limit = g_value_get_int (value);
520 case GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY:
521 priv->local_only = g_value_get_boolean (value);
523 case GTK_RECENT_CHOOSER_PROP_SORT_TYPE:
524 priv->sort_type = g_value_get_enum (value);
526 case GTK_RECENT_CHOOSER_PROP_FILTER:
527 set_current_filter (action, g_value_get_object (value));
529 case GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE:
530 g_warning ("%s: Choosers of type `%s' do not support selecting multiple items.",
532 G_OBJECT_TYPE_NAME (gobject));
534 case GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER:
535 set_recent_manager (action, g_value_get_object (value));
538 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
544 gtk_recent_action_get_property (GObject *gobject,
549 GtkRecentActionPrivate *priv = GTK_RECENT_ACTION_GET_PRIVATE (gobject);
553 case PROP_SHOW_NUMBERS:
554 g_value_set_boolean (value, priv->show_numbers);
556 case GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE:
557 g_value_set_boolean (value, priv->show_private);
559 case GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND:
560 g_value_set_boolean (value, priv->show_not_found);
562 case GTK_RECENT_CHOOSER_PROP_SHOW_TIPS:
563 g_value_set_boolean (value, priv->show_tips);
565 case GTK_RECENT_CHOOSER_PROP_SHOW_ICONS:
566 g_value_set_boolean (value, priv->show_icons);
568 case GTK_RECENT_CHOOSER_PROP_LIMIT:
569 g_value_set_int (value, priv->limit);
571 case GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY:
572 g_value_set_boolean (value, priv->local_only);
574 case GTK_RECENT_CHOOSER_PROP_SORT_TYPE:
575 g_value_set_enum (value, priv->sort_type);
577 case GTK_RECENT_CHOOSER_PROP_FILTER:
578 g_value_set_object (value, priv->current_filter);
580 case GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE:
581 g_value_set_boolean (value, FALSE);
584 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
590 gtk_recent_action_class_init (GtkRecentActionClass *klass)
592 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
593 GtkActionClass *action_class = GTK_ACTION_CLASS (klass);
595 g_type_class_add_private (klass, sizeof (GtkRecentActionPrivate));
597 gobject_class->finalize = gtk_recent_action_finalize;
598 gobject_class->dispose = gtk_recent_action_dispose;
599 gobject_class->set_property = gtk_recent_action_set_property;
600 gobject_class->get_property = gtk_recent_action_get_property;
602 action_class->activate = gtk_recent_action_activate;
603 action_class->connect_proxy = gtk_recent_action_connect_proxy;
604 action_class->disconnect_proxy = gtk_recent_action_disconnect_proxy;
605 action_class->create_menu_item = gtk_recent_action_create_menu_item;
606 action_class->create_tool_item = gtk_recent_action_create_tool_item;
607 action_class->create_menu = gtk_recent_action_create_menu;
608 action_class->menu_item_type = GTK_TYPE_IMAGE_MENU_ITEM;
609 action_class->toolbar_item_type = GTK_TYPE_MENU_TOOL_BUTTON;
611 _gtk_recent_chooser_install_properties (gobject_class);
613 g_object_class_install_property (gobject_class,
615 g_param_spec_boolean ("show-numbers",
617 P_("Whether the items should be displayed with a number"),
624 gtk_recent_action_init (GtkRecentAction *action)
626 GtkRecentActionPrivate *priv;
628 action->priv = priv = GTK_RECENT_ACTION_GET_PRIVATE (action);
630 priv->show_numbers = FALSE;
631 priv->show_icons = TRUE;
632 priv->show_tips = FALSE;
633 priv->show_not_found = TRUE;
634 priv->show_private = FALSE;
635 priv->local_only = TRUE;
637 priv->limit = FALLBACK_ITEM_LIMIT;
639 priv->sort_type = GTK_RECENT_SORT_NONE;
640 priv->sort_func = NULL;
641 priv->sort_data = NULL;
642 priv->data_destroy = NULL;
644 priv->current_filter = NULL;
646 priv->manager = NULL;
650 * gtk_recent_action_new:
651 * @name: a unique name for the action
652 * @label: (allow-none): the label displayed in menu items and on buttons, or %NULL
653 * @tooltip: (allow-none): a tooltip for the action, or %NULL
654 * @stock_id: the stock icon to display in widgets representing the
657 * Creates a new #GtkRecentAction object. To add the action to
658 * a #GtkActionGroup and set the accelerator for the action,
659 * call gtk_action_group_add_action_with_accel().
661 * Return value: the newly created #GtkRecentAction.
666 gtk_recent_action_new (const gchar *name,
668 const gchar *tooltip,
669 const gchar *stock_id)
671 g_return_val_if_fail (name != NULL, NULL);
673 return g_object_new (GTK_TYPE_RECENT_ACTION,
677 "stock-id", stock_id,
682 * gtk_recent_action_new_for_manager:
683 * @name: a unique name for the action
684 * @label: (allow-none): the label displayed in menu items and on buttons, or %NULL
685 * @tooltip: (allow-none): a tooltip for the action, or %NULL
686 * @stock_id: the stock icon to display in widgets representing the
688 * @manager: (allow-none): a #GtkRecentManager, or %NULL for using the default
691 * Creates a new #GtkRecentAction object. To add the action to
692 * a #GtkActionGroup and set the accelerator for the action,
693 * call gtk_action_group_add_action_with_accel().
695 * Return value: the newly created #GtkRecentAction
700 gtk_recent_action_new_for_manager (const gchar *name,
702 const gchar *tooltip,
703 const gchar *stock_id,
704 GtkRecentManager *manager)
706 g_return_val_if_fail (name != NULL, NULL);
707 g_return_val_if_fail (manager == NULL || GTK_IS_RECENT_MANAGER (manager), NULL);
709 return g_object_new (GTK_TYPE_RECENT_ACTION,
713 "stock-id", stock_id,
714 "recent-manager", manager,
719 * gtk_recent_action_get_show_numbers:
720 * @action: a #GtkRecentAction
722 * Returns the value set by gtk_recent_chooser_menu_set_show_numbers().
724 * Return value: %TRUE if numbers should be shown.
729 gtk_recent_action_get_show_numbers (GtkRecentAction *action)
731 g_return_val_if_fail (GTK_IS_RECENT_ACTION (action), FALSE);
733 return action->priv->show_numbers;
737 * gtk_recent_action_set_show_numbers:
738 * @action: a #GtkRecentAction
739 * @show_numbers: %TRUE if the shown items should be numbered
741 * Sets whether a number should be added to the items shown by the
742 * widgets representing @action. The numbers are shown to provide
743 * a unique character for a mnemonic to be used inside the menu item's
744 * label. Only the first ten items get a number to avoid clashes.
749 gtk_recent_action_set_show_numbers (GtkRecentAction *action,
750 gboolean show_numbers)
752 GtkRecentActionPrivate *priv;
754 g_return_if_fail (GTK_IS_RECENT_ACTION (action));
758 if (priv->show_numbers != show_numbers)
760 g_object_ref (action);
762 priv->show_numbers = show_numbers;
764 g_object_notify (G_OBJECT (action), "show-numbers");
765 g_object_unref (action);
769 #define __GTK_RECENT_ACTION_C__
770 #include "gtkaliasdef.c"