1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
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
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
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.
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
);
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
);
89 gdkcolor_to_string (GValue
* value
, GVariant
* variant
, gpointer user_data
)
92 gdk_color_parse (g_variant_get_string (variant
, NULL
), &color
);
93 g_value_set_boxed (value
, &color
);
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
));
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;
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
);
130 * anjuta_preferences_register_property:
131 * @pr: a #AnjutaPreferences object
132 * @settings: the #GSettings object associated with that property
133 * @object: Widget to register
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.
143 anjuta_preferences_register_property (AnjutaPreferences
*pr
,
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
,
160 G_SETTINGS_BIND_DEFAULT
,
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
))
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
),
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
);
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
),
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
);
208 else if (GTK_IS_COMBO_BOX (object
))
210 g_settings_bind_with_mapping (settings
, key
,
212 G_SETTINGS_BIND_DEFAULT
,
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
);
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.
247 anjuta_preferences_register_all_properties_from_builder_xml (AnjutaPreferences
*pr
,
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
))
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
))
272 name
= gtk_buildable_get_name (GTK_BUILDABLE (widget
));
274 if (!g_str_has_prefix (name
, PREFERENCE_PROPERTY_PREFIX
))
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
!= ':'))
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 */
293 const gchar
*id
= strrchr (key
, '.');
296 schema_id
= g_string_new (pr
->priv
->common_schema_id
);
299 g_string_append_len (schema_id
, key
, id
- key
);
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
);
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
);
325 p
= gtk_widget_get_parent (p
);
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:
355 * preferences(_.*)?:(.SCHEMAID)?PROPERTYKEY
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'.
362 * The widget must derivated from one of the following Gtk widget:
366 * * GtkFileChooserButton
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.
382 anjuta_preferences_add_from_builder (AnjutaPreferences
*pr
,
385 const gchar
*widget_name
,
387 const gchar
*icon_filename
)
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
));
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
))
408 page_num
= gtk_notebook_page_num (GTK_NOTEBOOK (parent
), page
);
409 gtk_notebook_remove_page (GTK_NOTEBOOK (parent
), page_num
);
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
);
423 g_object_unref (pixbuf
);
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
),
438 on_preferences_dialog_destroyed (GtkWidget
*preferencess_dialog
,
439 AnjutaPreferences
*pr
)
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
),
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
473 anjuta_preferences_get_dialog (AnjutaPreferences
*pr
)
476 GList
*current_plugin
;
478 if (pr
->priv
->prefs_dialog
)
479 return pr
->priv
->prefs_dialog
;
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
),
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
),
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
515 anjuta_preferences_is_dialog_created (AnjutaPreferences
*pr
)
517 return (pr
->priv
->prefs_dialog
!= NULL
);
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
;
535 anjuta_preferences_init (AnjutaPreferences
*pr
)
537 pr
->priv
= g_new0 (AnjutaPreferencesPriv
, 1);
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
);
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.
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
,
580 (GDestroyNotify
) g_object_unref
);