1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19 * James Willcox <jwillcox@cs.indiana.edu>
20 * Paolo Bacchilega <paobac@cvs.gnome.org>
31 #include <libgnomevfs/gnome-vfs.h>
32 #ifndef USE_STABLE_LIBGNOMEUI
33 #include <libgnomeui/gnome-icon-theme.h>
35 #include <gconf/gconf-client.h>
36 #include "egg-recent-model.h"
37 #include "egg-recent-view.h"
38 #include "egg-recent-view-uimanager.h"
39 #include "egg-recent-util.h"
40 #include "egg-recent-item.h"
42 #define EGG_RECENT_NAME_PREFIX "EggRecentAction"
43 #define EGG_RECENT_ACTION "EggRecentFile"
44 #define EGG_RECENT_SEPARATOR (NULL)
46 #ifndef EGG_COMPILATION
47 #include <glib/gi18n.h>
53 #define DEFAULT_LABEL_WIDTH_CHARS 30
55 struct _EggRecentViewUIManager {
56 GObject parent_instance;
58 GCallback action_callback;
59 gpointer action_user_data;
62 gboolean trailing_sep;
64 GtkUIManager *uimanager;
65 GtkActionGroup *action_group;
72 gboolean show_numbers;
73 #ifndef USE_STABLE_LIBGNOMEUI
74 GnomeIconTheme *theme;
77 EggUIManagerTooltipFunc tooltip_func;
78 gpointer tooltip_func_data;
80 EggRecentModel *model;
82 GtkIconSize icon_size;
88 struct _EggRecentViewUIManagerMenuData {
89 EggRecentViewUIManager *view;
93 typedef struct _EggRecentViewUIManagerMenuData EggRecentViewUIManagerMenuData;
100 /* GObject properties */
110 static guint view_signals[LAST_SIGNAL] = { 0 };
113 connect_proxy_cb (GtkActionGroup *action_group,
116 EggRecentViewUIManager *view)
118 if (GTK_IS_MENU_ITEM (proxy))
122 label = GTK_BIN (proxy)->child;
124 gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
125 gtk_label_set_max_width_chars (GTK_LABEL (label), view->label_width);
130 egg_recent_view_uimanager_clear (EggRecentViewUIManager *view)
132 if (view->merge_id != 0) {
133 gtk_ui_manager_remove_ui (view->uimanager, view->merge_id);
137 if (view->action_group != NULL) {
138 gtk_ui_manager_remove_action_group (view->uimanager, view->action_group);
139 g_object_unref (view->action_group);
140 view->action_group = NULL;
143 gtk_ui_manager_ensure_update (view->uimanager);
147 egg_recent_view_uimanager_set_list (EggRecentViewUIManager *view, GList *list)
152 g_return_if_fail (view);
154 egg_recent_view_uimanager_clear (view);
156 if (view->merge_id == 0)
157 view->merge_id = gtk_ui_manager_new_merge_id (view->uimanager);
159 if (view->action_group == NULL) {
160 gchar *group = g_strdup_printf ("EggRecentActions%u",
162 view->action_group = gtk_action_group_new (group);
163 g_signal_connect (view->action_group, "connect-proxy",
164 G_CALLBACK (connect_proxy_cb), view);
165 gtk_ui_manager_insert_action_group (view->uimanager,
166 view->action_group, -1);
170 if (view->leading_sep) {
171 gchar *action = g_strdup_printf ("EggRecentLeadingSeparator%u",
173 gtk_ui_manager_add_ui (view->uimanager,
177 EGG_RECENT_SEPARATOR,
183 for (scan = list; scan; scan = scan->next, index++) {
184 EggRecentItem *item = scan->data;
191 gchar *tooltip = NULL;
193 uri = egg_recent_item_get_uri_for_display (item);
197 name = g_strdup_printf (EGG_RECENT_NAME_PREFIX"%u-%u",
201 if (view->tooltip_func != NULL)
202 tooltip = (*view->tooltip_func) (item, view->tooltip_func_data);
205 tooltip = g_strdup_printf (_("Open “%s”"), uri);
207 basename = egg_recent_item_get_short_name (item);
208 escaped = egg_recent_util_escape_underlines (basename);
212 if (view->show_numbers) {
214 label = g_strdup_printf ("%d. %s",
218 label = g_strdup_printf ("_%d. %s",
225 action = g_object_new (GTK_TYPE_ACTION,
228 (view->show_icons)? "stock_id": NULL,
231 if (tooltip != NULL) {
232 g_object_set (action, "tooltip", tooltip, NULL);
235 egg_recent_item_ref (item);
236 g_object_set_data_full (G_OBJECT (action),
239 (GFreeFunc) egg_recent_item_unref);
241 if (view->action_callback != NULL) {
243 closure = g_cclosure_new (view->action_callback, view->action_user_data, NULL);
244 g_signal_connect_closure (action, "activate", closure, FALSE);
247 gtk_action_group_add_action (view->action_group, action);
248 g_object_unref (action);
250 gtk_ui_manager_add_ui (view->uimanager,
262 if (view->trailing_sep) {
263 gchar *action = g_strdup_printf ("EggRecentTrailingSeparator%u",
265 gtk_ui_manager_add_ui (view->uimanager,
269 EGG_RECENT_SEPARATOR,
277 egg_recent_view_uimanager_set_empty_list (EggRecentViewUIManager *view)
279 gboolean is_embedded;
281 g_return_if_fail (view);
283 egg_recent_view_uimanager_clear (view);
285 if (view->merge_id == 0)
286 view->merge_id = gtk_ui_manager_new_merge_id (view->uimanager);
288 if (view->action_group == NULL) {
289 gchar *group = g_strdup_printf ("EggRecentActions%u",
291 view->action_group = gtk_action_group_new (group);
292 g_signal_connect (view->action_group, "connect-proxy",
293 G_CALLBACK (connect_proxy_cb), view);
294 gtk_ui_manager_insert_action_group (view->uimanager,
295 view->action_group, -1);
299 if (view->leading_sep) {
300 gchar *sep_action = g_strdup_printf ("EggRecentLeadingSeparator%u",
302 gtk_ui_manager_add_ui (view->uimanager,
306 EGG_RECENT_SEPARATOR,
312 is_embedded = (view->leading_sep && view->trailing_sep);
318 name = g_strdup_printf (EGG_RECENT_NAME_PREFIX "%u-0", view->merge_id);
320 action = g_object_new (GTK_TYPE_ACTION,
326 gtk_action_group_add_action (view->action_group, action);
327 g_object_unref (action);
329 gtk_ui_manager_add_ui (view->uimanager,
340 if (view->trailing_sep) {
341 gchar *sep_action = g_strdup_printf ("EggRecentTrailingSeparator%u",
343 gtk_ui_manager_add_ui (view->uimanager,
347 EGG_RECENT_SEPARATOR,
355 model_changed_cb (EggRecentModel *model,
357 EggRecentViewUIManager *view)
360 egg_recent_view_uimanager_set_list (view, list);
362 egg_recent_view_uimanager_set_empty_list (view);
364 gtk_ui_manager_ensure_update (view->uimanager);
367 static EggRecentModel *
368 egg_recent_view_uimanager_get_model (EggRecentView *view_parent)
370 EggRecentViewUIManager *view;
372 g_return_val_if_fail (view_parent != NULL, NULL);
373 view = EGG_RECENT_VIEW_UIMANAGER (view_parent);
378 egg_recent_view_uimanager_set_model (EggRecentView *view_parent,
379 EggRecentModel *model)
381 EggRecentViewUIManager *view;
383 g_return_if_fail (view_parent != NULL);
384 view = EGG_RECENT_VIEW_UIMANAGER (view_parent);
386 if (view->model != NULL) {
387 if (view->changed_cb_id != 0)
388 g_signal_handler_disconnect (G_OBJECT (view->model),
389 view->changed_cb_id);
390 g_object_unref (view->model);
394 g_object_ref (view->model);
396 view->changed_cb_id = g_signal_connect_object (G_OBJECT (model),
398 G_CALLBACK (model_changed_cb),
401 egg_recent_model_changed (view->model);
405 egg_recent_view_uimanager_set_leading_sep (EggRecentViewUIManager *view,
408 view->leading_sep = val;
409 egg_recent_view_uimanager_clear (view);
411 egg_recent_model_changed (view->model);
415 egg_recent_view_uimanager_set_trailing_sep (EggRecentViewUIManager *view,
418 view->trailing_sep = val;
419 egg_recent_view_uimanager_clear (view);
421 egg_recent_model_changed (view->model);
425 egg_recent_view_uimanager_set_property (GObject *object,
430 EggRecentViewUIManager *view = EGG_RECENT_VIEW_UIMANAGER (object);
434 egg_recent_view_uimanager_set_uimanager (view, (GtkUIManager*)g_value_get_object (value));
437 egg_recent_view_uimanager_set_path (view, g_value_get_string (value));
439 case PROP_SHOW_ICONS:
440 egg_recent_view_uimanager_show_icons (view, g_value_get_boolean (value));
442 case PROP_SHOW_NUMBERS:
443 egg_recent_view_uimanager_show_numbers (view, g_value_get_boolean (value));
445 case PROP_LABEL_WIDTH:
446 egg_recent_view_uimanager_set_label_width (view, g_value_get_int (value));
449 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
455 egg_recent_view_uimanager_get_property (GObject *object,
460 EggRecentViewUIManager *view = EGG_RECENT_VIEW_UIMANAGER (object);
464 g_value_set_object (value, view->uimanager);
467 g_value_set_string (value, view->path);
469 case PROP_SHOW_ICONS:
470 g_value_set_boolean (value, view->show_icons);
472 case PROP_SHOW_NUMBERS:
473 g_value_set_boolean (value, view->show_numbers);
475 case PROP_LABEL_WIDTH:
476 g_value_set_int (value, view->label_width);
479 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
485 egg_recent_view_uimanager_finalize (GObject *object)
487 EggRecentViewUIManager *view = EGG_RECENT_VIEW_UIMANAGER (object);
489 if (view->changed_cb_id != 0) {
490 g_signal_handler_disconnect (G_OBJECT (view->model),
491 view->changed_cb_id);
492 view->changed_cb_id = 0;
497 egg_recent_view_uimanager_clear (view);
499 if (view->action_group != NULL) {
500 g_object_unref (view->action_group);
501 view->action_group = NULL;
504 if (view->uimanager != NULL) {
505 g_object_unref (view->uimanager);
506 view->uimanager = NULL;
509 if (view->model != NULL) {
510 g_object_unref (view->model);
514 #ifndef USE_STABLE_LIBGNOMEUI
515 if (view->theme != NULL) {
516 g_object_unref (view->theme);
521 if (view->client != NULL) {
522 g_object_unref (view->client);
526 G_OBJECT_CLASS (egg_recent_view_uimanager_parent_class)->finalize (object);
530 egg_recent_view_uimanager_class_init (EggRecentViewUIManagerClass * klass)
532 GObjectClass *object_class;
534 object_class = G_OBJECT_CLASS (klass);
536 object_class->set_property = egg_recent_view_uimanager_set_property;
537 object_class->get_property = egg_recent_view_uimanager_get_property;
538 object_class->finalize = egg_recent_view_uimanager_finalize;
540 view_signals[ACTIVATE] = g_signal_new ("activate",
541 G_OBJECT_CLASS_TYPE (object_class),
543 G_STRUCT_OFFSET (EggRecentViewUIManagerClass, activate),
545 g_cclosure_marshal_VOID__BOXED,
547 EGG_TYPE_RECENT_ITEM);
549 g_object_class_install_property (object_class,
551 g_param_spec_object ("uimanager",
553 "The UI manager this object will use to update.the UI",
556 g_object_class_install_property (object_class,
558 g_param_spec_string ("path",
560 "The UI path this object will update.",
563 g_object_class_install_property (object_class,
565 g_param_spec_boolean ("show-icons",
567 "Whether or not to show icons",
571 g_object_class_install_property (object_class,
573 g_param_spec_boolean ("show-numbers",
575 "Whether or not to show numbers",
578 g_object_class_install_property (object_class,
580 g_param_spec_int ("label-width",
582 "The desired width of the menu label, in characters",
585 DEFAULT_LABEL_WIDTH_CHARS,
589 klass->activate = NULL;
593 egg_recent_view_init (EggRecentViewClass *iface)
595 iface->do_get_model = egg_recent_view_uimanager_get_model;
596 iface->do_set_model = egg_recent_view_uimanager_set_model;
600 show_menus_changed_cb (GConfClient *client,
603 EggRecentViewUIManager *view)
607 value = gconf_entry_get_value (entry);
608 g_return_if_fail (value->type == GCONF_VALUE_BOOL);
610 egg_recent_view_uimanager_show_icons (view, gconf_value_get_bool (value));
613 #ifndef USE_STABLE_LIBGNOMEUI
615 theme_changed_cb (GnomeIconTheme *theme,
616 EggRecentViewUIManager *view)
618 if (view->model != NULL)
619 egg_recent_model_changed (view->model);
624 egg_recent_view_uimanager_init (EggRecentViewUIManager * view)
626 view->client = gconf_client_get_default ();
628 view->show_icons = gconf_client_get_bool (view->client,
629 "/desktop/gnome/interface/menus_have_icons",
632 gconf_client_add_dir (view->client, "/desktop/gnome/interface",
633 GCONF_CLIENT_PRELOAD_NONE,
635 gconf_client_notify_add (view->client,
636 "/desktop/gnome/interface/menus_have_icons",
637 (GConfClientNotifyFunc)show_menus_changed_cb,
641 view->leading_sep = FALSE;
642 view->trailing_sep = FALSE;
643 view->show_numbers = TRUE;
645 view->uimanager = NULL;
646 view->action_group = NULL;
648 view->changed_cb_id = 0;
652 #ifndef USE_STABLE_LIBGNOMEUI
653 view->theme = gnome_icon_theme_new ();
654 gnome_icon_theme_set_allow_svg (view->theme, TRUE);
655 g_signal_connect_object (view->theme, "changed",
656 G_CALLBACK (theme_changed_cb), view, 0);
659 view->tooltip_func = NULL;
660 view->tooltip_func_data = NULL;
662 view->icon_size = GTK_ICON_SIZE_MENU;
663 view->label_width = DEFAULT_LABEL_WIDTH_CHARS;
667 egg_recent_view_uimanager_set_icon_size (EggRecentViewUIManager *view,
668 GtkIconSize icon_size)
670 if (view->icon_size != icon_size) {
671 view->icon_size = icon_size;
672 egg_recent_model_changed (view->model);
674 view->icon_size = icon_size;
679 egg_recent_view_uimanager_get_icon_size (EggRecentViewUIManager *view)
681 return view->icon_size;
685 egg_recent_view_uimanager_show_icons (EggRecentViewUIManager *view,
688 view->show_icons = show;
689 if (view->model != NULL)
690 egg_recent_model_changed (view->model);
694 egg_recent_view_uimanager_show_numbers (EggRecentViewUIManager *view,
697 view->show_numbers = show;
698 if (view->model != NULL)
699 egg_recent_model_changed (view->model);
703 egg_recent_view_uimanager_set_tooltip_func (EggRecentViewUIManager *view,
704 EggUIManagerTooltipFunc func,
707 view->tooltip_func = func;
708 view->tooltip_func_data = user_data;
710 egg_recent_model_changed (view->model);
714 * egg_recent_view_uimanager_set_uimanager:
715 * @view: A EggRecentViewUIManager object.
716 * @uimanager: The ui manager used to put the menu items in.
718 * Use this function to change the ui manager used to update the menu.
722 egg_recent_view_uimanager_set_uimanager (EggRecentViewUIManager *view,
723 GtkUIManager *uimanager)
725 g_return_if_fail (EGG_IS_RECENT_VIEW_UIMANAGER (view));
726 g_return_if_fail (uimanager != NULL);
728 if (view->uimanager != NULL)
729 g_object_unref (view->uimanager);
730 view->uimanager = uimanager;
731 g_object_ref (view->uimanager);
735 * egg_recent_view_uimanager_get_uimanager:
736 * @view: A EggRecentViewUIManager object.
740 egg_recent_view_uimanager_get_uimanager (EggRecentViewUIManager *view)
742 g_return_val_if_fail (EGG_IS_RECENT_VIEW_UIMANAGER (view), NULL);
743 return view->uimanager;
747 * egg_recent_view_uimanager_set_path:
748 * @view: A EggRecentViewUIManager object.
749 * @path: The path to put the menu items in.
751 * Use this function to change the path where the recent
752 * documents appear in.
756 egg_recent_view_uimanager_set_path (EggRecentViewUIManager *view,
759 g_return_if_fail (EGG_IS_RECENT_VIEW_UIMANAGER (view));
760 g_return_if_fail (path);
763 view->path = g_strdup (path);
767 * egg_recent_view_uimanager_get_path:
768 * @view: A EggRecentViewUIManager object.
771 G_CONST_RETURN gchar*
772 egg_recent_view_uimanager_get_path (EggRecentViewUIManager *view)
774 g_return_val_if_fail (EGG_IS_RECENT_VIEW_UIMANAGER (view), NULL);
779 egg_recent_view_uimanager_set_label_width (EggRecentViewUIManager *view,
782 g_return_if_fail (EGG_IS_RECENT_VIEW_UIMANAGER (view));
783 view->label_width = chars;
787 egg_recent_view_uimanager_get_label_width (EggRecentViewUIManager *view)
789 g_return_val_if_fail (EGG_IS_RECENT_VIEW_UIMANAGER (view), DEFAULT_LABEL_WIDTH_CHARS);
790 return view->label_width;
794 egg_recent_view_uimanager_set_action_func (EggRecentViewUIManager *view,
798 g_return_if_fail (EGG_IS_RECENT_VIEW_UIMANAGER (view));
799 view->action_callback = callback;
800 view->action_user_data = user_data;
804 * egg_recent_view_uimanager_new:
805 * @appname: The name of your application.
806 * @limit: The maximum number of items allowed.
808 * This creates a new EggRecentViewUIManager object.
810 * Returns: a EggRecentViewUIManager object
812 EggRecentViewUIManager *
813 egg_recent_view_uimanager_new (GtkUIManager *uimanager,
820 g_return_val_if_fail (uimanager, NULL);
821 g_return_val_if_fail (path, NULL);
823 view = g_object_new (egg_recent_view_uimanager_get_type (),
824 "uimanager", uimanager,
828 g_return_val_if_fail (view, NULL);
830 egg_recent_view_uimanager_set_action_func (EGG_RECENT_VIEW_UIMANAGER (view),
834 return EGG_RECENT_VIEW_UIMANAGER (view);
838 egg_recent_view_uimanager_get_type (void)
840 static GType egg_recent_view_uimanager_type = 0;
842 if(!egg_recent_view_uimanager_type) {
843 const GTypeInfo egg_recent_view_uimanager_info = {
844 sizeof (EggRecentViewUIManagerClass),
845 NULL, /* base init */
846 NULL, /* base finalize */
847 (GClassInitFunc)egg_recent_view_uimanager_class_init, /* class init */
848 NULL, /* class finalize */
849 NULL, /* class data */
850 sizeof (EggRecentViewUIManager),
852 (GInstanceInitFunc) egg_recent_view_uimanager_init
855 const GInterfaceInfo view_info =
857 (GInterfaceInitFunc) egg_recent_view_init,
862 egg_recent_view_uimanager_type = g_type_register_static (G_TYPE_OBJECT,
863 "EggRecentViewUIManager",
864 &egg_recent_view_uimanager_info, 0);
865 g_type_add_interface_static (egg_recent_view_uimanager_type,
866 EGG_TYPE_RECENT_VIEW,
870 return egg_recent_view_uimanager_type;
874 egg_recent_view_uimanager_get_item (EggRecentViewUIManager *view,
877 return g_object_get_data (G_OBJECT(action), "egg_recent_uri");