Merge commit 'git-svn'
[anjuta-git-plugin.git] / libegg / egg-recent-action.c
blobb7c6cd050da7c5e8fdadbc76f6ddd1b735bf9c3b
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /* egg-recent-action widget
5 * Copyright (C) Naba Kumar <naba@gnome.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
22 #include <stdio.h>
23 #include <gtk/gtkwidget.h>
24 #include <gtk/gtktoggletoolbutton.h>
25 #include <libegg/recent-files/egg-recent-view.h>
26 #include <libegg/recent-files/egg-recent-view-gtk.h>
27 #include "egg-recent-action.h"
29 #ifndef _
30 # define _(s) (s)
31 #endif
33 struct _EggRecentActionPriv
35 GList *recent_models;
36 gint size;
37 gchar *selected_uri;
40 static void egg_recent_action_init (EggRecentAction *action);
41 static void egg_recent_action_class_init (EggRecentActionClass *class);
43 static GtkWidget * create_tool_item (GtkAction *action);
44 static GtkWidget * create_menu_item (GtkAction *action);
45 static void connect_proxy (GtkAction *action,
46 GtkWidget *proxy);
47 static void disconnect_proxy (GtkAction *action,
48 GtkWidget *proxy);
49 static void egg_recent_action_finalize (GObject *object);
50 static void egg_recent_action_dispose (GObject *object);
51 static gboolean on_recent_select (EggRecentView *recent, EggRecentItem *item,
52 EggRecentAction *plugin);
54 static GObjectClass *parent_class = NULL;
56 GType
57 egg_recent_action_get_type (void)
59 static GtkType type = 0;
61 if (!type)
63 static const GTypeInfo type_info =
65 sizeof (EggRecentActionClass),
66 (GBaseInitFunc) NULL,
67 (GBaseFinalizeFunc) NULL,
68 (GClassInitFunc) egg_recent_action_class_init,
69 (GClassFinalizeFunc) NULL,
70 NULL,
72 sizeof (EggRecentAction),
73 0, /* n_preallocs */
74 (GInstanceInitFunc) egg_recent_action_init,
77 type = g_type_register_static (GTK_TYPE_ACTION,
78 "EggRecentAction",
79 &type_info, 0);
81 return type;
84 static void
85 egg_recent_action_class_init (EggRecentActionClass *class)
87 GtkActionClass *action_class;
88 GObjectClass *object_class;
90 parent_class = g_type_class_peek_parent (class);
91 action_class = GTK_ACTION_CLASS (class);
92 object_class = G_OBJECT_CLASS (class);
94 object_class->finalize = egg_recent_action_finalize;
95 object_class->dispose = egg_recent_action_dispose;
97 action_class->connect_proxy = connect_proxy;
98 action_class->disconnect_proxy = disconnect_proxy;
99 action_class->menu_item_type = GTK_TYPE_MENU_ITEM;
100 action_class->toolbar_item_type = GTK_TYPE_TOOL_ITEM;
101 action_class->create_tool_item = create_tool_item;
102 action_class->create_menu_item = create_menu_item;
105 static void
106 egg_recent_action_init (EggRecentAction *action)
108 action->priv = g_new0 (EggRecentActionPriv, 1);
109 action->priv->recent_models = NULL;
110 action->priv->selected_uri = NULL;
113 static void
114 egg_recent_action_dispose (GObject *object)
116 EggRecentActionPriv *priv;
118 priv = EGG_RECENT_ACTION (object)->priv;
119 if (priv->recent_models)
121 GList *node;
122 node = priv->recent_models;
123 while (node)
125 g_object_unref (node->data);
126 node = g_list_next (node);
128 g_list_free (priv->recent_models);
129 priv->recent_models = NULL;
131 if (parent_class->dispose)
132 parent_class->dispose (object);
135 static void
136 egg_recent_action_finalize (GObject *object)
138 g_free (EGG_RECENT_ACTION (object)->priv->selected_uri);
139 g_free (EGG_RECENT_ACTION (object)->priv);
140 if (parent_class->finalize)
141 parent_class->finalize (object);
144 static gboolean
145 on_recent_select (EggRecentView *view, EggRecentItem *item,
146 EggRecentAction *action)
148 gchar *uri;
149 gboolean ret = TRUE;
151 uri = egg_recent_item_get_uri (item);
152 if (uri)
154 g_free (action->priv->selected_uri);
155 action->priv->selected_uri = g_strdup (uri);
156 g_free (uri);
157 gtk_action_activate (GTK_ACTION (action));
159 return ret;
162 static void
163 on_recent_files_tooltip (GtkTooltips *tooltips, GtkWidget *menu_item,
164 EggRecentItem *item, gpointer user_data)
166 char *uri, *tip;
168 uri = egg_recent_item_get_uri_for_display (item);
169 tip = g_strdup_printf ("Open '%s'", uri);
171 gtk_tooltips_set_tip (tooltips, menu_item, tip, NULL);
173 g_free (tip);
174 g_free (uri);
177 static void
178 update_recent_submenu (EggRecentAction *action, GtkWidget *submenu,
179 EggRecentModel *model, gint id)
181 EggRecentViewGtk *recent_view;
182 GtkWidget *sep = NULL;
183 gchar buff[64];
185 if (id != 0)
187 sep = gtk_menu_item_new ();
188 gtk_widget_show (sep);
189 gtk_menu_shell_append (GTK_MENU_SHELL (submenu), sep);
191 recent_view = egg_recent_view_gtk_new (submenu, sep);
192 egg_recent_view_gtk_set_tooltip_func (recent_view,
193 on_recent_files_tooltip, NULL);
194 egg_recent_view_set_model (EGG_RECENT_VIEW (recent_view),
195 model);
196 snprintf (buff, 64, "recent-view-%d", id);
197 g_object_set_data_full (G_OBJECT (submenu), buff, recent_view,
198 g_object_unref);
199 g_signal_connect (G_OBJECT (recent_view), "activate",
200 G_CALLBACK (on_recent_select), action);
203 static GtkWidget*
204 create_recent_submenu (EggRecentAction *action)
206 GtkWidget *submenu;
207 GList *node;
208 gint id;
210 submenu = gtk_menu_new ();
211 node = action->priv->recent_models;
212 id = 0;
213 while (node)
215 update_recent_submenu (action, submenu, node->data, id);
216 id++;
217 node = g_list_next (node);
219 return submenu;
222 static void
223 on_reposition_menu (GtkMenu *menu, gint *x, gint *y, gboolean *push_in,
224 gpointer data)
226 gint x1, y1, w, h, d;
227 GtkWidget *button = GTK_WIDGET (data);
228 gdk_window_get_origin (button->window, x, y);
229 gdk_window_get_geometry (button->window, &x1, &y1, &w, &h, &d);
230 *y += button->allocation.height;
231 if (GTK_WIDGET_NO_WINDOW (button))
233 *x += button->allocation.x;
234 *y += button->allocation.y;
238 static void
239 on_selection_done_menu (GtkMenu *menu, GtkWidget *button)
241 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
244 static void
245 on_button_pressed (GtkToggleToolButton *button, EggRecentAction *action)
247 GtkWidget *submenu;
249 /* g_message ("Recent toolitem toggled"); */
250 submenu = g_object_get_data (G_OBJECT (button), "submenu");
251 if (!submenu)
253 submenu = create_recent_submenu (action);
254 g_object_set_data_full (G_OBJECT (button), "submenu", submenu,
255 (GDestroyNotify)gtk_widget_destroy);
256 g_object_set_data (G_OBJECT (submenu), "thebutton", button);
257 g_signal_connect (G_OBJECT (submenu), "selection-done",
258 G_CALLBACK (on_selection_done_menu), button);
259 gtk_widget_show (submenu);
261 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
263 gtk_menu_popup (GTK_MENU (submenu), NULL, NULL, on_reposition_menu,
264 button, 0, gtk_get_current_event_time ());
265 gtk_menu_reposition (GTK_MENU (submenu));
267 else
269 gtk_menu_popdown (GTK_MENU (submenu));
273 static GtkWidget *
274 create_tool_item (GtkAction *action)
276 GtkWidget *arrow;
277 GtkWidget *button;
278 GtkToolItem *item;
280 g_return_val_if_fail (EGG_IS_RECENT_ACTION (action), NULL);
281 /* g_message ("Creating recent toolitem"); */
283 item = gtk_tool_item_new ();
284 gtk_widget_show(GTK_WIDGET (item));
285 button = gtk_toggle_button_new ();
286 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
287 gtk_container_add (GTK_CONTAINER (item), button);
288 gtk_widget_show(GTK_WIDGET (button));
289 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
290 gtk_widget_show (arrow);
291 gtk_container_add (GTK_CONTAINER (button), arrow);
292 return GTK_WIDGET (item);
295 static GtkWidget *
296 create_menu_item (GtkAction *action)
298 GtkWidget *menuitem, *submenu;
299 menuitem = (* GTK_ACTION_CLASS (parent_class)->create_menu_item) (action);
300 submenu = create_recent_submenu (EGG_RECENT_ACTION (action));
301 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
302 return menuitem;
305 static void
306 connect_proxy (GtkAction *action, GtkWidget *proxy)
308 EggRecentAction *recent_action;
310 recent_action = EGG_RECENT_ACTION (action);
312 /* do this before hand, so that we don't call the "activate" handler */
313 if (GTK_IS_TOOL_ITEM (proxy))
315 g_signal_connect (G_OBJECT (gtk_bin_get_child(GTK_BIN (proxy))), "toggled",
316 G_CALLBACK (on_button_pressed), action);
318 (* GTK_ACTION_CLASS (parent_class)->connect_proxy) (action, proxy);
321 static void
322 disconnect_proxy (GtkAction *action, GtkWidget *proxy)
324 EggRecentAction *recent_action;
326 recent_action = EGG_RECENT_ACTION (action);
328 /* do this before hand, so that we don't call the "activate" handler */
329 if (GTK_IS_TOOL_ITEM (proxy))
331 g_signal_handlers_disconnect_by_func (G_OBJECT (gtk_bin_get_child(GTK_BIN (proxy))),
332 G_CALLBACK (on_button_pressed), action);
334 (* GTK_ACTION_CLASS (parent_class)->connect_proxy) (action, proxy);
338 * egg_recent_action_set_model:
339 * @action: the action object
340 * @model: a GtkTreeModel
342 * Sets a model in the action.
344 void
345 egg_recent_action_add_model (EggRecentAction *action, EggRecentModel *model)
347 GSList *slist;
349 g_return_if_fail (EGG_IS_RECENT_ACTION (action));
350 g_return_if_fail (EGG_IS_RECENT_MODEL (model));
352 g_object_ref (model);
353 action->priv->recent_models =
354 g_list_append (action->priv->recent_models, model);
356 for (slist = gtk_action_get_proxies (GTK_ACTION(action));
357 slist; slist = slist->next)
359 GtkWidget *proxy = slist->data;
361 gtk_action_block_activate_from (GTK_ACTION (action), proxy);
363 if (GTK_IS_MENU_ITEM (proxy))
365 GtkWidget *submenu;
367 submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM(proxy));
368 update_recent_submenu (action, submenu, model,
369 g_list_length (action->priv->recent_models)-1);
371 else if (GTK_IS_TOOL_ITEM (proxy))
373 GtkWidget *submenu;
375 submenu = g_object_get_data (G_OBJECT (gtk_bin_get_child(GTK_BIN(proxy))), "submenu");
376 update_recent_submenu (action, submenu, model,
377 g_list_length (action->priv->recent_models)-1);
379 else
381 g_warning ("Don't know how to set popdown for `%s' widgets",
382 G_OBJECT_TYPE_NAME (proxy));
384 gtk_action_unblock_activate_from (GTK_ACTION (action), proxy);
388 const gchar*
389 egg_recent_action_get_selected_uri (EggRecentAction *action)
391 return action->priv->selected_uri;