Updated Spanish translation
[anjuta.git] / libanjuta / anjuta-preferences.c
blobfc94b41939a64c22b57bed9c71a9e746c40810f9
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * preferences.c
4 * Copyright (C) 2000 - 2003 Naba Kumar <naba@gnome.org>
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 of the License, or
9 * (at your option) 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
21 /**
22 * SECTION:anjuta-preferences
23 * @short_description: Anjuta Preferences system.
24 * @see_also: #AnjutaPreferencesDialog
25 * @stability: Unstable
26 * @include: libanjuta/anjuta-preferences.h
28 * #AnjutaPreferences is a way to let plugins register their preferences. There
29 * are mainly two ways a plugin could register its preferences in Anjuta.
31 * First is to not use #AnjutaPreferences at all. Simply register a
32 * preferences page in #AnjutaPreferencesDialog using the function
33 * anjuta_preferences_dialog_add_page(). The plugin should take
34 * care of loading, saving and widgets synchronization of the
35 * preferences values. This can be done using #GSettings bindings
36 * for example.
38 * Second is to use anjuta_preferences_add_page(), which will
39 * automatically register the preferences keys and values from
40 * a glade xml file. The glade xml file contains a preferences
41 * page of the plugin. The widget names in the page are
42 * given in a particular way (see anjuta_preferences_add_page()) to
43 * let it know property key details. The preference dialog will automatically
44 * setup the bindings between GSettings and the widgets.
48 #ifdef HAVE_CONFIG_H
49 # include <config.h>
50 #endif
52 #include <sys/stat.h>
53 #include <unistd.h>
54 #include <string.h>
55 #include <stdlib.h>
57 #include <libanjuta/anjuta-preferences.h>
58 #include <libanjuta/anjuta-utils.h>
59 #include <libanjuta/resources.h>
60 #include <libanjuta/anjuta-debug.h>
61 #include <libanjuta/interfaces/ianjuta-preferences.h>
63 struct _AnjutaPreferencesPriv
65 GtkWidget *prefs_dialog;
66 AnjutaPluginManager *plugin_manager;
68 gchar *common_schema_id;
69 GHashTable *common_gsettings;
72 #define PREFERENCE_PROPERTY_PREFIX "preferences"
74 G_DEFINE_TYPE (AnjutaPreferences, anjuta_preferences, G_TYPE_OBJECT);
76 static GVariant*
77 string_to_gdkcolor (const GValue* value, const GVariantType* type, gpointer user_data)
79 GdkColor* color = g_value_get_boxed (value);
80 gchar* name = gdk_color_to_string (color);
82 GVariant* variant = g_variant_new_string (name);
83 g_free (name);
85 return variant;
88 static gboolean
89 gdkcolor_to_string (GValue* value, GVariant* variant, gpointer user_data)
91 GdkColor color;
92 gdk_color_parse (g_variant_get_string (variant, NULL), &color);
93 g_value_set_boxed (value, &color);
94 return TRUE;
97 static GVariant*
98 active_to_string (const GValue* value, const GVariantType* type, gpointer user_data)
100 GtkComboBox* combo = GTK_COMBO_BOX(user_data);
102 return g_variant_new_string (gtk_combo_box_get_active_id (combo));
105 static gboolean
106 string_to_active (GValue* value, GVariant* variant, gpointer user_data)
108 GtkComboBox* combo = GTK_COMBO_BOX(user_data);
110 gtk_combo_box_set_active_id (combo, g_variant_get_string (variant, NULL));
111 g_value_set_int (value, gtk_combo_box_get_active (combo));
113 return g_value_get_int (value) >= 0;
116 static void
117 update_file_property (GtkWidget* widget, gpointer user_data)
119 GtkFileChooser *chooser = GTK_FILE_CHOOSER (user_data);
120 GSettings *gsettings = g_object_get_data (G_OBJECT (chooser), "anjuta-bind-gsettings");
121 const gchar *key = g_object_get_data (G_OBJECT (chooser), "anjuta-bind-key");
122 gchar* text_value = gtk_file_chooser_get_filename (chooser);
124 g_settings_set_string (gsettings, key, text_value);
126 g_free (text_value);
130 * anjuta_preferences_register_property:
131 * @pr: a #AnjutaPreferences object
132 * @settings: the #GSettings object associated with that property
133 * @object: Widget to register
134 * @key: Property key
136 * This registers only one widget. The widget could be shown elsewhere.
137 * The widget needs to fulfill the properties described in
138 * #anjuta_preferences_add_page documentation.
140 * Return value: %TRUE if sucessful.
142 gboolean
143 anjuta_preferences_register_property (AnjutaPreferences *pr,
144 GSettings *settings,
145 GtkWidget *object,
146 const gchar *key)
148 gboolean ok = TRUE;
150 g_return_val_if_fail (ANJUTA_IS_PREFERENCES (pr), FALSE);
151 g_return_val_if_fail (GTK_IS_WIDGET (object), FALSE);
152 g_return_val_if_fail (strlen(key) > 0, FALSE);
154 /* Start with the most specialized widget as a GtkSpinButton
155 * is a GtkEntry too */
156 if (GTK_IS_COLOR_BUTTON (object))
158 g_settings_bind_with_mapping (settings, key,
159 object, "color",
160 G_SETTINGS_BIND_DEFAULT,
161 gdkcolor_to_string,
162 string_to_gdkcolor,
163 object,
164 NULL);
166 else if (GTK_IS_FONT_BUTTON (object))
168 g_settings_bind (settings, key, object, "font-name",
169 G_SETTINGS_BIND_DEFAULT);
171 else if (GTK_IS_SPIN_BUTTON (object))
173 g_settings_bind (settings, key, object, "value",
174 G_SETTINGS_BIND_DEFAULT);
176 else if (GTK_IS_FILE_CHOOSER_BUTTON (object))
178 gchar *filename;
180 switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (object)))
182 case GTK_FILE_CHOOSER_ACTION_OPEN:
183 case GTK_FILE_CHOOSER_ACTION_SAVE:
184 filename = g_settings_get_string (settings, key);
185 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (object),
186 filename);
187 g_free (filename);
188 g_object_set_data_full (G_OBJECT (object), "anjuta-bind-gsettings", g_object_ref (settings), (GDestroyNotify)g_object_unref);
189 g_object_set_data_full (G_OBJECT (object), "anjuta-bind-key", g_strdup (key), (GDestroyNotify)g_free);
190 g_signal_connect (G_OBJECT (object), "file-set",
191 G_CALLBACK (update_file_property), object);
192 break;
193 case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
194 case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
195 filename = g_settings_get_string (settings, key);
196 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (object),
197 filename);
198 g_free (filename);
199 g_object_set_data_full (G_OBJECT (object), "anjuta-bind-gsettings", g_object_ref (settings), (GDestroyNotify)g_object_unref);
200 g_object_set_data_full (G_OBJECT (object), "anjuta-bind-key", g_strdup (key), (GDestroyNotify)g_free);
201 g_signal_connect (G_OBJECT(object), "current-folder-changed",
202 G_CALLBACK (update_file_property), object);
203 break;
204 default:
205 ok = FALSE;
208 else if (GTK_IS_COMBO_BOX (object))
210 g_settings_bind_with_mapping (settings, key,
211 object, "active",
212 G_SETTINGS_BIND_DEFAULT,
213 string_to_active,
214 active_to_string,
215 object,
216 NULL);
218 else if (GTK_IS_CHECK_BUTTON (object))
220 g_settings_bind (settings, key, object, "active",
221 G_SETTINGS_BIND_DEFAULT);
223 else if (GTK_IS_ENTRY (object))
225 g_settings_bind (settings, key, object, "text",
226 G_SETTINGS_BIND_DEFAULT);
228 else
230 ok = FALSE;
233 return ok;
237 * anjuta_preferences_register_all_properties_from_builder_xml:
238 * @pr: a #AnjutaPreferences Object
239 * @builder: GtkBuilder object containing the properties widgets.
240 * @parent: Parent widget in the builder object
242 * This will register all the properties names of the format described above
243 * without considering the UI. Useful if you have the widgets shown elsewhere
244 * but you want them to be part of preferences system.
246 void
247 anjuta_preferences_register_all_properties_from_builder_xml (AnjutaPreferences *pr,
248 GtkBuilder *builder,
249 GSettings *settings,
250 GtkWidget *parent)
252 GSList *widgets;
253 GSList *node;
255 g_return_if_fail (ANJUTA_IS_PREFERENCES (pr));
256 g_return_if_fail (builder != NULL);
258 widgets = gtk_builder_get_objects (builder);
259 for (node = widgets; node != NULL; node = g_slist_next (node))
261 const gchar *name;
262 const gchar *key;
263 const gchar *ptr;
264 GtkWidget *widget, *p;
265 gboolean cont_flag = FALSE;
266 GSettings *key_settings = settings;
268 if (!GTK_IS_WIDGET (node->data) || !GTK_IS_BUILDABLE (node->data))
269 continue;
271 widget = node->data;
272 name = gtk_buildable_get_name (GTK_BUILDABLE (widget));
274 if (!g_str_has_prefix (name, PREFERENCE_PROPERTY_PREFIX))
275 continue;
277 /* Only ':' is needed between "preferences" and the key name but accept
278 * '_' and additional fields separated by ':' to work with the old
279 * widget naming scheme. */
280 key = &name[strlen (PREFERENCE_PROPERTY_PREFIX)];
281 if ((*key != '_') && (*key != ':'))
282 continue;
284 for (ptr = ++key; *ptr != '\0'; ptr++)
286 if (*ptr == ':') key = ptr + 1;
288 if (*key == '\0') continue;
290 /* Check if we need to use common settings */
291 if (*key == '.')
293 const gchar *id = strrchr (key, '.');
294 GString *schema_id;
296 schema_id = g_string_new (pr->priv->common_schema_id);
297 if (key != id)
299 g_string_append_len (schema_id, key, id - key);
301 key = id + 1;
303 key_settings = (GSettings *)g_hash_table_lookup (pr->priv->common_gsettings, schema_id->str);
304 if (key_settings == NULL)
306 key_settings = g_settings_new (schema_id->str);
307 g_hash_table_insert (pr->priv->common_gsettings, schema_id->str, key_settings);
308 g_string_free (schema_id, FALSE);
310 else
312 g_string_free (schema_id, TRUE);
316 /* Added only if it's a descendant child of the parent */
317 p = gtk_widget_get_parent (widget);
318 while (p != parent)
320 if (p == NULL)
322 cont_flag = TRUE;
323 break;
325 p = gtk_widget_get_parent (p);
327 if (cont_flag)
328 continue;
330 if (!anjuta_preferences_register_property (pr, key_settings, widget, key))
332 g_critical ("Invalid preference widget named %s, check anjuta_preferences_add_page function documentation.", name);
338 * anjuta_preferences_add_page:
339 * @pr: a #AnjutaPreferences object
340 * @builder: #GtkBuilder object containing the preferences page
341 * @settings: the #GSettings object associated with that page
342 * @gwidget_name: Page widget name (as give with glade interface editor).
343 * The widget will be searched with the given name and detached
344 * (that is, removed from the container, if present) from it's parent.
345 * @icon_filename: File name (of the form filename.png) of the icon representing
346 * the preference page.
348 * Add a page to the preferences sytem.
349 * builder is the GtkBuilder object of the dialog containing the page widget.
350 * The dialog will contain the layout of the preferences widgets.
351 * The widgets which are preference widgets (e.g. toggle button) should have
352 * widget names of the form:
354 * <programlisting>
355 * preferences(_.*)?:(.SCHEMAID)?PROPERTYKEY
356 * where,
357 * SCHEMAID if present the key will be added not in the page settings but
358 * in common settings using SCHEMAID as a suffix.
359 * PROPERTYKEY is the property key. e.g - 'tab-size'.
360 * </programlisting>
362 * The widget must derivated from one of the following Gtk widget:
363 * * GtkColorButton
364 * * GtkFontButton
365 * * GtkSpinButton
366 * * GtkFileChooserButton
367 * * GtkComboBox
368 * * GtkCheckButton
369 * * GtkEntry
371 * In addition, the model of a GtkComboBox must have an id column.
372 * It is the value of this column which is saved as preference.
374 * All widgets having the above names in the gxml tree will be registered
375 * and will become part of auto saving/loading. For example, refer to
376 * anjuta preferences dialogs and study the widget names.
378 * Older versions of Anjuta use more fields in the widget name. They do not
379 * need an id column in GtkComboBox model and could work with a custom widget.
381 void
382 anjuta_preferences_add_from_builder (AnjutaPreferences *pr,
383 GtkBuilder *builder,
384 GSettings *settings,
385 const gchar *widget_name,
386 const gchar *title,
387 const gchar *icon_filename)
389 GtkWidget *parent;
390 GtkWidget *page;
391 GdkPixbuf *pixbuf;
392 gchar *image_path;
394 g_return_if_fail (ANJUTA_IS_PREFERENCES (pr));
395 g_return_if_fail (widget_name != NULL);
396 g_return_if_fail (icon_filename != NULL);
398 page = GTK_WIDGET(gtk_builder_get_object (builder, widget_name));
399 g_object_ref (page);
400 g_return_if_fail (GTK_IS_WIDGET (page));
401 parent = gtk_widget_get_parent (page);
402 if (parent && GTK_IS_CONTAINER (parent))
404 if (GTK_IS_NOTEBOOK (parent))
406 gint page_num;
408 page_num = gtk_notebook_page_num (GTK_NOTEBOOK (parent), page);
409 gtk_notebook_remove_page (GTK_NOTEBOOK (parent), page_num);
411 else
413 gtk_container_remove (GTK_CONTAINER (parent), page);
416 image_path = anjuta_res_get_pixmap_file (icon_filename);
417 pixbuf = gdk_pixbuf_new_from_file (image_path, NULL);
418 anjuta_preferences_dialog_add_page (ANJUTA_PREFERENCES_DIALOG (pr->priv->prefs_dialog),
419 widget_name, title, pixbuf, page);
420 anjuta_preferences_register_all_properties_from_builder_xml (pr, builder, settings, page);
421 g_object_unref (page);
422 g_free (image_path);
423 g_object_unref (pixbuf);
426 void
427 anjuta_preferences_remove_page (AnjutaPreferences *pr,
428 const gchar *page_name)
430 if (pr->priv->prefs_dialog)
432 anjuta_preferences_dialog_remove_page (ANJUTA_PREFERENCES_DIALOG (pr->priv->prefs_dialog),
433 page_name);
437 static void
438 on_preferences_dialog_destroyed (GtkWidget *preferencess_dialog,
439 AnjutaPreferences *pr)
441 GList *plugins;
442 GList *current_plugin;
444 plugins = anjuta_plugin_manager_get_active_plugin_objects (pr->priv->plugin_manager);
445 current_plugin = plugins;
447 while (current_plugin)
449 if (IANJUTA_IS_PREFERENCES (current_plugin->data))
451 ianjuta_preferences_unmerge (IANJUTA_PREFERENCES (current_plugin->data),
452 pr, NULL);
455 current_plugin = g_list_next (current_plugin);
459 g_object_unref (pr->priv->prefs_dialog);
461 g_list_free (plugins);
462 pr->priv->prefs_dialog = NULL;
467 * anjuta_preferences_get_dialog:
468 * @pr: AnjutaPreferences object
470 * Returns: The preference dialog. Creates the dialog if it doesn't exist
472 GtkWidget *
473 anjuta_preferences_get_dialog (AnjutaPreferences *pr)
475 GList *plugins;
476 GList *current_plugin;
478 if (pr->priv->prefs_dialog)
479 return pr->priv->prefs_dialog;
480 else
482 pr->priv->prefs_dialog = anjuta_preferences_dialog_new ();
484 g_signal_connect (G_OBJECT (pr->priv->prefs_dialog), "destroy",
485 G_CALLBACK (on_preferences_dialog_destroyed),
486 pr);
488 plugins = anjuta_plugin_manager_get_active_plugin_objects (pr->priv->plugin_manager);
489 current_plugin = plugins;
491 while (current_plugin)
493 if (IANJUTA_IS_PREFERENCES (current_plugin->data))
495 ianjuta_preferences_merge (IANJUTA_PREFERENCES (current_plugin->data),
496 pr, NULL);
499 current_plugin = g_list_next (current_plugin);
502 g_list_free (plugins);
504 return g_object_ref_sink (pr->priv->prefs_dialog);
509 * anjuta_preferences_is_dialog_created:
510 * @pr: AnjutaPreferences
512 * Returns: Whether the preference dialog was already created
514 gboolean
515 anjuta_preferences_is_dialog_created (AnjutaPreferences *pr)
517 return (pr->priv->prefs_dialog != NULL);
520 static void
521 anjuta_preferences_dispose (GObject *obj)
523 AnjutaPreferences *pr = ANJUTA_PREFERENCES (obj);
525 if (pr->priv->common_gsettings)
527 g_hash_table_destroy (pr->priv->common_gsettings);
528 pr->priv->common_gsettings = NULL;
530 g_free (pr->priv->common_schema_id);
531 pr->priv->common_schema_id = NULL;
534 static void
535 anjuta_preferences_init (AnjutaPreferences *pr)
537 pr->priv = g_new0 (AnjutaPreferencesPriv, 1);
540 static void
541 anjuta_preferences_finalize (GObject *obj)
543 AnjutaPreferences *pr = ANJUTA_PREFERENCES (obj);
545 if (pr->priv->prefs_dialog)
546 gtk_widget_destroy (pr->priv->prefs_dialog);
548 g_object_unref (pr->priv->plugin_manager);
549 g_free (pr->priv);
552 static void
553 anjuta_preferences_class_init (AnjutaPreferencesClass *class)
555 GObjectClass *object_class = G_OBJECT_CLASS (class);
557 object_class->dispose = anjuta_preferences_dispose;
558 object_class->finalize = anjuta_preferences_finalize;
562 * anjuta_preferences_new:
563 * @plugin_manager: #AnjutaPluginManager to be used
564 * @common_schema_id: Common schema id used for key starting with .
566 * Creates a new #AnjutaPreferences object
568 * Return value: A #AnjutaPreferences object.
570 AnjutaPreferences *
571 anjuta_preferences_new (AnjutaPluginManager *plugin_manager, const gchar *common_schema_id)
573 AnjutaPreferences *pr;
575 pr = g_object_new (ANJUTA_TYPE_PREFERENCES, NULL);
576 pr->priv->plugin_manager = g_object_ref (plugin_manager);
577 pr->priv->common_schema_id = g_strdup (common_schema_id);
578 pr->priv->common_gsettings = g_hash_table_new_full (g_str_hash, g_str_equal,
579 g_free,
580 (GDestroyNotify) g_object_unref);
581 return pr;