Added initial Spanish translation
[anjuta-git-plugin.git] / libanjuta / anjuta-plugin-manager.c
blobb8b028867156049b7d357f62c307aa6ad5014e4c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-plugin-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /**
22 * SECTION:anjuta-plugin-manager
23 * @short_description: Plugins management and activation
24 * @see_also: #AnjutaPlugin, #AnjutaProfileManager
25 * @stability: Unstable
26 * @include: libanjuta/anjuta-plugin-manager.h
30 #include <sys/types.h>
31 #include <dirent.h>
32 #include <string.h>
33 #include <libgnomevfs/gnome-vfs.h>
35 #include <libanjuta/anjuta-plugin-manager.h>
36 #include <libanjuta/anjuta-marshal.h>
37 #include <libanjuta/anjuta-debug.h>
38 #include <libanjuta/anjuta-plugin-handle.h>
39 #include <libanjuta/anjuta-plugin.h>
40 #include <libanjuta/anjuta-glue-factory.h>
41 #include <libanjuta/anjuta-glue-c.h>
42 #include <libanjuta/interfaces/ianjuta-plugin-loader.h>
44 enum
46 PROP_0,
48 PROP_SHELL,
49 PROP_STATUS,
50 PROP_PROFILES,
51 PROP_AVAILABLE_PLUGINS,
52 PROP_ACTIVATED_PLUGINS
55 enum
57 PROFILE_PUSHED,
58 PROFILE_POPPED,
59 PLUGINS_TO_LOAD,
60 PLUGINS_TO_UNLOAD,
61 PLUGIN_ACTIVATED,
62 PLUGIN_DEACTIVATED,
64 LAST_SIGNAL
67 struct _AnjutaPluginManagerPriv
69 GObject *shell;
70 AnjutaStatus *status;
71 GList *plugin_dirs;
72 GList *available_plugins;
74 /* Indexes => plugin handles */
75 GHashTable *plugins_by_interfaces;
76 GHashTable *plugins_by_name;
77 GHashTable *plugins_by_description;
79 /* Plugins that are currently activated */
80 GHashTable *activated_plugins;
82 /* Plugins that have been previously loaded but current deactivated */
83 GHashTable *plugins_cache;
85 /* Remember plugin selection */
86 GHashTable *remember_plugins;
89 /* Available plugins page treeview */
90 enum {
91 COL_ACTIVABLE,
92 COL_ENABLED,
93 COL_ICON,
94 COL_NAME,
95 COL_PLUGIN,
96 N_COLS
99 /* Remembered plugins page treeview */
100 enum {
101 COL_REM_ICON,
102 COL_REM_NAME,
103 COL_REM_PLUGIN_KEY,
104 N_REM_COLS
107 /* Plugin class types */
109 static GHashTable *plugin_types = NULL;
110 static AnjutaGlueFactory *anjuta_glue_factory = NULL;
112 static GObjectClass* parent_class = NULL;
113 static guint plugin_manager_signals[LAST_SIGNAL] = { 0 };
115 static GHashTable* plugin_set_update (AnjutaPluginManager *plugin_manager,
116 AnjutaPluginHandle* selected_plugin,
117 gboolean load);
119 static GType get_plugin_loader_type (AnjutaPluginManager *plugin_manager,
120 const gchar *language);
122 GQuark
123 anjuta_plugin_manager_error_quark (void)
125 static GQuark quark = 0;
127 if (quark == 0) {
128 quark = g_quark_from_static_string ("anjuta-plugin-manager-quark");
130 return quark;
133 /** Dependency Resolution **/
135 static gboolean
136 collect_cycle (AnjutaPluginManager *plugin_manager,
137 AnjutaPluginHandle *base_plugin, AnjutaPluginHandle *cur_plugin,
138 GList **cycle)
140 AnjutaPluginManagerPriv *priv;
141 GList *l;
143 priv = plugin_manager->priv;
145 for (l = anjuta_plugin_handle_get_dependency_names (cur_plugin);
146 l != NULL; l = l->next)
148 AnjutaPluginHandle *dep = g_hash_table_lookup (priv->plugins_by_name,
149 l->data);
150 if (dep)
152 if (dep == base_plugin)
154 *cycle = g_list_prepend (NULL, dep);
155 /* DEBUG_PRINT ("%s ", anjuta_plugin_handle_get_name (dep)); */
156 return TRUE;
158 else
160 if (collect_cycle (plugin_manager, base_plugin, dep, cycle))
162 *cycle = g_list_prepend (*cycle, dep);
163 /* DEBUG_PRINT ("%s ", anjuta_plugin_handle_get_name (dep)); */
164 return TRUE;
169 return FALSE;
172 static void
173 add_dependency (AnjutaPluginHandle *dependent, AnjutaPluginHandle *dependency)
175 g_hash_table_insert (anjuta_plugin_handle_get_dependents (dependency),
176 dependent, dependency);
177 g_hash_table_insert (anjuta_plugin_handle_get_dependencies (dependent),
178 dependency, dependent);
181 static void
182 child_dep_foreach_cb (gpointer key, gpointer value, gpointer user_data)
184 add_dependency (ANJUTA_PLUGIN_HANDLE (user_data),
185 ANJUTA_PLUGIN_HANDLE (key));
188 /* Resolves dependencies for a single module recursively. Shortcuts if
189 * the module has already been resolved. Returns a list representing
190 * any cycles found, or NULL if no cycles are found. If a cycle is found,
191 * the graph is left unresolved.
193 static GList*
194 resolve_for_module (AnjutaPluginManager *plugin_manager,
195 AnjutaPluginHandle *plugin, int pass)
197 AnjutaPluginManagerPriv *priv;
198 GList *l;
199 GList *ret = NULL;
201 priv = plugin_manager->priv;
203 if (anjuta_plugin_handle_get_checked (plugin))
205 return NULL;
208 if (anjuta_plugin_handle_get_resolve_pass (plugin) == pass)
210 GList *cycle = NULL;
211 g_warning ("cycle found: %s on pass %d",
212 anjuta_plugin_handle_get_name (plugin),
213 anjuta_plugin_handle_get_resolve_pass (plugin));
214 collect_cycle (plugin_manager, plugin, plugin, &cycle);
215 return cycle;
218 if (anjuta_plugin_handle_get_resolve_pass (plugin) != -1)
220 return NULL;
223 anjuta_plugin_handle_set_can_load (plugin, TRUE);
224 anjuta_plugin_handle_set_resolve_pass (plugin, pass);
226 for (l = anjuta_plugin_handle_get_dependency_names (plugin);
227 l != NULL; l = l->next)
229 char *dep = l->data;
230 AnjutaPluginHandle *child =
231 g_hash_table_lookup (priv->plugins_by_name, dep);
232 if (child)
234 ret = resolve_for_module (plugin_manager, child, pass);
235 if (ret)
237 break;
240 /* Add the dependency's dense dependency list
241 * to the current module's dense dependency list */
242 g_hash_table_foreach (anjuta_plugin_handle_get_dependencies (child),
243 child_dep_foreach_cb, plugin);
244 add_dependency (plugin, child);
246 /* If the child can't load due to dependency problems,
247 * the current module can't either */
248 anjuta_plugin_handle_set_can_load (plugin,
249 anjuta_plugin_handle_get_can_load (child));
250 } else {
251 g_warning ("Dependency %s not found.\n", dep);
252 anjuta_plugin_handle_set_can_load (plugin, FALSE);
253 ret = NULL;
256 anjuta_plugin_handle_set_checked (plugin, TRUE);
258 return ret;
261 /* Clean up the results of a resolving run */
262 static void
263 unresolve_dependencies (AnjutaPluginManager *plugin_manager)
265 AnjutaPluginManagerPriv *priv;
266 GList *l;
268 priv = plugin_manager->priv;
270 for (l = priv->available_plugins; l != NULL; l = l->next)
272 AnjutaPluginHandle *plugin = l->data;
273 anjuta_plugin_handle_unresolve_dependencies (plugin);
277 /* done upto here */
279 static void
280 prune_modules (AnjutaPluginManager *plugin_manager, GList *modules)
282 AnjutaPluginManagerPriv *priv;
283 GList *l;
285 priv = plugin_manager->priv;
287 for (l = modules; l != NULL; l = l->next) {
288 AnjutaPluginHandle *plugin = l->data;
290 g_hash_table_remove (priv->plugins_by_name,
291 anjuta_plugin_handle_get_id (plugin));
292 priv->available_plugins = g_list_remove (priv->available_plugins, plugin);
296 static int
297 dependency_compare (AnjutaPluginHandle *plugin_a,
298 AnjutaPluginHandle *plugin_b)
300 int a = g_hash_table_size (anjuta_plugin_handle_get_dependencies (plugin_a));
301 int b = g_hash_table_size (anjuta_plugin_handle_get_dependencies (plugin_b));
303 return a - b;
306 /* Resolves the dependencies of the priv->available_plugins list. When this
307 * function is complete, the following will be true:
309 * 1) The dependencies and dependents hash tables of the modules will
310 * be filled.
312 * 2) Cycles in the graph will be removed.
314 * 3) Modules which cannot be loaded due to failed dependencies will
315 * be marked as such.
317 * 4) priv->available_plugins will be sorted such that no module depends on a
318 * module after it.
320 * If a cycle in the graph is found, it is pruned from the tree and
321 * returned as a list stored in the cycles list.
323 static void
324 resolve_dependencies (AnjutaPluginManager *plugin_manager, GList **cycles)
326 AnjutaPluginManagerPriv *priv;
327 GList *cycle = NULL;
328 GList *l;
330 priv = plugin_manager->priv;
331 *cycles = NULL;
333 /* Try resolving dependencies. If there is a cycle, prune the
334 * cycle and try to resolve again */
337 int pass = 1;
338 cycle = NULL;
339 for (l = priv->available_plugins; l != NULL && !cycle; l = l->next) {
340 cycle = resolve_for_module (plugin_manager, l->data, pass++);
341 cycle = NULL;
343 if (cycle) {
344 *cycles = g_list_prepend (*cycles, cycle);
345 prune_modules (plugin_manager, cycle);
346 unresolve_dependencies (plugin_manager);
348 } while (cycle);
350 /* Now that there is a fully resolved dependency tree, sort
351 * priv->available_plugins to create a valid load order */
352 priv->available_plugins = g_list_sort (priv->available_plugins,
353 (GCompareFunc)dependency_compare);
356 /* Plugins loading */
358 static gboolean
359 str_has_suffix (const char *haystack, const char *needle)
361 const char *h, *n;
363 if (needle == NULL) {
364 return TRUE;
366 if (haystack == NULL) {
367 return needle[0] == '\0';
370 /* Eat one character at a time. */
371 h = haystack + strlen(haystack);
372 n = needle + strlen(needle);
373 do {
374 if (n == needle) {
375 return TRUE;
377 if (h == haystack) {
378 return FALSE;
380 } while (*--h == *--n);
381 return FALSE;
384 static void
385 load_plugin (AnjutaPluginManager *plugin_manager,
386 const gchar *plugin_desc_path)
388 AnjutaPluginManagerPriv *priv;
389 AnjutaPluginHandle *plugin_handle;
391 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager));
392 priv = plugin_manager->priv;
394 plugin_handle = anjuta_plugin_handle_new (plugin_desc_path);
395 if (plugin_handle)
397 if (g_hash_table_lookup (priv->plugins_by_name,
398 anjuta_plugin_handle_get_id (plugin_handle)))
400 g_object_unref (plugin_handle);
402 else
404 GList *node;
405 /* Available plugin */
406 priv->available_plugins = g_list_prepend (priv->available_plugins,
407 plugin_handle);
408 /* Index by id */
409 g_hash_table_insert (priv->plugins_by_name,
410 (gchar *)anjuta_plugin_handle_get_id (plugin_handle),
411 plugin_handle);
413 /* Index by description */
414 g_hash_table_insert (priv->plugins_by_description,
415 anjuta_plugin_handle_get_description (plugin_handle),
416 plugin_handle);
418 /* Index by interfaces exported by this plugin */
419 node = anjuta_plugin_handle_get_interfaces (plugin_handle);
420 while (node)
422 GList *objs;
423 gchar *iface;
424 GList *obj_node;
425 gboolean found;
427 iface = node->data;
428 objs = (GList*)g_hash_table_lookup (priv->plugins_by_interfaces, iface);
430 obj_node = objs;
431 found = FALSE;
432 while (obj_node)
434 if (obj_node->data == plugin_handle)
436 found = TRUE;
437 break;
439 obj_node = g_list_next (obj_node);
441 if (!found)
443 g_hash_table_steal (priv->plugins_by_interfaces, iface);
444 objs = g_list_prepend (objs, plugin_handle);
445 g_hash_table_insert (priv->plugins_by_interfaces, iface, objs);
447 node = g_list_next (node);
451 return;
454 static void
455 load_plugins_from_directory (AnjutaPluginManager* plugin_manager,
456 const gchar *dirname)
458 DIR *dir;
459 struct dirent *entry;
461 dir = opendir (dirname);
463 if (!dir)
465 return;
468 for (entry = readdir (dir); entry != NULL; entry = readdir (dir))
470 if (str_has_suffix (entry->d_name, ".plugin"))
472 gchar *pathname;
473 pathname = g_strdup_printf ("%s/%s", dirname, entry->d_name);
474 load_plugin (plugin_manager,pathname);
475 g_free (pathname);
478 closedir (dir);
481 /* Plugin activation and deactivation */
483 static void
484 on_plugin_activated (AnjutaPlugin *plugin_object, AnjutaPluginHandle *plugin)
486 AnjutaPluginManager *plugin_manager;
487 AnjutaPluginManagerPriv *priv;
489 /* FIXME: Pass plugin_manager directly in signal arguments */
490 plugin_manager = anjuta_shell_get_plugin_manager (plugin_object->shell, NULL);
492 g_return_if_fail(plugin_manager != NULL);
494 priv = plugin_manager->priv;
496 g_hash_table_insert (priv->activated_plugins, plugin,
497 G_OBJECT (plugin_object));
498 if (g_hash_table_lookup (priv->plugins_cache, plugin))
499 g_hash_table_remove (priv->plugins_cache, plugin);
501 g_signal_emit_by_name (plugin_manager, "plugin-activated",
502 anjuta_plugin_handle_get_description (plugin),
503 plugin_object);
506 static void
507 on_plugin_deactivated (AnjutaPlugin *plugin_object, AnjutaPluginHandle *plugin)
509 AnjutaPluginManager *plugin_manager;
510 AnjutaPluginManagerPriv *priv;
512 /* FIXME: Pass plugin_manager directly in signal arguments */
513 plugin_manager = anjuta_shell_get_plugin_manager (plugin_object->shell, NULL);
515 g_return_if_fail (plugin_manager != NULL);
517 priv = plugin_manager->priv;
519 g_hash_table_insert (priv->plugins_cache, plugin, G_OBJECT (plugin_object));
520 g_hash_table_remove (priv->activated_plugins, plugin);
522 g_signal_emit_by_name (plugin_manager, "plugin-deactivated",
523 anjuta_plugin_handle_get_description (plugin),
524 plugin_object);
527 static GObject *
528 activate_plugin (AnjutaPluginManager *plugin_manager,
529 AnjutaPluginHandle *plugin, GError **error)
531 AnjutaPluginManagerPriv *priv;
532 GType type;
533 GType glue_type;
534 GObject *ret;
535 gchar* lang = NULL;
536 const gchar *plugin_id;
537 const gchar *language;
538 gboolean resident;
540 priv = plugin_manager->priv;
542 if (!plugin_types)
544 plugin_types = g_hash_table_new (g_str_hash, g_str_equal);
547 plugin_id = anjuta_plugin_handle_get_id (plugin);
549 resident = anjuta_plugin_handle_get_resident (plugin);
550 language = anjuta_plugin_handle_get_language (plugin);
552 glue_type = get_plugin_loader_type (plugin_manager, language);
553 if (glue_type == G_TYPE_INVALID)
555 g_set_error (error, ANJUTA_PLUGIN_MANAGER_ERROR,
556 ANJUTA_PLUGIN_MANAGER_ERROR_INVALID_TYPE,
557 _("Invalid plugin: %s"), plugin_id);
559 return NULL;
562 type = GPOINTER_TO_UINT (g_hash_table_lookup (plugin_types, plugin_id));
564 if (!type)
566 char **pieces;
567 /* DEBUG_PRINT ("Loading: %s", plugin_id); */
568 pieces = g_strsplit (plugin_id, ":", -1);
569 type = anjuta_glue_factory_get_object_type (anjuta_glue_factory,
570 pieces[0], pieces[1],
571 resident, glue_type);
572 g_hash_table_insert (plugin_types, g_strdup (plugin_id),
573 GUINT_TO_POINTER (type));
574 g_strfreev (pieces);
576 g_free (lang);
578 if (type == G_TYPE_INVALID)
580 g_set_error (error, ANJUTA_PLUGIN_MANAGER_ERROR,
581 ANJUTA_PLUGIN_MANAGER_ERROR_INVALID_TYPE,
582 _("Invalid plugin: %s"), plugin_id);
583 ret = NULL;
585 else
587 ret = g_object_new (type, "shell", priv->shell, NULL);
588 g_signal_connect (ret, "activated",
589 G_CALLBACK (on_plugin_activated), plugin);
590 g_signal_connect (ret, "deactivated",
591 G_CALLBACK (on_plugin_deactivated), plugin);
593 return ret;
596 static gboolean
597 g_hashtable_foreach_true (gpointer key, gpointer value, gpointer user_data)
599 return TRUE;
602 void
603 anjuta_plugin_manager_unload_all_plugins (AnjutaPluginManager *plugin_manager)
605 AnjutaPluginManagerPriv *priv;
607 priv = plugin_manager->priv;
608 if (g_hash_table_size (priv->activated_plugins) > 0 ||
609 g_hash_table_size (priv->plugins_cache) > 0)
611 priv->available_plugins = g_list_reverse (priv->available_plugins);
612 if (g_hash_table_size (priv->activated_plugins) > 0)
614 GList *node;
615 node = priv->available_plugins;
616 while (node)
618 AnjutaPluginHandle *selected_plugin = node->data;
619 if (g_hash_table_lookup (priv->activated_plugins, selected_plugin))
621 plugin_set_update (plugin_manager, selected_plugin, FALSE);
622 /* DEBUG_PRINT ("Unloading plugin: %s",
623 anjuta_plugin_handle_get_id (selected_plugin));
626 node = g_list_next (node);
628 g_hash_table_foreach_remove (priv->activated_plugins,
629 g_hashtable_foreach_true, NULL);
631 if (g_hash_table_size (priv->plugins_cache) > 0)
633 GList *node;
634 node = priv->available_plugins;
635 while (node)
637 GObject *plugin_obj;
638 AnjutaPluginHandle *selected_plugin = node->data;
640 plugin_obj = g_hash_table_lookup (priv->plugins_cache,
641 selected_plugin);
642 if (plugin_obj)
644 /* DEBUG_PRINT ("Destroying plugin: %s",
645 anjuta_plugin_handle_get_id (selected_plugin));
647 g_object_unref (plugin_obj);
649 node = g_list_next (node);
651 g_hash_table_foreach_remove (priv->plugins_cache,
652 g_hashtable_foreach_true, NULL);
654 priv->available_plugins = g_list_reverse (priv->available_plugins);
658 static gboolean
659 should_unload (GHashTable *activated_plugins, AnjutaPluginHandle *plugin_to_unload,
660 AnjutaPluginHandle *plugin)
662 GObject *plugin_obj = g_hash_table_lookup (activated_plugins, plugin);
664 if (!plugin_obj)
665 return FALSE;
667 if (plugin_to_unload == plugin)
668 return TRUE;
670 gboolean dependent =
671 GPOINTER_TO_INT (g_hash_table_lookup (anjuta_plugin_handle_get_dependents (plugin),
672 plugin));
673 return dependent;
676 static gboolean
677 should_load (GHashTable *activated_plugins, AnjutaPluginHandle *plugin_to_load,
678 AnjutaPluginHandle *plugin)
680 GObject *plugin_obj = g_hash_table_lookup (activated_plugins, plugin);
682 if (plugin_obj)
683 return FALSE;
685 if (plugin_to_load == plugin)
686 return anjuta_plugin_handle_get_can_load (plugin);
688 gboolean dependency =
689 GPOINTER_TO_INT (g_hash_table_lookup (anjuta_plugin_handle_get_dependencies (plugin_to_load),
690 plugin));
691 return (dependency && anjuta_plugin_handle_get_can_load (plugin));
694 static AnjutaPluginHandle *
695 plugin_for_iter (GtkListStore *store, GtkTreeIter *iter)
697 AnjutaPluginHandle *plugin;
699 gtk_tree_model_get (GTK_TREE_MODEL (store), iter, COL_PLUGIN, &plugin, -1);
700 return plugin;
703 static void
704 update_enabled (GtkTreeModel *model, GHashTable *activated_plugins)
706 GtkTreeIter iter;
708 if (gtk_tree_model_get_iter_first (model, &iter)) {
709 do {
710 AnjutaPluginHandle *plugin;
711 GObject *plugin_obj;
712 gboolean installed;
714 plugin = plugin_for_iter(GTK_LIST_STORE(model), &iter);
715 plugin_obj = g_hash_table_lookup (activated_plugins, plugin);
716 installed = (plugin_obj != NULL) ? TRUE : FALSE;
717 gtk_tree_model_get (model, &iter, COL_PLUGIN, &plugin, -1);
718 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
719 COL_ENABLED, installed, -1);
720 } while (gtk_tree_model_iter_next (model, &iter));
724 static GHashTable*
725 plugin_set_update (AnjutaPluginManager *plugin_manager,
726 AnjutaPluginHandle* selected_plugin,
727 gboolean load)
729 AnjutaPluginManagerPriv *priv;
730 GObject *plugin_obj;
731 GList *l;
733 priv = plugin_manager->priv;
734 plugin_obj = g_hash_table_lookup (priv->activated_plugins, selected_plugin);
736 if (plugin_obj && load)
738 g_warning ("Trying to install already installed plugin '%s'",
739 anjuta_plugin_handle_get_name (selected_plugin));
740 return priv->activated_plugins;
742 if (!plugin_obj && !load)
744 g_warning ("Trying to uninstall a not installed plugin '%s'",
745 anjuta_plugin_handle_get_name (selected_plugin));
746 return priv->activated_plugins;
749 if (priv->status)
750 anjuta_status_busy_push (priv->status);
752 if (!load)
754 /* reverse priv->available_plugins when unloading, so that plugins are
755 * unloaded in the right order */
756 priv->available_plugins = g_list_reverse (priv->available_plugins);
758 for (l = priv->available_plugins; l != NULL; l = l->next)
760 AnjutaPluginHandle *plugin = l->data;
761 if (should_unload (priv->activated_plugins, selected_plugin, plugin))
763 /* FIXME: Unload the class and sharedlib if possible */
764 AnjutaPlugin *anjuta_plugin = ANJUTA_PLUGIN (plugin_obj);
765 if (!anjuta_plugin_deactivate (ANJUTA_PLUGIN (anjuta_plugin)))
767 anjuta_util_dialog_info (GTK_WINDOW (priv->shell),
768 "Plugin '%s' do not want to be deactivated",
769 anjuta_plugin_handle_get_name (plugin));
773 priv->available_plugins = g_list_reverse (priv->available_plugins);
775 else
777 for (l = priv->available_plugins; l != NULL; l = l->next)
779 AnjutaPluginHandle *plugin = l->data;
780 if (should_load (priv->activated_plugins, selected_plugin, plugin))
782 GObject *plugin_obj;
783 plugin_obj = g_hash_table_lookup (priv->plugins_cache, plugin);
784 if (!plugin_obj)
786 GError *error = NULL;
787 plugin_obj = activate_plugin (plugin_manager, plugin,
788 &error);
791 if (plugin_obj)
793 anjuta_plugin_activate (ANJUTA_PLUGIN (plugin_obj));
798 if (priv->status)
799 anjuta_status_busy_pop (priv->status);
800 return priv->activated_plugins;
803 static void
804 plugin_toggled (GtkCellRendererToggle *cell, char *path_str, gpointer data)
806 AnjutaPluginManager *plugin_manager;
807 AnjutaPluginManagerPriv *priv;
808 GtkListStore *store = GTK_LIST_STORE (data);
809 GtkTreeIter iter;
810 GtkTreePath *path;
811 AnjutaPluginHandle *plugin;
812 gboolean enabled;
813 GHashTable *activated_plugins;
815 path = gtk_tree_path_new_from_string (path_str);
817 plugin_manager = g_object_get_data (G_OBJECT (store), "plugin-manager");
818 priv = plugin_manager->priv;
820 gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
821 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
822 COL_ENABLED, &enabled,
823 COL_PLUGIN, &plugin,
824 -1);
826 enabled = !enabled;
828 activated_plugins = plugin_set_update (plugin_manager, plugin, enabled);
829 update_enabled (GTK_TREE_MODEL (store), activated_plugins);
830 gtk_tree_path_free (path);
833 #if 0
834 static void
835 selection_changed (GtkTreeSelection *selection, GtkListStore *store)
837 GtkTreeIter iter;
839 if (gtk_tree_selection_get_selected (selection, NULL,
840 &iter)) {
841 GtkTextBuffer *buffer;
843 GtkWidget *txt = g_object_get_data (G_OBJECT (store),
844 "AboutText");
846 GtkWidget *image = g_object_get_data (G_OBJECT (store),
847 "Icon");
848 AnjutaPluginHandle *plugin = plugin_for_iter (store, &iter);
850 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (txt));
851 gtk_text_buffer_set_text (buffer, plugin->about, -1);
853 if (plugin->icon_path) {
854 gtk_image_set_from_file (GTK_IMAGE (image),
855 plugin->icon_path);
856 gtk_widget_show (GTK_WIDGET (image));
857 } else {
858 gtk_widget_hide (GTK_WIDGET (image));
862 #endif
864 static GtkWidget *
865 create_plugin_tree (void)
867 GtkListStore *store;
868 GtkWidget *tree;
869 GtkCellRenderer *renderer;
870 GtkTreeViewColumn *column;
872 store = gtk_list_store_new (N_COLS,
873 G_TYPE_BOOLEAN,
874 G_TYPE_BOOLEAN,
875 GDK_TYPE_PIXBUF,
876 G_TYPE_STRING,
877 G_TYPE_POINTER);
878 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
880 renderer = gtk_cell_renderer_toggle_new ();
881 g_signal_connect (G_OBJECT (renderer), "toggled",
882 G_CALLBACK (plugin_toggled), store);
883 column = gtk_tree_view_column_new_with_attributes (_("Load"),
884 renderer,
885 "active",
886 COL_ENABLED,
887 "activatable",
888 COL_ACTIVABLE,
889 NULL);
890 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
891 gtk_tree_view_column_set_sizing (column,
892 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
894 column = gtk_tree_view_column_new ();
895 renderer = gtk_cell_renderer_pixbuf_new ();
896 gtk_tree_view_column_pack_start (column, renderer, FALSE);
897 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
898 COL_ICON);
899 renderer = gtk_cell_renderer_text_new ();
900 gtk_tree_view_column_pack_start (column, renderer, FALSE);
901 gtk_tree_view_column_add_attribute (column, renderer, "markup",
902 COL_NAME);
903 gtk_tree_view_column_set_sizing (column,
904 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
905 gtk_tree_view_column_set_title (column, _("Available Plugins"));
906 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
907 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (tree), column);
909 g_object_unref (store);
910 return tree;
913 /* Sort function for plugins */
914 static gint
915 sort_plugins(gconstpointer a, gconstpointer b)
917 g_return_val_if_fail (a != NULL, 0);
918 g_return_val_if_fail (b != NULL, 0);
920 AnjutaPluginHandle* plugin_a = ANJUTA_PLUGIN_HANDLE (a);
921 AnjutaPluginHandle* plugin_b = ANJUTA_PLUGIN_HANDLE (b);
923 return strcmp (anjuta_plugin_handle_get_name (plugin_a),
924 anjuta_plugin_handle_get_name (plugin_b));
927 /* If show_all == FALSE, show only user activatable plugins
928 * If show_all == TRUE, show all plugins
930 static void
931 populate_plugin_model (AnjutaPluginManager *plugin_manager,
932 GtkListStore *store,
933 GHashTable *plugins_to_show,
934 GHashTable *activated_plugins,
935 gboolean show_all)
937 AnjutaPluginManagerPriv *priv;
938 GList *l;
940 priv = plugin_manager->priv;
941 gtk_list_store_clear (store);
943 priv->available_plugins = g_list_sort (priv->available_plugins, sort_plugins);
945 for (l = priv->available_plugins; l != NULL; l = l->next)
947 AnjutaPluginHandle *plugin = l->data;
949 /* If plugins to show is NULL, show all available plugins */
950 if (plugins_to_show == NULL ||
951 g_hash_table_lookup (plugins_to_show, plugin))
954 gboolean enable = FALSE;
955 if (g_hash_table_lookup (activated_plugins, plugin))
956 enable = TRUE;
958 if (anjuta_plugin_handle_get_name (plugin) &&
959 anjuta_plugin_handle_get_description (plugin) &&
960 (anjuta_plugin_handle_get_user_activatable (plugin) ||
961 show_all))
963 GtkTreeIter iter;
964 gchar *text;
966 text = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
967 anjuta_plugin_handle_get_name (plugin),
968 anjuta_plugin_handle_get_about (plugin));
970 gtk_list_store_append (store, &iter);
971 gtk_list_store_set (store, &iter,
972 COL_ACTIVABLE,
973 anjuta_plugin_handle_get_user_activatable (plugin),
974 COL_ENABLED, enable,
975 COL_NAME, text,
976 COL_PLUGIN, plugin,
977 -1);
978 if (anjuta_plugin_handle_get_icon_path (plugin))
980 GdkPixbuf *icon;
981 icon = gdk_pixbuf_new_from_file_at_size (anjuta_plugin_handle_get_icon_path (plugin),
982 48, 48, NULL);
983 if (icon) {
984 gtk_list_store_set (store, &iter,
985 COL_ICON, icon, -1);
986 gdk_pixbuf_unref (icon);
989 g_free (text);
995 static GtkWidget *
996 create_remembered_plugins_tree (void)
998 GtkListStore *store;
999 GtkWidget *tree;
1000 GtkCellRenderer *renderer;
1001 GtkTreeViewColumn *column;
1003 store = gtk_list_store_new (N_REM_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING,
1004 G_TYPE_STRING);
1005 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1007 column = gtk_tree_view_column_new ();
1008 renderer = gtk_cell_renderer_pixbuf_new ();
1009 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1010 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
1011 COL_REM_ICON);
1012 renderer = gtk_cell_renderer_text_new ();
1013 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1014 gtk_tree_view_column_add_attribute (column, renderer, "markup",
1015 COL_REM_NAME);
1016 gtk_tree_view_column_set_sizing (column,
1017 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1018 gtk_tree_view_column_set_title (column, _("Preferred plugins"));
1019 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1020 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (tree), column);
1022 g_object_unref (store);
1023 return tree;
1026 static void
1027 foreach_remembered_plugin (gpointer key, gpointer value, gpointer user_data)
1029 AnjutaPluginDescription *desc = (AnjutaPluginDescription *) value;
1030 GtkListStore *store = GTK_LIST_STORE (user_data);
1031 AnjutaPluginManager *manager = g_object_get_data (G_OBJECT (store),
1032 "plugin-manager");
1033 AnjutaPluginHandle *plugin =
1034 g_hash_table_lookup (manager->priv->plugins_by_description, desc);
1035 g_return_if_fail (plugin != NULL);
1037 if (anjuta_plugin_handle_get_name (plugin) &&
1038 anjuta_plugin_handle_get_description (plugin))
1040 GtkTreeIter iter;
1041 gchar *text;
1043 text = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
1044 anjuta_plugin_handle_get_name (plugin),
1045 anjuta_plugin_handle_get_about (plugin));
1047 gtk_list_store_append (store, &iter);
1048 gtk_list_store_set (store, &iter,
1049 COL_REM_NAME, text,
1050 COL_REM_PLUGIN_KEY, key,
1051 -1);
1052 if (anjuta_plugin_handle_get_icon_path (plugin))
1054 GdkPixbuf *icon;
1055 icon = gdk_pixbuf_new_from_file_at_size (anjuta_plugin_handle_get_icon_path (plugin),
1056 48, 48, NULL);
1057 if (icon) {
1058 gtk_list_store_set (store, &iter,
1059 COL_REM_ICON, icon, -1);
1060 gdk_pixbuf_unref (icon);
1063 g_free (text);
1067 static void
1068 populate_remembered_plugins_model (AnjutaPluginManager *plugin_manager,
1069 GtkListStore *store)
1071 AnjutaPluginManagerPriv *priv = plugin_manager->priv;
1072 gtk_list_store_clear (store);
1073 g_hash_table_foreach (priv->remember_plugins, foreach_remembered_plugin,
1074 store);
1077 static void
1078 on_show_all_plugins_toggled (GtkToggleButton *button, GtkListStore *store)
1080 AnjutaPluginManager *plugin_manager;
1082 plugin_manager = g_object_get_data (G_OBJECT (button), "__plugin_manager");
1084 populate_plugin_model (plugin_manager, store, NULL,
1085 plugin_manager->priv->activated_plugins,
1086 !gtk_toggle_button_get_active (button));
1089 static void
1090 on_forget_plugin_clicked (GtkWidget *button, GtkTreeView *view)
1092 GtkTreeIter iter;
1093 GtkTreeModel *model;
1094 GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
1095 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1097 gchar *plugin_key;
1098 AnjutaPluginManager *manager = g_object_get_data (G_OBJECT (model),
1099 "plugin-manager");
1100 gtk_tree_model_get (model, &iter, COL_REM_PLUGIN_KEY, &plugin_key, -1);
1101 g_hash_table_remove (manager->priv->remember_plugins, plugin_key);
1102 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1103 g_free (plugin_key);
1107 static void
1108 on_forget_plugin_sel_changed (GtkTreeSelection *selection,
1109 GtkWidget *button)
1111 GtkTreeIter iter;
1113 if (gtk_tree_selection_get_selected (selection, NULL, &iter))
1114 gtk_widget_set_sensitive (button, TRUE);
1115 else
1116 gtk_widget_set_sensitive (button, FALSE);
1119 GtkWidget *
1120 anjuta_plugin_manager_get_plugins_page (AnjutaPluginManager *plugin_manager)
1122 GtkWidget *vbox;
1123 GtkWidget *checkbutton;
1124 GtkWidget *tree;
1125 GtkWidget *scrolled;
1126 GtkListStore *store;
1128 /* Plugins page */
1129 vbox = gtk_vbox_new (FALSE, 0);
1130 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
1132 checkbutton = gtk_check_button_new_with_label (_("Only show user activatable plugins"));
1133 gtk_container_set_border_width (GTK_CONTAINER (checkbutton), 10);
1134 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), TRUE);
1135 gtk_box_pack_start (GTK_BOX (vbox), checkbutton, FALSE, FALSE, 0);
1137 scrolled = gtk_scrolled_window_new (NULL, NULL);
1138 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
1139 GTK_SHADOW_IN);
1140 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1141 GTK_POLICY_AUTOMATIC,
1142 GTK_POLICY_AUTOMATIC);
1143 gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
1145 tree = create_plugin_tree ();
1146 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree)));
1148 populate_plugin_model (plugin_manager, store, NULL,
1149 plugin_manager->priv->activated_plugins, FALSE);
1151 gtk_container_add (GTK_CONTAINER (scrolled), tree);
1152 g_object_set_data (G_OBJECT (store), "plugin-manager", plugin_manager);
1155 g_object_set_data (G_OBJECT (checkbutton), "__plugin_manager", plugin_manager);
1156 g_signal_connect (G_OBJECT (checkbutton), "toggled",
1157 G_CALLBACK (on_show_all_plugins_toggled),
1158 store);
1159 gtk_widget_show_all (vbox);
1160 return vbox;
1163 GtkWidget *
1164 anjuta_plugin_manager_get_remembered_plugins_page (AnjutaPluginManager *plugin_manager)
1166 GtkWidget *vbox;
1167 GtkWidget *tree;
1168 GtkWidget *scrolled;
1169 GtkListStore *store;
1170 GtkWidget *hbox;
1171 GtkWidget *display_label;
1172 GtkWidget *forget_button;
1173 GtkTreeSelection *selection;
1175 /* Remembered plugin */
1176 vbox = gtk_vbox_new (FALSE, 10);
1177 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
1179 display_label = gtk_label_new (_("These are the plugins selected by you "
1180 "when Anjuta prompted to choose one of "
1181 "many suitable plugins. Removing the "
1182 "preferred plugin will let Anjuta prompt "
1183 "you again to choose different plugin."));
1184 gtk_label_set_line_wrap (GTK_LABEL (display_label), TRUE);
1185 gtk_box_pack_start (GTK_BOX (vbox), display_label, FALSE, FALSE, 0);
1187 scrolled = gtk_scrolled_window_new (NULL, NULL);
1188 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
1189 GTK_SHADOW_IN);
1190 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1191 GTK_POLICY_AUTOMATIC,
1192 GTK_POLICY_AUTOMATIC);
1193 gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
1195 tree = create_remembered_plugins_tree ();
1196 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree)));
1198 gtk_container_add (GTK_CONTAINER (scrolled), tree);
1199 g_object_set_data (G_OBJECT (store), "plugin-manager", plugin_manager);
1200 populate_remembered_plugins_model (plugin_manager, store);
1202 hbox = gtk_hbox_new (FALSE, 0);
1203 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
1204 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1205 forget_button = gtk_button_new_with_label ("Forget selected plugin");
1206 gtk_widget_set_sensitive (forget_button, FALSE);
1207 gtk_box_pack_end (GTK_BOX (hbox), forget_button, FALSE, FALSE, 0);
1209 g_signal_connect (forget_button, "clicked",
1210 G_CALLBACK (on_forget_plugin_clicked),
1211 tree);
1212 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
1213 g_signal_connect (selection, "changed",
1214 G_CALLBACK (on_forget_plugin_sel_changed),
1215 forget_button);
1216 gtk_widget_show_all (vbox);
1217 return vbox;
1220 static GList *
1221 property_to_list (const char *value)
1223 GList *l = NULL;
1224 char **split_str;
1225 char **p;
1227 split_str = g_strsplit (value, ",", -1);
1228 for (p = split_str; *p != NULL; p++) {
1229 l = g_list_prepend (l, g_strdup (g_strstrip (*p)));
1231 g_strfreev (split_str);
1232 return l;
1235 static GType
1236 get_plugin_loader_type (AnjutaPluginManager *plugin_manager,
1237 const gchar *language)
1239 AnjutaPluginManagerPriv *priv;
1240 AnjutaPluginHandle *plugin;
1241 GList *loader_plugins, *node;
1242 GList *valid_plugins;
1243 GObject *obj = NULL;
1245 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), G_TYPE_INVALID);
1248 if ((language == NULL) || (g_ascii_strcasecmp (language, "C") == 0))
1250 /* Support of C plugin is built-in */
1251 return ANJUTA_GLUE_TYPE_C_PLUGIN;
1254 priv = plugin_manager->priv;
1255 plugin = NULL;
1257 /* Find all plugins implementing the IAnjutaPluginLoader interface. */
1258 loader_plugins = g_hash_table_lookup (priv->plugins_by_interfaces, "IAnjutaPluginLoader");
1260 /* Create a list of loader supporting this language */
1261 node = loader_plugins;
1262 valid_plugins = NULL;
1263 while (node)
1265 AnjutaPluginDescription *desc;
1266 gchar *val;
1267 GList *vals = NULL;
1268 GList *l_node;
1269 gboolean found;
1271 plugin = node->data;
1273 desc = anjuta_plugin_handle_get_description (plugin);
1274 if (anjuta_plugin_description_get_string (desc, "Plugin Loader", "SupportedLanguage", &val))
1276 if (val != NULL)
1278 vals = property_to_list (val);
1279 g_free (val);
1283 found = FALSE;
1284 l_node = vals;
1285 while (l_node)
1287 if (!found && (g_ascii_strcasecmp (l_node->data, language) == 0))
1289 found = TRUE;
1291 g_free (l_node->data);
1292 l_node = g_list_next (l_node);
1294 g_list_free (vals);
1296 if (found)
1298 valid_plugins = g_list_prepend (valid_plugins, plugin);
1301 node = g_list_next (node);
1304 /* Find the first installed plugin from the valid plugins */
1305 node = valid_plugins;
1306 while (node)
1308 plugin = node->data;
1309 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1310 if (obj) break;
1311 node = g_list_next (node);
1314 /* If no plugin is installed yet, do something */
1315 if ((obj == NULL) && valid_plugins && g_list_length (valid_plugins) == 1)
1317 /* If there is just one plugin, consider it selected */
1318 plugin = valid_plugins->data;
1320 /* Install and return it */
1321 plugin_set_update (plugin_manager, plugin, TRUE);
1322 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1324 else if ((obj == NULL) && valid_plugins)
1326 /* Prompt the user to select one of these plugins */
1328 GList *descs = NULL;
1329 node = valid_plugins;
1330 while (node)
1332 plugin = node->data;
1333 descs = g_list_prepend (descs, anjuta_plugin_handle_get_description (plugin));
1334 node = g_list_next (node);
1336 descs = g_list_reverse (descs);
1337 obj = anjuta_plugin_manager_select_and_activate (plugin_manager,
1338 "Select a plugin",
1339 "Please select a plugin to activate",
1340 descs);
1341 g_list_free (descs);
1343 g_list_free (valid_plugins);
1345 if (obj != NULL)
1347 /* Get type of glue object */
1348 IAnjutaPluginLoader *loader;
1350 loader = IANJUTA_PLUGIN_LOADER (ANJUTA_PLUGIN(obj));
1352 return ianjuta_plugin_loader_glue_plugin_get_type (loader, NULL);
1355 /* No plugin implementing this interface found */
1356 g_warning ("No plugin found to load a %s plugin.", language);
1358 return G_TYPE_INVALID;
1362 * anjuta_plugin_manager_get_plugin:
1363 * @plugin_manager: A #AnjutaPluginManager object
1364 * @iface_name: The interface implemented by the object to be found
1366 * Searches the currently available plugins to find the one which
1367 * implements the given interface as primary interface and returns it. If
1368 * the plugin is not yet loaded, it will be loaded and activated.
1369 * The returned object is garanteed to be an implementor of the
1370 * interface (as exported by the plugin metafile). It only searches
1371 * from the pool of plugin objects loaded in this shell and can only search
1372 * by primary interface. If there are more objects implementing this primary
1373 * interface, user might be prompted to select one from them (and might give
1374 * the option to use it as default for future queries). A typical usage of this
1375 * function is:
1376 * <programlisting>
1377 * GObject *docman =
1378 * anjuta_plugin_manager_get_plugin (plugin_manager, "IAnjutaDocumentManager", error);
1379 * </programlisting>
1380 * Notice that this function takes the interface name string as string, unlike
1381 * anjuta_plugins_get_interface() which takes the type directly.
1383 * Return value: The plugin object (subclass of #AnjutaPlugin) which implements
1384 * the given interface. See #AnjutaPlugin for more detail on interfaces
1385 * implemented by plugins.
1387 GObject *
1388 anjuta_plugin_manager_get_plugin (AnjutaPluginManager *plugin_manager,
1389 const gchar *iface_name)
1391 AnjutaPluginManagerPriv *priv;
1392 AnjutaPluginHandle *plugin;
1393 GList *valid_plugins, *node;
1395 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1396 g_return_val_if_fail (iface_name != NULL, NULL);
1398 priv = plugin_manager->priv;
1399 plugin = NULL;
1401 /* Find all plugins implementing this (primary) interface. */
1402 valid_plugins = g_hash_table_lookup (priv->plugins_by_interfaces, iface_name);
1404 /* Find the first installed plugin from the valid plugins */
1405 node = valid_plugins;
1406 while (node)
1408 GObject *obj;
1409 plugin = node->data;
1410 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1411 if (obj)
1412 return obj;
1413 node = g_list_next (node);
1416 /* If no plugin is installed yet, do something */
1417 if (valid_plugins && g_list_length (valid_plugins) == 1)
1419 /* If there is just one plugin, consider it selected */
1420 GObject *obj;
1421 plugin = valid_plugins->data;
1423 /* Install and return it */
1424 plugin_set_update (plugin_manager, plugin, TRUE);
1425 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1427 return obj;
1429 else if (valid_plugins)
1431 /* Prompt the user to select one of these plugins */
1432 GObject *obj;
1433 GList *descs = NULL;
1434 node = valid_plugins;
1435 while (node)
1437 plugin = node->data;
1438 descs = g_list_prepend (descs, anjuta_plugin_handle_get_description (plugin));
1439 node = g_list_next (node);
1441 descs = g_list_reverse (descs);
1442 obj = anjuta_plugin_manager_select_and_activate (plugin_manager,
1443 "Select a plugin",
1444 "Please select a plugin to activate",
1445 descs);
1446 g_list_free (descs);
1447 return obj;
1450 /* No plugin implementing this interface found */
1451 g_warning ("No plugin found implementing %s Interface.", iface_name);
1452 return NULL;
1455 GObject *
1456 anjuta_plugin_manager_get_plugin_by_id (AnjutaPluginManager *plugin_manager,
1457 const gchar *plugin_id)
1459 AnjutaPluginManagerPriv *priv;
1460 AnjutaPluginHandle *plugin;
1462 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1463 g_return_val_if_fail (plugin_id != NULL, NULL);
1465 priv = plugin_manager->priv;
1466 plugin = g_hash_table_lookup (priv->plugins_by_name, plugin_id);
1467 if (plugin)
1469 GObject *obj;
1470 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1471 if (obj)
1473 return obj;
1474 } else
1476 plugin_set_update (plugin_manager, plugin, TRUE);
1477 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1478 return obj;
1481 g_warning ("No plugin found with id \"%s\".", plugin_id);
1482 return NULL;
1485 static void
1486 on_activated_plugins_foreach (gpointer key, gpointer data, gpointer user_data)
1488 AnjutaPluginHandle *plugin = ANJUTA_PLUGIN_HANDLE (key);
1489 GList **active_plugins = (GList **)user_data;
1490 *active_plugins = g_list_prepend (*active_plugins,
1491 anjuta_plugin_handle_get_description (plugin));
1494 static void
1495 on_activated_plugin_objects_foreach (gpointer key, gpointer data, gpointer user_data)
1497 GList **active_plugins = (GList **)user_data;
1498 *active_plugins = g_list_prepend (*active_plugins,
1499 data);
1502 GList*
1503 anjuta_plugin_manager_get_active_plugins (AnjutaPluginManager *plugin_manager)
1505 GList *active_plugins = NULL;
1507 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1508 g_hash_table_foreach (plugin_manager->priv->activated_plugins,
1509 on_activated_plugins_foreach,
1510 &active_plugins);
1511 return g_list_reverse (active_plugins);
1514 GList*
1515 anjuta_plugin_manager_get_active_plugin_objects (AnjutaPluginManager *plugin_manager)
1517 GList *active_plugins = NULL;
1519 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1520 g_hash_table_foreach (plugin_manager->priv->activated_plugins,
1521 on_activated_plugin_objects_foreach,
1522 &active_plugins);
1523 return g_list_reverse (active_plugins);
1526 gboolean
1527 anjuta_plugin_manager_unload_plugin_by_id (AnjutaPluginManager *plugin_manager,
1528 const gchar *plugin_id)
1530 AnjutaPluginManagerPriv *priv;
1531 AnjutaPluginHandle *plugin;
1533 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
1534 g_return_val_if_fail (plugin_id != NULL, FALSE);
1536 priv = plugin_manager->priv;
1538 plugin = g_hash_table_lookup (priv->plugins_by_name, plugin_id);
1539 if (plugin)
1541 plugin_set_update (plugin_manager, plugin, FALSE);
1543 /* Check if the plugin has been indeed unloaded */
1544 if (!g_hash_table_lookup (priv->activated_plugins, plugin))
1545 return TRUE;
1546 else
1547 return FALSE;
1549 g_warning ("No plugin found with id \"%s\".", plugin_id);
1550 return FALSE;
1553 static gboolean
1554 find_plugin_for_object (gpointer key, gpointer value, gpointer data)
1556 if (value == data)
1558 g_object_set_data (G_OBJECT (data), "__plugin_plugin", key);
1559 return TRUE;
1561 return FALSE;
1564 gboolean
1565 anjuta_plugin_manager_unload_plugin (AnjutaPluginManager *plugin_manager,
1566 GObject *plugin_object)
1568 AnjutaPluginManagerPriv *priv;
1569 AnjutaPluginHandle *plugin;
1571 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
1572 g_return_val_if_fail (ANJUTA_IS_PLUGIN (plugin_object), FALSE);
1574 priv = plugin_manager->priv;
1576 plugin = NULL;
1578 /* Find the plugin that correspond to this plugin object */
1579 g_hash_table_find (priv->activated_plugins, find_plugin_for_object,
1580 plugin_object);
1581 plugin = g_object_get_data (G_OBJECT (plugin_object), "__plugin_plugin");
1583 if (plugin)
1585 plugin_set_update (plugin_manager, plugin, FALSE);
1587 /* Check if the plugin has been indeed unloaded */
1588 if (!g_hash_table_lookup (priv->activated_plugins, plugin))
1589 return TRUE;
1590 else
1591 return FALSE;
1593 g_warning ("No plugin found with object \"%p\".", plugin_object);
1594 return FALSE;
1597 GList*
1598 anjuta_plugin_manager_query (AnjutaPluginManager *plugin_manager,
1599 const gchar *section_name,
1600 const gchar *attribute_name,
1601 const gchar *attribute_value,
1602 ...)
1604 AnjutaPluginManagerPriv *priv;
1605 va_list var_args;
1606 GList *secs = NULL;
1607 GList *anames = NULL;
1608 GList *avalues = NULL;
1609 const gchar *sec = section_name;
1610 const gchar *aname = attribute_name;
1611 const gchar *avalue = attribute_value;
1612 GList *selected_plugins = NULL;
1613 GList *available;
1616 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1618 priv = plugin_manager->priv;
1619 available = priv->available_plugins;
1621 if (section_name == NULL)
1623 /* If no query is given, select all plugins */
1624 while (available)
1626 AnjutaPluginHandle *plugin = available->data;
1627 AnjutaPluginDescription *desc =
1628 anjuta_plugin_handle_get_description (plugin);
1629 selected_plugins = g_list_prepend (selected_plugins, desc);
1630 available = g_list_next (available);
1632 return g_list_reverse (selected_plugins);
1635 g_return_val_if_fail (section_name != NULL, NULL);
1636 g_return_val_if_fail (attribute_name != NULL, NULL);
1637 g_return_val_if_fail (attribute_value != NULL, NULL);
1639 secs = g_list_prepend (secs, g_strdup (section_name));
1640 anames = g_list_prepend (anames, g_strdup (attribute_name));
1641 avalues = g_list_prepend (avalues, g_strdup (attribute_value));
1643 va_start (var_args, attribute_value);
1644 while (sec)
1646 sec = va_arg (var_args, const gchar *);
1647 if (sec)
1649 aname = va_arg (var_args, const gchar *);
1650 if (aname)
1652 avalue = va_arg (var_args, const gchar *);
1653 if (avalue)
1655 secs = g_list_prepend (secs, g_strdup (sec));
1656 anames = g_list_prepend (anames, g_strdup (aname));
1657 avalues = g_list_prepend (avalues, g_strdup (avalue));
1662 va_end (var_args);
1664 secs = g_list_reverse (secs);
1665 anames = g_list_reverse (anames);
1666 avalues = g_list_reverse (avalues);
1668 while (available)
1670 GList* s_node = secs;
1671 GList* n_node = anames;
1672 GList* v_node = avalues;
1674 gboolean satisfied = FALSE;
1676 AnjutaPluginHandle *plugin = available->data;
1677 AnjutaPluginDescription *desc =
1678 anjuta_plugin_handle_get_description (plugin);
1680 while (s_node)
1682 gchar *val;
1683 GList *vals;
1684 GList *node;
1685 gboolean found = FALSE;
1687 satisfied = TRUE;
1689 sec = s_node->data;
1690 aname = n_node->data;
1691 avalue = v_node->data;
1693 if (!anjuta_plugin_description_get_string (desc, sec, aname, &val))
1695 satisfied = FALSE;
1696 break;
1699 vals = property_to_list (val);
1700 g_free (val);
1702 node = vals;
1703 while (node)
1705 if (strchr(node->data, '*') != NULL)
1707 // Star match.
1708 gchar **segments;
1709 gchar **seg_ptr;
1710 const gchar *cursor;
1712 segments = g_strsplit (node->data, "*", -1);
1714 seg_ptr = segments;
1715 cursor = avalue;
1716 while (*seg_ptr != NULL)
1718 if (strlen (*seg_ptr) > 0) {
1719 cursor = strstr (cursor, *seg_ptr);
1720 if (cursor == NULL)
1721 break;
1723 cursor += strlen (*seg_ptr);
1724 seg_ptr++;
1726 if (*seg_ptr == NULL)
1727 found = TRUE;
1728 g_strfreev (segments);
1730 else if (g_ascii_strcasecmp (node->data, avalue) == 0)
1732 // String match.
1733 found = TRUE;
1735 g_free (node->data);
1736 node = g_list_next (node);
1738 g_list_free (vals);
1739 if (!found)
1741 satisfied = FALSE;
1742 break;
1744 s_node = g_list_next (s_node);
1745 n_node = g_list_next (n_node);
1746 v_node = g_list_next (v_node);
1748 if (satisfied)
1750 selected_plugins = g_list_prepend (selected_plugins, desc);
1751 /* DEBUG_PRINT ("Satisfied, Adding %s",
1752 anjuta_plugin_handle_get_name (plugin));*/
1754 available = g_list_next (available);
1756 anjuta_util_glist_strings_free (secs);
1757 anjuta_util_glist_strings_free (anames);
1758 anjuta_util_glist_strings_free (avalues);
1760 return g_list_reverse (selected_plugins);
1763 enum {
1764 PIXBUF_COLUMN,
1765 PLUGIN_COLUMN,
1766 PLUGIN_DESCRIPTION_COLUMN,
1767 N_COLUMNS
1770 static void
1771 on_plugin_list_row_activated (GtkTreeView *tree_view,
1772 GtkTreePath *path,
1773 GtkTreeViewColumn *column,
1774 GtkDialog *dialog)
1776 gtk_dialog_response (dialog, GTK_RESPONSE_OK);
1779 AnjutaPluginDescription *
1780 anjuta_plugin_manager_select (AnjutaPluginManager *plugin_manager,
1781 gchar *title, gchar *description,
1782 GList *plugin_descriptions)
1784 AnjutaPluginDescription *desc;
1785 AnjutaPluginManagerPriv *priv;
1786 GtkWidget *dlg;
1787 GtkTreeModel *model;
1788 GtkWidget *view;
1789 GtkTreeViewColumn *column;
1790 GtkCellRenderer *renderer;
1791 GList *node;
1792 GtkWidget *label;
1793 GtkWidget *sc;
1794 GtkWidget *remember_checkbox;
1795 gint response;
1796 GtkTreeIter selected;
1797 GtkTreeSelection *selection;
1798 GtkTreeModel *store;
1799 GList *selection_ids = NULL;
1800 GString *remember_key = g_string_new ("");
1802 g_return_val_if_fail (title != NULL, NULL);
1803 g_return_val_if_fail (description != NULL, NULL);
1804 g_return_val_if_fail (plugin_descriptions != NULL, NULL);
1806 priv = plugin_manager->priv;
1808 if (g_list_length (plugin_descriptions) <= 0)
1809 return NULL;
1811 dlg = gtk_dialog_new_with_buttons (title, GTK_WINDOW (priv->shell),
1812 GTK_DIALOG_DESTROY_WITH_PARENT,
1813 GTK_STOCK_CANCEL,
1814 GTK_RESPONSE_CANCEL,
1815 GTK_STOCK_OK, GTK_RESPONSE_OK,
1816 NULL);
1817 gtk_widget_set_size_request (dlg, 400, 300);
1818 gtk_window_set_default_size (GTK_WINDOW (dlg), 400, 300);
1820 label = gtk_label_new (description);
1821 gtk_widget_show (label);
1822 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), label,
1823 FALSE, FALSE, 5);
1825 sc = gtk_scrolled_window_new (NULL, NULL);
1826 gtk_widget_show (sc);
1827 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sc),
1828 GTK_SHADOW_IN);
1829 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sc),
1830 GTK_POLICY_AUTOMATIC,
1831 GTK_POLICY_AUTOMATIC);
1833 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dlg)->vbox), sc,
1834 TRUE, TRUE, 5);
1836 model = GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS, GDK_TYPE_PIXBUF,
1837 G_TYPE_STRING, G_TYPE_POINTER));
1838 view = gtk_tree_view_new_with_model (model);
1839 gtk_widget_show (view);
1840 gtk_container_add (GTK_CONTAINER (sc), view);
1842 column = gtk_tree_view_column_new ();
1843 gtk_tree_view_column_set_sizing (column,
1844 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1845 gtk_tree_view_column_set_title (column, _("Available Plugins"));
1847 renderer = gtk_cell_renderer_pixbuf_new ();
1848 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1849 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
1850 PIXBUF_COLUMN);
1852 renderer = gtk_cell_renderer_text_new ();
1853 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1854 gtk_tree_view_column_add_attribute (column, renderer, "markup",
1855 PLUGIN_COLUMN);
1857 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
1858 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (view), column);
1860 g_signal_connect (view, "row-activated",
1861 G_CALLBACK (on_plugin_list_row_activated),
1862 GTK_DIALOG(dlg));
1863 remember_checkbox =
1864 gtk_check_button_new_with_label (_("Remember this selection"));
1865 gtk_container_set_border_width (GTK_CONTAINER (remember_checkbox), 10);
1866 gtk_widget_show (remember_checkbox);
1867 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dlg)->vbox), remember_checkbox,
1868 FALSE, FALSE, 0);
1870 node = plugin_descriptions;
1871 while (node)
1873 GdkPixbuf *icon_pixbuf = NULL;
1874 gchar *plugin_name = NULL;
1875 gchar *plugin_desc = NULL;
1876 gchar *icon_filename = NULL;
1877 gchar *location = NULL;
1879 desc = (AnjutaPluginDescription*)node->data;
1881 if (anjuta_plugin_description_get_string (desc,
1882 "Anjuta Plugin",
1883 "Icon",
1884 &icon_filename))
1886 gchar *icon_path = NULL;
1887 icon_path = g_strconcat (PACKAGE_PIXMAPS_DIR"/",
1888 icon_filename, NULL);
1889 /* DEBUG_PRINT ("Icon: %s", icon_path); */
1890 icon_pixbuf =
1891 gdk_pixbuf_new_from_file (icon_path, NULL);
1892 if (icon_pixbuf == NULL)
1894 g_warning ("Plugin pixmap not found: %s", plugin_name);
1896 g_free (icon_path);
1898 else
1900 g_warning ("Plugin does not define Icon attribute");
1902 if (!anjuta_plugin_description_get_string (desc,
1903 "Anjuta Plugin",
1904 "Name",
1905 &plugin_name))
1907 g_warning ("Plugin does not define Name attribute");
1909 if (!anjuta_plugin_description_get_string (desc,
1910 "Anjuta Plugin",
1911 "Description",
1912 &plugin_desc))
1914 g_warning ("Plugin does not define Description attribute");
1916 if (!anjuta_plugin_description_get_string (desc,
1917 "Anjuta Plugin",
1918 "Location",
1919 &location))
1921 g_warning ("Plugin does not define Location attribute");
1924 if (plugin_name && plugin_desc)
1926 GtkTreeIter iter;
1927 gchar *text;
1929 text = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s", plugin_name, plugin_desc);
1931 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1932 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1933 PLUGIN_COLUMN, text,
1934 PLUGIN_DESCRIPTION_COLUMN, desc, -1);
1935 if (icon_pixbuf) {
1936 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1937 PIXBUF_COLUMN, icon_pixbuf, -1);
1938 g_object_unref (icon_pixbuf);
1940 g_free (text);
1942 selection_ids = g_list_prepend (selection_ids, location);
1944 node = g_list_next (node);
1947 /* Prepare remembering key */
1948 selection_ids = g_list_sort (selection_ids,
1949 (GCompareFunc)strcmp);
1950 node = selection_ids;
1951 while (node)
1953 g_string_append (remember_key, (gchar*)node->data);
1954 g_string_append (remember_key, ",");
1955 node = g_list_next (node);
1957 g_list_foreach (selection_ids, (GFunc) g_free, NULL);
1958 g_list_free (selection_ids);
1960 /* Find if the selection is remembered */
1961 desc = g_hash_table_lookup (priv->remember_plugins, remember_key->str);
1962 if (desc)
1964 g_string_free (remember_key, TRUE);
1965 gtk_widget_destroy (dlg);
1966 return desc;
1969 /* Prompt dialog */
1970 response = gtk_dialog_run (GTK_DIALOG (dlg));
1971 switch (response)
1973 case GTK_RESPONSE_OK:
1974 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
1975 if (gtk_tree_selection_get_selected (selection, &store,
1976 &selected))
1978 gtk_tree_model_get (model, &selected,
1979 PLUGIN_DESCRIPTION_COLUMN, &desc, -1);
1980 if (desc)
1982 /* Remember selection */
1983 if (gtk_toggle_button_get_active
1984 (GTK_TOGGLE_BUTTON (remember_checkbox)))
1986 /* DEBUG_PRINT ("Remembering selection '%s'",
1987 remember_key->str);*/
1988 g_hash_table_insert (priv->remember_plugins,
1989 g_strdup (remember_key->str), desc);
1991 g_string_free (remember_key, TRUE);
1992 gtk_widget_destroy (dlg);
1993 return desc;
1996 break;
1998 g_string_free (remember_key, TRUE);
1999 gtk_widget_destroy (dlg);
2000 return NULL;
2003 GObject*
2004 anjuta_plugin_manager_select_and_activate (AnjutaPluginManager *plugin_manager,
2005 gchar *title,
2006 gchar *description,
2007 GList *plugin_descriptions)
2009 AnjutaPluginDescription *d;
2011 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
2013 d = anjuta_plugin_manager_select (plugin_manager, title, description,
2014 plugin_descriptions);
2015 if (d)
2017 GObject *plugin = NULL;
2018 gchar *location = NULL;
2020 anjuta_plugin_description_get_string (d,
2021 "Anjuta Plugin",
2022 "Location",
2023 &location);
2024 g_return_val_if_fail (location != NULL, NULL);
2025 plugin =
2026 anjuta_plugin_manager_get_plugin_by_id (plugin_manager, location);
2027 g_free (location);
2028 return plugin;
2030 return NULL;
2033 /* Plugin manager */
2035 static void
2036 anjuta_plugin_manager_init (AnjutaPluginManager *object)
2038 object->priv = g_new0 (AnjutaPluginManagerPriv, 1);
2039 object->priv->plugins_by_name = g_hash_table_new (g_str_hash, g_str_equal);
2040 object->priv->plugins_by_interfaces = g_hash_table_new_full (g_str_hash,
2041 g_str_equal,
2042 NULL,
2043 (GDestroyNotify) g_list_free);
2044 object->priv->plugins_by_description = g_hash_table_new (g_direct_hash,
2045 g_direct_equal);
2046 object->priv->activated_plugins = g_hash_table_new (g_direct_hash,
2047 g_direct_equal);
2048 object->priv->plugins_cache = g_hash_table_new (g_direct_hash,
2049 g_direct_equal);
2050 object->priv->remember_plugins = g_hash_table_new_full (g_str_hash,
2051 g_str_equal,
2052 g_free, NULL);
2055 static void
2056 anjuta_plugin_manager_finalize (GObject *object)
2058 AnjutaPluginManagerPriv *priv;
2059 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2060 if (priv->available_plugins)
2062 /* anjuta_plugin_manager_unload_all_plugins (ANJUTA_PLUGIN_MANAGER (object)); */
2063 g_list_foreach (priv->available_plugins, (GFunc)g_object_unref, NULL);
2064 g_list_free (priv->available_plugins);
2065 priv->available_plugins = NULL;
2067 if (priv->activated_plugins)
2069 g_hash_table_destroy (priv->activated_plugins);
2070 priv->activated_plugins = NULL;
2072 if (priv->plugins_cache)
2074 g_hash_table_destroy (priv->plugins_cache);
2075 priv->plugins_cache = NULL;
2077 if (priv->plugins_by_name)
2079 g_hash_table_destroy (priv->plugins_by_name);
2080 priv->plugins_by_name = NULL;
2082 if (priv->plugins_by_description)
2084 g_hash_table_destroy (priv->plugins_by_description);
2085 priv->plugins_by_description = NULL;
2087 if (priv->plugins_by_interfaces)
2089 g_hash_table_destroy (priv->plugins_by_interfaces);
2090 priv->plugins_by_interfaces = NULL;
2092 if (priv->plugin_dirs)
2094 g_list_foreach (priv->plugin_dirs, (GFunc)g_free, NULL);
2095 g_list_free (priv->plugin_dirs);
2096 priv->plugin_dirs = NULL;
2098 #if 0
2099 if (plugin_types)
2101 g_hash_table_destroy (plugin_types);
2102 plugin_types = NULL;
2104 if (anjuta_glue_factory)
2106 g_object_unref (anjuta_glue_factory);
2107 anjuta_glue_factory = NULL;
2109 #endif
2110 G_OBJECT_CLASS (parent_class)->finalize (object);
2113 static void
2114 anjuta_plugin_manager_set_property (GObject *object, guint prop_id,
2115 const GValue *value, GParamSpec *pspec)
2117 AnjutaPluginManagerPriv *priv;
2119 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object));
2120 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2122 switch (prop_id)
2124 case PROP_STATUS:
2125 priv->status = g_value_get_object (value);
2126 break;
2127 case PROP_SHELL:
2128 priv->shell = g_value_get_object (value);
2129 break;
2130 default:
2131 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2132 break;
2136 static void
2137 anjuta_plugin_manager_get_property (GObject *object, guint prop_id,
2138 GValue *value, GParamSpec *pspec)
2140 AnjutaPluginManagerPriv *priv;
2142 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object));
2143 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2145 switch (prop_id)
2147 case PROP_SHELL:
2148 g_value_set_object (value, priv->shell);
2149 break;
2150 case PROP_STATUS:
2151 g_value_set_object (value, priv->status);
2152 break;
2153 case PROP_AVAILABLE_PLUGINS:
2154 g_value_set_pointer (value, priv->available_plugins);
2155 break;
2156 case PROP_ACTIVATED_PLUGINS:
2157 g_value_set_pointer (value, priv->activated_plugins);
2158 break;
2159 default:
2160 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2161 break;
2164 static void
2165 anjuta_plugin_manager_plugin_activated (AnjutaPluginManager *self,
2166 AnjutaPluginDescription* plugin_desc,
2167 GObject *plugin)
2169 /* TODO: Add default signal handler implementation here */
2172 static void
2173 anjuta_plugin_manager_plugin_deactivated (AnjutaPluginManager *self,
2174 AnjutaPluginDescription* plugin_desc,
2175 GObject *plugin)
2177 /* TODO: Add default signal handler implementation here */
2180 static void
2181 anjuta_plugin_manager_class_init (AnjutaPluginManagerClass *klass)
2183 GObjectClass* object_class = G_OBJECT_CLASS (klass);
2184 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
2186 object_class->finalize = anjuta_plugin_manager_finalize;
2187 object_class->set_property = anjuta_plugin_manager_set_property;
2188 object_class->get_property = anjuta_plugin_manager_get_property;
2190 klass->plugin_activated = anjuta_plugin_manager_plugin_activated;
2191 klass->plugin_deactivated = anjuta_plugin_manager_plugin_deactivated;
2193 g_object_class_install_property (object_class,
2194 PROP_PROFILES,
2195 g_param_spec_pointer ("profiles",
2196 _("Profiles"),
2197 _("Current stack of profiles"),
2198 G_PARAM_READABLE));
2199 g_object_class_install_property (object_class,
2200 PROP_AVAILABLE_PLUGINS,
2201 g_param_spec_pointer ("available-plugins",
2202 _("Available plugins"),
2203 _("Currently available plugins found in plugin paths"),
2204 G_PARAM_READABLE));
2206 g_object_class_install_property (object_class,
2207 PROP_ACTIVATED_PLUGINS,
2208 g_param_spec_pointer ("activated-plugins",
2209 _("Activated plugins"),
2210 _("Currently activated plugins"),
2211 G_PARAM_READABLE));
2212 g_object_class_install_property (object_class,
2213 PROP_SHELL,
2214 g_param_spec_object ("shell",
2215 _("Anjuta Shell"),
2216 _("Anjuta shell for which the plugins are"),
2217 G_TYPE_OBJECT,
2218 G_PARAM_READABLE |
2219 G_PARAM_WRITABLE |
2220 G_PARAM_CONSTRUCT));
2221 g_object_class_install_property (object_class,
2222 PROP_STATUS,
2223 g_param_spec_object ("status",
2224 _("Anjuta Status"),
2225 _("Anjuta status to use in loading and unloading of plugins"),
2226 ANJUTA_TYPE_STATUS,
2227 G_PARAM_READABLE |
2228 G_PARAM_WRITABLE |
2229 G_PARAM_CONSTRUCT));
2231 plugin_manager_signals[PLUGIN_ACTIVATED] =
2232 g_signal_new ("plugin-activated",
2233 G_OBJECT_CLASS_TYPE (klass),
2234 G_SIGNAL_RUN_FIRST,
2235 G_STRUCT_OFFSET (AnjutaPluginManagerClass,
2236 plugin_activated),
2237 NULL, NULL,
2238 anjuta_cclosure_marshal_VOID__POINTER_OBJECT,
2239 G_TYPE_NONE, 2,
2240 G_TYPE_POINTER, ANJUTA_TYPE_PLUGIN);
2242 plugin_manager_signals[PLUGIN_DEACTIVATED] =
2243 g_signal_new ("plugin-deactivated",
2244 G_OBJECT_CLASS_TYPE (klass),
2245 G_SIGNAL_RUN_FIRST,
2246 G_STRUCT_OFFSET (AnjutaPluginManagerClass,
2247 plugin_deactivated),
2248 NULL, NULL,
2249 anjuta_cclosure_marshal_VOID__POINTER_OBJECT,
2250 G_TYPE_NONE, 2,
2251 G_TYPE_POINTER, ANJUTA_TYPE_PLUGIN);
2254 GType
2255 anjuta_plugin_manager_get_type (void)
2257 static GType our_type = 0;
2259 if(our_type == 0)
2261 static const GTypeInfo our_info =
2263 sizeof (AnjutaPluginManagerClass), /* class_size */
2264 (GBaseInitFunc) NULL, /* base_init */
2265 (GBaseFinalizeFunc) NULL, /* base_finalize */
2266 (GClassInitFunc) anjuta_plugin_manager_class_init, /* class_init */
2267 (GClassFinalizeFunc) NULL, /* class_finalize */
2268 NULL /* class_data */,
2269 sizeof (AnjutaPluginManager), /* instance_size */
2270 0, /* n_preallocs */
2271 (GInstanceInitFunc) anjuta_plugin_manager_init, /* instance_init */
2272 NULL /* value_table */
2274 our_type = g_type_register_static (G_TYPE_OBJECT,
2275 "AnjutaPluginManager",
2276 &our_info, 0);
2279 return our_type;
2282 AnjutaPluginManager*
2283 anjuta_plugin_manager_new (GObject *shell, AnjutaStatus *status,
2284 GList* plugins_directories)
2286 GObject *manager_object;
2287 AnjutaPluginManager *plugin_manager;
2288 GList *cycles = NULL;
2289 const char *gnome2_path;
2290 char **pathv;
2291 char **p;
2292 GList *node;
2293 GList *plugin_dirs = NULL;
2295 /* Initialize the anjuta plugin system */
2296 manager_object = g_object_new (ANJUTA_TYPE_PLUGIN_MANAGER,
2297 "shell", shell, "status", status, NULL);
2298 plugin_manager = ANJUTA_PLUGIN_MANAGER (manager_object);
2300 if (anjuta_glue_factory == NULL)
2302 anjuta_glue_factory = anjuta_glue_factory_new ();
2305 gnome2_path = g_getenv ("GNOME2_PATH");
2306 if (gnome2_path) {
2307 pathv = g_strsplit (gnome2_path, ":", 1);
2309 for (p = pathv; *p != NULL; p++) {
2310 char *path = g_strdup (*p);
2311 plugin_dirs = g_list_prepend (plugin_dirs, path);
2312 anjuta_glue_factory_add_path (anjuta_glue_factory, path);
2314 g_strfreev (pathv);
2317 node = plugins_directories;
2318 while (node) {
2319 if (!node->data)
2320 continue;
2321 char *path = g_strdup (node->data);
2322 plugin_dirs = g_list_prepend (plugin_dirs, path);
2323 anjuta_glue_factory_add_path (anjuta_glue_factory, path);
2324 node = g_list_next (node);
2326 plugin_dirs = g_list_reverse (plugin_dirs);
2327 /* load_plugins (); */
2329 node = plugin_dirs;
2330 while (node)
2332 load_plugins_from_directory (plugin_manager, (char*)node->data);
2333 node = g_list_next (node);
2335 resolve_dependencies (plugin_manager, &cycles);
2336 return plugin_manager;
2339 void
2340 anjuta_plugin_manager_activate_plugins (AnjutaPluginManager *plugin_manager,
2341 GList *plugins_to_activate)
2343 AnjutaPluginManagerPriv *priv;
2344 GdkPixbuf *icon_pixbuf;
2345 GList *node;
2347 priv = plugin_manager->priv;
2349 /* Freeze shell operations */
2350 anjuta_shell_freeze (ANJUTA_SHELL (priv->shell), NULL);
2351 if (plugins_to_activate)
2353 anjuta_status_progress_add_ticks (ANJUTA_STATUS (priv->status),
2354 g_list_length (plugins_to_activate));
2356 node = plugins_to_activate;
2357 while (node)
2359 AnjutaPluginDescription *d;
2360 gchar *plugin_id;
2361 gchar *icon_filename, *label;
2362 gchar *icon_path = NULL;
2364 d = node->data;
2366 icon_pixbuf = NULL;
2367 label = NULL;
2368 if (anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2369 "Icon",
2370 &icon_filename))
2372 gchar *title, *description;
2373 anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2374 "Name",
2375 &title);
2376 anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2377 "Description",
2378 &description);
2379 icon_path = g_strconcat (PACKAGE_PIXMAPS_DIR"/",
2380 icon_filename, NULL);
2381 /* DEBUG_PRINT ("Icon: %s", icon_path); */
2382 label = g_strconcat (_("Loaded: "), title, _("..."), NULL);
2383 icon_pixbuf = gdk_pixbuf_new_from_file (icon_path, NULL);
2384 if (!icon_pixbuf)
2385 g_warning ("Plugin does not define Icon: No such file %s",
2386 icon_path);
2387 g_free (icon_path);
2388 g_free (icon_filename);
2391 if (anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2392 "Location", &plugin_id))
2394 GObject *plugin_obj;
2396 plugin_obj =
2397 anjuta_plugin_manager_get_plugin_by_id (plugin_manager,
2398 plugin_id);
2399 g_free (plugin_id);
2401 anjuta_status_progress_tick (ANJUTA_STATUS (priv->status),
2402 icon_pixbuf, label);
2403 g_free (label);
2404 if (icon_pixbuf)
2405 g_object_unref (icon_pixbuf);
2407 node = g_list_next (node);
2410 /* Thaw shell operations */
2411 anjuta_shell_thaw (ANJUTA_SHELL (priv->shell), NULL);
2414 static void
2415 on_collect (gpointer key, gpointer value, gpointer user_data)
2417 gchar *id;
2418 gchar *query = (gchar*) key;
2419 AnjutaPluginDescription *desc = (AnjutaPluginDescription *) value;
2420 GString *write_buffer = (GString *) user_data;
2422 anjuta_plugin_description_get_string (desc, "Anjuta Plugin", "Location",
2423 &id);
2424 g_string_append_printf (write_buffer, "%s=%s;", query, id);
2425 g_free (id);
2428 gchar*
2429 anjuta_plugin_manager_get_remembered_plugins (AnjutaPluginManager *plugin_manager)
2431 AnjutaPluginManagerPriv *priv;
2432 GString *write_buffer = g_string_new ("");
2434 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
2436 priv = plugin_manager->priv;
2437 g_hash_table_foreach (priv->remember_plugins, on_collect,
2438 write_buffer);
2439 return g_string_free (write_buffer, FALSE);
2442 static gboolean
2443 on_foreach_remove_true (gpointer k, gpointer v, gpointer d)
2445 return TRUE;
2448 void
2449 anjuta_plugin_manager_set_remembered_plugins (AnjutaPluginManager *plugin_manager,
2450 const gchar *remembered_plugins)
2452 AnjutaPluginManagerPriv *priv;
2453 gchar **strv_lines, **line_idx;
2455 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager));
2456 g_return_if_fail (remembered_plugins != NULL);
2458 priv = plugin_manager->priv;
2460 g_hash_table_foreach_remove (priv->remember_plugins,
2461 on_foreach_remove_true, NULL);
2463 strv_lines = g_strsplit (remembered_plugins, ";", -1);
2464 line_idx = strv_lines;
2465 while (*line_idx)
2467 gchar **strv_keyvals;
2468 strv_keyvals = g_strsplit (*line_idx, "=", -1);
2469 if (strv_keyvals && strv_keyvals[0] && strv_keyvals[1])
2471 AnjutaPluginHandle *plugin;
2472 plugin = g_hash_table_lookup (priv->plugins_by_name,
2473 strv_keyvals[1]);
2474 if (plugin)
2476 AnjutaPluginDescription *desc;
2477 desc = anjuta_plugin_handle_get_description (plugin);
2479 DEBUG_PRINT ("Restoring remember plugin: %s=%s",
2480 strv_keyvals[0],
2481 strv_keyvals[1]);
2483 g_hash_table_insert (priv->remember_plugins,
2484 g_strdup (strv_keyvals[0]), desc);
2486 g_strfreev (strv_keyvals);
2488 line_idx++;
2490 g_strfreev (strv_lines);