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 /* AnjutaPreferences is a singleton */
64 static AnjutaPreferences
* default_preferences
= NULL
;
66 struct _AnjutaPreferencesPriv
68 GtkWidget
*prefs_dialog
;
69 AnjutaPluginManager
*plugin_manager
;
71 gchar
*common_schema_id
;
72 GHashTable
*common_gsettings
;
75 #define PREFERENCE_PROPERTY_PREFIX "preferences"
77 G_DEFINE_TYPE (AnjutaPreferences
, anjuta_preferences
, G_TYPE_OBJECT
);
80 string_to_gdkcolor (const GValue
* value
, const GVariantType
* type
, gpointer user_data
)
82 GdkColor
* color
= g_value_get_boxed (value
);
83 gchar
* name
= gdk_color_to_string (color
);
85 GVariant
* variant
= g_variant_new_string (name
);
92 gdkcolor_to_string (GValue
* value
, GVariant
* variant
, gpointer user_data
)
95 gdk_color_parse (g_variant_get_string (variant
, NULL
), &color
);
96 g_value_set_boxed (value
, &color
);
101 active_to_string (const GValue
* value
, const GVariantType
* type
, gpointer user_data
)
103 GtkComboBox
* combo
= GTK_COMBO_BOX(user_data
);
105 return g_variant_new_string (gtk_combo_box_get_active_id (combo
));
109 string_to_active (GValue
* value
, GVariant
* variant
, gpointer user_data
)
111 GtkComboBox
* combo
= GTK_COMBO_BOX(user_data
);
113 gtk_combo_box_set_active_id (combo
, g_variant_get_string (variant
, NULL
));
114 g_value_set_int (value
, gtk_combo_box_get_active (combo
));
116 return g_value_get_int (value
) >= 0;
120 update_file_property (GtkWidget
* widget
, gpointer user_data
)
122 GtkFileChooser
*chooser
= GTK_FILE_CHOOSER (user_data
);
123 GSettings
*gsettings
= g_object_get_data (G_OBJECT (chooser
), "anjuta-bind-gsettings");
124 const gchar
*key
= g_object_get_data (G_OBJECT (chooser
), "anjuta-bind-key");
125 gchar
* text_value
= gtk_file_chooser_get_filename (chooser
);
127 g_settings_set_string (gsettings
, key
, text_value
);
133 * anjuta_preferences_register_property:
134 * @pr: a #AnjutaPreferences object
135 * @settings: the #GSettings object associated with that property
136 * @object: Widget to register
139 * This registers only one widget. The widget could be shown elsewhere.
140 * The widget needs to fulfill the properties described in
141 * #anjuta_preferences_add_page documentation.
143 * Return value: TRUE if sucessful.
146 anjuta_preferences_register_property (AnjutaPreferences
*pr
,
153 g_return_val_if_fail (ANJUTA_IS_PREFERENCES (pr
), FALSE
);
154 g_return_val_if_fail (GTK_IS_WIDGET (object
), FALSE
);
155 g_return_val_if_fail (strlen(key
) > 0, FALSE
);
157 /* Start with the most specialized widget as a GtkSpinButton
158 * is a GtkEntry too */
159 if (GTK_IS_COLOR_BUTTON (object
))
161 g_settings_bind_with_mapping (settings
, key
,
163 G_SETTINGS_BIND_DEFAULT
,
169 else if (GTK_IS_FONT_BUTTON (object
))
171 g_settings_bind (settings
, key
, object
, "font-name",
172 G_SETTINGS_BIND_DEFAULT
);
174 else if (GTK_IS_SPIN_BUTTON (object
))
176 g_settings_bind (settings
, key
, object
, "value",
177 G_SETTINGS_BIND_DEFAULT
);
179 else if (GTK_IS_FILE_CHOOSER_BUTTON (object
))
183 switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (object
)))
185 case GTK_FILE_CHOOSER_ACTION_OPEN
:
186 case GTK_FILE_CHOOSER_ACTION_SAVE
:
187 filename
= g_settings_get_string (settings
, key
);
188 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (object
),
191 g_object_set_data_full (G_OBJECT (object
), "anjuta-bind-gsettings", g_object_ref (settings
), (GDestroyNotify
)g_object_unref
);
192 g_object_set_data_full (G_OBJECT (object
), "anjuta-bind-key", g_strdup (key
), (GDestroyNotify
)g_free
);
193 g_signal_connect (G_OBJECT (object
), "file-set",
194 G_CALLBACK (update_file_property
), object
);
196 case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
:
197 case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
:
198 filename
= g_settings_get_string (settings
, key
);
199 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (object
),
202 g_object_set_data_full (G_OBJECT (object
), "anjuta-bind-gsettings", g_object_ref (settings
), (GDestroyNotify
)g_object_unref
);
203 g_object_set_data_full (G_OBJECT (object
), "anjuta-bind-key", g_strdup (key
), (GDestroyNotify
)g_free
);
204 g_signal_connect (G_OBJECT(object
), "current-folder-changed",
205 G_CALLBACK (update_file_property
), object
);
211 else if (GTK_IS_COMBO_BOX (object
))
213 g_settings_bind_with_mapping (settings
, key
,
215 G_SETTINGS_BIND_DEFAULT
,
221 else if (GTK_IS_CHECK_BUTTON (object
))
223 g_settings_bind (settings
, key
, object
, "active",
224 G_SETTINGS_BIND_DEFAULT
);
226 else if (GTK_IS_ENTRY (object
))
228 g_settings_bind (settings
, key
, object
, "text",
229 G_SETTINGS_BIND_DEFAULT
);
240 * anjuta_preferences_register_all_properties_from_builder_xml:
241 * @pr: a #AnjutaPreferences Object
242 * @builder: GtkBuilder object containing the properties widgets.
243 * @parent: Parent widget in the builder object
245 * This will register all the properties names of the format described above
246 * without considering the UI. Useful if you have the widgets shown elsewhere
247 * but you want them to be part of preferences system.
250 anjuta_preferences_register_all_properties_from_builder_xml (AnjutaPreferences
*pr
,
258 g_return_if_fail (ANJUTA_IS_PREFERENCES (pr
));
259 g_return_if_fail (builder
!= NULL
);
261 widgets
= gtk_builder_get_objects (builder
);
262 for (node
= widgets
; node
!= NULL
; node
= g_slist_next (node
))
267 GtkWidget
*widget
, *p
;
268 gboolean cont_flag
= FALSE
;
269 GSettings
*key_settings
= settings
;
271 if (!GTK_IS_WIDGET (node
->data
) || !GTK_IS_BUILDABLE (node
->data
))
275 name
= gtk_buildable_get_name (GTK_BUILDABLE (widget
));
277 if (!g_str_has_prefix (name
, PREFERENCE_PROPERTY_PREFIX
))
280 /* Only ':' is needed between "preferences" and the key name but accept
281 * '_' and additional fields separated by ':' to work with the old
282 * widget naming scheme. */
283 key
= &name
[strlen (PREFERENCE_PROPERTY_PREFIX
)];
284 if ((*key
!= '_') && (*key
!= ':'))
287 for (ptr
= ++key
; *ptr
!= '\0'; ptr
++)
289 if (*ptr
== ':') key
= ptr
+ 1;
291 if (*key
== '\0') continue;
293 /* Check if we need to use common settings */
296 const gchar
*id
= strrchr (key
, '.');
299 schema_id
= g_string_new (pr
->priv
->common_schema_id
);
302 g_string_append_len (schema_id
, key
, id
- key
);
306 key_settings
= (GSettings
*)g_hash_table_lookup (pr
->priv
->common_gsettings
, schema_id
->str
);
307 if (key_settings
== NULL
)
309 key_settings
= g_settings_new (schema_id
->str
);
310 g_hash_table_insert (pr
->priv
->common_gsettings
, schema_id
->str
, key_settings
);
311 g_string_free (schema_id
, FALSE
);
315 g_string_free (schema_id
, TRUE
);
319 /* Added only if it's a descendant child of the parent */
320 p
= gtk_widget_get_parent (widget
);
328 p
= gtk_widget_get_parent (p
);
333 if (!anjuta_preferences_register_property (pr
, key_settings
, widget
, key
))
335 g_critical ("Invalid preference widget named %s, check anjuta_preferences_add_page function documentation.", name
);
341 * anjuta_preferences_add_page:
342 * @pr: a #AnjutaPreferences object
343 * @builder: #GtkBuilder object containing the preferences page
344 * @settings: the #GSettings object associated with that page
345 * @gwidget_name: Page widget name (as give with glade interface editor).
346 * The widget will be searched with the given name and detached
347 * (that is, removed from the container, if present) from it's parent.
348 * @icon_filename: File name (of the form filename.png) of the icon representing
349 * the preference page.
351 * Add a page to the preferences sytem.
352 * builder is the GtkBuilder object of the dialog containing the page widget.
353 * The dialog will contain the layout of the preferences widgets.
354 * The widgets which are preference widgets (e.g. toggle button) should have
355 * widget names of the form:
358 * preferences(_.*)?:(.SCHEMAID)?PROPERTYKEY
360 * SCHEMAID if present the key will be added not in the page settings but
361 * in common settings using SCHEMAID as a suffix.
362 * PROPERTYKEY is the property key. e.g - 'tab-size'.
365 * The widget must derivated from one of the following Gtk widget:
369 * * GtkFileChooserButton
374 * In addition, the model of a GtkComboBox must have an id column.
375 * It is the value of this column which is saved as preference.
377 * All widgets having the above names in the gxml tree will be registered
378 * and will become part of auto saving/loading. For example, refer to
379 * anjuta preferences dialogs and study the widget names.
381 * Older versions of Anjuta use more fields in the widget name. They do not
382 * need an id column in GtkComboBox model and could work with a custom widget.
385 anjuta_preferences_add_from_builder (AnjutaPreferences
*pr
,
388 const gchar
*widget_name
,
390 const gchar
*icon_filename
)
397 g_return_if_fail (ANJUTA_IS_PREFERENCES (pr
));
398 g_return_if_fail (widget_name
!= NULL
);
399 g_return_if_fail (icon_filename
!= NULL
);
401 page
= GTK_WIDGET(gtk_builder_get_object (builder
, widget_name
));
403 g_return_if_fail (GTK_IS_WIDGET (page
));
404 parent
= gtk_widget_get_parent (page
);
405 if (parent
&& GTK_IS_CONTAINER (parent
))
407 if (GTK_IS_NOTEBOOK (parent
))
411 page_num
= gtk_notebook_page_num (GTK_NOTEBOOK (parent
), page
);
412 gtk_notebook_remove_page (GTK_NOTEBOOK (parent
), page_num
);
416 gtk_container_remove (GTK_CONTAINER (parent
), page
);
419 image_path
= anjuta_res_get_pixmap_file (icon_filename
);
420 pixbuf
= gdk_pixbuf_new_from_file (image_path
, NULL
);
421 anjuta_preferences_dialog_add_page (ANJUTA_PREFERENCES_DIALOG (pr
->priv
->prefs_dialog
),
422 widget_name
, title
, pixbuf
, page
);
423 anjuta_preferences_register_all_properties_from_builder_xml (pr
, builder
, settings
, page
);
424 g_object_unref (page
);
426 g_object_unref (pixbuf
);
430 anjuta_preferences_remove_page (AnjutaPreferences
*pr
,
431 const gchar
*page_name
)
433 if (pr
->priv
->prefs_dialog
)
435 anjuta_preferences_dialog_remove_page (ANJUTA_PREFERENCES_DIALOG (pr
->priv
->prefs_dialog
),
441 on_preferences_dialog_destroyed (GtkWidget
*preferencess_dialog
,
442 AnjutaPreferences
*pr
)
445 GList
*current_plugin
;
447 plugins
= anjuta_plugin_manager_get_active_plugin_objects (pr
->priv
->plugin_manager
);
448 current_plugin
= plugins
;
450 while (current_plugin
)
452 if (IANJUTA_IS_PREFERENCES (current_plugin
->data
))
454 ianjuta_preferences_unmerge (IANJUTA_PREFERENCES (current_plugin
->data
),
458 current_plugin
= g_list_next (current_plugin
);
462 g_object_unref (pr
->priv
->prefs_dialog
);
464 g_list_free (plugins
);
465 pr
->priv
->prefs_dialog
= NULL
;
470 * anjuta_preferences_get_dialog:
471 * @pr: AnjutaPreferences object
473 * Returns: The preference dialog. Creates the dialog if it doesn't exist
476 anjuta_preferences_get_dialog (AnjutaPreferences
*pr
)
479 GList
*current_plugin
;
481 if (pr
->priv
->prefs_dialog
)
482 return pr
->priv
->prefs_dialog
;
485 pr
->priv
->prefs_dialog
= anjuta_preferences_dialog_new ();
487 g_signal_connect (G_OBJECT (pr
->priv
->prefs_dialog
), "destroy",
488 G_CALLBACK (on_preferences_dialog_destroyed
),
491 plugins
= anjuta_plugin_manager_get_active_plugin_objects (pr
->priv
->plugin_manager
);
492 current_plugin
= plugins
;
494 while (current_plugin
)
496 if (IANJUTA_IS_PREFERENCES (current_plugin
->data
))
498 ianjuta_preferences_merge (IANJUTA_PREFERENCES (current_plugin
->data
),
502 current_plugin
= g_list_next (current_plugin
);
505 g_list_free (plugins
);
507 return g_object_ref_sink (pr
->priv
->prefs_dialog
);
512 * anjuta_preferences_is_dialog_created:
513 * @pr: AnjutaPreferences
515 * Returns: Whether the preference dialog was already created
518 anjuta_preferences_is_dialog_created (AnjutaPreferences
*pr
)
520 return (pr
->priv
->prefs_dialog
!= NULL
);
524 anjuta_preferences_dispose (GObject
*obj
)
526 AnjutaPreferences
*pr
= ANJUTA_PREFERENCES (obj
);
528 if (pr
->priv
->common_gsettings
)
530 g_hash_table_destroy (pr
->priv
->common_gsettings
);
531 pr
->priv
->common_gsettings
= NULL
;
533 g_free (pr
->priv
->common_schema_id
);
534 pr
->priv
->common_schema_id
= NULL
;
538 anjuta_preferences_init (AnjutaPreferences
*pr
)
540 pr
->priv
= g_new0 (AnjutaPreferencesPriv
, 1);
544 anjuta_preferences_finalize (GObject
*obj
)
546 AnjutaPreferences
*pr
= ANJUTA_PREFERENCES (obj
);
548 if (pr
->priv
->prefs_dialog
)
549 gtk_widget_destroy (pr
->priv
->prefs_dialog
);
551 g_object_unref (pr
->priv
->plugin_manager
);
556 anjuta_preferences_class_init (AnjutaPreferencesClass
*class)
558 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
560 object_class
->dispose
= anjuta_preferences_dispose
;
561 object_class
->finalize
= anjuta_preferences_finalize
;
565 * anjuta_preferences_new:
566 * @plugin_manager: #AnjutaPluginManager to be used
567 * @common_schema_id: Common schema id used for key starting with .
569 * Creates a new #AnjutaPreferences object
571 * Return value: A #AnjutaPreferences object.
574 anjuta_preferences_new (AnjutaPluginManager
*plugin_manager
, const gchar
*common_schema_id
)
576 AnjutaPreferences
*pr
;
578 if (!default_preferences
)
580 pr
= g_object_new (ANJUTA_TYPE_PREFERENCES
, NULL
);
581 pr
->priv
->plugin_manager
= g_object_ref (plugin_manager
);
582 pr
->priv
->common_schema_id
= g_strdup (common_schema_id
);
583 pr
->priv
->common_gsettings
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
585 (GDestroyNotify
) g_object_unref
);
586 default_preferences
= pr
;
590 return default_preferences
;
595 * anjuta_preferences_default:
597 * Get the default instace of anjuta preferences
599 * Return value: A #AnjutaPreferences object.
601 AnjutaPreferences
*anjuta_preferences_default ()
603 return default_preferences
;