1 /*
2 * glade-clipboard.c - An object for handling Cut/Copy/Paste.
3 *
4 * Copyright (C) 2005 The GNOME Foundation.
5 *
6 * Author(s):
7 * Tristan Van Berkom <tvb@gnome.org>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22 * USA.
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <glib-object.h>
30 #include <glib/gi18n-lib.h>
31 #include <string.h>
32 #include "glade-builtins.h"
33 #include "glade-displayable-values.h"
34
35
36 struct _GladeParamSpecObjects
37 {
38 GParamSpec parent_instance;
39
40 GType type; /* Object or interface type accepted
41 * in this object list.
42 */
43 };
44
45 typedef struct _GladeStockItem
46 {
47 gchar *value_name;
48 gchar *value_nick;
49 gchar *clean_name;
50 gint value;
51 } GladeStockItem;
52
53
54 /************************************************************
55 * Auto-generate the enum type for stock properties *
56 ************************************************************/
57
58 /* Hard-coded list of stock images (and displayable translations) from gtk+ that are not stock "items" */
59 static const gchar *builtin_stock_images[] = {
60 "gtk-dialog-authentication", /* GTK_STOCK_DIALOG_AUTHENTICATION */
61 "gtk-dnd", /* GTK_STOCK_DND */
62 "gtk-dnd-multiple", /* GTK_STOCK_DND_MULTIPLE */
63 "gtk-color-picker", /* GTK_STOCK_COLOR_PICKER */
64 "gtk-directory", /* GTK_STOCK_DIRECTORY */
65 "gtk-file", /* GTK_STOCK_FILE */
66 "gtk-missing-image" /* GTK_STOCK_MISSING_IMAGE */
67 };
68
69 static const gchar *builtin_stock_displayables[] = {
70 /* GTK_STOCK_DIALOG_AUTHENTICATION */
71 N_("Authentication"),
72 /* GTK_STOCK_DND */
73 N_("Drag and Drop"),
74 /* GTK_STOCK_DND_MULTIPLE */
75 N_("Drag and Drop Multiple"),
76 /* GTK_STOCK_COLOR_PICKER */
77 N_("Color Picker"),
78 /* GTK_STOCK_DIRECTORY */
79 N_("Directory"),
80 /* GTK_STOCK_FILE */
81 N_("File"),
82 /* GTK_STOCK_MISSING_IMAGE */
83 N_("Missing Image")
84 };
85
86 static GSList *stock_prefixs = NULL;
87 static gboolean stock_prefixs_done = FALSE;
88
89 /* FIXME: func needs documentation
90 */
91 void
glade_standard_stock_append_prefix(const gchar * prefix)92 glade_standard_stock_append_prefix (const gchar * prefix)
93 {
94 if (stock_prefixs_done)
95 {
96 g_warning
97 ("glade_standard_stock_append_prefix should be used in catalog init-function");
98 return;
99 }
100
101 stock_prefixs = g_slist_append (stock_prefixs, g_strdup (prefix));
102 }
103
104 static GladeStockItem *
new_from_values(const gchar * name,const gchar * nick,gint value)105 new_from_values (const gchar * name, const gchar * nick, gint value)
106 {
107 GladeStockItem *new_gsi = NULL;
108 gchar *clean_name;
109 size_t len = 0;
110 guint i = 0;
111 guint j = 0;
112
113 new_gsi = (GladeStockItem *) g_malloc0 (sizeof (GladeStockItem));
114
115 new_gsi->value_name = g_strdup (name);
116 new_gsi->value_nick = g_strdup (nick);
117 new_gsi->value = value;
118
119
120 clean_name = g_strdup (name);
121 len = strlen (clean_name);
122
123 while (i + j <= len)
124 {
125 if (clean_name[i + j] == '_')
126 j++;
127
128 clean_name[i] = clean_name[i + j];
129 i++;
130 }
131
132 new_gsi->clean_name = g_utf8_collate_key (clean_name, i - j);
133
134 g_free (clean_name);
135
136 return new_gsi;
137 }
138
139
140 static gint
compare_two_gsi(gconstpointer a,gconstpointer b)141 compare_two_gsi (gconstpointer a, gconstpointer b)
142 {
143 GladeStockItem *gsi1 = (GladeStockItem *) a;
144 GladeStockItem *gsi2 = (GladeStockItem *) b;
145
146 return strcmp (gsi1->clean_name, gsi2->clean_name);
147 }
148
149 static GArray *
list_stock_items(gboolean include_images)150 list_stock_items (gboolean include_images)
151 {
152 GtkStockItem item;
153 GSList *l = NULL, *stock_list = NULL, *p = NULL;
154 gchar *stock_id = NULL, *prefix = NULL;
155 gint stock_enum = 0, i = 0;
156 GEnumValue value;
157 GArray *values = NULL;
158 GladeStockItem *gsi;
159 GSList *gsi_list = NULL;
160 GSList *gsi_list_list = NULL;
161
162 if (gdk_display_get_default () == NULL)
163 {
164 values = g_array_sized_new (TRUE, TRUE, sizeof (GEnumValue), 1);
165
166 value.value = 0;
167 value.value_name = "dummy";
168 value.value_nick = "Dummy";
169 g_array_append_val (values, value);
170
171 return values;
172 }
173
174 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
175 stock_list = g_slist_reverse (gtk_stock_list_ids ());
176 G_GNUC_END_IGNORE_DEPRECATIONS
177
178 values = g_array_sized_new (TRUE, TRUE, sizeof (GEnumValue),
179 g_slist_length (stock_list));
180
181 /* We want gtk+ stock items to appear first */
182 if ((stock_prefixs && strcmp (stock_prefixs->data, "gtk-")) ||
183 stock_prefixs == NULL)
184 stock_prefixs = g_slist_prepend (stock_prefixs, g_strdup ("gtk-"));
185
186 for (p = stock_prefixs; p; p = g_slist_next (p))
187 {
188 prefix = p->data;
189
190 for (l = stock_list; l; l = g_slist_next (l))
191 {
192 stock_id = l->data;
193 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
194 if (g_str_has_prefix (stock_id, prefix) == FALSE ||
195 gtk_stock_lookup (stock_id, &item) == FALSE)
196 continue;
197 G_GNUC_END_IGNORE_DEPRECATIONS
198
199 gsi = new_from_values (item.label, stock_id, stock_enum++);
200 gsi_list =
201 g_slist_insert_sorted (gsi_list, gsi,
202 (GCompareFunc) compare_two_gsi);
203 }
204
205 gsi_list_list = g_slist_append (gsi_list_list, gsi_list);
206 gsi_list = NULL;
207
208 /* Images are appended after the gtk+ group of items */
209 if (include_images && !strcmp (prefix, "gtk-"))
210 {
211 for (i = 0; i < G_N_ELEMENTS (builtin_stock_images); i++)
212 {
213 gsi =
214 new_from_values (builtin_stock_images[i],
215 builtin_stock_images[i], stock_enum++);
216 gsi_list =
217 g_slist_insert_sorted (gsi_list, gsi,
218 (GCompareFunc) compare_two_gsi);
219 }
220 gsi_list_list = g_slist_append (gsi_list_list, gsi_list);
221 gsi_list = NULL;
222 }
223 }
224
225 for (p = gsi_list_list; p; p = g_slist_next (p))
226 {
227
228 for (l = (GSList *) p->data; l; l = g_slist_next (l))
229 {
230 gsi = (GladeStockItem *) l->data;
231 value.value = gsi->value;
232 value.value_name = g_strdup (gsi->value_name);
233 value.value_nick = g_strdup (gsi->value_nick);
234 values = g_array_append_val (values, value);
235
236 g_free (gsi->value_nick);
237 g_free (gsi->value_name);
238 g_free (gsi->clean_name);
239 g_free (gsi);
240 }
241 g_slist_free ((GSList *) p->data);
242 }
243
244 g_slist_free (gsi_list_list);
245
246 stock_prefixs_done = TRUE;
247 g_slist_free (stock_list);
248
249 return values;
250 }
251
252 static gchar *
clean_stock_name(const gchar * name)253 clean_stock_name (const gchar * name)
254 {
255 gchar *clean_name, *str;
256 size_t len = 0;
257 guint i = 0;
258 guint j = 0;
259
260 g_assert (name && name[0]);
261
262 str = g_strdup (name);
263 len = strlen (str);
264
265 while (i + j <= len)
266 {
267 if (str[i + j] == '_')
268 j++;
269
270 str[i] = str[i + j];
271 i++;
272 }
273 clean_name = g_strndup (str, i - j);
274 g_free (str);
275
276 return clean_name;
277 }
278
279 GType
glade_standard_stock_get_type(void)280 glade_standard_stock_get_type (void)
281 {
282 static GType etype = 0;
283
284 if (etype == 0)
285 {
286 GArray *values = list_stock_items (FALSE);
287 gint i, n_values = values->len;
288 GEnumValue *enum_values = (GEnumValue *) values->data;
289 GtkStockItem item;
290
291 etype = g_enum_register_static ("GladeStock",
292 (GEnumValue *) g_array_free (values,
293 FALSE));
294
295 /* Register displayable by GType, i.e. after the types been created. */
296 for (i = 0; i < n_values; i++)
297 {
298 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
299 gboolean valid_item = gtk_stock_lookup (enum_values[i].value_nick, &item);
300 G_GNUC_END_IGNORE_DEPRECATIONS
301
302 if (valid_item)
303 {
304 gchar *clean_name = clean_stock_name (item.label);
305
306 if (!glade_get_displayable_value (etype, enum_values[i].value_nick))
307 glade_register_translated_value (etype, enum_values[i].value_nick, clean_name);
308 g_free (clean_name);
309 }
310 }
311 }
312 return etype;
313 }
314
315
316 GType
glade_standard_stock_image_get_type(void)317 glade_standard_stock_image_get_type (void)
318 {
319 static GType etype = 0;
320
321 if (etype == 0)
322 {
323 GArray *values = list_stock_items (TRUE);
324 gint i, n_values = values->len;
325 GEnumValue *enum_values = (GEnumValue *) values->data;
326 GtkStockItem item;
327
328 etype = g_enum_register_static ("GladeStockImage",
329 (GEnumValue *) g_array_free (values,
330 FALSE));
331
332 /* Register displayable by GType, i.e. after the types been created. */
333 for (i = 0; i < n_values; i++)
334 {
335 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
336 gboolean valid_item = gtk_stock_lookup (enum_values[i].value_nick, &item);
337 G_GNUC_END_IGNORE_DEPRECATIONS
338 if (valid_item)
339 {
340 gchar *clean_name = clean_stock_name (item.label);
341
342 /* These are translated, we just cut out the mnemonic underscores */
343 if (!glade_get_displayable_value (etype, enum_values[i].value_nick))
344 glade_register_translated_value (etype, enum_values[i].value_nick, clean_name);
345 g_free (clean_name);
346 }
347 }
348
349 for (i = 0; i < G_N_ELEMENTS (builtin_stock_images); i++)
350 {
351 /* these ones are translated from glade */
352 if (!glade_get_displayable_value (etype, builtin_stock_images[i]))
353 glade_register_displayable_value (etype,
354 builtin_stock_images[i],
355 GETTEXT_PACKAGE,
356 builtin_stock_displayables[i]);
357 }
358 }
359 return etype;
360 }
361
362 GParamSpec *
glade_standard_stock_spec(void)363 glade_standard_stock_spec (void)
364 {
365 return g_param_spec_enum ("stock", _("Stock"),
366 _("A builtin stock item"),
367 GLADE_TYPE_STOCK, 0, G_PARAM_READWRITE);
368 }
369
370 GParamSpec *
glade_standard_stock_image_spec(void)371 glade_standard_stock_image_spec (void)
372 {
373 return g_param_spec_enum ("stock-image", _("Stock Image"),
374 _("A builtin stock image"),
375 GLADE_TYPE_STOCK_IMAGE, 0, G_PARAM_READWRITE);
376 }
377
378 /****************************************************************
379 * A GList boxed type used by GladeParamSpecObjects and *
380 * GladeParamSpecAccel (which is now in the glade-gtk backend) *
381 ****************************************************************/
382 GType
glade_glist_get_type(void)383 glade_glist_get_type (void)
384 {
385 static GType type_id = 0;
386
387 if (!type_id)
388 type_id = g_boxed_type_register_static
389 ("GladeGList",
390 (GBoxedCopyFunc) g_list_copy, (GBoxedFreeFunc) g_list_free);
391 return type_id;
392 }
393
394 /****************************************************************
395 * Built-in GladeParamSpecObjects for object list properties *
396 * (Used as a pspec to desctibe an AtkRelationSet, but can *
397 * for any object list property) *
398 ****************************************************************/
399 static void
param_objects_init(GParamSpec * pspec)400 param_objects_init (GParamSpec * pspec)
401 {
402 GladeParamSpecObjects *ospec = GLADE_PARAM_SPEC_OBJECTS (pspec);
403 ospec->type = G_TYPE_OBJECT;
404 }
405
406 static void
param_objects_set_default(GParamSpec * pspec,GValue * value)407 param_objects_set_default (GParamSpec * pspec, GValue * value)
408 {
409 if (value->data[0].v_pointer != NULL)
410 {
411 g_free (value->data[0].v_pointer);
412 }
413 value->data[0].v_pointer = NULL;
414 }
415
416 static gboolean
param_objects_validate(GParamSpec * pspec,GValue * value)417 param_objects_validate (GParamSpec * pspec, GValue * value)
418 {
419 GladeParamSpecObjects *ospec = GLADE_PARAM_SPEC_OBJECTS (pspec);
420 GList *objects, *list, *toremove = NULL;
421 GObject *object;
422
423 objects = value->data[0].v_pointer;
424
425 for (list = objects; list; list = list->next)
426 {
427 object = list->data;
428
429 if (!(G_OBJECT_TYPE (object) == ospec->type ||
430 g_type_is_a (G_OBJECT_TYPE (object), ospec->type)))
431 toremove = g_list_prepend (toremove, object);
432 }
433
434 for (list = toremove; list; list = list->next)
435 {
436 object = list->data;
437 objects = g_list_remove (objects, object);
438 }
439 if (toremove)
440 g_list_free (toremove);
441
442 value->data[0].v_pointer = objects;
443
444 return toremove != NULL;
445 }
446
447 static gint
param_objects_values_cmp(GParamSpec * pspec,const GValue * value1,const GValue * value2)448 param_objects_values_cmp (GParamSpec * pspec,
449 const GValue * value1, const GValue * value2)
450 {
451 guint8 *p1 = value1->data[0].v_pointer;
452 guint8 *p2 = value2->data[0].v_pointer;
453
454 /* not much to compare here, try to at least provide stable lesser/greater result */
455
456 return p1 < p2 ? -1 : p1 > p2;
457 }
458
459 GType
glade_param_objects_get_type(void)460 glade_param_objects_get_type (void)
461 {
462 static GType objects_type = 0;
463
464 if (objects_type == 0)
465 {
466 static /* const */ GParamSpecTypeInfo pspec_info = {
467 sizeof (GladeParamSpecObjects), /* instance_size */
468 16, /* n_preallocs */
469 param_objects_init, /* instance_init */
470 0xdeadbeef, /* value_type, assigned further down */
471 NULL, /* finalize */
472 param_objects_set_default, /* value_set_default */
473 param_objects_validate, /* value_validate */
474 param_objects_values_cmp, /* values_cmp */
475 };
476 pspec_info.value_type = GLADE_TYPE_GLIST;
477
478 objects_type = g_param_type_register_static
479 ("GladeParamObjects", &pspec_info);
480 }
481 return objects_type;
482 }
483
484 GParamSpec *
glade_param_spec_objects(const gchar * name,const gchar * nick,const gchar * blurb,GType accepted_type,GParamFlags flags)485 glade_param_spec_objects (const gchar * name,
486 const gchar * nick,
487 const gchar * blurb,
488 GType accepted_type, GParamFlags flags)
489 {
490 GladeParamSpecObjects *pspec;
491
492 pspec = g_param_spec_internal (GLADE_TYPE_PARAM_OBJECTS,
493 name, nick, blurb, flags);
494
495 pspec->type = accepted_type;
496 return G_PARAM_SPEC (pspec);
497 }
498
499 void
glade_param_spec_objects_set_type(GladeParamSpecObjects * pspec,GType type)500 glade_param_spec_objects_set_type (GladeParamSpecObjects * pspec, GType type)
501 {
502 pspec->type = type;
503 }
504
505 GType
glade_param_spec_objects_get_type(GladeParamSpecObjects * pspec)506 glade_param_spec_objects_get_type (GladeParamSpecObjects * pspec)
507 {
508 return pspec->type;
509 }
510
511 /* This was developed for the purpose of holding a list
512 * of 'targets' in an AtkRelation (we are setting it up
513 * as a property)
514 */
515 GParamSpec *
glade_standard_objects_spec(void)516 glade_standard_objects_spec (void)
517 {
518 return glade_param_spec_objects ("objects", _("Objects"),
519 _("A list of objects"),
520 G_TYPE_OBJECT, G_PARAM_READWRITE);
521 }
522
523 /* Pixbuf Type */
524 GParamSpec *
glade_standard_pixbuf_spec(void)525 glade_standard_pixbuf_spec (void)
526 {
527 return g_param_spec_object ("pixbuf", _("Image File Name"),
528 _("Enter a filename, relative path or full path to "
529 "load the image"), GDK_TYPE_PIXBUF,
530 G_PARAM_READWRITE);
531 }
532
533 /* GdkColor */
534 GParamSpec *
glade_standard_gdkcolor_spec(void)535 glade_standard_gdkcolor_spec (void)
536 {
537 return g_param_spec_boxed ("gdkcolor", _("Color"),
538 _("A GDK color value"), GDK_TYPE_COLOR,
539 G_PARAM_READWRITE);
540 }
541
542 /****************************************************************
543 * Basic types follow *
544 ****************************************************************/
545 GParamSpec *
glade_standard_int_spec(void)546 glade_standard_int_spec (void)
547 {
548 return g_param_spec_int ("int", "Integer",
549 "An integer value",
550 G_MININT, G_MAXINT, 0, G_PARAM_READWRITE);
551 }
552
553 GParamSpec *
glade_standard_uint_spec(void)554 glade_standard_uint_spec (void)
555 {
556 return g_param_spec_uint ("uint", "Unsigned Integer",
557 "An unsigned integer value",
558 0, G_MAXUINT, 0, G_PARAM_READWRITE);
559 }
560
561 GParamSpec *
glade_standard_string_spec(void)562 glade_standard_string_spec (void)
563 {
564 return g_param_spec_string ("string", _("String"),
565 _("An entry"), "", G_PARAM_READWRITE);
566 }
567
568 GParamSpec *
glade_standard_strv_spec(void)569 glade_standard_strv_spec (void)
570 {
571 return g_param_spec_boxed ("strv", "Strv",
572 "String array", G_TYPE_STRV, G_PARAM_READWRITE);
573 }
574
575 GParamSpec *
glade_standard_float_spec(void)576 glade_standard_float_spec (void)
577 {
578 return g_param_spec_float ("float", "Float",
579 "A floating point entry",
580 0.0F, G_MAXFLOAT, 0.0F, G_PARAM_READWRITE);
581 }
582
583 GParamSpec *
glade_standard_boolean_spec(void)584 glade_standard_boolean_spec (void)
585 {
586 return g_param_spec_boolean ("boolean", "Boolean",
587 "A boolean value", FALSE, G_PARAM_READWRITE);
588 }
589