1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-profile.c
4 * Copyright (C) Naba Kumar <naba@gnome.org>
5 *
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.
10 *
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.
15 *
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
19 */
20
21 /**
22 * SECTION:anjuta-profile
23 * @short_description: Profile is a collection of plugins
24 * @see_also: #AnjutaProfileManager, #AnjutaPlugin
25 * @stability: Unstable
26 * @include: libanjuta/anjuta-profile.h
27 *
28 * A anjuta profile contains the list of all plugins used in one Anjuta session.
29 * It is possible to add and remove plugins,
30 * check if one is included or get the whole list. The plugins list can be saved
31 * into a xml file and loaded from it.
32 *
33 * A profile in an Anjuta session includes plugins from up to 3 different xml
34 * sources:
35 * <variablelist>
36 * <varlistentry>
37 * <term>$prefix/share/anjuta/profiles/default.profile</term>
38 * <listitem>
39 * <para>
40 * This contains the system plugins. It is loaded in special system
41 * profile and contains mandatory plugins for Anjuta. These plugins
42 * cannot be unloaded. Anjuta can load a different profile using the -P
43 * command line option.
44 * </para>
45 * </listitem>
46 * </varlistentry>
47 * <varlistentry>
48 * <term>$project_dir/$project_name.anjuta</term>
49 * <listitem>
50 * <para>
51 * This contains the project plugins. It lists mandatory plugins for the
52 * project. This file is version controlled and distributed with the source
53 * code. Every user working on the project uses the same one. If there
54 * is no project loaded, no project plugins are loaded.
55 * </para>
56 * </listitem>
57 * </varlistentry>
58 * <varlistentry>
59 * <term>$project_dir/.anjuta/default.profile</term>
60 * <listitem>
61 * <para>
62 * This contains the user plugins. This is the only list of plugins
63 * which is updated when the user add or remove one plugin.
64 * If there is no project loaded, the user home directory is used
65 * instead of the project directory but this list is used only in this case.
66 * There is no global user plugins list.
67 * </para>
68 * </listitem>
69 * </varlistentry>
70 * </variablelist>
71 */
72
73 #include <glib/gi18n.h>
74 #include <glib.h>
75 #include <string.h>
76 #include <libxml/parser.h>
77 #include <libxml/tree.h>
78
79 #include "anjuta-profile.h"
80 #include "anjuta-marshal.h"
81 #include "anjuta-debug.h"
82
83 enum
84 {
85 PROP_0,
86 PROP_PLUGIN_MANAGER,
87 PROP_PROFILE_NAME,
88 PROP_SYNC_FILE,
89 };
90
91 enum
92 {
93 PLUGIN_ADDED,
94 PLUGIN_REMOVED,
95 CHANGED,
96 DESCOPED,
97 SCOPED,
98 LAST_SIGNAL
99 };
100
101 typedef struct _AnjutaProfileXml AnjutaProfileXml;
102
103 struct _AnjutaProfileXml
104 {
105 GFile *file;
106 xmlDocPtr doc;
107 gboolean exclude_from_sync;
108 AnjutaProfileXml *next;
109 };
110
111
112 struct _AnjutaProfilePriv
113 {
114 gchar *name;
115 AnjutaPluginManager *plugin_manager;
116 GHashTable *plugins_to_load;
117 GHashTable *plugins_to_exclude_from_sync;
118 GList *plugins_to_disable;
119 GList *configuration;
120 GList *config_keys;
121 GFile *sync_file;
122 AnjutaProfileXml *xml;
123 };
124
125 static GObjectClass* parent_class = NULL;
126 static guint profile_signals[LAST_SIGNAL] = { 0 };
127
128 GQuark
anjuta_profile_error_quark(void)129 anjuta_profile_error_quark (void)
130 {
131 static GQuark quark = 0;
132
133 if (quark == 0) {
134 quark = g_quark_from_static_string ("anjuta-profile-quark");
135 }
136
137 return quark;
138 }
139
140 static void
anjuta_profile_init(AnjutaProfile * object)141 anjuta_profile_init (AnjutaProfile *object)
142 {
143 object->priv = g_new0 (AnjutaProfilePriv, 1);
144 object->priv->plugins_to_load = g_hash_table_new (g_direct_hash,
145 g_direct_equal);
146 object->priv->plugins_to_exclude_from_sync = g_hash_table_new (g_direct_hash,
147 g_direct_equal);
148 }
149
150 static void
anjuta_profile_finalize(GObject * object)151 anjuta_profile_finalize (GObject *object)
152 {
153 AnjutaProfilePriv *priv = ANJUTA_PROFILE (object)->priv;
154 g_free (priv->name);
155 g_hash_table_destroy (priv->plugins_to_load);
156 g_hash_table_destroy (priv->plugins_to_exclude_from_sync);
157 g_list_free (priv->plugins_to_disable);
158 g_list_free_full (priv->config_keys, (GDestroyNotify)g_free);
159 g_list_free (priv->configuration);
160
161 while (priv->xml != NULL)
162 {
163 AnjutaProfileXml *next;
164
165 next = priv->xml->next;
166 g_object_unref (priv->xml->file);
167 g_free (priv->xml);
168 priv->xml = next;
169 }
170
171 G_OBJECT_CLASS (parent_class)->finalize (object);
172 }
173
174 static void
anjuta_profile_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)175 anjuta_profile_set_property (GObject *object, guint prop_id,
176 const GValue *value, GParamSpec *pspec)
177 {
178 AnjutaProfilePriv *priv = ANJUTA_PROFILE (object)->priv;
179
180 g_return_if_fail (ANJUTA_IS_PROFILE (object));
181
182 switch (prop_id)
183 {
184 case PROP_PLUGIN_MANAGER:
185 priv->plugin_manager = g_value_get_object (value);
186 break;
187 case PROP_PROFILE_NAME:
188 g_return_if_fail (g_value_get_string (value) != NULL);
189 g_free (priv->name);
190 priv->name = g_strdup (g_value_get_string (value));
191 break;
192 case PROP_SYNC_FILE:
193 if (priv->sync_file)
194 g_object_unref (priv->sync_file);
195 priv->sync_file = g_value_dup_object (value);
196 break;
197 default:
198 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
199 break;
200 }
201 }
202
203 static void
anjuta_profile_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)204 anjuta_profile_get_property (GObject *object, guint prop_id,
205 GValue *value, GParamSpec *pspec)
206 {
207 AnjutaProfilePriv *priv = ANJUTA_PROFILE (object)->priv;
208
209 g_return_if_fail (ANJUTA_IS_PROFILE (object));
210
211 switch (prop_id)
212 {
213 case PROP_PLUGIN_MANAGER:
214 g_value_set_object (value, priv->plugin_manager);
215 break;
216 case PROP_PROFILE_NAME:
217 g_value_set_string (value, priv->name);
218 break;
219 case PROP_SYNC_FILE:
220 g_value_set_object (value, priv->sync_file);
221 break;
222 default:
223 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
224 break;
225 }
226 }
227
228 static void
anjuta_profile_plugin_added(AnjutaProfile * self,AnjutaPluginHandle * plugin)229 anjuta_profile_plugin_added (AnjutaProfile *self,
230 AnjutaPluginHandle *plugin)
231 {
232 }
233
234 static void
anjuta_profile_plugin_removed(AnjutaProfile * self,AnjutaPluginHandle * plugin)235 anjuta_profile_plugin_removed (AnjutaProfile *self,
236 AnjutaPluginHandle *plugin)
237 {
238 }
239
240 static void
anjuta_profile_changed(AnjutaProfile * self)241 anjuta_profile_changed (AnjutaProfile *self)
242 {
243 GError *error = NULL;
244 anjuta_profile_sync (self, &error);
245 if (error)
246 {
247 g_warning ("Failed to synchronize plugins profile '%s': %s",
248 self->priv->name, error->message);
249 g_error_free (error);
250 }
251 }
252
253 static void
anjuta_profile_class_init(AnjutaProfileClass * klass)254 anjuta_profile_class_init (AnjutaProfileClass *klass)
255 {
256 GObjectClass* object_class = G_OBJECT_CLASS (klass);
257 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
258
259 object_class->finalize = anjuta_profile_finalize;
260 object_class->set_property = anjuta_profile_set_property;
261 object_class->get_property = anjuta_profile_get_property;
262
263 klass->plugin_added = anjuta_profile_plugin_added;
264 klass->plugin_removed = anjuta_profile_plugin_removed;
265 klass->changed = anjuta_profile_changed;
266
267 g_object_class_install_property (object_class,
268 PROP_PLUGIN_MANAGER,
269 g_param_spec_object ("plugin-manager",
270 _("Plugin Manager"),
271 _("The plugin manager to use for resolving plugins"),
272 ANJUTA_TYPE_PLUGIN_MANAGER,
273 G_PARAM_READABLE |
274 G_PARAM_WRITABLE |
275 G_PARAM_CONSTRUCT));
276 g_object_class_install_property (object_class,
277 PROP_PROFILE_NAME,
278 g_param_spec_string ("profile-name",
279 _("Profile Name"),
280 _("Name of the plugin profile"),
281 NULL,
282 G_PARAM_READABLE |
283 G_PARAM_WRITABLE |
284 G_PARAM_CONSTRUCT));
285 g_object_class_install_property (object_class,
286 PROP_SYNC_FILE,
287 g_param_spec_object ("sync-file",
288 _("Synchronization file"),
289 _("File to syncronize the profile XML"),
290 G_TYPE_FILE,
291 G_PARAM_READABLE |
292 G_PARAM_WRITABLE |
293 G_PARAM_CONSTRUCT));
294
295 /**
296 * AnjutaProfile::plugin-added:
297 * @profile: a #AnjutaProfile object.
298 * @plugin: the new plugin as a #AnjutaPluginHandle.
299 *
300 * Emitted when a plugin is added in the list.
301 */
302 profile_signals[PLUGIN_ADDED] =
303 g_signal_new ("plugin-added",
304 G_OBJECT_CLASS_TYPE (klass),
305 G_SIGNAL_RUN_FIRST,
306 G_STRUCT_OFFSET (AnjutaProfileClass, plugin_added),
307 NULL, NULL,
308 anjuta_cclosure_marshal_VOID__POINTER,
309 G_TYPE_NONE, 1,
310 G_TYPE_POINTER);
311
312 /**
313 * AnjutaProfile::plugin-removed:
314 * @profile: a #AnjutaProfile object.
315 * @plugin: the removed plugin as a #AnjutaPluginHandle.
316 *
317 * Emitted when a plugin is removed from the list.
318 */
319 profile_signals[PLUGIN_REMOVED] =
320 g_signal_new ("plugin-removed",
321 G_OBJECT_CLASS_TYPE (klass),
322 G_SIGNAL_RUN_FIRST,
323 G_STRUCT_OFFSET (AnjutaProfileClass, plugin_removed),
324 NULL, NULL,
325 anjuta_cclosure_marshal_VOID__POINTER,
326 G_TYPE_NONE, 1,
327 G_TYPE_POINTER);
328
329 /**
330 * AnjutaProfile::changed:
331 * @profile: a #AnjutaProfile object.
332 *
333 * Emitted when a plugin is added or removed from the list.
334 */
335 profile_signals[CHANGED] =
336 g_signal_new ("changed",
337 G_OBJECT_CLASS_TYPE (klass),
338 G_SIGNAL_RUN_FIRST,
339 G_STRUCT_OFFSET (AnjutaProfileClass, changed),
340 NULL, NULL,
341 anjuta_cclosure_marshal_VOID__VOID,
342 G_TYPE_NONE, 0);
343
344 /**
345 * AnjutaProfile::profile-descoped:
346 * @profile: the old unloaded #AnjutaProfile
347 *
348 * Emitted when a profile will be unloaded.
349 */
350 profile_signals[DESCOPED] =
351 g_signal_new ("descoped",
352 G_OBJECT_CLASS_TYPE (klass),
353 G_SIGNAL_RUN_FIRST,
354 G_STRUCT_OFFSET (AnjutaProfileClass,
355 descoped),
356 NULL, NULL,
357 g_cclosure_marshal_VOID__VOID,
358 G_TYPE_NONE, 0);
359
360 /**
361 * AnjutaProfileManager::profile-scoped:
362 * @profile_manager: a #AnjutaProfileManager object.
363 * @profile: the current loaded #AnjutaProfile.
364 *
365 * Emitted when a new profile is loaded.
366 */
367 profile_signals[SCOPED] =
368 g_signal_new ("scoped",
369 G_OBJECT_CLASS_TYPE (klass),
370 G_SIGNAL_RUN_FIRST,
371 G_STRUCT_OFFSET (AnjutaProfileClass,
372 scoped),
373 NULL, NULL,
374 g_cclosure_marshal_VOID__VOID,
375 G_TYPE_NONE, 0);
376 }
377
378 GType
anjuta_profile_get_type(void)379 anjuta_profile_get_type (void)
380 {
381 static GType our_type = 0;
382
383 if(our_type == 0)
384 {
385 static const GTypeInfo our_info =
386 {
387 sizeof (AnjutaProfileClass), /* class_size */
388 (GBaseInitFunc) NULL, /* base_init */
389 (GBaseFinalizeFunc) NULL, /* base_finalize */
390 (GClassInitFunc) anjuta_profile_class_init, /* class_init */
391 (GClassFinalizeFunc) NULL, /* class_finalize */
392 NULL /* class_data */,
393 sizeof (AnjutaProfile), /* instance_size */
394 0, /* n_preallocs */
395 (GInstanceInitFunc) anjuta_profile_init, /* instance_init */
396 NULL /* value_table */
397 };
398
399 our_type = g_type_register_static (G_TYPE_OBJECT, "AnjutaProfile",
400 &our_info, 0);
401 }
402
403 return our_type;
404 }
405
406 static void
on_plugin_activated(AnjutaPluginManager * plugin_manager,AnjutaPluginHandle * plugin_handle,GObject * plugin_object,AnjutaProfile * profile)407 on_plugin_activated (AnjutaPluginManager *plugin_manager,
408 AnjutaPluginHandle *plugin_handle,
409 GObject *plugin_object,
410 AnjutaProfile *profile)
411 {
412 /* Add it current profile */
413 gboolean exclude;
414 AnjutaPluginDescription *desc;
415
416 desc = anjuta_plugin_handle_get_description (plugin_handle);
417 if (!anjuta_plugin_description_get_boolean (desc, "Anjuta Plugin", "ExcludeFromSession", &exclude) || !exclude)
418 {
419 anjuta_profile_add_plugin (profile, plugin_handle);
420 }
421 }
422
423 static void
on_plugin_deactivated(AnjutaPluginManager * plugin_manager,AnjutaPluginHandle * plugin_handle,GObject * plugin_object,AnjutaProfile * profile)424 on_plugin_deactivated (AnjutaPluginManager *plugin_manager,
425 AnjutaPluginHandle *plugin_handle,
426 GObject *plugin_object,
427 AnjutaProfile *profile)
428 {
429 /* Remove from current profile */
430 anjuta_profile_remove_plugin (profile, plugin_handle);
431 }
432
433 /**
434 * anjuta_profile_new:
435 * @name: the new profile name.
436 * @plugin_manager: the #AnjutaPluginManager used by this profile.
437 *
438 * Create a new profile.
439 *
440 * Return value: the new #AnjutaProfile object.
441 */
442 AnjutaProfile*
anjuta_profile_new(const gchar * name,AnjutaPluginManager * plugin_manager)443 anjuta_profile_new (const gchar* name, AnjutaPluginManager *plugin_manager)
444 {
445 GObject *profile;
446 profile = g_object_new (ANJUTA_TYPE_PROFILE, "profile-name", name,
447 "plugin-manager", plugin_manager, NULL);
448 return ANJUTA_PROFILE (profile);
449 }
450
451 /**
452 * anjuta_profile_get_name:
453 * @profile: a #AnjutaProfile object.
454 *
455 * Get the profile name.
456 *
457 * Return value: the profile name.
458 */
459 const gchar*
anjuta_profile_get_name(AnjutaProfile * profile)460 anjuta_profile_get_name (AnjutaProfile *profile)
461 {
462 AnjutaProfilePriv *priv;
463 g_return_val_if_fail (ANJUTA_IS_PROFILE (profile), NULL);
464 priv = ANJUTA_PROFILE (profile)->priv;
465 return priv->name;
466 }
467
468 /**
469 * anjuta_profile_add_plugin:
470 * @profile: a #AnjutaProfile object.
471 * @plugin: a #AnjutaPluginHandle.
472 *
473 * Add one plugin into the profile plugin list.
474 */
475 void
anjuta_profile_add_plugin(AnjutaProfile * profile,AnjutaPluginHandle * plugin)476 anjuta_profile_add_plugin (AnjutaProfile *profile,
477 AnjutaPluginHandle *plugin)
478 {
479 AnjutaProfilePriv *priv;
480 g_return_if_fail (ANJUTA_IS_PROFILE (profile));
481 g_return_if_fail (plugin != NULL);
482 priv = ANJUTA_PROFILE (profile)->priv;
483 if (g_hash_table_lookup (priv->plugins_to_load, plugin) == NULL)
484 {
485 g_hash_table_add (priv->plugins_to_load, plugin);
486 g_signal_emit_by_name (profile, "plugin-added", plugin);
487 g_signal_emit_by_name (profile, "changed");
488 }
489 }
490
491 /**
492 * anjuta_profile_remove_plugin:
493 * @profile: a #AnjutaProfile object.
494 * @plugin: a #AnjutaPluginHandle.
495 *
496 * Remove one plugin from the profile plugin list.
497 */
498 void
anjuta_profile_remove_plugin(AnjutaProfile * profile,AnjutaPluginHandle * plugin)499 anjuta_profile_remove_plugin (AnjutaProfile *profile,
500 AnjutaPluginHandle *plugin)
501 {
502 AnjutaProfilePriv *priv;
503 g_return_if_fail (ANJUTA_IS_PROFILE (profile));
504 g_return_if_fail (plugin != NULL);
505 priv = ANJUTA_PROFILE (profile)->priv;
506 if (g_hash_table_remove (priv->plugins_to_load, plugin))
507 {
508 g_hash_table_remove (priv->plugins_to_exclude_from_sync, plugin);
509 g_signal_emit_by_name (profile, "plugin-removed", plugin);
510 g_signal_emit_by_name (profile, "changed");
511 }
512 }
513
514 /**
515 * anjuta_profile_has_plugin:
516 * @profile: a #AnjutaProfile object
517 * @plugin: a #AnjutaPluginHandle
518 *
519 * Check if a plugin is included in the profile plugin list.
520 *
521 * Return value: %TRUE if the plugin is included in the list.
522 */
523 gboolean
anjuta_profile_has_plugin(AnjutaProfile * profile,AnjutaPluginHandle * plugin)524 anjuta_profile_has_plugin (AnjutaProfile *profile,
525 AnjutaPluginHandle *plugin)
526 {
527 AnjutaProfilePriv *priv;
528 g_return_val_if_fail (ANJUTA_IS_PROFILE (profile), FALSE);
529 g_return_val_if_fail (plugin != NULL, FALSE);
530 priv = ANJUTA_PROFILE (profile)->priv;
531
532 return g_hash_table_lookup (priv->plugins_to_load, plugin) != NULL;
533 }
534
535 static gboolean
anjuta_profile_configure_plugins(AnjutaProfile * profile,GList * handles_list,GList * config_list)536 anjuta_profile_configure_plugins (AnjutaProfile *profile,
537 GList *handles_list,
538 GList *config_list)
539 {
540 AnjutaProfilePriv *priv;
541 GList *item;
542 GList *config;
543
544 g_return_val_if_fail (ANJUTA_IS_PROFILE (profile), FALSE);
545
546 priv = ANJUTA_PROFILE (profile)->priv;
547 for (config = config_list, item = handles_list; item != NULL; item = g_list_next (item), config = g_list_next (config))
548 {
549 GList *plugin;
550 GList *set;
551
552 for (plugin = g_list_first ((GList *)item->data); plugin != NULL; plugin = g_list_next (plugin))
553 {
554 AnjutaPluginHandle *handle = ANJUTA_PLUGIN_HANDLE (plugin->data);
555 AnjutaPluginDescription *desc;
556
557 desc = anjuta_plugin_handle_get_description (handle);
558 for (set = g_list_first ((GList *)config->data); set != NULL; set = g_list_next (set))
559 {
560 gchar *group = (gchar *)set->data;
561 gchar *key = group + strlen (group) + 1;
562 gchar *value = key + strlen (key) + 1;
563
564 anjuta_plugin_description_override (desc, group, key, value);
565 priv->configuration = g_list_prepend (priv->configuration, group);
566 priv->configuration = g_list_prepend (priv->configuration, handle);
567 }
568 }
569 for (set = g_list_first ((GList *)config->data); set != NULL; set = g_list_delete_link (set, set))
570 {
571 priv->config_keys = g_list_prepend (priv->config_keys, set->data);
572 }
573 }
574 g_list_free (config_list);
575
576 return TRUE;
577 }
578
579
580 static gboolean
anjuta_profile_unconfigure_plugins(AnjutaProfile * profile)581 anjuta_profile_unconfigure_plugins (AnjutaProfile *profile)
582 {
583 AnjutaProfilePriv *priv;
584 GList *item;
585
586 g_return_val_if_fail (ANJUTA_IS_PROFILE (profile), FALSE);
587
588 priv = ANJUTA_PROFILE (profile)->priv;
589 for (item = g_list_first (priv->configuration); item != NULL; item = g_list_delete_link (item, item))
590 {
591 AnjutaPluginHandle *handle = ANJUTA_PLUGIN_HANDLE (item->data);
592 AnjutaPluginDescription *desc;
593 gchar *group;
594 gchar *key;
595
596 item = g_list_delete_link (item, item);
597 group = (gchar *)(item->data);
598 key = group + strlen (group) + 1;
599
600 desc = anjuta_plugin_handle_get_description (handle);
601 anjuta_plugin_description_remove (desc, group, key);
602 }
603 priv->configuration = NULL;
604 g_list_free_full (priv->config_keys, (GDestroyNotify)g_free);
605 priv->config_keys = NULL;
606
607 return TRUE;
608 }
609
610 static GList*
anjuta_profile_select_plugins(AnjutaProfile * profile,GList * handles_list)611 anjuta_profile_select_plugins (AnjutaProfile *profile,
612 GList *handles_list)
613 {
614 GList *selected_plugins = NULL;
615 GList *node = handles_list;
616 AnjutaProfilePriv *priv;
617
618 priv = profile->priv;
619
620 while (node)
621 {
622 GList *descs = node->data;
623 if (g_list_length (descs) == 1)
624 {
625 selected_plugins = g_list_prepend (selected_plugins, descs->data);
626 }
627 else
628 {
629 AnjutaPluginHandle* handle;
630 handle = anjuta_plugin_manager_select (priv->plugin_manager,
631 _("Select a plugin"),
632 _("Please select a plugin from the list"),
633 descs);
634 if (handle)
635 selected_plugins = g_list_prepend (selected_plugins, handle);
636 }
637 node = g_list_next (node);
638 }
639 return g_list_reverse (selected_plugins);
640 }
641
642
643 /* Read profile from XML
644 *---------------------------------------------------------------------------*/
645
646 /* Error during parsing */
647 static gboolean
set_parse_error(GError ** error,GFile * file)648 set_parse_error (GError **error, GFile*file)
649 {
650 gchar *uri = g_file_get_uri (file);
651
652 g_error_free (*error);
653 *error = g_error_new (ANJUTA_PROFILE_ERROR,
654 ANJUTA_PROFILE_ERROR_URI_READ_FAILED,
655 _("Failed to read '%s': XML parse error. "
656 "Invalid or corrupted Anjuta plugins profile."),
657 uri);
658 g_free (uri);
659
660 return FALSE;
661 }
662
663 static xmlDocPtr
load_profile_from_xml(GFile * file,GError ** error)664 load_profile_from_xml (GFile *file, GError **error)
665 {
666 gchar *read_buf;
667 gsize size;
668 xmlDocPtr xml_doc;
669
670 /* Read xml file */
671 if (!g_file_load_contents (file, NULL, &read_buf, &size, NULL, error))
672 {
673 return NULL;
674 }
675
676 /* Parse xml file */
677 xml_doc = xmlParseMemory (read_buf, size);
678 g_free (read_buf);
679 if (xml_doc != NULL)
680 {
681 xmlNodePtr xml_root;
682
683 xml_root = xmlDocGetRootElement(xml_doc);
684 if (xml_root ||
685 (xml_root->name) ||
686 xmlStrEqual(xml_root->name, (const xmlChar *)"anjuta"))
687 {
688 return xml_doc;
689 }
690 xmlFreeDoc(xml_doc);
691 }
692 set_parse_error (error, file);
693
694 return NULL;
695 }
696
697 static GList *
parse_set(xmlNodePtr xml_node,GFile * file,GError ** error)698 parse_set (xmlNodePtr xml_node, GFile *file, GError **error)
699 {
700 GList *config = NULL;
701 gboolean parse_error = FALSE;
702 xmlNodePtr xml_require_node;
703
704 /* Read attribute conditions */
705 for (xml_require_node = xml_node->xmlChildrenNode;
706 xml_require_node;
707 xml_require_node = xml_require_node->next)
708 {
709 xmlChar *group;
710 xmlChar *attrib;
711 xmlChar *value;
712
713 if (!xml_require_node->name ||
714 !xmlStrEqual (xml_require_node->name,
715 (const xmlChar*)"set"))
716 {
717 continue;
718 }
719 group = xmlGetProp (xml_require_node,
720 (const xmlChar *)"group");
721 attrib = xmlGetProp(xml_require_node,
722 (const xmlChar *)"attribute");
723 value = xmlGetProp(xml_require_node,
724 (const xmlChar *)"value");
725
726 if (group && attrib && value)
727 {
728 GString *str;
729
730 str = g_string_new ((const gchar *)group);
731 g_string_append_c (str, '\0');
732 g_string_append (str, (const gchar *)attrib);
733 g_string_append_c (str, '\0');
734 g_string_append (str, (const gchar *)value);
735
736 config = g_list_prepend (config, g_string_free (str, FALSE));
737 }
738 else
739 {
740 parse_error = TRUE;
741 g_warning ("XML parse error: group, attribute and value should be defined in set");
742 }
743 if (group) xmlFree (group);
744 if (attrib) xmlFree (attrib);
745 if (value) xmlFree (value);
746 if (parse_error) break;
747 }
748
749 if (parse_error)
750 {
751 set_parse_error (error, file);
752 }
753
754 return g_list_reverse (config);
755 }
756
757
758 static GList *
parse_requires(xmlNodePtr xml_node,AnjutaPluginManager * plugin_manager,GFile * file,GError ** error)759 parse_requires (xmlNodePtr xml_node, AnjutaPluginManager *plugin_manager, GFile *file, GError **error)
760 {
761 GList *plugin_handles = NULL;
762 GList *groups = NULL;
763 GList *attribs = NULL;
764 GList *values = NULL;
765 gboolean parse_error = FALSE;
766 xmlNodePtr xml_require_node;
767
768 /* Read attribute conditions */
769 for (xml_require_node = xml_node->xmlChildrenNode;
770 xml_require_node;
771 xml_require_node = xml_require_node->next)
772 {
773 xmlChar *group;
774 xmlChar *attrib;
775 xmlChar *value;
776
777 if (!xml_require_node->name ||
778 !xmlStrEqual (xml_require_node->name,
779 (const xmlChar*)"require"))
780 {
781 continue;
782 }
783 group = xmlGetProp (xml_require_node,
784 (const xmlChar *)"group");
785 attrib = xmlGetProp(xml_require_node,
786 (const xmlChar *)"attribute");
787 value = xmlGetProp(xml_require_node,
788 (const xmlChar *)"value");
789
790 if (group && attrib && value)
791 {
792 groups = g_list_prepend (groups, group);
793 attribs = g_list_prepend (attribs, attrib);
794 values = g_list_prepend (values, value);
795 }
796 else
797 {
798 if (group) xmlFree (group);
799 if (attrib) xmlFree (attrib);
800 if (value) xmlFree (value);
801 parse_error = TRUE;
802 g_warning ("XML parse error: group, attribute and value should be defined in require");
803 break;
804 }
805 }
806
807 if (parse_error)
808 {
809 set_parse_error (error, file);
810 }
811 else
812 {
813 if (g_list_length (groups) == 0)
814 {
815 parse_error = TRUE;
816 g_warning ("XML Error: No attributes to match given");
817 }
818 else
819 {
820 plugin_handles =
821 anjuta_plugin_manager_list_query (plugin_manager,
822 groups,
823 attribs,
824 values);
825 }
826 }
827 g_list_free_full (groups, (GDestroyNotify)xmlFree);
828 g_list_free_full (attribs, (GDestroyNotify)xmlFree);
829 g_list_free_full (values, (GDestroyNotify)xmlFree);
830
831
832 return plugin_handles;
833 }
834
835 /* Read filter */
836 static GList*
parse_filter(GList ** set_list,xmlNodePtr xml_root,AnjutaPluginManager * plugin_manager,GFile * file,GError ** error)837 parse_filter (GList **set_list, xmlNodePtr xml_root, AnjutaPluginManager *plugin_manager, GFile *file, GError **error)
838 {
839 xmlNodePtr xml_node;
840 GError *parse_error = NULL;
841 GList *handles_list = NULL;
842
843 for (xml_node = xml_root->xmlChildrenNode; xml_node; xml_node = xml_node->next)
844 {
845 GList *plugin_handles = NULL;
846 GList *set;
847
848 if (!xml_node->name ||
849 !xmlStrEqual (xml_node->name, (const xmlChar*)"filter"))
850 {
851 continue;
852 }
853
854 /* Get all plugins fullfiling filter requirements */
855 plugin_handles = parse_requires (xml_node, plugin_manager, file, &parse_error);
856 if (parse_error != NULL)
857 {
858 g_propagate_error (error, parse_error);
859 break;
860 }
861 handles_list = g_list_prepend (handles_list, plugin_handles);
862
863 set = parse_set (xml_node, file, &parse_error);
864 if (parse_error != NULL)
865 {
866 g_propagate_error (error, parse_error);
867 break;
868 }
869 *set_list = g_list_prepend (*set_list, set);
870 }
871
872 return handles_list;
873 }
874
875 /* Read plugins, return a list of plugin list */
876 static GList *
parse_plugins(GList ** set_list,xmlNodePtr xml_root,AnjutaPluginManager * plugin_manager,GFile * file,GError ** error)877 parse_plugins (GList **set_list, xmlNodePtr xml_root, AnjutaPluginManager *plugin_manager, GFile *file, GError **error)
878 {
879 xmlNodePtr xml_node;
880 GError *parse_error = NULL;
881 GList *handles_list = NULL;
882 GList *not_found_names = NULL;
883 GList *not_found_urls = NULL;
884
885 /* Read plugin list */
886 for (xml_node = xml_root->xmlChildrenNode; xml_node; xml_node = xml_node->next)
887 {
888 xmlChar *name, *url, *mandatory_text;
889 gboolean mandatory;
890 GList *plugin_handles = NULL;
891
892 if (!xml_node->name ||
893 !xmlStrEqual (xml_node->name, (const xmlChar*)"plugin"))
894 {
895 continue;
896 }
897
898 name = xmlGetProp (xml_node, (const xmlChar*)"name");
899 url = xmlGetProp (xml_node, (const xmlChar*)"url");
900
901 /* Ensure that both name is given */
902 if (!name)
903 {
904 g_warning ("XML error: Plugin name should be present in plugin tag");
905 set_parse_error (&parse_error, file);
906 break;
907 }
908 if (!url)
909 url = xmlCharStrdup ("http://anjuta.org/plugins/");
910
911 /* Check if the plugin is mandatory */
912 mandatory_text = xmlGetProp (xml_node, (const xmlChar*)"mandatory");
913 mandatory = mandatory_text && (xmlStrcasecmp (mandatory_text, (const xmlChar *)"yes") == 0);
914 xmlFree(mandatory_text);
915
916 plugin_handles = parse_requires (xml_node, plugin_manager, file, &parse_error);
917 if (parse_error != NULL) break;
918 if (plugin_handles)
919 {
920 GList *set = parse_set (xml_node, file, &parse_error);
921 if (parse_error != NULL) break;
922
923 handles_list = g_list_prepend (handles_list, plugin_handles);
924 *set_list = g_list_prepend (*set_list, set);
925 }
926 else if (mandatory)
927 {
928 not_found_names = g_list_prepend (not_found_names, g_strdup ((const gchar *)name));
929 not_found_urls = g_list_prepend (not_found_urls, g_strdup ((const gchar *)url));
930 }
931 }
932
933 if (parse_error != NULL)
934 {
935 g_propagate_error (error, parse_error);
936 g_list_free_full (handles_list, (GDestroyNotify)g_list_free);
937 handles_list = NULL;
938 }
939 else if (not_found_names)
940 {
941 /*
942 * FIXME: Present a nice dialog box to promt the user to download
943 * the plugin from corresponding URLs, install them and proceed.
944 */
945 GList *node_name, *node_url;
946 GString *mesg = g_string_new ("");
947
948 not_found_names = g_list_reverse (not_found_names);
949 not_found_urls = g_list_reverse (not_found_urls);
950
951 node_name = not_found_names;
952 node_url = not_found_urls;
953 while (node_name)
954 {
955 /* <Pluginname>: Install it from <some location on the web> */
956 g_string_append_printf (mesg, _("%s: Install it from '%s'\n"),
957 (char *)node_name->data,
958 (char*)node_url->data);
959 node_name = g_list_next (node_name);
960 node_url = g_list_next (node_url);
961 }
962 g_set_error (error, ANJUTA_PROFILE_ERROR,
963 ANJUTA_PROFILE_ERROR_PLUGIN_MISSING,
964 _("Failed to read '%s': Following mandatory plugins are missing"),
965 mesg->str);
966 g_string_free (mesg, TRUE);
967
968 g_list_foreach (not_found_names, (GFunc)g_free, NULL);
969 g_list_free (not_found_names);
970 g_list_foreach (not_found_urls, (GFunc)g_free, NULL);
971 g_list_free (not_found_urls);
972
973 g_list_free_full (handles_list, (GDestroyNotify)g_list_free);
974 handles_list = NULL;
975 }
976
977 return handles_list;
978 }
979
980 static gboolean
anjuta_profile_read_xml(AnjutaProfile * profile,GError ** error)981 anjuta_profile_read_xml (AnjutaProfile *profile,
982 GError **error)
983 {
984 AnjutaProfilePriv *priv;
985 AnjutaProfileXml *xml;
986 xmlNodePtr xml_root;
987 GError *parse_error = NULL;
988 GList *disable_list;
989 GHashTable *disable_hash;
990 gboolean filter = FALSE;
991
992 /* Check if there are new XML files */
993 priv = profile->priv;
994 if (priv->xml == NULL) return TRUE;
995
996 /* Read all xml file */
997 for (xml = priv->xml; xml != NULL; xml = xml->next)
998 {
999 xml->doc = load_profile_from_xml (xml->file, &parse_error);
1000 if (parse_error != NULL)
1001 {
1002 g_propagate_error (error, parse_error);
1003
1004 return FALSE;
1005 }
1006 }
1007
1008 /* Get all plugins to load */
1009 for (xml = priv->xml; xml != NULL; xml = xml->next)
1010 {
1011 GList *handles_list;
1012 GList *plugin_list;
1013 GList *set_list = NULL;
1014
1015 /* Parse plugin in xml file */
1016 xml_root = xmlDocGetRootElement(xml->doc);
1017 handles_list = parse_plugins (&set_list, xml_root, priv->plugin_manager, xml->file, &parse_error);
1018 if (parse_error != NULL) break;
1019
1020 anjuta_profile_configure_plugins (profile, handles_list, set_list);
1021
1022 plugin_list = anjuta_profile_select_plugins (profile, handles_list);
1023 g_list_foreach (handles_list, (GFunc)g_list_free, NULL);
1024 g_list_free (handles_list);
1025 for (; plugin_list != NULL; plugin_list = g_list_delete_link (plugin_list, plugin_list))
1026 {
1027 g_hash_table_add (priv->plugins_to_load, plugin_list->data);
1028 if (xml->exclude_from_sync) g_hash_table_add (priv->plugins_to_exclude_from_sync, plugin_list->data);
1029 }
1030 }
1031
1032 /* Get all disable plugins */
1033 if (priv->plugins_to_disable == NULL)
1034 {
1035 disable_list = anjuta_plugin_manager_list_query (priv->plugin_manager, NULL, NULL, NULL);
1036 }
1037 else
1038 {
1039 disable_list = priv->plugins_to_disable;
1040 }
1041 disable_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
1042 for (; disable_list != NULL; disable_list = g_list_delete_link (disable_list, disable_list))
1043 {
1044 g_hash_table_add (disable_hash, disable_list->data);
1045 }
1046 for (xml = priv->xml; xml != NULL; xml = xml->next)
1047 {
1048 GList *handles_list;
1049 GList *plugin_list;
1050 GList *set_list = NULL;
1051
1052 /* Parse filter in xml file */
1053 xml_root = xmlDocGetRootElement(xml->doc);
1054 handles_list = parse_filter (&set_list, xml_root, priv->plugin_manager, xml->file, &parse_error);
1055 if (parse_error != NULL) break;
1056
1057 anjuta_profile_configure_plugins (profile, handles_list, set_list);
1058
1059 filter = filter || (handles_list != NULL);
1060 for (plugin_list = g_list_first (handles_list); plugin_list != NULL; plugin_list = g_list_next (plugin_list))
1061 {
1062 GList *node;
1063 for (node = g_list_first ((GList *)plugin_list->data); node != NULL; node = g_list_next (node))
1064 {
1065 g_hash_table_remove (disable_hash, node->data);
1066 }
1067 }
1068 g_list_foreach (handles_list, (GFunc)g_list_free, NULL);
1069 g_list_free (handles_list);
1070 }
1071 if (filter)
1072 {
1073 /* Filter some plugins */
1074 priv->plugins_to_disable = g_hash_table_get_keys (disable_hash);
1075 anjuta_plugin_manager_set_disable_plugins (priv->plugin_manager, priv->plugins_to_disable, TRUE);
1076 }
1077 else
1078 {
1079 /* No filter, keep all plugins */
1080 priv->plugins_to_disable = NULL;
1081 }
1082 g_hash_table_destroy (disable_hash);
1083 if (parse_error != NULL) return FALSE;
1084
1085
1086 /* Remove xml object */
1087 while (priv->xml != NULL)
1088 {
1089 AnjutaProfileXml *next;
1090
1091 next = priv->xml->next;
1092 g_object_unref (priv->xml->file);
1093 xmlFreeDoc(priv->xml->doc);
1094 g_free (priv->xml);
1095 priv->xml = next;
1096 }
1097
1098 if (parse_error != NULL) g_propagate_error (error, parse_error);
1099
1100 return parse_error == NULL;
1101 }
1102
1103
1104
1105 /* Public functions
1106 *---------------------------------------------------------------------------*/
1107
1108 /**
1109 * anjuta_profile_add_plugins_from_xml:
1110 * @profile: a #AnjutaProfile object.
1111 * @profile_xml_file: xml file containing plugin list.
1112 * @exclude_from_sync: %TRUE if these plugins shouldn't be saved in user session.
1113 * @error: error propagation and reporting.
1114 *
1115 * Add all plugins inscribed in the xml file into the profile plugin list.
1116 *
1117 * Return value: %TRUE on success, %FALSE otherwise.
1118 */
1119 gboolean
anjuta_profile_add_plugins_from_xml(AnjutaProfile * profile,GFile * profile_xml_file,gboolean exclude_from_sync,GError ** error)1120 anjuta_profile_add_plugins_from_xml (AnjutaProfile *profile,
1121 GFile* profile_xml_file,
1122 gboolean exclude_from_sync,
1123 GError **error)
1124 {
1125 AnjutaProfilePriv *priv;
1126 AnjutaProfileXml *xml;
1127 AnjutaProfileXml **last;
1128
1129 g_return_val_if_fail (ANJUTA_IS_PROFILE (profile), FALSE);
1130
1131 priv = profile->priv;
1132
1133 /* Just save the file name, the xml wil be loaded later after unloading the
1134 * previous profile if needed */
1135
1136 xml = g_new (AnjutaProfileXml, 1);
1137 xml->file = g_object_ref (profile_xml_file);
1138 xml->doc = NULL;
1139 xml->exclude_from_sync = exclude_from_sync;
1140 xml->next = NULL;
1141 for (last = &(priv->xml); *last != NULL; last = &((*last)->next));
1142 *last = xml;
1143
1144 return TRUE;
1145 }
1146
1147 /**
1148 * anjuta_profile_to_xml :
1149 * @profile: a #AnjutaProfile object.
1150 *
1151 * Return a string in xml format containing the list of saved plugins.
1152 *
1153 * Return value: (transfer full): a newly-allocated string that must be freed with g_free().
1154 */
1155 static gchar*
anjuta_profile_to_xml(AnjutaProfile * profile)1156 anjuta_profile_to_xml (AnjutaProfile *profile)
1157 {
1158 GList *node;
1159 GString *str;
1160 AnjutaProfilePriv *priv;
1161
1162 g_return_val_if_fail (ANJUTA_IS_PROFILE (profile), FALSE);
1163 priv = profile->priv;
1164
1165 str = g_string_new ("<?xml version=\"1.0\"?>\n<anjuta>\n");
1166 for (node = g_hash_table_get_keys (priv->plugins_to_load); node != NULL; node = g_list_delete_link (node, node))
1167 {
1168 AnjutaPluginHandle *handle;
1169 AnjutaPluginDescription *desc;
1170 gboolean user_activatable = TRUE;
1171 gchar *name = NULL, *plugin_id = NULL;
1172
1173 if (g_hash_table_lookup (priv->plugins_to_exclude_from_sync, node->data))
1174 {
1175 /* Do not save plugin in the exclude list */
1176 continue;
1177 }
1178 handle = (AnjutaPluginHandle *)node->data;
1179 desc = anjuta_plugin_handle_get_description(handle);
1180 if (anjuta_plugin_description_get_boolean (desc, "Anjuta Plugin",
1181 "UserActivatable", &user_activatable)
1182 && !user_activatable)
1183 {
1184 /* Do not save plugins that are auto activated */
1185 continue;
1186 }
1187
1188 /* Do not use the _locale_ version because it's not in UI */
1189 anjuta_plugin_description_get_string (desc, "Anjuta Plugin",
1190 "Name", &name);
1191 DEBUG_PRINT("Saving plugin: %s", name);
1192 if (!name)
1193 name = g_strdup ("Unknown");
1194
1195 if (anjuta_plugin_description_get_string (desc, "Anjuta Plugin",
1196 "Location", &plugin_id))
1197 {
1198 g_string_append (str, " <plugin name=\"");
1199 g_string_append (str, name);
1200 g_string_append (str, "\" mandatory=\"no\">\n");
1201 g_string_append (str, " <require group=\"Anjuta Plugin\"\n");
1202 g_string_append (str, " attribute=\"Location\"\n");
1203 g_string_append (str, " value=\"");
1204 g_string_append (str, plugin_id);
1205 g_string_append (str, "\"/>\n");
1206 g_string_append (str, " </plugin>\n");
1207
1208 g_free (plugin_id);
1209 }
1210 g_free (name);
1211 }
1212 g_string_append (str, "</anjuta>\n");
1213
1214 return g_string_free (str, FALSE);
1215 }
1216
1217 /**
1218 * anjuta_profile_set_sync_file:
1219 * @profile: a #AnjutaProfile object.
1220 * @sync_file: file used to save profile.
1221 *
1222 * Define the file used to save plugins list.
1223 */
1224
1225 void
anjuta_profile_set_sync_file(AnjutaProfile * profile,GFile * sync_file)1226 anjuta_profile_set_sync_file (AnjutaProfile *profile, GFile *sync_file)
1227 {
1228 AnjutaProfilePriv *priv;
1229
1230 g_return_if_fail (ANJUTA_IS_PROFILE (profile));
1231
1232 priv = profile->priv;
1233
1234 if (priv->sync_file)
1235 g_object_unref (priv->sync_file);
1236 priv->sync_file = sync_file;
1237 if (priv->sync_file)
1238 g_object_ref (priv->sync_file);
1239 }
1240
1241 /**
1242 * anjuta_profile_sync:
1243 * @profile: a #AnjutaProfile object.
1244 * @error: error propagation and reporting.
1245 *
1246 * Save the current plugins list in the xml file set with anjuta_profile_set_sync_file().
1247 *
1248 * Return value: %TRUE on success, %FALSE otherwise.
1249 */
1250 gboolean
anjuta_profile_sync(AnjutaProfile * profile,GError ** error)1251 anjuta_profile_sync (AnjutaProfile *profile, GError **error)
1252 {
1253 gboolean ok;
1254 gchar *xml_buffer;
1255 AnjutaProfilePriv *priv;
1256 GError* file_error = NULL;
1257
1258 g_return_val_if_fail (ANJUTA_IS_PROFILE (profile), FALSE);
1259 priv = profile->priv;
1260
1261 if (!priv->sync_file)
1262 return FALSE;
1263
1264 xml_buffer = anjuta_profile_to_xml (profile);
1265 ok = g_file_replace_contents (priv->sync_file, xml_buffer, strlen(xml_buffer),
1266 NULL, FALSE, G_FILE_CREATE_NONE,
1267 NULL, NULL, &file_error);
1268 if (!ok && g_error_matches (file_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
1269 {
1270 /* Try to create parent directory */
1271 GFile* parent = g_file_get_parent (priv->sync_file);
1272 if (g_file_make_directory (parent, NULL, NULL))
1273 {
1274 g_clear_error (&file_error);
1275 ok = g_file_replace_contents (priv->sync_file, xml_buffer, strlen(xml_buffer),
1276 NULL, FALSE, G_FILE_CREATE_NONE,
1277 NULL, NULL, &file_error);
1278 }
1279 g_object_unref (parent);
1280 }
1281 g_free (xml_buffer);
1282 if (file_error != NULL) g_propagate_error (error, file_error);
1283
1284 return ok;
1285 }
1286
1287 /**
1288 * anjuta_profile_load:
1289 * @profile: a #AnjutaProfile object.
1290 * @error: error propagation and reporting.
1291 *
1292 * Load the profile
1293 *
1294 * Return value: TRUE on success, FALSE otherwise.
1295 */
1296 gboolean
anjuta_profile_load(AnjutaProfile * profile,GError ** error)1297 anjuta_profile_load (AnjutaProfile *profile, GError **error)
1298 {
1299 AnjutaProfilePriv *priv;
1300 GList *active_plugins, *node;
1301 GHashTable *active_hash;
1302
1303 /* Read XML file if needed */
1304 if (!anjuta_profile_read_xml (profile, error)) return FALSE;
1305 priv = profile->priv;
1306
1307 /* Deactivate plugins that are already active, but are not requested to be
1308 * active */
1309 active_plugins = anjuta_plugin_manager_get_active_plugins (priv->plugin_manager);
1310 for (node = active_plugins; node != NULL; node = g_list_next (node))
1311 {
1312 AnjutaPluginHandle *handle = (AnjutaPluginHandle *)node->data;
1313
1314 if (anjuta_plugin_handle_get_can_unload (handle) &&
1315 !g_hash_table_lookup (priv->plugins_to_load, handle))
1316 {
1317 anjuta_plugin_manager_unload_plugin_by_handle (priv->plugin_manager,
1318 handle);
1319 }
1320 }
1321
1322 /* Prepare active plugins hash */
1323 active_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
1324 for (node = active_plugins; node != NULL; node = g_list_next (node))
1325 {
1326 g_hash_table_add (active_hash, node->data);
1327 }
1328 g_list_free (active_plugins);
1329
1330 /* Prepare the plugins to activate */
1331 active_plugins = g_hash_table_get_keys (priv->plugins_to_load);
1332 for (node = active_plugins; node != NULL;)
1333 {
1334 AnjutaPluginHandle *handle = (AnjutaPluginHandle *)node->data;
1335 GList *next = g_list_next (node);
1336
1337 if (g_hash_table_lookup (active_hash, handle) != NULL)
1338 {
1339 active_plugins = g_list_delete_link (active_plugins, node);
1340 }
1341 node = next;
1342 }
1343 g_hash_table_destroy (active_hash);
1344
1345 /* For system profile, marks its plugin to keep them activated */
1346 if (strcmp (priv->name, ANJUTA_SYSTEM_PROFILE_NAME) == 0)
1347 {
1348 for (node = g_list_first (active_plugins); node != NULL; node = g_list_next (node))
1349 {
1350 anjuta_plugin_handle_set_can_unload (ANJUTA_PLUGIN_HANDLE (node->data), FALSE);
1351 }
1352 }
1353
1354 /* Now activate the plugins */
1355 if (active_plugins != NULL)
1356 {
1357 anjuta_plugin_manager_activate_plugins (priv->plugin_manager,
1358 active_plugins);
1359 g_list_free (active_plugins);
1360 }
1361
1362 /* Enable profile synchronization */
1363 g_signal_connect (priv->plugin_manager, "plugin-activated",
1364 G_CALLBACK (on_plugin_activated), profile);
1365 g_signal_connect (priv->plugin_manager, "plugin-deactivated",
1366 G_CALLBACK (on_plugin_deactivated), profile);
1367
1368 g_signal_emit_by_name (profile, "scoped");
1369
1370
1371 return TRUE;
1372 }
1373
1374 /**
1375 * anjuta_profile_unload:
1376 * @profile: a #AnjutaProfile object.
1377 * @error: error propagation and reporting.
1378 *
1379 * Unload the profile
1380 *
1381 * Return value: TRUE on success, FALSE otherwise.
1382 */
1383 gboolean
anjuta_profile_unload(AnjutaProfile * profile,GError ** error)1384 anjuta_profile_unload (AnjutaProfile *profile, GError **error)
1385 {
1386 AnjutaProfilePriv *priv;
1387
1388 /* Disable profile synchronization while the profile is being activated */
1389 priv = profile->priv;
1390 g_signal_handlers_disconnect_by_func (priv->plugin_manager,
1391 G_CALLBACK (on_plugin_activated),
1392 profile);
1393 g_signal_handlers_disconnect_by_func (priv->plugin_manager,
1394 G_CALLBACK (on_plugin_deactivated),
1395 profile);
1396
1397 /* Do not unload system profile */
1398 if (strcmp (priv->name, ANJUTA_SYSTEM_PROFILE_NAME) == 0) return TRUE;
1399
1400 /* Remove profile configuration */
1401 anjuta_profile_unconfigure_plugins (profile);
1402
1403 /* Re-enable disabled plugins */
1404 anjuta_plugin_manager_set_disable_plugins (priv->plugin_manager, priv->plugins_to_disable, FALSE);
1405
1406 /* Emit pre-change for the last profile */
1407 if (profile)
1408 {
1409 g_signal_emit_by_name (profile, "descoped");
1410 }
1411
1412 return TRUE;
1413 }
1414