Added functions for getting Site nodes
[ephy-soc.git] / src / ephy-encoding-menu.c
blob28b6bf7f3a9fecb2ffb41d81ae633c00262ba5a0
1 /*
2 * Copyright © 2002 Ricardo Fernández Pascual
3 * Copyright © 2003 Marco Pesenti Gritti
4 * Copyright © 2003 Christian Persch
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * $Id: ephy-encoding-menu.c 6952 2007-03-11 19:42:02Z chpe $
23 #include "config.h"
25 #include "ephy-encoding-menu.h"
26 #include "ephy-encoding-dialog.h"
27 #include "ephy-encodings.h"
28 #include "ephy-embed.h"
29 #include "ephy-embed-shell.h"
30 #include "ephy-shell.h"
31 #include "ephy-debug.h"
33 #include <gtk/gtkaction.h>
34 #include <gtk/gtktoggleaction.h>
35 #include <gtk/gtkradioaction.h>
36 #include <gtk/gtkuimanager.h>
37 #include <glib/gi18n.h>
38 #include <string.h>
40 #define EPHY_ENCODING_MENU_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_ENCODING_MENU, EphyEncodingMenuPrivate))
42 struct _EphyEncodingMenuPrivate
44 EphyEncodings *encodings;
45 EphyWindow *window;
46 GtkUIManager *manager;
47 GtkActionGroup *action_group;
48 gboolean update_tag;
49 guint merge_id;
50 GSList *encodings_radio_group;
51 EphyEncodingDialog *dialog;
54 #define ENCODING_PLACEHOLDER_PATH "/menubar/ViewMenu/ViewEncodingMenu/ViewEncodingPlaceholder"
56 static void ephy_encoding_menu_class_init (EphyEncodingMenuClass *klass);
57 static void ephy_encoding_menu_init (EphyEncodingMenu *menu);
59 enum
61 PROP_0,
62 PROP_WINDOW
65 static GObjectClass *parent_class = NULL;
67 GType
68 ephy_encoding_menu_get_type (void)
70 static GType type = 0;
72 if (G_UNLIKELY (type == 0))
74 const GTypeInfo our_info =
76 sizeof (EphyEncodingMenuClass),
77 NULL,
78 NULL,
79 (GClassInitFunc) ephy_encoding_menu_class_init,
80 NULL,
81 NULL,
82 sizeof (EphyEncodingMenu),
84 (GInstanceInitFunc) ephy_encoding_menu_init
87 type = g_type_register_static (G_TYPE_OBJECT,
88 "EphyEncodingMenu",
89 &our_info, 0);
92 return type;
95 static void
96 ephy_encoding_menu_init (EphyEncodingMenu *menu)
98 menu->priv = EPHY_ENCODING_MENU_GET_PRIVATE (menu);
100 menu->priv->encodings =
101 EPHY_ENCODINGS (ephy_embed_shell_get_encodings
102 (EPHY_EMBED_SHELL (ephy_shell)));
105 static int
106 sort_encodings (gconstpointer a, gconstpointer b)
108 EphyNode *node1 = (EphyNode *) a;
109 EphyNode *node2 = (EphyNode *) b;
110 const char *key1, *key2;
112 key1 = ephy_node_get_property_string
113 (node1, EPHY_NODE_ENCODING_PROP_COLLATION_KEY);
114 key2 = ephy_node_get_property_string
115 (node2, EPHY_NODE_ENCODING_PROP_COLLATION_KEY);
117 return strcmp (key1, key2);
120 static void
121 add_menu_item (EphyNode *node, EphyEncodingMenu *menu)
123 const char *code;
124 char action[128], name[128];
126 code = ephy_node_get_property_string
127 (node, EPHY_NODE_ENCODING_PROP_ENCODING);
129 g_snprintf (action, sizeof (action), "Encoding%s", code);
130 g_snprintf (name, sizeof (name), "%sItem", action);
132 gtk_ui_manager_add_ui (menu->priv->manager, menu->priv->merge_id,
133 ENCODING_PLACEHOLDER_PATH,
134 name, action,
135 GTK_UI_MANAGER_MENUITEM, FALSE);
138 static void
139 update_encoding_menu_cb (GtkAction *dummy, EphyEncodingMenu *menu)
141 EphyEncodingMenuPrivate *p = menu->priv;
142 EphyEmbed *embed;
143 GtkAction *action;
144 char name[128];
145 char *encoding;
146 EphyNode *enc_node;
147 GList *recent, *related = NULL, *l;
148 EphyLanguageGroup groups;
149 gboolean is_automatic;
151 START_PROFILER ("Rebuilding encoding menu")
153 /* FIXME: block the "activate" signal on the actions instead; needs to
154 * wait until g_signal_handlers_block_matched supports blocking
155 * by signal id alone.
157 menu->priv->update_tag = TRUE;
159 /* get most recently used encodings */
160 recent = ephy_encodings_get_recent (p->encodings);
162 embed = ephy_window_get_active_embed (p->window);
163 encoding = ephy_embed_get_encoding (embed);
164 if (encoding == NULL) goto build_menu;
166 enc_node = ephy_encodings_get_node (p->encodings, encoding, TRUE);
167 g_assert (EPHY_IS_NODE (enc_node));
169 /* check if encoding was overridden */
170 is_automatic = ephy_embed_has_automatic_encoding (embed);
172 action = gtk_action_group_get_action (p->action_group,
173 "ViewEncodingAutomatic");
174 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), is_automatic);
175 gtk_action_set_sensitive (action, !is_automatic);
177 /* set the encodings group's active member */
178 g_snprintf (name, sizeof (name), "Encoding%s", encoding);
179 action = gtk_action_group_get_action (p->action_group, name);
180 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
182 /* get encodings related to the current encoding */
183 groups = ephy_node_get_property_int
184 (enc_node, EPHY_NODE_ENCODING_PROP_LANGUAGE_GROUPS);
186 related = ephy_encodings_get_encodings (p->encodings, groups);
187 related = g_list_sort (related, (GCompareFunc) sort_encodings);
189 /* add the current encoding to the list of
190 * things to display, making sure we don't add it more than once
192 if (g_list_find (related, enc_node) == NULL
193 && g_list_find (recent, enc_node) == NULL)
195 related = g_list_prepend (related, enc_node);
198 /* make sure related and recent are disjoint so we don't display twice */
199 for (l = related; l != NULL; l = l->next)
201 recent = g_list_remove (recent, l->data);
204 recent = g_list_sort (recent, (GCompareFunc) sort_encodings);
206 build_menu:
207 /* clear the menu */
208 if (p->merge_id > 0)
210 gtk_ui_manager_remove_ui (p->manager, p->merge_id);
211 gtk_ui_manager_ensure_update (p->manager);
214 /* build the new menu */
215 p->merge_id = gtk_ui_manager_new_merge_id (p->manager);
217 gtk_ui_manager_add_ui (p->manager, p->merge_id,
218 ENCODING_PLACEHOLDER_PATH,
219 "ViewEncodingAutomaticItem",
220 "ViewEncodingAutomatic",
221 GTK_UI_MANAGER_MENUITEM, FALSE);
223 gtk_ui_manager_add_ui (p->manager, p->merge_id,
224 ENCODING_PLACEHOLDER_PATH,
225 "Sep1Item", "Sep1",
226 GTK_UI_MANAGER_SEPARATOR, FALSE);
228 g_list_foreach (recent, (GFunc) add_menu_item, menu);
230 gtk_ui_manager_add_ui (p->manager, p->merge_id,
231 ENCODING_PLACEHOLDER_PATH,
232 "Sep2Item", "Sep2",
233 GTK_UI_MANAGER_SEPARATOR, FALSE);
235 g_list_foreach (related, (GFunc) add_menu_item, menu);
237 gtk_ui_manager_add_ui (p->manager, p->merge_id,
238 ENCODING_PLACEHOLDER_PATH,
239 "Sep3Item", "Sep3",
240 GTK_UI_MANAGER_SEPARATOR, FALSE);
242 gtk_ui_manager_add_ui (p->manager, p->merge_id,
243 ENCODING_PLACEHOLDER_PATH,
244 "ViewEncodingOtherItem",
245 "ViewEncodingOther",
246 GTK_UI_MANAGER_MENUITEM, FALSE);
248 /* cleanup */
249 g_list_free (related);
250 g_list_free (recent);
252 g_free (encoding);
254 menu->priv->update_tag = FALSE;
256 STOP_PROFILER ("Rebuilding encoding menu")
259 static void
260 encoding_activate_cb (GtkAction *action, EphyEncodingMenu *menu)
262 EphyEmbed *embed;
263 const char *name, *encoding;
265 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) == FALSE
266 || menu->priv->update_tag)
268 return;
271 name = gtk_action_get_name (GTK_ACTION (action));
272 encoding = name + strlen("Encoding");
274 embed = ephy_window_get_active_embed (menu->priv->window);
276 ephy_embed_set_encoding (embed, encoding);
278 ephy_encodings_add_recent (menu->priv->encodings, encoding);
281 static void
282 add_action (EphyNode *encodings, EphyNode *node, EphyEncodingMenu *menu)
284 GtkAction *action;
285 char name[128];
286 const char *encoding, *title;
288 encoding = ephy_node_get_property_string
289 (node, EPHY_NODE_ENCODING_PROP_ENCODING);
290 title = ephy_node_get_property_string
291 (node, EPHY_NODE_ENCODING_PROP_TITLE);
293 LOG ("add_action for encoding '%s'", encoding);
295 g_snprintf (name, sizeof (name), "Encoding%s", encoding);
297 action = g_object_new (GTK_TYPE_RADIO_ACTION,
298 "name", name,
299 "label", title,
300 NULL);
302 gtk_radio_action_set_group (GTK_RADIO_ACTION (action),
303 menu->priv->encodings_radio_group);
304 menu->priv->encodings_radio_group = gtk_radio_action_get_group
305 (GTK_RADIO_ACTION (action));
307 g_signal_connect (action, "activate",
308 G_CALLBACK (encoding_activate_cb),
309 menu);
311 gtk_action_group_add_action_with_accel
312 (menu->priv->action_group, action, NULL);
313 g_object_unref (action);
316 static void
317 ephy_encoding_menu_view_dialog_cb (GtkAction *action, EphyEncodingMenu *menu)
319 if (menu->priv->dialog == NULL)
321 EphyEncodingDialog **dialog = &menu->priv->dialog;
322 menu->priv->dialog = ephy_encoding_dialog_new
323 (menu->priv->window);
325 g_object_add_weak_pointer(G_OBJECT (menu->priv->dialog),
326 (gpointer *)dialog);
329 ephy_dialog_show (EPHY_DIALOG (menu->priv->dialog));
332 static void
333 ephy_encoding_menu_automatic_cb (GtkAction *action, EphyEncodingMenu *menu)
335 EphyEmbed *embed;
337 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) == FALSE
338 || menu->priv->update_tag)
340 return;
343 embed = ephy_window_get_active_embed (menu->priv->window);
345 /* setting "" will clear the forced encoding */
346 ephy_embed_set_encoding (embed, "");
349 static const GtkActionEntry menu_entries [] =
351 { "ViewEncodingOther", NULL, N_("_Other…"), NULL,
352 N_("Other encodings"),
353 G_CALLBACK (ephy_encoding_menu_view_dialog_cb) }
356 static const GtkToggleActionEntry toggle_menu_entries [] =
358 { "ViewEncodingAutomatic", NULL, N_("_Automatic"), NULL,
359 N_("Use the encoding specified by the document"),
360 G_CALLBACK (ephy_encoding_menu_automatic_cb), FALSE }
363 static void
364 ephy_encoding_menu_set_window (EphyEncodingMenu *menu, EphyWindow *window)
366 GtkActionGroup *action_group;
367 GtkAction *action;
368 EphyNode *encodings;
369 GPtrArray *children;
370 int i;
372 g_return_if_fail (EPHY_IS_WINDOW (window));
374 menu->priv->window = window;
375 menu->priv->manager = GTK_UI_MANAGER (ephy_window_get_ui_manager (window));
377 action_group = gtk_action_group_new ("EncodingActions");
378 gtk_action_group_set_translation_domain (action_group, NULL);
379 menu->priv->action_group = action_group;
381 gtk_action_group_add_actions (action_group, menu_entries,
382 G_N_ELEMENTS (menu_entries), menu);
383 gtk_action_group_add_toggle_actions (action_group, toggle_menu_entries,
384 G_N_ELEMENTS (toggle_menu_entries), menu);
386 /* add actions for the existing encodings */
387 encodings = ephy_encodings_get_all (menu->priv->encodings);
388 children = ephy_node_get_children (encodings);
389 for (i = 0; i < children->len; i++)
391 EphyNode *encoding;
393 encoding = (EphyNode *) g_ptr_array_index (children, i);
394 add_action (encodings, encoding, menu);
397 /* when we encounter an unknown encoding, it is added to the database,
398 * so we need to listen to child_added on the encodings node to
399 * add an action for it
401 ephy_node_signal_connect_object (encodings,
402 EPHY_NODE_CHILD_ADDED,
403 (EphyNodeCallback) add_action,
404 G_OBJECT (menu));
406 gtk_ui_manager_insert_action_group (menu->priv->manager,
407 action_group, 0);
408 g_object_unref (action_group);
410 action = gtk_ui_manager_get_action (menu->priv->manager,
411 "/menubar/ViewMenu");
412 g_signal_connect_object (action, "activate",
413 G_CALLBACK (update_encoding_menu_cb),
414 menu, 0);
417 static void
418 ephy_encoding_menu_set_property (GObject *object,
419 guint prop_id,
420 const GValue *value,
421 GParamSpec *pspec)
423 EphyEncodingMenu *menu = EPHY_ENCODING_MENU (object);
425 switch (prop_id)
427 case PROP_WINDOW:
428 ephy_encoding_menu_set_window (menu, g_value_get_object (value));
429 break;
433 static void
434 ephy_encoding_menu_get_property (GObject *object,
435 guint prop_id,
436 GValue *value,
437 GParamSpec *pspec)
439 EphyEncodingMenu *menu = EPHY_ENCODING_MENU (object);
441 switch (prop_id)
443 case PROP_WINDOW:
444 g_value_set_object (value, menu->priv->window);
445 break;
449 static void
450 ephy_encoding_menu_finalize (GObject *object)
452 EphyEncodingMenu *menu = EPHY_ENCODING_MENU (object);
454 if (menu->priv->dialog)
456 g_object_unref (menu->priv->dialog);
459 G_OBJECT_CLASS (parent_class)->finalize (object);
462 static void
463 ephy_encoding_menu_class_init (EphyEncodingMenuClass *klass)
465 GObjectClass *object_class = G_OBJECT_CLASS (klass);
467 parent_class = g_type_class_peek_parent (klass);
469 object_class->finalize = ephy_encoding_menu_finalize;
470 object_class->set_property = ephy_encoding_menu_set_property;
471 object_class->get_property = ephy_encoding_menu_get_property;
473 g_object_class_install_property (object_class,
474 PROP_WINDOW,
475 g_param_spec_object ("window",
476 "Window",
477 "Parent window",
478 EPHY_TYPE_WINDOW,
479 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
480 G_PARAM_CONSTRUCT_ONLY));
482 g_type_class_add_private (object_class, sizeof(EphyEncodingMenuPrivate));
485 EphyEncodingMenu *
486 ephy_encoding_menu_new (EphyWindow *window)
488 return g_object_new (EPHY_TYPE_ENCODING_MENU,
489 "window", window,
490 NULL);