document-manager: Fixes on find in files
[anjuta.git] / libanjuta / anjuta-profile-manager.c
blob241e5127d6f28d5488d29cdeecbc5ad2e91cd0ae
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-profile-manager.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.
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-profile-manager
23 * @short_description: Managers a stack of plugins profiles
24 * @see_also: #AnjutaPluginManager, #AnjutaProfile
25 * @stability: Unstable
26 * @include: libanjuta/anjuta-profile-manager.h
28 * Anjuta uses up to two profiles. A "no project" profile is used when no
29 * project is loaded a project profile when one is loaded.
30 * If a second project is loaded, it is loaded in another instance of Anjuta.
31 * When a project is closed, Anjuta goes back to the "no project" profile.
33 * The profile manager can be in a frozen state where you can push or
34 * pop a profile from the stack without triggering a change of the profile.
37 #include <string.h>
39 #include <libanjuta/anjuta-debug.h>
40 #include <libanjuta/anjuta-marshal.h>
41 #include "anjuta-profile-manager.h"
43 enum
45 PROP_0,
46 PROP_PLUGIN_MANAGER,
47 PROP_PROFILES
50 enum
52 PROFILE_PUSHED,
53 PROFILE_POPPED,
54 PROFILE_DESCOPED,
55 PROFILE_SCOPED,
56 LAST_SIGNAL
59 struct _AnjutaProfileManagerPriv
61 AnjutaPluginManager *plugin_manager;
62 GList *profiles;
64 /* Pending queue. Profiles are queued until freeze count becomes 0 */
65 GList *profiles_queue;
67 /* Freeze count. Pending profiles are loaded when it reaches 0 */
68 gint freeze_count;
71 static GObjectClass* parent_class = NULL;
72 static guint profile_manager_signals[LAST_SIGNAL] = { 0 };
74 static void
75 on_plugin_activated (AnjutaPluginManager *plugin_manager,
76 AnjutaPluginDescription *plugin_desc,
77 GObject *plugin_object,
78 AnjutaProfileManager *profile_manager)
80 AnjutaProfileManagerPriv *priv;
81 priv = profile_manager->priv;
83 if (priv->profiles)
85 /* Add it current profile */
86 gboolean exclude;
88 if (!anjuta_plugin_description_get_boolean (plugin_desc, "Anjuta Plugin", "ExcludeFromSession", &exclude) || !exclude)
90 anjuta_profile_add_plugin (ANJUTA_PROFILE (priv->profiles->data),
91 plugin_desc);
96 static void
97 on_plugin_deactivated (AnjutaPluginManager *plugin_manager,
98 AnjutaPluginDescription *plugin_desc,
99 GObject *plugin_object,
100 AnjutaProfileManager *profile_manager)
102 AnjutaProfileManagerPriv *priv;
103 priv = profile_manager->priv;
105 if (priv->profiles)
107 /* Remove from current profile */
108 anjuta_profile_remove_plugin (ANJUTA_PROFILE (priv->profiles->data),
109 plugin_desc);
113 static void
114 anjuta_profile_manager_init (AnjutaProfileManager *object)
116 object->priv = g_new0 (AnjutaProfileManagerPriv, 1);
119 static void
120 anjuta_profile_manager_finalize (GObject *object)
122 AnjutaProfileManagerPriv *priv;
123 priv = ANJUTA_PROFILE_MANAGER (object)->priv;
124 if (priv->profiles)
126 g_list_foreach (priv->profiles, (GFunc)g_object_unref, NULL);
127 g_list_free (priv->profiles);
128 priv->profiles = NULL;
130 if (priv->profiles_queue)
132 g_list_foreach (priv->profiles_queue, (GFunc)g_object_unref, NULL);
133 g_list_free (priv->profiles_queue);
134 priv->profiles_queue = NULL;
137 G_OBJECT_CLASS (parent_class)->finalize (object);
140 static void
141 anjuta_profile_manager_set_property (GObject *object, guint prop_id,
142 const GValue *value, GParamSpec *pspec)
144 AnjutaProfileManagerPriv *priv;
145 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (object));
146 priv = ANJUTA_PROFILE_MANAGER (object)->priv;
148 switch (prop_id)
150 case PROP_PLUGIN_MANAGER:
151 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (g_value_get_object (value)));
152 priv->plugin_manager = g_value_get_object (value);
153 g_signal_connect (priv->plugin_manager, "plugin-activated",
154 G_CALLBACK (on_plugin_activated), object);
155 g_signal_connect (priv->plugin_manager, "plugin-deactivated",
156 G_CALLBACK (on_plugin_deactivated), object);
157 break;
158 default:
159 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
160 break;
164 static void
165 anjuta_profile_manager_get_property (GObject *object, guint prop_id,
166 GValue *value, GParamSpec *pspec)
168 AnjutaProfileManagerPriv *priv;
169 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (object));
170 priv = ANJUTA_PROFILE_MANAGER (object)->priv;
172 switch (prop_id)
174 case PROP_PLUGIN_MANAGER:
175 g_value_set_object (value, priv->plugin_manager);
176 break;
177 case PROP_PROFILES:
178 g_value_set_pointer (value, priv->profiles);
179 break;
180 default:
181 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
182 break;
186 static void
187 anjuta_profile_manager_class_init (AnjutaProfileManagerClass *klass)
189 GObjectClass* object_class = G_OBJECT_CLASS (klass);
190 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
192 object_class->finalize = anjuta_profile_manager_finalize;
193 object_class->set_property = anjuta_profile_manager_set_property;
194 object_class->get_property = anjuta_profile_manager_get_property;
196 g_object_class_install_property (object_class,
197 PROP_PLUGIN_MANAGER,
198 g_param_spec_object ("plugin-manager",
199 "Plugin Manager",
200 "The plugin manager to use for profile plugins",
201 ANJUTA_TYPE_PLUGIN_MANAGER,
202 G_PARAM_READABLE |
203 G_PARAM_WRITABLE |
204 G_PARAM_CONSTRUCT));
206 * AnjutaProfileManager::profile-pushed:
207 * @profile_manager: a #AnjutaProfileManager object.
208 * @profile: the new #AnjutaProfile added.
210 * Emitted when a profile is added in the stack. If the profile manager is
211 * not frozen, the current profile will be unloaded and the new one
212 * will be loaded.
214 profile_manager_signals[PROFILE_PUSHED] =
215 g_signal_new ("profile-pushed",
216 G_OBJECT_CLASS_TYPE (klass),
217 G_SIGNAL_RUN_FIRST,
218 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
219 profile_pushed),
220 NULL, NULL,
221 anjuta_cclosure_marshal_VOID__OBJECT,
222 G_TYPE_NONE, 1,
223 ANJUTA_TYPE_PROFILE);
226 * AnjutaProfileManager::profile-popped:
227 * @profile_manager: a #AnjutaProfileManager object.
228 * @profile: the current removed #AnjutaProfile.
230 * Emitted when a profile is removed from the stack. If the profile manager
231 * is not frozen, the current profile will be unloaded and the previous one
232 * will be loaded.
234 profile_manager_signals[PROFILE_POPPED] =
235 g_signal_new ("profile-popped",
236 G_OBJECT_CLASS_TYPE (klass),
237 G_SIGNAL_RUN_FIRST,
238 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
239 profile_popped),
240 NULL, NULL,
241 anjuta_cclosure_marshal_VOID__OBJECT,
242 G_TYPE_NONE, 1,
243 ANJUTA_TYPE_PROFILE);
246 * AnjutaProfileManager::profile-descoped:
247 * @profile_manager: a #AnjutaProfileManager object.
248 * @profile: the old unloaded #AnjutaProfile.
250 * Emitted when a profile will be unloaded.
252 profile_manager_signals[PROFILE_DESCOPED] =
253 g_signal_new ("profile-descoped",
254 G_OBJECT_CLASS_TYPE (klass),
255 G_SIGNAL_RUN_FIRST,
256 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
257 profile_descoped),
258 NULL, NULL,
259 anjuta_cclosure_marshal_VOID__OBJECT,
260 G_TYPE_NONE, 1,
261 ANJUTA_TYPE_PROFILE);
264 * AnjutaProfileManager::profile-scoped:
265 * @profile_manager: a #AnjutaProfileManager object.
266 * @profile: the current loaded #AnjutaProfile.
268 * Emitted when a new profile is loaded.
270 profile_manager_signals[PROFILE_SCOPED] =
271 g_signal_new ("profile-scoped",
272 G_OBJECT_CLASS_TYPE (klass),
273 G_SIGNAL_RUN_FIRST,
274 G_STRUCT_OFFSET (AnjutaProfileManagerClass,
275 profile_scoped),
276 NULL, NULL,
277 anjuta_cclosure_marshal_VOID__OBJECT,
278 G_TYPE_NONE, 1,
279 ANJUTA_TYPE_PROFILE);
282 GType
283 anjuta_profile_manager_get_type (void)
285 static GType our_type = 0;
287 if(our_type == 0)
289 static const GTypeInfo our_info =
291 sizeof (AnjutaProfileManagerClass), /* class_size */
292 (GBaseInitFunc) NULL, /* base_init */
293 (GBaseFinalizeFunc) NULL, /* base_finalize */
294 (GClassInitFunc) anjuta_profile_manager_class_init, /* class_init */
295 (GClassFinalizeFunc) NULL, /* class_finalize */
296 NULL /* class_data */,
297 sizeof (AnjutaProfileManager), /* instance_size */
298 0, /* n_preallocs */
299 (GInstanceInitFunc) anjuta_profile_manager_init, /* instance_init */
300 NULL /* value_table */
303 our_type = g_type_register_static (G_TYPE_OBJECT, "AnjutaProfileManager",
304 &our_info, 0);
307 return our_type;
311 * anjuta_profile_manager_new:
312 * @plugin_manager: the #AnjutaPluginManager used by all profiles.
314 * Create a new profile manager.
316 * Return value: the new #AnjutaProfileManager object.
318 AnjutaProfileManager*
319 anjuta_profile_manager_new (AnjutaPluginManager *plugin_manager)
321 GObject *obj;
323 obj = g_object_new (ANJUTA_TYPE_PROFILE_MANAGER, "plugin-manager",
324 plugin_manager, NULL);
325 return ANJUTA_PROFILE_MANAGER (obj);
328 static gboolean
329 anjuta_profile_manager_load_profile (AnjutaProfileManager *profile_manager,
330 AnjutaProfile *profile,
331 AnjutaProfile *previous_profile,
332 GError **error)
334 AnjutaProfileManagerPriv *priv;
335 GList *active_plugins, *node;
336 GList *plugins_to_activate, *plugins_to_deactivate;
337 GList *selected_plugins;
339 GHashTable *active_plugins_hash, *plugins_to_activate_hash;
341 priv = profile_manager->priv;
343 /* Disable profile synchronization while the profile is being activated */
344 g_signal_handlers_block_by_func (priv->plugin_manager,
345 G_CALLBACK (on_plugin_activated),
346 profile_manager);
347 g_signal_handlers_block_by_func (priv->plugin_manager,
348 G_CALLBACK (on_plugin_deactivated),
349 profile_manager);
351 /* Emit pre-change for the last profile */
352 if (previous_profile)
354 g_signal_emit_by_name (profile_manager, "profile-descoped",
355 previous_profile);
358 /* Prepare plugins to activate */
359 plugins_to_activate_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
361 /* Select plugins in the profile */
362 if (profile)
363 selected_plugins = anjuta_profile_get_plugins (profile);
364 else
365 selected_plugins = NULL;
367 node = selected_plugins;
368 while (node)
370 g_hash_table_insert (plugins_to_activate_hash, node->data, node->data);
371 node = g_list_next (node);
374 /* Prepare active plugins hash */
375 active_plugins =
376 anjuta_plugin_manager_get_active_plugins (priv->plugin_manager);
377 active_plugins_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
378 node = active_plugins;
379 while (node)
381 g_hash_table_insert (active_plugins_hash, node->data, node->data);
382 node = g_list_next (node);
385 plugins_to_deactivate = NULL;
387 /* Prepare plugins to deactiveate that are already active, but are
388 * not requested to be active
390 node = active_plugins;
391 while (node)
393 if (!g_hash_table_lookup (plugins_to_activate_hash, node->data))
395 plugins_to_deactivate = g_list_prepend (plugins_to_deactivate,
396 node->data);
398 node = g_list_next (node);
400 plugins_to_deactivate = g_list_reverse (plugins_to_deactivate);
402 /* Deactivate plugins */
403 node = plugins_to_deactivate;
404 while (node)
406 AnjutaPluginDescription *desc;
407 GObject *plugin_object;
408 gchar *plugin_id = NULL;
410 desc = (AnjutaPluginDescription *)node->data;
411 anjuta_plugin_description_get_string (desc, "Anjuta Plugin",
412 "Location", &plugin_id);
413 g_assert (plugin_id != NULL);
415 /* DEBUG_PRINT ("Profile: deactivating %s", plugin_id); */
417 plugin_object =
418 anjuta_plugin_manager_get_plugin_by_id (priv->plugin_manager,
419 plugin_id);
420 g_assert (plugin_object != NULL);
422 anjuta_plugin_manager_unload_plugin (priv->plugin_manager,
423 plugin_object);
424 g_free (plugin_id);
425 node = g_list_next (node);
428 /* Prepare the plugins to activate */
429 plugins_to_activate = NULL;
430 node = selected_plugins;
431 while (node)
433 if (!g_hash_table_lookup (active_plugins_hash, node->data))
434 plugins_to_activate = g_list_prepend (plugins_to_activate,
435 node->data);
436 node = g_list_next (node);
439 /* Now activate the plugins */
440 if (plugins_to_activate)
442 /* Activate them */
443 plugins_to_activate = g_list_reverse (plugins_to_activate);
444 anjuta_plugin_manager_activate_plugins (priv->plugin_manager,
445 plugins_to_activate);
448 g_list_free (plugins_to_activate);
449 g_list_free (active_plugins);
451 g_hash_table_destroy (plugins_to_activate_hash);
452 g_hash_table_destroy (active_plugins_hash);
454 /* Enable profile synchronization */
455 g_signal_handlers_unblock_by_func (priv->plugin_manager,
456 G_CALLBACK (on_plugin_activated),
457 profile_manager);
458 g_signal_handlers_unblock_by_func (priv->plugin_manager,
459 G_CALLBACK (on_plugin_deactivated),
460 profile_manager);
461 g_signal_emit_by_name (profile_manager, "profile-scoped", profile);
462 return TRUE;
465 static gboolean
466 anjuta_profile_manager_queue_profile (AnjutaProfileManager *profile_manager,
467 AnjutaProfile *profile,
468 GError **error)
470 AnjutaProfileManagerPriv *priv;
472 priv = profile_manager->priv;
473 priv->profiles_queue = g_list_prepend (priv->profiles_queue,
474 profile);
475 /* If there is no freeze load profile now */
476 if (priv->freeze_count <= 0)
478 AnjutaProfile *previous_profile = NULL;
480 if (priv->profiles)
481 previous_profile = priv->profiles->data;
483 /* Push queued profiles in stack */
484 priv->profiles = g_list_concat (priv->profiles_queue, priv->profiles);
485 priv->profiles_queue = NULL;
487 return anjuta_profile_manager_load_profile (profile_manager,
488 ANJUTA_PROFILE (priv->profiles->data),
489 previous_profile,
490 error);
492 else
494 return FALSE;
499 * anjuta_profile_manager_push:
500 * @profile_manager: the #AnjutaProfileManager object.
501 * @profile: the new #AnjutaProfile.
502 * @error: error propagation and reporting.
504 * Add a new profile at the top of the profile manager stack. If the profile
505 * manager is not frozen, this new profile will be loaded immediatly and
506 * become the current profile.
508 * Return value: TRUE on success, FALSE otherwise.
510 gboolean
511 anjuta_profile_manager_push (AnjutaProfileManager *profile_manager,
512 AnjutaProfile *profile, GError **error)
514 AnjutaProfileManagerPriv *priv;
516 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
517 priv = profile_manager->priv;
519 /* Emit profile push signal */
520 g_signal_emit_by_name (profile_manager, "profile-pushed",
521 profile);
523 return anjuta_profile_manager_queue_profile (profile_manager, profile,
524 error);
528 * anjuta_profile_manager_pop:
529 * @profile_manager: the #AnjutaProfileManager object.
530 * @profile_name: the name of the profile to remove.
531 * @error: error propagation and reporting.
533 * Remove a profile from the profile manager stack. If the manager is not
534 * frozen, only the current profile can be removed. It will be unloaded and
535 * the previous profile will be loaded.
536 * If the manager is frozen, the current profile or the last pushed profile
537 * can be removed.
539 * Return value: TRUE on success, FALSE otherwise.
541 gboolean
542 anjuta_profile_manager_pop (AnjutaProfileManager *profile_manager,
543 const gchar *profile_name, GError **error)
545 AnjutaProfileManagerPriv *priv;
546 AnjutaProfile *profile;
547 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
549 priv = profile_manager->priv;
551 /* First check in the queue */
552 if (priv->profiles_queue)
554 profile = priv->profiles_queue->data;
555 g_return_val_if_fail (strcmp (anjuta_profile_get_name (profile),
556 profile_name) == 0, FALSE);
557 priv->profiles_queue = g_list_remove (priv->profiles_queue, profile);
559 g_signal_emit_by_name (profile_manager, "profile-popped",
560 profile);
562 g_object_unref (profile);
563 return TRUE;
566 /* Then check in the current stack */
567 if (priv->profiles)
569 profile = priv->profiles->data;
570 g_return_val_if_fail (strcmp (anjuta_profile_get_name (profile),
571 profile_name) == 0, FALSE);
572 priv->profiles = g_list_remove (priv->profiles, profile);
574 g_signal_emit_by_name (profile_manager, "profile-popped",
575 profile);
577 /* Restore the next profile in the stack */
578 if (priv->profiles)
580 return anjuta_profile_manager_load_profile (profile_manager,
581 ANJUTA_PROFILE (priv->profiles->data),
582 profile,
583 error);
585 else
587 return anjuta_profile_manager_load_profile (profile_manager,
588 NULL, profile,
589 error);
591 g_object_unref (profile);
594 g_warning ("No profiles in the stack. Can not pop out any profile: %s",
595 profile_name);
596 return FALSE;
600 * anjuta_profile_manager_freeze:
601 * @profile_manager: the #AnjutaProfileManager object.
603 * Freeze the plugin manager. In this state, plugins can be added and removed
604 * from the stack without triggering any change in the current profile. It is
605 * possible to freeze the manager several times but it will be back in its normal
606 * state only after as much call of anjuta_profile_manager_thaw().
608 void
609 anjuta_profile_manager_freeze (AnjutaProfileManager *profile_manager)
611 AnjutaProfileManagerPriv *priv;
612 g_return_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager));
613 priv = profile_manager->priv;
614 priv->freeze_count++;
618 * anjuta_profile_manager_thaw:
619 * @profile_manager: the #AnjutaProfileManager object.
620 * @error: error propagation and reporting.
622 * Put back the plugin manager in its normal mode after calling
623 * anjuta_profile_manager_freeze(). It will load a new profile if one has been
624 * added while the manager was frozen.
626 * Return value: TRUE on success, FALSE otherwise.
628 gboolean
629 anjuta_profile_manager_thaw (AnjutaProfileManager *profile_manager,
630 GError **error)
632 AnjutaProfileManagerPriv *priv;
633 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), FALSE);
634 priv = profile_manager->priv;
636 if (priv->freeze_count > 0)
637 priv->freeze_count--;
639 if (priv->freeze_count <= 0 && priv->profiles_queue)
641 AnjutaProfile *previous_profile = NULL;
643 if (priv->profiles)
644 previous_profile = priv->profiles->data;
646 /* Push queued profiles in stack */
647 priv->profiles = g_list_concat (priv->profiles_queue, priv->profiles);
648 priv->profiles_queue = NULL;
650 /* Load the profile */
651 return anjuta_profile_manager_load_profile (profile_manager,
652 ANJUTA_PROFILE (priv->profiles->data),
653 previous_profile,
654 error);
656 else
658 return FALSE;
663 * anjuta_profile_manager_get_current :
664 * @profile_manager: A #AnjutaProfileManager object.
666 * Return the current profile.
668 * Return value: a #AnjutaProfile object or NULL if the profile stack is empty.
670 AnjutaProfile*
671 anjuta_profile_manager_get_current (AnjutaProfileManager *profile_manager)
673 g_return_val_if_fail (ANJUTA_IS_PROFILE_MANAGER (profile_manager), NULL);
674 if (profile_manager->priv->profiles_queue)
675 return ANJUTA_PROFILE (profile_manager->priv->profiles_queue->data);
676 else if (profile_manager->priv->profiles)
677 return ANJUTA_PROFILE (profile_manager->priv->profiles->data);
678 else
679 return NULL;