1 /*
2  * This file is part of Amtk - Actions, Menus and Toolbars Kit
3  *
4  * Copyright 2017, 2018, 2020 - Sébastien Wilmet <swilmet@gnome.org>
5  *
6  * Amtk is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by the
8  * Free Software Foundation; either version 2.1 of the License, or (at your
9  * option) any later version.
10  *
11  * Amtk is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14  * License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "config.h"
21 #include "amtk-action-info.h"
22 #include <glib/gi18n-lib.h>
23 #include "amtk-utils.h"
24 
25 /**
26  * SECTION:amtk-action-info
27  * @Short_description: #GAction information
28  * @Title: AmtkActionInfo
29  * @See_also: #AmtkActionInfoStore
30  *
31  * An #AmtkActionInfo instance contains a set of information about a #GAction.
32  * Those pieces of information are useful to create UI elements that trigger the
33  * #GAction, for example a menu item or a toolbar item.
34  *
35  * The recommended way to create a set of #AmtkActionInfo's is to use the
36  * amtk_action_info_store_add_entries() function.
37  */
38 
39 struct _AmtkActionInfo
40 {
41 	gchar *action_name;
42 	gchar *icon_name;
43 	gchar *label;
44 	gchar *tooltip;
45 
46 	/* Must never be NULL, must be a NULL-terminated array. This way, it
47 	 * can be used directly as an argument to
48 	 * gtk_application_set_accels_for_action().
49 	 */
50 	gchar **accels;
51 
52 	gint ref_count;
53 
54 	guint used : 1;
55 };
56 
57 static void _amtk_action_info_free (AmtkActionInfo *info);
58 
G_DEFINE_BOXED_TYPE(AmtkActionInfo,amtk_action_info,amtk_action_info_copy,_amtk_action_info_free)59 G_DEFINE_BOXED_TYPE (AmtkActionInfo, amtk_action_info,
60 		     amtk_action_info_copy,
61 		     _amtk_action_info_free)
62 
63 static void
64 _amtk_action_info_free (AmtkActionInfo *info)
65 {
66 	if (info != NULL)
67 	{
68 		g_free (info->action_name);
69 		g_free (info->icon_name);
70 		g_free (info->label);
71 		g_free (info->tooltip);
72 		g_strfreev (info->accels);
73 
74 		g_free (info);
75 	}
76 }
77 
78 /**
79  * amtk_action_info_new:
80  *
81  * Returns: a new #AmtkActionInfo.
82  * Since: 2.0
83  */
84 AmtkActionInfo *
amtk_action_info_new(void)85 amtk_action_info_new (void)
86 {
87 	AmtkActionInfo *info;
88 
89 	info = g_new0 (AmtkActionInfo, 1);
90 	info->accels = g_malloc0 (sizeof (gchar *));
91 	info->ref_count = 1;
92 
93 	return info;
94 }
95 
96 /**
97  * amtk_action_info_new_from_entry:
98  * @info_entry: an #AmtkActionInfoEntry.
99  * @translation_domain: (nullable): a gettext domain, or %NULL.
100  *
101  * Creates a new #AmtkActionInfo from an #AmtkActionInfoEntry.
102  *
103  * If @translation_domain is not %NULL, g_dgettext() is used to translate the
104  * @label and @tooltip before setting them to the #AmtkActionInfo.
105  *
106  * Returns: a new #AmtkActionInfo.
107  * Since: 2.0
108  */
109 AmtkActionInfo *
amtk_action_info_new_from_entry(const AmtkActionInfoEntry * info_entry,const gchar * translation_domain)110 amtk_action_info_new_from_entry (const AmtkActionInfoEntry *info_entry,
111 				 const gchar               *translation_domain)
112 {
113 	AmtkActionInfo *info;
114 
115 	info = amtk_action_info_new ();
116 	info->action_name = g_strdup (info_entry->action_name);
117 	info->icon_name = g_strdup (info_entry->icon_name);
118 
119 	if (translation_domain != NULL)
120 	{
121 		info->label = g_strdup (g_dgettext (translation_domain, info_entry->label));
122 		info->tooltip = g_strdup (g_dgettext (translation_domain, info_entry->tooltip));
123 	}
124 	else
125 	{
126 		info->label = g_strdup (info_entry->label);
127 		info->tooltip = g_strdup (info_entry->tooltip);
128 	}
129 
130 	if (info_entry->accel != NULL)
131 	{
132 		g_strfreev (info->accels);
133 
134 		info->accels = g_malloc (2 * sizeof (gchar *));
135 		info->accels[0] = g_strdup (info_entry->accel);
136 		info->accels[1] = NULL;
137 	}
138 
139 	return info;
140 }
141 
142 /**
143  * amtk_action_info_ref:
144  * @info: an #AmtkActionInfo.
145  *
146  * Increments the reference count of @info by one.
147  *
148  * Returns: the passed in @info.
149  * Since: 2.0
150  */
151 AmtkActionInfo *
amtk_action_info_ref(AmtkActionInfo * info)152 amtk_action_info_ref (AmtkActionInfo *info)
153 {
154 	g_return_val_if_fail (info != NULL, NULL);
155 
156 	info->ref_count++;
157 
158 	return info;
159 }
160 
161 /**
162  * amtk_action_info_unref:
163  * @info: an #AmtkActionInfo.
164  *
165  * Decrements the reference count of @info by one. If the reference count drops
166  * to 0, @info is freed.
167  *
168  * Since: 2.0
169  */
170 void
amtk_action_info_unref(AmtkActionInfo * info)171 amtk_action_info_unref (AmtkActionInfo *info)
172 {
173 	g_return_if_fail (info != NULL);
174 
175 	info->ref_count--;
176 
177 	if (info->ref_count == 0)
178 	{
179 		_amtk_action_info_free (info);
180 	}
181 }
182 
183 /**
184  * amtk_action_info_copy:
185  * @info: an #AmtkActionInfo.
186  *
187  * Returns: (transfer full): a copy of @info. The copy will have a reference
188  * count of one.
189  * Since: 2.0
190  */
191 AmtkActionInfo *
amtk_action_info_copy(const AmtkActionInfo * info)192 amtk_action_info_copy (const AmtkActionInfo *info)
193 {
194 	AmtkActionInfo *new_info;
195 
196 	g_return_val_if_fail (info != NULL, NULL);
197 
198 	new_info = amtk_action_info_new ();
199 
200 	new_info->action_name = g_strdup (info->action_name);
201 	new_info->icon_name = g_strdup (info->icon_name);
202 	new_info->label = g_strdup (info->label);
203 	new_info->tooltip = g_strdup (info->tooltip);
204 
205 	amtk_action_info_set_accels (new_info, (const gchar * const *)info->accels);
206 
207 	return new_info;
208 }
209 
210 /**
211  * amtk_action_info_get_action_name:
212  * @info: an #AmtkActionInfo.
213  *
214  * Returns: (nullable): the action name, or %NULL. Example: `"win.save"`. Can be
215  * a detailed action name, see g_action_parse_detailed_name().
216  * Since: 2.0
217  */
218 const gchar *
amtk_action_info_get_action_name(const AmtkActionInfo * info)219 amtk_action_info_get_action_name (const AmtkActionInfo *info)
220 {
221 	g_return_val_if_fail (info != NULL, NULL);
222 
223 	return info->action_name;
224 }
225 
226 /**
227  * amtk_action_info_set_action_name:
228  * @info: an #AmtkActionInfo.
229  * @action_name: the action name.
230  *
231  * Sets the action name, for example `"win.save"`. Can be a detailed action
232  * name, see g_action_parse_detailed_name().
233  *
234  * Since: 2.0
235  */
236 void
amtk_action_info_set_action_name(AmtkActionInfo * info,const gchar * action_name)237 amtk_action_info_set_action_name (AmtkActionInfo *info,
238 				  const gchar    *action_name)
239 {
240 	g_return_if_fail (info != NULL);
241 	g_return_if_fail (action_name != NULL);
242 
243 	g_free (info->action_name);
244 	info->action_name = g_strdup (action_name);
245 }
246 
247 /**
248  * amtk_action_info_get_icon_name:
249  * @info: an #AmtkActionInfo.
250  *
251  * Returns: (nullable): the icon name, or %NULL.
252  * Since: 2.0
253  */
254 const gchar *
amtk_action_info_get_icon_name(const AmtkActionInfo * info)255 amtk_action_info_get_icon_name (const AmtkActionInfo *info)
256 {
257 	g_return_val_if_fail (info != NULL, NULL);
258 
259 	return info->icon_name;
260 }
261 
262 /**
263  * amtk_action_info_set_icon_name:
264  * @info: an #AmtkActionInfo.
265  * @icon_name: (nullable): the icon name, or %NULL.
266  *
267  * Since: 2.0
268  */
269 void
amtk_action_info_set_icon_name(AmtkActionInfo * info,const gchar * icon_name)270 amtk_action_info_set_icon_name (AmtkActionInfo *info,
271 				const gchar    *icon_name)
272 {
273 	g_return_if_fail (info != NULL);
274 
275 	g_free (info->icon_name);
276 	info->icon_name = g_strdup (icon_name);
277 }
278 
279 /**
280  * amtk_action_info_get_label:
281  * @info: an #AmtkActionInfo.
282  *
283  * Gets the label. The label has normally a mnemonic. To remove the mnemonic,
284  * there is the amtk_utils_remove_mnemonic() function.
285  *
286  * Returns: (nullable): the label (i.e. a short description), or %NULL.
287  * Since: 2.0
288  */
289 const gchar *
amtk_action_info_get_label(const AmtkActionInfo * info)290 amtk_action_info_get_label (const AmtkActionInfo *info)
291 {
292 	g_return_val_if_fail (info != NULL, NULL);
293 
294 	return info->label;
295 }
296 
297 /**
298  * amtk_action_info_set_label:
299  * @info: an #AmtkActionInfo.
300  * @label: (nullable): the label (i.e. a short description), or %NULL.
301  *
302  * Sets the label with a mnemonic. To know how to encode the mnemonic, see the
303  * documentation of gtk_label_new_with_mnemonic().
304  *
305  * Since: 2.0
306  */
307 void
amtk_action_info_set_label(AmtkActionInfo * info,const gchar * label)308 amtk_action_info_set_label (AmtkActionInfo *info,
309 			    const gchar    *label)
310 {
311 	g_return_if_fail (info != NULL);
312 
313 	g_free (info->label);
314 	info->label = g_strdup (label);
315 }
316 
317 /**
318  * amtk_action_info_get_tooltip:
319  * @info: an #AmtkActionInfo.
320  *
321  * Returns: (nullable): the tooltip (i.e. a long description), or %NULL.
322  * Since: 2.0
323  */
324 const gchar *
amtk_action_info_get_tooltip(const AmtkActionInfo * info)325 amtk_action_info_get_tooltip (const AmtkActionInfo *info)
326 {
327 	g_return_val_if_fail (info != NULL, NULL);
328 
329 	return info->tooltip;
330 }
331 
332 /**
333  * amtk_action_info_set_tooltip:
334  * @info: an #AmtkActionInfo.
335  * @tooltip: (nullable): the tooltip (i.e. a long description), or %NULL.
336  *
337  * Since: 2.0
338  */
339 void
amtk_action_info_set_tooltip(AmtkActionInfo * info,const gchar * tooltip)340 amtk_action_info_set_tooltip (AmtkActionInfo *info,
341 			      const gchar    *tooltip)
342 {
343 	g_return_if_fail (info != NULL);
344 
345 	g_free (info->tooltip);
346 	info->tooltip = g_strdup (tooltip);
347 }
348 
349 /**
350  * amtk_action_info_get_accels:
351  * @info: an #AmtkActionInfo.
352  *
353  * Returns the accelerators. This function never returns %NULL, it always
354  * returns a %NULL-terminated array, to be suitable for
355  * gtk_application_set_accels_for_action().
356  *
357  * Returns: (transfer none) (array zero-terminated=1): a %NULL-terminated array
358  * of accelerators in the format understood by gtk_accelerator_parse().
359  * Since: 2.0
360  */
361 const gchar * const *
amtk_action_info_get_accels(const AmtkActionInfo * info)362 amtk_action_info_get_accels (const AmtkActionInfo *info)
363 {
364 	g_return_val_if_fail (info != NULL, NULL);
365 
366 	g_assert (info->accels != NULL);
367 
368 	return (const gchar * const *)info->accels;
369 }
370 
371 /**
372  * amtk_action_info_set_accels:
373  * @info: an #AmtkActionInfo.
374  * @accels: (array zero-terminated=1): a %NULL-terminated array of accelerators
375  * in the format understood by gtk_accelerator_parse().
376  *
377  * A function similar to gtk_application_set_accels_for_action().
378  *
379  * @accels must not be %NULL, it must be a %NULL-terminated array, to be
380  * consistent with gtk_application_set_accels_for_action().
381  *
382  * Since: 2.0
383  */
384 void
amtk_action_info_set_accels(AmtkActionInfo * info,const gchar * const * accels)385 amtk_action_info_set_accels (AmtkActionInfo      *info,
386 			     const gchar * const *accels)
387 {
388 	g_return_if_fail (info != NULL);
389 	g_return_if_fail (accels != NULL);
390 
391 	g_strfreev (info->accels);
392 	info->accels = g_strdupv ((gchar **) accels);
393 }
394 
395 /**
396  * amtk_action_info_mark_as_used:
397  * @info: an #AmtkActionInfo.
398  *
399  * Mark @info as used. An #AmtkFactory function that uses an #AmtkActionInfo
400  * should call this function. See amtk_action_info_store_check_all_used().
401  *
402  * Since: 3.0
403  */
404 void
amtk_action_info_mark_as_used(AmtkActionInfo * info)405 amtk_action_info_mark_as_used (AmtkActionInfo *info)
406 {
407 	g_return_if_fail (info != NULL);
408 
409 	info->used = TRUE;
410 }
411 
412 /**
413  * amtk_action_info_has_been_used:
414  * @info: an #AmtkActionInfo.
415  *
416  * Returns whether @info has been used (for example by an #AmtkFactory
417  * function). See also amtk_action_info_store_check_all_used().
418  *
419  * Returns: whether @info has been used.
420  * Since: 3.0
421  */
422 gboolean
amtk_action_info_has_been_used(const AmtkActionInfo * info)423 amtk_action_info_has_been_used (const AmtkActionInfo *info)
424 {
425 	g_return_val_if_fail (info != NULL, FALSE);
426 
427 	return info->used;
428 }
429