add GSimpleActionGroup
[platform/upstream/glib.git] / gio / gsimpleactiongroup.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation; either version 2 of the licence or (at
7  * your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General
15  * Public License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Authors: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #include "gsimpleactiongroup.h"
23 #include "gaction.h"
24
25 /**
26  * SECTION:gsimpleactiongroup
27  * @title: GSimpleActionGroup
28  * @short_description: a simple #GActionGroup implementation
29  *
30  * #GSimpleActionGroup is a hash table filled with #GAction objects,
31  * implementing the #GActionGroup interface.
32  **/
33
34 struct _GSimpleActionGroupPrivate
35 {
36   GHashTable *table;  /* string -> GAction */
37 };
38
39 G_DEFINE_TYPE (GSimpleActionGroup, g_simple_action_group, G_TYPE_ACTION_GROUP)
40
41 static gchar **
42 g_simple_action_group_list_actions (GActionGroup *group)
43 {
44   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
45   GHashTableIter iter;
46   gint n, i = 0;
47   gchar **keys;
48   gpointer key;
49
50   n = g_hash_table_size (simple->priv->table);
51   keys = g_new (gchar *, n + 1);
52
53   g_hash_table_iter_init (&iter, simple->priv->table);
54   while (g_hash_table_iter_next (&iter, &key, NULL))
55     keys[i++] = g_strdup (key);
56   g_assert_cmpint (i, ==, n);
57   keys[n] = NULL;
58
59   return keys;
60 }
61
62 static gboolean
63 g_simple_action_group_has_action (GActionGroup *group,
64                                   const gchar  *action_name)
65 {
66   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
67
68   return g_hash_table_lookup (simple->priv->table, action_name) != NULL;
69 }
70
71 static const GVariantType *
72 g_simple_action_group_get_parameter_type (GActionGroup *group,
73                                           const gchar  *action_name)
74 {
75   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
76   GAction *action;
77
78   action = g_hash_table_lookup (simple->priv->table, action_name);
79
80   if (action == NULL)
81     return NULL;
82
83   return g_action_get_parameter_type (action);
84 }
85
86 static const GVariantType *
87 g_simple_action_group_get_state_type (GActionGroup *group,
88                                       const gchar  *action_name)
89 {
90   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
91   GAction *action;
92
93   action = g_hash_table_lookup (simple->priv->table, action_name);
94
95   if (action == NULL)
96     return NULL;
97
98   return g_action_get_state_type (action);
99 }
100
101 static GVariant *
102 g_simple_action_group_get_state_hint (GActionGroup *group,
103                                        const gchar  *action_name)
104 {
105   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
106   GAction *action;
107
108   action = g_hash_table_lookup (simple->priv->table, action_name);
109
110   if (action == NULL)
111     return NULL;
112
113   return g_action_get_state_hint (action);
114 }
115
116 static gboolean
117 g_simple_action_group_get_enabled (GActionGroup *group,
118                                    const gchar  *action_name)
119 {
120   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
121   GAction *action;
122
123   action = g_hash_table_lookup (simple->priv->table, action_name);
124
125   if (action == NULL)
126     return FALSE;
127
128   return g_action_get_enabled (action);
129 }
130
131 static GVariant *
132 g_simple_action_group_get_state (GActionGroup *group,
133                                  const gchar  *action_name)
134 {
135   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
136   GAction *action;
137
138   action = g_hash_table_lookup (simple->priv->table, action_name);
139
140   if (action == NULL)
141     return NULL;
142
143   return g_action_get_state (action);
144 }
145
146 static void
147 g_simple_action_group_set_state (GActionGroup *group,
148                                  const gchar  *action_name,
149                                  GVariant     *value)
150 {
151   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
152   GAction *action;
153
154   action = g_hash_table_lookup (simple->priv->table, action_name);
155
156   if (action == NULL)
157     return;
158
159   return g_action_set_state (action, value);
160 }
161
162 static void
163 g_simple_action_group_activate (GActionGroup *group,
164                                 const gchar  *action_name,
165                                 GVariant     *parameter)
166 {
167   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
168   GAction *action;
169
170   action = g_hash_table_lookup (simple->priv->table, action_name);
171
172   if (action == NULL)
173     return;
174
175   return g_action_activate (action, parameter);
176 }
177
178 static void
179 action_enabled_changed (GAction  *action,
180                         gboolean  enabled,
181                         gpointer  user_data)
182 {
183   g_action_group_action_enabled_changed (user_data,
184                                          g_action_get_name (action),
185                                          enabled);
186 }
187
188 static void
189 action_state_changed (GAction  *action,
190                       GVariant *value,
191                       gpointer  user_data)
192 {
193   g_action_group_action_state_changed (user_data,
194                                        g_action_get_name (action),
195                                        value);
196 }
197
198 static void
199 g_simple_action_group_disconnect (gpointer key,
200                                   gpointer value,
201                                   gpointer user_data)
202 {
203   g_signal_handlers_disconnect_by_func (value, action_enabled_changed,
204                                         user_data);
205   g_signal_handlers_disconnect_by_func (value, action_state_changed,
206                                         user_data);
207 }
208
209 static void
210 g_simple_action_group_finalize (GObject *object)
211 {
212   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (object);
213
214   g_hash_table_foreach (simple->priv->table,
215                         g_simple_action_group_disconnect,
216                         simple);
217   g_hash_table_unref (simple->priv->table);
218
219   G_OBJECT_CLASS (g_simple_action_group_parent_class)
220     ->finalize (object);
221 }
222
223 static void
224 g_simple_action_group_init (GSimpleActionGroup *simple)
225 {
226   simple->priv = G_TYPE_INSTANCE_GET_PRIVATE (simple,
227                                               G_TYPE_SIMPLE_ACTION_GROUP,
228                                               GSimpleActionGroupPrivate);
229   simple->priv->table = g_hash_table_new_full (g_str_hash, g_str_equal,
230                                                g_free, g_object_unref);
231 }
232
233 static void
234 g_simple_action_group_class_init (GSimpleActionGroupClass *class)
235 {
236   GActionGroupClass *group_class = G_ACTION_GROUP_CLASS (class);
237   GObjectClass *object_class = G_OBJECT_CLASS (class);
238
239   object_class->finalize = g_simple_action_group_finalize;
240
241   group_class->list_actions = g_simple_action_group_list_actions;
242   group_class->has_action = g_simple_action_group_has_action;
243   group_class->get_parameter_type = g_simple_action_group_get_parameter_type;
244   group_class->get_state_type = g_simple_action_group_get_state_type;
245   group_class->get_state_hint = g_simple_action_group_get_state_hint;
246   group_class->get_enabled = g_simple_action_group_get_enabled;
247   group_class->get_state = g_simple_action_group_get_state;
248   group_class->set_state = g_simple_action_group_set_state;
249   group_class->activate = g_simple_action_group_activate;
250
251   g_type_class_add_private (class, sizeof (GSimpleActionGroupPrivate));
252 }
253
254 /**
255  * g_simple_action_group_new:
256  *
257  * Creates a new, empty, #GSimpleActionGroup.
258  *
259  * Returns: a new #GSimpleActionGroup
260  *
261  * Since: 2.26
262  **/
263 GSimpleActionGroup *
264 g_simple_action_group_new (void)
265 {
266   return g_object_new (G_TYPE_SIMPLE_ACTION_GROUP, NULL);
267 }
268
269 /**
270  * g_simple_action_group_lookup:
271  * @simple: a #GSimpleActionGroup
272  * @action_name: the name of an action
273  *
274  * Looks up the action with the name @action_name in the group.
275  *
276  * If no such action exists, returns %NULL.
277  *
278  * Returns: (transfer none): a #GAction, or %NULL
279  *
280  * Since: 2.26
281  **/
282 GAction *
283 g_simple_action_group_lookup (GSimpleActionGroup *simple,
284                               const gchar        *action_name)
285 {
286   g_return_val_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple), NULL);
287
288   return g_hash_table_lookup (simple->priv->table, action_name);
289 }
290
291 /**
292  * g_simple_action_group_insert:
293  * @simple: a #GSimpleActionGroup
294  * @action: a #GAction
295  *
296  * Adds an action to the action group.
297  *
298  * If the action group already contains an action with the same name as
299  * @action then the old action is dropped from the group.
300  *
301  * The action group takes its own reference on @action.
302  *
303  * Since: 2.26
304  **/
305 void
306 g_simple_action_group_insert (GSimpleActionGroup *simple,
307                               GAction            *action)
308 {
309   const gchar *action_name;
310   GAction *old_action;
311
312   g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple));
313   g_return_if_fail (G_IS_ACTION (action));
314
315   action_name = g_action_get_name (action);
316   old_action = g_hash_table_lookup (simple->priv->table, action_name);
317
318   if (old_action != action)
319     {
320       if (old_action != NULL)
321         {
322           g_action_group_action_removed (G_ACTION_GROUP (simple),
323                                          action_name);
324           g_simple_action_group_disconnect (NULL, old_action, simple);
325         }
326
327       g_signal_connect (action, "notify::enabled",
328                         G_CALLBACK (action_enabled_changed), simple);
329
330       if (g_action_get_state_type (action) != NULL)
331         g_signal_connect (action, "notify::state",
332                           G_CALLBACK (action_state_changed), simple);
333
334       g_hash_table_insert (simple->priv->table,
335                            g_strdup (action_name),
336                            g_object_ref (action));
337
338       g_action_group_action_added (G_ACTION_GROUP (simple), action_name);
339     }
340 }
341
342 /**
343  * g_simple_action_group_remove:
344  * @simple: a #GSimpleActionGroup
345  * @action_name: the name of the action
346  *
347  * Removes the named action from the action group.
348  *
349  * If no action of this name is in the group then nothing happens.
350  *
351  * Since: 2.26
352  **/
353 void
354 g_simple_action_group_remove (GSimpleActionGroup *simple,
355                               const gchar        *action_name)
356 {
357   GAction *action;
358
359   g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple));
360
361   action = g_hash_table_lookup (simple->priv->table, action_name);
362
363   if (action != NULL)
364     {
365       g_action_group_action_removed (G_ACTION_GROUP (simple), action_name);
366       g_simple_action_group_disconnect (NULL, action, simple);
367       g_hash_table_remove (simple->priv->table, action_name);
368     }
369 }
370
371 /**
372  * g_simple_action_group_set_enabled:
373  * @simple: a #GSimpleActionGroup
374  * @action_name: the name of an action
375  * @enabled: if the action should be enabled
376  *
377  * Sets an action in the group as being enabled or not.
378  *
379  * This is a convenience function, equivalent to calling
380  * g_simple_action_group_lookup() and using g_action_set_enabled() on
381  * the result.
382  *
383  * If no action named @action_name exists then this function does
384  * nothing.
385  *
386  * Since: 2.26
387  **/
388 void
389 g_simple_action_group_set_enabled (GSimpleActionGroup *simple,
390                                    const gchar        *action_name,
391                                    gboolean            enabled)
392 {
393   GAction *action;
394
395   g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple));
396
397   action = g_hash_table_lookup (simple->priv->table, action_name);
398
399   if (action != NULL)
400     g_action_set_enabled (action, enabled);
401 }