Updated Spanish translation
[anjuta-git-plugin.git] / libanjuta / anjuta-plugin-manager.c
blobacf6d68ab194c648571ccbfd586d75e583146b6a
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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-c-plugin-factory.h>
41 #include <libanjuta/interfaces/ianjuta-plugin-factory.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 AnjutaCPluginFactory *anjuta_plugin_factory = NULL;
111 static GObjectClass* parent_class = NULL;
112 static guint plugin_manager_signals[LAST_SIGNAL] = { 0 };
114 static GHashTable* plugin_set_update (AnjutaPluginManager *plugin_manager,
115 AnjutaPluginHandle* selected_plugin,
116 gboolean load);
118 static IAnjutaPluginFactory* get_plugin_factory (AnjutaPluginManager *plugin_manager,
119 const gchar *language, GError **error);
121 GQuark
122 anjuta_plugin_manager_error_quark (void)
124 static GQuark quark = 0;
126 if (quark == 0) {
127 quark = g_quark_from_static_string ("anjuta-plugin-manager-quark");
129 return quark;
132 /** Dependency Resolution **/
134 static gboolean
135 collect_cycle (AnjutaPluginManager *plugin_manager,
136 AnjutaPluginHandle *base_plugin, AnjutaPluginHandle *cur_plugin,
137 GList **cycle)
139 AnjutaPluginManagerPriv *priv;
140 GList *l;
142 priv = plugin_manager->priv;
144 for (l = anjuta_plugin_handle_get_dependency_names (cur_plugin);
145 l != NULL; l = l->next)
147 AnjutaPluginHandle *dep = g_hash_table_lookup (priv->plugins_by_name,
148 l->data);
149 if (dep)
151 if (dep == base_plugin)
153 *cycle = g_list_prepend (NULL, dep);
154 /* DEBUG_PRINT ("%s ", anjuta_plugin_handle_get_name (dep)); */
155 return TRUE;
157 else
159 if (collect_cycle (plugin_manager, base_plugin, dep, cycle))
161 *cycle = g_list_prepend (*cycle, dep);
162 /* DEBUG_PRINT ("%s ", anjuta_plugin_handle_get_name (dep)); */
163 return TRUE;
168 return FALSE;
171 static void
172 add_dependency (AnjutaPluginHandle *dependent, AnjutaPluginHandle *dependency)
174 g_hash_table_insert (anjuta_plugin_handle_get_dependents (dependency),
175 dependent, dependency);
176 g_hash_table_insert (anjuta_plugin_handle_get_dependencies (dependent),
177 dependency, dependent);
180 static void
181 child_dep_foreach_cb (gpointer key, gpointer value, gpointer user_data)
183 add_dependency (ANJUTA_PLUGIN_HANDLE (user_data),
184 ANJUTA_PLUGIN_HANDLE (key));
187 /* Resolves dependencies for a single module recursively. Shortcuts if
188 * the module has already been resolved. Returns a list representing
189 * any cycles found, or NULL if no cycles are found. If a cycle is found,
190 * the graph is left unresolved.
192 static GList*
193 resolve_for_module (AnjutaPluginManager *plugin_manager,
194 AnjutaPluginHandle *plugin, int pass)
196 AnjutaPluginManagerPriv *priv;
197 GList *l;
198 GList *ret = NULL;
200 priv = plugin_manager->priv;
202 if (anjuta_plugin_handle_get_checked (plugin))
204 return NULL;
207 if (anjuta_plugin_handle_get_resolve_pass (plugin) == pass)
209 GList *cycle = NULL;
210 g_warning ("cycle found: %s on pass %d",
211 anjuta_plugin_handle_get_name (plugin),
212 anjuta_plugin_handle_get_resolve_pass (plugin));
213 collect_cycle (plugin_manager, plugin, plugin, &cycle);
214 return cycle;
217 if (anjuta_plugin_handle_get_resolve_pass (plugin) != -1)
219 return NULL;
222 anjuta_plugin_handle_set_can_load (plugin, TRUE);
223 anjuta_plugin_handle_set_resolve_pass (plugin, pass);
225 for (l = anjuta_plugin_handle_get_dependency_names (plugin);
226 l != NULL; l = l->next)
228 char *dep = l->data;
229 AnjutaPluginHandle *child =
230 g_hash_table_lookup (priv->plugins_by_name, dep);
231 if (child)
233 ret = resolve_for_module (plugin_manager, child, pass);
234 if (ret)
236 break;
239 /* Add the dependency's dense dependency list
240 * to the current module's dense dependency list */
241 g_hash_table_foreach (anjuta_plugin_handle_get_dependencies (child),
242 child_dep_foreach_cb, plugin);
243 add_dependency (plugin, child);
245 /* If the child can't load due to dependency problems,
246 * the current module can't either */
247 anjuta_plugin_handle_set_can_load (plugin,
248 anjuta_plugin_handle_get_can_load (child));
249 } else {
250 g_warning ("Dependency %s not found.\n", dep);
251 anjuta_plugin_handle_set_can_load (plugin, FALSE);
252 ret = NULL;
255 anjuta_plugin_handle_set_checked (plugin, TRUE);
257 return ret;
260 /* Clean up the results of a resolving run */
261 static void
262 unresolve_dependencies (AnjutaPluginManager *plugin_manager)
264 AnjutaPluginManagerPriv *priv;
265 GList *l;
267 priv = plugin_manager->priv;
269 for (l = priv->available_plugins; l != NULL; l = l->next)
271 AnjutaPluginHandle *plugin = l->data;
272 anjuta_plugin_handle_unresolve_dependencies (plugin);
276 /* done upto here */
278 static void
279 prune_modules (AnjutaPluginManager *plugin_manager, GList *modules)
281 AnjutaPluginManagerPriv *priv;
282 GList *l;
284 priv = plugin_manager->priv;
286 for (l = modules; l != NULL; l = l->next) {
287 AnjutaPluginHandle *plugin = l->data;
289 g_hash_table_remove (priv->plugins_by_name,
290 anjuta_plugin_handle_get_id (plugin));
291 priv->available_plugins = g_list_remove (priv->available_plugins, plugin);
295 static int
296 dependency_compare (AnjutaPluginHandle *plugin_a,
297 AnjutaPluginHandle *plugin_b)
299 int a = g_hash_table_size (anjuta_plugin_handle_get_dependencies (plugin_a));
300 int b = g_hash_table_size (anjuta_plugin_handle_get_dependencies (plugin_b));
302 return a - b;
305 /* Resolves the dependencies of the priv->available_plugins list. When this
306 * function is complete, the following will be true:
308 * 1) The dependencies and dependents hash tables of the modules will
309 * be filled.
311 * 2) Cycles in the graph will be removed.
313 * 3) Modules which cannot be loaded due to failed dependencies will
314 * be marked as such.
316 * 4) priv->available_plugins will be sorted such that no module depends on a
317 * module after it.
319 * If a cycle in the graph is found, it is pruned from the tree and
320 * returned as a list stored in the cycles list.
322 static void
323 resolve_dependencies (AnjutaPluginManager *plugin_manager, GList **cycles)
325 AnjutaPluginManagerPriv *priv;
326 GList *cycle = NULL;
327 GList *l;
329 priv = plugin_manager->priv;
330 *cycles = NULL;
332 /* Try resolving dependencies. If there is a cycle, prune the
333 * cycle and try to resolve again */
336 int pass = 1;
337 cycle = NULL;
338 for (l = priv->available_plugins; l != NULL && !cycle; l = l->next) {
339 cycle = resolve_for_module (plugin_manager, l->data, pass++);
340 cycle = NULL;
342 if (cycle) {
343 *cycles = g_list_prepend (*cycles, cycle);
344 prune_modules (plugin_manager, cycle);
345 unresolve_dependencies (plugin_manager);
347 } while (cycle);
349 /* Now that there is a fully resolved dependency tree, sort
350 * priv->available_plugins to create a valid load order */
351 priv->available_plugins = g_list_sort (priv->available_plugins,
352 (GCompareFunc)dependency_compare);
355 /* Plugins loading */
357 static gboolean
358 str_has_suffix (const char *haystack, const char *needle)
360 const char *h, *n;
362 if (needle == NULL) {
363 return TRUE;
365 if (haystack == NULL) {
366 return needle[0] == '\0';
369 /* Eat one character at a time. */
370 h = haystack + strlen(haystack);
371 n = needle + strlen(needle);
372 do {
373 if (n == needle) {
374 return TRUE;
376 if (h == haystack) {
377 return FALSE;
379 } while (*--h == *--n);
380 return FALSE;
383 static void
384 load_plugin (AnjutaPluginManager *plugin_manager,
385 const gchar *plugin_desc_path)
387 AnjutaPluginManagerPriv *priv;
388 AnjutaPluginHandle *plugin_handle;
390 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager));
391 priv = plugin_manager->priv;
393 plugin_handle = anjuta_plugin_handle_new (plugin_desc_path);
394 if (plugin_handle)
396 if (g_hash_table_lookup (priv->plugins_by_name,
397 anjuta_plugin_handle_get_id (plugin_handle)))
399 g_object_unref (plugin_handle);
401 else
403 GList *node;
404 /* Available plugin */
405 priv->available_plugins = g_list_prepend (priv->available_plugins,
406 plugin_handle);
407 /* Index by id */
408 g_hash_table_insert (priv->plugins_by_name,
409 (gchar *)anjuta_plugin_handle_get_id (plugin_handle),
410 plugin_handle);
412 /* Index by description */
413 g_hash_table_insert (priv->plugins_by_description,
414 anjuta_plugin_handle_get_description (plugin_handle),
415 plugin_handle);
417 /* Index by interfaces exported by this plugin */
418 node = anjuta_plugin_handle_get_interfaces (plugin_handle);
419 while (node)
421 GList *objs;
422 gchar *iface;
423 GList *obj_node;
424 gboolean found;
426 iface = node->data;
427 objs = (GList*)g_hash_table_lookup (priv->plugins_by_interfaces, iface);
429 obj_node = objs;
430 found = FALSE;
431 while (obj_node)
433 if (obj_node->data == plugin_handle)
435 found = TRUE;
436 break;
438 obj_node = g_list_next (obj_node);
440 if (!found)
442 g_hash_table_steal (priv->plugins_by_interfaces, iface);
443 objs = g_list_prepend (objs, plugin_handle);
444 g_hash_table_insert (priv->plugins_by_interfaces, iface, objs);
446 node = g_list_next (node);
450 return;
453 static void
454 load_plugins_from_directory (AnjutaPluginManager* plugin_manager,
455 const gchar *dirname)
457 DIR *dir;
458 struct dirent *entry;
460 dir = opendir (dirname);
462 if (!dir)
464 return;
467 for (entry = readdir (dir); entry != NULL; entry = readdir (dir))
469 if (str_has_suffix (entry->d_name, ".plugin"))
471 gchar *pathname;
472 pathname = g_strdup_printf ("%s/%s", dirname, entry->d_name);
473 load_plugin (plugin_manager,pathname);
474 g_free (pathname);
477 closedir (dir);
480 /* Plugin activation and deactivation */
482 static void
483 on_plugin_activated (AnjutaPlugin *plugin_object, AnjutaPluginHandle *plugin)
485 AnjutaPluginManager *plugin_manager;
486 AnjutaPluginManagerPriv *priv;
488 /* FIXME: Pass plugin_manager directly in signal arguments */
489 plugin_manager = anjuta_shell_get_plugin_manager (plugin_object->shell, NULL);
491 g_return_if_fail(plugin_manager != NULL);
493 priv = plugin_manager->priv;
495 g_hash_table_insert (priv->activated_plugins, plugin,
496 G_OBJECT (plugin_object));
497 if (g_hash_table_lookup (priv->plugins_cache, plugin))
498 g_hash_table_remove (priv->plugins_cache, plugin);
500 g_signal_emit_by_name (plugin_manager, "plugin-activated",
501 anjuta_plugin_handle_get_description (plugin),
502 plugin_object);
505 static void
506 on_plugin_deactivated (AnjutaPlugin *plugin_object, AnjutaPluginHandle *plugin)
508 AnjutaPluginManager *plugin_manager;
509 AnjutaPluginManagerPriv *priv;
511 /* FIXME: Pass plugin_manager directly in signal arguments */
512 plugin_manager = anjuta_shell_get_plugin_manager (plugin_object->shell, NULL);
514 g_return_if_fail (plugin_manager != NULL);
516 priv = plugin_manager->priv;
518 g_hash_table_insert (priv->plugins_cache, plugin, G_OBJECT (plugin_object));
519 g_hash_table_remove (priv->activated_plugins, plugin);
521 g_signal_emit_by_name (plugin_manager, "plugin-deactivated",
522 anjuta_plugin_handle_get_description (plugin),
523 plugin_object);
526 static AnjutaPlugin*
527 activate_plugin (AnjutaPluginManager *plugin_manager,
528 AnjutaPluginHandle *handle, GError **error)
530 AnjutaPluginManagerPriv *priv;
531 IAnjutaPluginFactory* factory;
532 AnjutaPlugin *plugin;
533 const gchar *plugin_id;
534 const gchar *language;
535 gboolean resident;
537 priv = plugin_manager->priv;
539 plugin_id = anjuta_plugin_handle_get_id (handle);
541 resident = anjuta_plugin_handle_get_resident (handle);
542 language = anjuta_plugin_handle_get_language (handle);
544 factory = get_plugin_factory (plugin_manager, language, error);
545 if (factory == NULL) return NULL;
547 plugin = ianjuta_plugin_factory_new_plugin (factory, handle, ANJUTA_SHELL (priv->shell), error);
549 if (plugin == NULL)
551 return NULL;
553 g_signal_connect (plugin, "activated",
554 G_CALLBACK (on_plugin_activated), handle);
555 g_signal_connect (plugin, "deactivated",
556 G_CALLBACK (on_plugin_deactivated), handle);
558 return plugin;
561 static gboolean
562 g_hashtable_foreach_true (gpointer key, gpointer value, gpointer user_data)
564 return TRUE;
567 void
568 anjuta_plugin_manager_unload_all_plugins (AnjutaPluginManager *plugin_manager)
570 AnjutaPluginManagerPriv *priv;
572 priv = plugin_manager->priv;
573 if (g_hash_table_size (priv->activated_plugins) > 0 ||
574 g_hash_table_size (priv->plugins_cache) > 0)
576 priv->available_plugins = g_list_reverse (priv->available_plugins);
577 if (g_hash_table_size (priv->activated_plugins) > 0)
579 GList *node;
580 node = priv->available_plugins;
581 while (node)
583 AnjutaPluginHandle *selected_plugin = node->data;
584 if (g_hash_table_lookup (priv->activated_plugins, selected_plugin))
586 plugin_set_update (plugin_manager, selected_plugin, FALSE);
587 /* DEBUG_PRINT ("Unloading plugin: %s",
588 anjuta_plugin_handle_get_id (selected_plugin));
591 node = g_list_next (node);
593 g_hash_table_foreach_remove (priv->activated_plugins,
594 g_hashtable_foreach_true, NULL);
596 if (g_hash_table_size (priv->plugins_cache) > 0)
598 GList *node;
599 node = priv->available_plugins;
600 while (node)
602 GObject *plugin_obj;
603 AnjutaPluginHandle *selected_plugin = node->data;
605 plugin_obj = g_hash_table_lookup (priv->plugins_cache,
606 selected_plugin);
607 if (plugin_obj)
609 /* DEBUG_PRINT ("Destroying plugin: %s",
610 anjuta_plugin_handle_get_id (selected_plugin));
612 g_object_unref (plugin_obj);
614 node = g_list_next (node);
616 g_hash_table_foreach_remove (priv->plugins_cache,
617 g_hashtable_foreach_true, NULL);
619 priv->available_plugins = g_list_reverse (priv->available_plugins);
623 static gboolean
624 should_unload (GHashTable *activated_plugins, AnjutaPluginHandle *plugin_to_unload,
625 AnjutaPluginHandle *plugin)
627 GObject *plugin_obj = g_hash_table_lookup (activated_plugins, plugin);
629 if (!plugin_obj)
630 return FALSE;
632 if (plugin_to_unload == plugin)
633 return TRUE;
635 gboolean dependent =
636 GPOINTER_TO_INT (g_hash_table_lookup (anjuta_plugin_handle_get_dependents (plugin),
637 plugin));
638 return dependent;
641 static gboolean
642 should_load (GHashTable *activated_plugins, AnjutaPluginHandle *plugin_to_load,
643 AnjutaPluginHandle *plugin)
645 GObject *plugin_obj = g_hash_table_lookup (activated_plugins, plugin);
647 if (plugin_obj)
648 return FALSE;
650 if (plugin_to_load == plugin)
651 return anjuta_plugin_handle_get_can_load (plugin);
653 gboolean dependency =
654 GPOINTER_TO_INT (g_hash_table_lookup (anjuta_plugin_handle_get_dependencies (plugin_to_load),
655 plugin));
656 return (dependency && anjuta_plugin_handle_get_can_load (plugin));
659 static AnjutaPluginHandle *
660 plugin_for_iter (GtkListStore *store, GtkTreeIter *iter)
662 AnjutaPluginHandle *plugin;
664 gtk_tree_model_get (GTK_TREE_MODEL (store), iter, COL_PLUGIN, &plugin, -1);
665 return plugin;
668 static void
669 update_enabled (GtkTreeModel *model, GHashTable *activated_plugins)
671 GtkTreeIter iter;
673 if (gtk_tree_model_get_iter_first (model, &iter)) {
674 do {
675 AnjutaPluginHandle *plugin;
676 GObject *plugin_obj;
677 gboolean installed;
679 plugin = plugin_for_iter(GTK_LIST_STORE(model), &iter);
680 plugin_obj = g_hash_table_lookup (activated_plugins, plugin);
681 installed = (plugin_obj != NULL) ? TRUE : FALSE;
682 gtk_tree_model_get (model, &iter, COL_PLUGIN, &plugin, -1);
683 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
684 COL_ENABLED, installed, -1);
685 } while (gtk_tree_model_iter_next (model, &iter));
689 static GHashTable*
690 plugin_set_update (AnjutaPluginManager *plugin_manager,
691 AnjutaPluginHandle* selected_plugin,
692 gboolean load)
694 AnjutaPluginManagerPriv *priv;
695 GObject *plugin_obj;
696 GList *l;
698 priv = plugin_manager->priv;
699 plugin_obj = g_hash_table_lookup (priv->activated_plugins, selected_plugin);
701 if (plugin_obj && load)
703 g_warning ("Trying to install already installed plugin '%s'",
704 anjuta_plugin_handle_get_name (selected_plugin));
705 return priv->activated_plugins;
707 if (!plugin_obj && !load)
709 g_warning ("Trying to uninstall a not installed plugin '%s'",
710 anjuta_plugin_handle_get_name (selected_plugin));
711 return priv->activated_plugins;
714 if (priv->status)
715 anjuta_status_busy_push (priv->status);
717 if (!load)
719 /* reverse priv->available_plugins when unloading, so that plugins are
720 * unloaded in the right order */
721 priv->available_plugins = g_list_reverse (priv->available_plugins);
723 for (l = priv->available_plugins; l != NULL; l = l->next)
725 AnjutaPluginHandle *plugin = l->data;
726 if (should_unload (priv->activated_plugins, selected_plugin, plugin))
728 /* FIXME: Unload the class and sharedlib if possible */
729 AnjutaPlugin *anjuta_plugin = ANJUTA_PLUGIN (plugin_obj);
730 if (!anjuta_plugin_deactivate (ANJUTA_PLUGIN (anjuta_plugin)))
732 anjuta_util_dialog_info (GTK_WINDOW (priv->shell),
733 "Plugin '%s' do not want to be deactivated",
734 anjuta_plugin_handle_get_name (plugin));
738 priv->available_plugins = g_list_reverse (priv->available_plugins);
740 else
742 for (l = priv->available_plugins; l != NULL; l = l->next)
744 AnjutaPluginHandle *plugin = l->data;
745 if (should_load (priv->activated_plugins, selected_plugin, plugin))
747 AnjutaPlugin *plugin_obj;
748 GError *error = NULL;
749 plugin_obj = g_hash_table_lookup (priv->plugins_cache, plugin);
750 if (!plugin_obj)
752 plugin_obj = activate_plugin (plugin_manager, plugin,
753 &error);
756 if (plugin_obj)
758 anjuta_plugin_activate (ANJUTA_PLUGIN (plugin_obj));
760 else
762 if (error)
764 gchar* message = g_strdup_printf (_("Could not load %s\n"
765 "This usually means that your installation is corrupted. The "
766 "error message leading to this was:\n%s"),
767 anjuta_plugin_handle_get_name (selected_plugin),
768 error->message);
769 anjuta_util_dialog_error (GTK_WINDOW(plugin_manager->priv->shell),
770 message);
771 g_error_free (error);
772 g_free(message);
778 if (priv->status)
779 anjuta_status_busy_pop (priv->status);
780 return priv->activated_plugins;
783 static void
784 plugin_toggled (GtkCellRendererToggle *cell, char *path_str, gpointer data)
786 AnjutaPluginManager *plugin_manager;
787 AnjutaPluginManagerPriv *priv;
788 GtkListStore *store = GTK_LIST_STORE (data);
789 GtkTreeIter iter;
790 GtkTreePath *path;
791 AnjutaPluginHandle *plugin;
792 gboolean enabled;
793 GHashTable *activated_plugins;
795 path = gtk_tree_path_new_from_string (path_str);
797 plugin_manager = g_object_get_data (G_OBJECT (store), "plugin-manager");
798 priv = plugin_manager->priv;
800 gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
801 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
802 COL_ENABLED, &enabled,
803 COL_PLUGIN, &plugin,
804 -1);
806 enabled = !enabled;
808 activated_plugins = plugin_set_update (plugin_manager, plugin, enabled);
809 update_enabled (GTK_TREE_MODEL (store), activated_plugins);
810 gtk_tree_path_free (path);
813 #if 0
814 static void
815 selection_changed (GtkTreeSelection *selection, GtkListStore *store)
817 GtkTreeIter iter;
819 if (gtk_tree_selection_get_selected (selection, NULL,
820 &iter)) {
821 GtkTextBuffer *buffer;
823 GtkWidget *txt = g_object_get_data (G_OBJECT (store),
824 "AboutText");
826 GtkWidget *image = g_object_get_data (G_OBJECT (store),
827 "Icon");
828 AnjutaPluginHandle *plugin = plugin_for_iter (store, &iter);
830 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (txt));
831 gtk_text_buffer_set_text (buffer, plugin->about, -1);
833 if (plugin->icon_path) {
834 gtk_image_set_from_file (GTK_IMAGE (image),
835 plugin->icon_path);
836 gtk_widget_show (GTK_WIDGET (image));
837 } else {
838 gtk_widget_hide (GTK_WIDGET (image));
842 #endif
844 static GtkWidget *
845 create_plugin_tree (void)
847 GtkListStore *store;
848 GtkWidget *tree;
849 GtkCellRenderer *renderer;
850 GtkTreeViewColumn *column;
852 store = gtk_list_store_new (N_COLS,
853 G_TYPE_BOOLEAN,
854 G_TYPE_BOOLEAN,
855 GDK_TYPE_PIXBUF,
856 G_TYPE_STRING,
857 G_TYPE_POINTER);
858 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
860 renderer = gtk_cell_renderer_toggle_new ();
861 g_signal_connect (G_OBJECT (renderer), "toggled",
862 G_CALLBACK (plugin_toggled), store);
863 column = gtk_tree_view_column_new_with_attributes (_("Load"),
864 renderer,
865 "active",
866 COL_ENABLED,
867 "activatable",
868 COL_ACTIVABLE,
869 NULL);
870 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
871 gtk_tree_view_column_set_sizing (column,
872 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
874 column = gtk_tree_view_column_new ();
875 renderer = gtk_cell_renderer_pixbuf_new ();
876 gtk_tree_view_column_pack_start (column, renderer, FALSE);
877 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
878 COL_ICON);
879 renderer = gtk_cell_renderer_text_new ();
880 gtk_tree_view_column_pack_start (column, renderer, FALSE);
881 gtk_tree_view_column_add_attribute (column, renderer, "markup",
882 COL_NAME);
883 gtk_tree_view_column_set_sizing (column,
884 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
885 gtk_tree_view_column_set_title (column, _("Available Plugins"));
886 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
887 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (tree), column);
889 g_object_unref (store);
890 return tree;
893 /* Sort function for plugins */
894 static gint
895 sort_plugins(gconstpointer a, gconstpointer b)
897 g_return_val_if_fail (a != NULL, 0);
898 g_return_val_if_fail (b != NULL, 0);
900 AnjutaPluginHandle* plugin_a = ANJUTA_PLUGIN_HANDLE (a);
901 AnjutaPluginHandle* plugin_b = ANJUTA_PLUGIN_HANDLE (b);
903 return strcmp (anjuta_plugin_handle_get_name (plugin_a),
904 anjuta_plugin_handle_get_name (plugin_b));
907 /* If show_all == FALSE, show only user activatable plugins
908 * If show_all == TRUE, show all plugins
910 static void
911 populate_plugin_model (AnjutaPluginManager *plugin_manager,
912 GtkListStore *store,
913 GHashTable *plugins_to_show,
914 GHashTable *activated_plugins,
915 gboolean show_all)
917 AnjutaPluginManagerPriv *priv;
918 GList *l;
920 priv = plugin_manager->priv;
921 gtk_list_store_clear (store);
923 priv->available_plugins = g_list_sort (priv->available_plugins, sort_plugins);
925 for (l = priv->available_plugins; l != NULL; l = l->next)
927 AnjutaPluginHandle *plugin = l->data;
929 /* If plugins to show is NULL, show all available plugins */
930 if (plugins_to_show == NULL ||
931 g_hash_table_lookup (plugins_to_show, plugin))
934 gboolean enable = FALSE;
935 if (g_hash_table_lookup (activated_plugins, plugin))
936 enable = TRUE;
938 if (anjuta_plugin_handle_get_name (plugin) &&
939 anjuta_plugin_handle_get_description (plugin) &&
940 (anjuta_plugin_handle_get_user_activatable (plugin) ||
941 show_all))
943 GtkTreeIter iter;
944 gchar *text;
946 text = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
947 anjuta_plugin_handle_get_name (plugin),
948 anjuta_plugin_handle_get_about (plugin));
950 gtk_list_store_append (store, &iter);
951 gtk_list_store_set (store, &iter,
952 COL_ACTIVABLE,
953 anjuta_plugin_handle_get_user_activatable (plugin),
954 COL_ENABLED, enable,
955 COL_NAME, text,
956 COL_PLUGIN, plugin,
957 -1);
958 if (anjuta_plugin_handle_get_icon_path (plugin))
960 GdkPixbuf *icon;
961 icon = gdk_pixbuf_new_from_file_at_size (anjuta_plugin_handle_get_icon_path (plugin),
962 48, 48, NULL);
963 if (icon) {
964 gtk_list_store_set (store, &iter,
965 COL_ICON, icon, -1);
966 gdk_pixbuf_unref (icon);
969 g_free (text);
975 static GtkWidget *
976 create_remembered_plugins_tree (void)
978 GtkListStore *store;
979 GtkWidget *tree;
980 GtkCellRenderer *renderer;
981 GtkTreeViewColumn *column;
983 store = gtk_list_store_new (N_REM_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING,
984 G_TYPE_STRING);
985 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
987 column = gtk_tree_view_column_new ();
988 renderer = gtk_cell_renderer_pixbuf_new ();
989 gtk_tree_view_column_pack_start (column, renderer, FALSE);
990 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
991 COL_REM_ICON);
992 renderer = gtk_cell_renderer_text_new ();
993 gtk_tree_view_column_pack_start (column, renderer, FALSE);
994 gtk_tree_view_column_add_attribute (column, renderer, "markup",
995 COL_REM_NAME);
996 gtk_tree_view_column_set_sizing (column,
997 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
998 gtk_tree_view_column_set_title (column, _("Preferred plugins"));
999 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1000 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (tree), column);
1002 g_object_unref (store);
1003 return tree;
1006 static void
1007 foreach_remembered_plugin (gpointer key, gpointer value, gpointer user_data)
1009 AnjutaPluginDescription *desc = (AnjutaPluginDescription *) value;
1010 GtkListStore *store = GTK_LIST_STORE (user_data);
1011 AnjutaPluginManager *manager = g_object_get_data (G_OBJECT (store),
1012 "plugin-manager");
1013 AnjutaPluginHandle *plugin =
1014 g_hash_table_lookup (manager->priv->plugins_by_description, desc);
1015 g_return_if_fail (plugin != NULL);
1017 if (anjuta_plugin_handle_get_name (plugin) &&
1018 anjuta_plugin_handle_get_description (plugin))
1020 GtkTreeIter iter;
1021 gchar *text;
1023 text = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
1024 anjuta_plugin_handle_get_name (plugin),
1025 anjuta_plugin_handle_get_about (plugin));
1027 gtk_list_store_append (store, &iter);
1028 gtk_list_store_set (store, &iter,
1029 COL_REM_NAME, text,
1030 COL_REM_PLUGIN_KEY, key,
1031 -1);
1032 if (anjuta_plugin_handle_get_icon_path (plugin))
1034 GdkPixbuf *icon;
1035 icon = gdk_pixbuf_new_from_file_at_size (anjuta_plugin_handle_get_icon_path (plugin),
1036 48, 48, NULL);
1037 if (icon) {
1038 gtk_list_store_set (store, &iter,
1039 COL_REM_ICON, icon, -1);
1040 gdk_pixbuf_unref (icon);
1043 g_free (text);
1047 static void
1048 populate_remembered_plugins_model (AnjutaPluginManager *plugin_manager,
1049 GtkListStore *store)
1051 AnjutaPluginManagerPriv *priv = plugin_manager->priv;
1052 gtk_list_store_clear (store);
1053 g_hash_table_foreach (priv->remember_plugins, foreach_remembered_plugin,
1054 store);
1057 static void
1058 on_show_all_plugins_toggled (GtkToggleButton *button, GtkListStore *store)
1060 AnjutaPluginManager *plugin_manager;
1062 plugin_manager = g_object_get_data (G_OBJECT (button), "__plugin_manager");
1064 populate_plugin_model (plugin_manager, store, NULL,
1065 plugin_manager->priv->activated_plugins,
1066 !gtk_toggle_button_get_active (button));
1069 static void
1070 on_forget_plugin_clicked (GtkWidget *button, GtkTreeView *view)
1072 GtkTreeIter iter;
1073 GtkTreeModel *model;
1074 GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
1075 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1077 gchar *plugin_key;
1078 AnjutaPluginManager *manager = g_object_get_data (G_OBJECT (model),
1079 "plugin-manager");
1080 gtk_tree_model_get (model, &iter, COL_REM_PLUGIN_KEY, &plugin_key, -1);
1081 g_hash_table_remove (manager->priv->remember_plugins, plugin_key);
1082 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1083 g_free (plugin_key);
1087 static void
1088 on_forget_plugin_sel_changed (GtkTreeSelection *selection,
1089 GtkWidget *button)
1091 GtkTreeIter iter;
1093 if (gtk_tree_selection_get_selected (selection, NULL, &iter))
1094 gtk_widget_set_sensitive (button, TRUE);
1095 else
1096 gtk_widget_set_sensitive (button, FALSE);
1099 GtkWidget *
1100 anjuta_plugin_manager_get_plugins_page (AnjutaPluginManager *plugin_manager)
1102 GtkWidget *vbox;
1103 GtkWidget *checkbutton;
1104 GtkWidget *tree;
1105 GtkWidget *scrolled;
1106 GtkListStore *store;
1108 /* Plugins page */
1109 vbox = gtk_vbox_new (FALSE, 0);
1110 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
1112 checkbutton = gtk_check_button_new_with_label (_("Only show user activatable plugins"));
1113 gtk_container_set_border_width (GTK_CONTAINER (checkbutton), 10);
1114 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), TRUE);
1115 gtk_box_pack_start (GTK_BOX (vbox), checkbutton, FALSE, FALSE, 0);
1117 scrolled = gtk_scrolled_window_new (NULL, NULL);
1118 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
1119 GTK_SHADOW_IN);
1120 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1121 GTK_POLICY_AUTOMATIC,
1122 GTK_POLICY_AUTOMATIC);
1123 gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
1125 tree = create_plugin_tree ();
1126 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree)));
1128 populate_plugin_model (plugin_manager, store, NULL,
1129 plugin_manager->priv->activated_plugins, FALSE);
1131 gtk_container_add (GTK_CONTAINER (scrolled), tree);
1132 g_object_set_data (G_OBJECT (store), "plugin-manager", plugin_manager);
1135 g_object_set_data (G_OBJECT (checkbutton), "__plugin_manager", plugin_manager);
1136 g_signal_connect (G_OBJECT (checkbutton), "toggled",
1137 G_CALLBACK (on_show_all_plugins_toggled),
1138 store);
1139 gtk_widget_show_all (vbox);
1140 return vbox;
1143 GtkWidget *
1144 anjuta_plugin_manager_get_remembered_plugins_page (AnjutaPluginManager *plugin_manager)
1146 GtkWidget *vbox;
1147 GtkWidget *tree;
1148 GtkWidget *scrolled;
1149 GtkListStore *store;
1150 GtkWidget *hbox;
1151 GtkWidget *display_label;
1152 GtkWidget *forget_button;
1153 GtkTreeSelection *selection;
1155 /* Remembered plugin */
1156 vbox = gtk_vbox_new (FALSE, 10);
1157 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
1159 display_label = gtk_label_new (_("These are the plugins selected by you "
1160 "when Anjuta prompted to choose one of "
1161 "many suitable plugins. Removing the "
1162 "preferred plugin will let Anjuta prompt "
1163 "you again to choose different plugin."));
1164 gtk_label_set_line_wrap (GTK_LABEL (display_label), TRUE);
1165 gtk_box_pack_start (GTK_BOX (vbox), display_label, FALSE, FALSE, 0);
1167 scrolled = gtk_scrolled_window_new (NULL, NULL);
1168 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
1169 GTK_SHADOW_IN);
1170 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1171 GTK_POLICY_AUTOMATIC,
1172 GTK_POLICY_AUTOMATIC);
1173 gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
1175 tree = create_remembered_plugins_tree ();
1176 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree)));
1178 gtk_container_add (GTK_CONTAINER (scrolled), tree);
1179 g_object_set_data (G_OBJECT (store), "plugin-manager", plugin_manager);
1180 populate_remembered_plugins_model (plugin_manager, store);
1182 hbox = gtk_hbox_new (FALSE, 0);
1183 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
1184 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1185 forget_button = gtk_button_new_with_label ("Forget selected plugin");
1186 gtk_widget_set_sensitive (forget_button, FALSE);
1187 gtk_box_pack_end (GTK_BOX (hbox), forget_button, FALSE, FALSE, 0);
1189 g_signal_connect (forget_button, "clicked",
1190 G_CALLBACK (on_forget_plugin_clicked),
1191 tree);
1192 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
1193 g_signal_connect (selection, "changed",
1194 G_CALLBACK (on_forget_plugin_sel_changed),
1195 forget_button);
1196 gtk_widget_show_all (vbox);
1197 return vbox;
1200 static GList *
1201 property_to_list (const char *value)
1203 GList *l = NULL;
1204 char **split_str;
1205 char **p;
1207 split_str = g_strsplit (value, ",", -1);
1208 for (p = split_str; *p != NULL; p++) {
1209 l = g_list_prepend (l, g_strdup (g_strstrip (*p)));
1211 g_strfreev (split_str);
1212 return l;
1215 static IAnjutaPluginFactory*
1216 get_plugin_factory (AnjutaPluginManager *plugin_manager,
1217 const gchar *language,
1218 GError **error)
1220 AnjutaPluginManagerPriv *priv;
1221 AnjutaPluginHandle *plugin;
1222 GList *loader_plugins, *node;
1223 GList *valid_plugins;
1224 GObject *obj = NULL;
1226 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), G_TYPE_INVALID);
1229 if ((language == NULL) || (g_ascii_strcasecmp (language, "C") == 0))
1231 /* Support of C plugin is built-in */
1232 return IANJUTA_PLUGIN_FACTORY (anjuta_plugin_factory);
1235 priv = plugin_manager->priv;
1236 plugin = NULL;
1238 /* Find all plugins implementing the IAnjutaPluginLoader interface. */
1239 loader_plugins = g_hash_table_lookup (priv->plugins_by_interfaces, "IAnjutaPluginLoader");
1241 /* Create a list of loader supporting this language */
1242 node = loader_plugins;
1243 valid_plugins = NULL;
1244 while (node)
1246 AnjutaPluginDescription *desc;
1247 gchar *val;
1248 GList *vals = NULL;
1249 GList *l_node;
1250 gboolean found;
1252 plugin = node->data;
1254 desc = anjuta_plugin_handle_get_description (plugin);
1255 if (anjuta_plugin_description_get_string (desc, "Plugin Loader", "SupportedLanguage", &val))
1257 if (val != NULL)
1259 vals = property_to_list (val);
1260 g_free (val);
1264 found = FALSE;
1265 l_node = vals;
1266 while (l_node)
1268 if (!found && (g_ascii_strcasecmp (l_node->data, language) == 0))
1270 found = TRUE;
1272 g_free (l_node->data);
1273 l_node = g_list_next (l_node);
1275 g_list_free (vals);
1277 if (found)
1279 valid_plugins = g_list_prepend (valid_plugins, plugin);
1282 node = g_list_next (node);
1285 /* Find the first installed plugin from the valid plugins */
1286 node = valid_plugins;
1287 while (node)
1289 plugin = node->data;
1290 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1291 if (obj) break;
1292 node = g_list_next (node);
1295 /* If no plugin is installed yet, do something */
1296 if ((obj == NULL) && valid_plugins && g_list_length (valid_plugins) == 1)
1298 /* If there is just one plugin, consider it selected */
1299 plugin = valid_plugins->data;
1301 /* Install and return it */
1302 plugin_set_update (plugin_manager, plugin, TRUE);
1303 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1305 else if ((obj == NULL) && valid_plugins)
1307 /* Prompt the user to select one of these plugins */
1309 GList *descs = NULL;
1310 node = valid_plugins;
1311 while (node)
1313 plugin = node->data;
1314 descs = g_list_prepend (descs, anjuta_plugin_handle_get_description (plugin));
1315 node = g_list_next (node);
1317 descs = g_list_reverse (descs);
1318 obj = anjuta_plugin_manager_select_and_activate (plugin_manager,
1319 _("Select a plugin"),
1320 _("Please select a plugin to activate"),
1321 descs);
1322 g_list_free (descs);
1324 g_list_free (valid_plugins);
1326 if (obj != NULL)
1328 return IANJUTA_PLUGIN_FACTORY (obj);
1331 /* No plugin implementing this interface found */
1332 g_set_error (error, ANJUTA_PLUGIN_MANAGER_ERROR,
1333 ANJUTA_PLUGIN_MANAGER_MISSING_FACTORY,
1334 _("No plugin able to load other plugins in %s"), language);
1336 return NULL;
1340 * anjuta_plugin_manager_get_plugin:
1341 * @plugin_manager: A #AnjutaPluginManager object
1342 * @iface_name: The interface implemented by the object to be found
1344 * Searches the currently available plugins to find the one which
1345 * implements the given interface as primary interface and returns it. If
1346 * the plugin is not yet loaded, it will be loaded and activated.
1347 * The returned object is garanteed to be an implementor of the
1348 * interface (as exported by the plugin metafile). It only searches
1349 * from the pool of plugin objects loaded in this shell and can only search
1350 * by primary interface. If there are more objects implementing this primary
1351 * interface, user might be prompted to select one from them (and might give
1352 * the option to use it as default for future queries). A typical usage of this
1353 * function is:
1354 * <programlisting>
1355 * GObject *docman =
1356 * anjuta_plugin_manager_get_plugin (plugin_manager, "IAnjutaDocumentManager", error);
1357 * </programlisting>
1358 * Notice that this function takes the interface name string as string, unlike
1359 * anjuta_plugins_get_interface() which takes the type directly.
1361 * Return value: The plugin object (subclass of #AnjutaPlugin) which implements
1362 * the given interface. See #AnjutaPlugin for more detail on interfaces
1363 * implemented by plugins.
1365 GObject *
1366 anjuta_plugin_manager_get_plugin (AnjutaPluginManager *plugin_manager,
1367 const gchar *iface_name)
1369 AnjutaPluginManagerPriv *priv;
1370 AnjutaPluginHandle *plugin;
1371 GList *valid_plugins, *node;
1373 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1374 g_return_val_if_fail (iface_name != NULL, NULL);
1376 priv = plugin_manager->priv;
1377 plugin = NULL;
1379 /* Find all plugins implementing this (primary) interface. */
1380 valid_plugins = g_hash_table_lookup (priv->plugins_by_interfaces, iface_name);
1382 /* Find the first installed plugin from the valid plugins */
1383 node = valid_plugins;
1384 while (node)
1386 GObject *obj;
1387 plugin = node->data;
1388 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1389 if (obj)
1390 return obj;
1391 node = g_list_next (node);
1394 /* If no plugin is installed yet, do something */
1395 if (valid_plugins && g_list_length (valid_plugins) == 1)
1397 /* If there is just one plugin, consider it selected */
1398 GObject *obj;
1399 plugin = valid_plugins->data;
1401 /* Install and return it */
1402 plugin_set_update (plugin_manager, plugin, TRUE);
1403 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1405 return obj;
1407 else if (valid_plugins)
1409 /* Prompt the user to select one of these plugins */
1410 GObject *obj;
1411 GList *descs = NULL;
1412 node = valid_plugins;
1413 while (node)
1415 plugin = node->data;
1416 descs = g_list_prepend (descs, anjuta_plugin_handle_get_description (plugin));
1417 node = g_list_next (node);
1419 descs = g_list_reverse (descs);
1420 obj = anjuta_plugin_manager_select_and_activate (plugin_manager,
1421 _("Select a plugin"),
1422 _("Please select a plugin to activate"),
1423 descs);
1424 g_list_free (descs);
1425 return obj;
1428 /* No plugin implementing this interface found */
1429 g_warning ("No plugin found implementing %s Interface.", iface_name);
1430 return NULL;
1433 GObject *
1434 anjuta_plugin_manager_get_plugin_by_id (AnjutaPluginManager *plugin_manager,
1435 const gchar *plugin_id)
1437 AnjutaPluginManagerPriv *priv;
1438 AnjutaPluginHandle *plugin;
1440 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1441 g_return_val_if_fail (plugin_id != NULL, NULL);
1443 priv = plugin_manager->priv;
1444 plugin = g_hash_table_lookup (priv->plugins_by_name, plugin_id);
1445 if (plugin)
1447 GObject *obj;
1448 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1449 if (obj)
1451 return obj;
1452 } else
1454 plugin_set_update (plugin_manager, plugin, TRUE);
1455 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1456 return obj;
1459 g_warning ("No plugin found with id \"%s\".", plugin_id);
1460 return NULL;
1463 static void
1464 on_activated_plugins_foreach (gpointer key, gpointer data, gpointer user_data)
1466 AnjutaPluginHandle *plugin = ANJUTA_PLUGIN_HANDLE (key);
1467 GList **active_plugins = (GList **)user_data;
1468 *active_plugins = g_list_prepend (*active_plugins,
1469 anjuta_plugin_handle_get_description (plugin));
1472 static void
1473 on_activated_plugin_objects_foreach (gpointer key, gpointer data, gpointer user_data)
1475 GList **active_plugins = (GList **)user_data;
1476 *active_plugins = g_list_prepend (*active_plugins,
1477 data);
1480 GList*
1481 anjuta_plugin_manager_get_active_plugins (AnjutaPluginManager *plugin_manager)
1483 GList *active_plugins = NULL;
1485 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1486 g_hash_table_foreach (plugin_manager->priv->activated_plugins,
1487 on_activated_plugins_foreach,
1488 &active_plugins);
1489 return g_list_reverse (active_plugins);
1492 GList*
1493 anjuta_plugin_manager_get_active_plugin_objects (AnjutaPluginManager *plugin_manager)
1495 GList *active_plugins = NULL;
1497 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1498 g_hash_table_foreach (plugin_manager->priv->activated_plugins,
1499 on_activated_plugin_objects_foreach,
1500 &active_plugins);
1501 return g_list_reverse (active_plugins);
1504 gboolean
1505 anjuta_plugin_manager_unload_plugin_by_id (AnjutaPluginManager *plugin_manager,
1506 const gchar *plugin_id)
1508 AnjutaPluginManagerPriv *priv;
1509 AnjutaPluginHandle *plugin;
1511 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
1512 g_return_val_if_fail (plugin_id != NULL, FALSE);
1514 priv = plugin_manager->priv;
1516 plugin = g_hash_table_lookup (priv->plugins_by_name, plugin_id);
1517 if (plugin)
1519 plugin_set_update (plugin_manager, plugin, FALSE);
1521 /* Check if the plugin has been indeed unloaded */
1522 if (!g_hash_table_lookup (priv->activated_plugins, plugin))
1523 return TRUE;
1524 else
1525 return FALSE;
1527 g_warning ("No plugin found with id \"%s\".", plugin_id);
1528 return FALSE;
1531 static gboolean
1532 find_plugin_for_object (gpointer key, gpointer value, gpointer data)
1534 if (value == data)
1536 g_object_set_data (G_OBJECT (data), "__plugin_plugin", key);
1537 return TRUE;
1539 return FALSE;
1542 gboolean
1543 anjuta_plugin_manager_unload_plugin (AnjutaPluginManager *plugin_manager,
1544 GObject *plugin_object)
1546 AnjutaPluginManagerPriv *priv;
1547 AnjutaPluginHandle *plugin;
1549 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
1550 g_return_val_if_fail (ANJUTA_IS_PLUGIN (plugin_object), FALSE);
1552 priv = plugin_manager->priv;
1554 plugin = NULL;
1556 /* Find the plugin that correspond to this plugin object */
1557 g_hash_table_find (priv->activated_plugins, find_plugin_for_object,
1558 plugin_object);
1559 plugin = g_object_get_data (G_OBJECT (plugin_object), "__plugin_plugin");
1561 if (plugin)
1563 plugin_set_update (plugin_manager, plugin, FALSE);
1565 /* Check if the plugin has been indeed unloaded */
1566 if (!g_hash_table_lookup (priv->activated_plugins, plugin))
1567 return TRUE;
1568 else
1569 return FALSE;
1571 g_warning ("No plugin found with object \"%p\".", plugin_object);
1572 return FALSE;
1575 GList*
1576 anjuta_plugin_manager_query (AnjutaPluginManager *plugin_manager,
1577 const gchar *section_name,
1578 const gchar *attribute_name,
1579 const gchar *attribute_value,
1580 ...)
1582 AnjutaPluginManagerPriv *priv;
1583 va_list var_args;
1584 GList *secs = NULL;
1585 GList *anames = NULL;
1586 GList *avalues = NULL;
1587 const gchar *sec = section_name;
1588 const gchar *aname = attribute_name;
1589 const gchar *avalue = attribute_value;
1590 GList *selected_plugins = NULL;
1591 GList *available;
1594 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1596 priv = plugin_manager->priv;
1597 available = priv->available_plugins;
1599 if (section_name == NULL)
1601 /* If no query is given, select all plugins */
1602 while (available)
1604 AnjutaPluginHandle *plugin = available->data;
1605 AnjutaPluginDescription *desc =
1606 anjuta_plugin_handle_get_description (plugin);
1607 selected_plugins = g_list_prepend (selected_plugins, desc);
1608 available = g_list_next (available);
1610 return g_list_reverse (selected_plugins);
1613 g_return_val_if_fail (section_name != NULL, NULL);
1614 g_return_val_if_fail (attribute_name != NULL, NULL);
1615 g_return_val_if_fail (attribute_value != NULL, NULL);
1617 secs = g_list_prepend (secs, g_strdup (section_name));
1618 anames = g_list_prepend (anames, g_strdup (attribute_name));
1619 avalues = g_list_prepend (avalues, g_strdup (attribute_value));
1621 va_start (var_args, attribute_value);
1622 while (sec)
1624 sec = va_arg (var_args, const gchar *);
1625 if (sec)
1627 aname = va_arg (var_args, const gchar *);
1628 if (aname)
1630 avalue = va_arg (var_args, const gchar *);
1631 if (avalue)
1633 secs = g_list_prepend (secs, g_strdup (sec));
1634 anames = g_list_prepend (anames, g_strdup (aname));
1635 avalues = g_list_prepend (avalues, g_strdup (avalue));
1640 va_end (var_args);
1642 secs = g_list_reverse (secs);
1643 anames = g_list_reverse (anames);
1644 avalues = g_list_reverse (avalues);
1646 while (available)
1648 GList* s_node = secs;
1649 GList* n_node = anames;
1650 GList* v_node = avalues;
1652 gboolean satisfied = FALSE;
1654 AnjutaPluginHandle *plugin = available->data;
1655 AnjutaPluginDescription *desc =
1656 anjuta_plugin_handle_get_description (plugin);
1658 while (s_node)
1660 gchar *val;
1661 GList *vals;
1662 GList *node;
1663 gboolean found = FALSE;
1665 satisfied = TRUE;
1667 sec = s_node->data;
1668 aname = n_node->data;
1669 avalue = v_node->data;
1671 if (!anjuta_plugin_description_get_string (desc, sec, aname, &val))
1673 satisfied = FALSE;
1674 break;
1677 vals = property_to_list (val);
1678 g_free (val);
1680 node = vals;
1681 while (node)
1683 if (strchr(node->data, '*') != NULL)
1685 // Star match.
1686 gchar **segments;
1687 gchar **seg_ptr;
1688 const gchar *cursor;
1690 segments = g_strsplit (node->data, "*", -1);
1692 seg_ptr = segments;
1693 cursor = avalue;
1694 while (*seg_ptr != NULL)
1696 if (strlen (*seg_ptr) > 0) {
1697 cursor = strstr (cursor, *seg_ptr);
1698 if (cursor == NULL)
1699 break;
1701 cursor += strlen (*seg_ptr);
1702 seg_ptr++;
1704 if (*seg_ptr == NULL)
1705 found = TRUE;
1706 g_strfreev (segments);
1708 else if (g_ascii_strcasecmp (node->data, avalue) == 0)
1710 // String match.
1711 found = TRUE;
1713 g_free (node->data);
1714 node = g_list_next (node);
1716 g_list_free (vals);
1717 if (!found)
1719 satisfied = FALSE;
1720 break;
1722 s_node = g_list_next (s_node);
1723 n_node = g_list_next (n_node);
1724 v_node = g_list_next (v_node);
1726 if (satisfied)
1728 selected_plugins = g_list_prepend (selected_plugins, desc);
1729 /* DEBUG_PRINT ("Satisfied, Adding %s",
1730 anjuta_plugin_handle_get_name (plugin));*/
1732 available = g_list_next (available);
1734 anjuta_util_glist_strings_free (secs);
1735 anjuta_util_glist_strings_free (anames);
1736 anjuta_util_glist_strings_free (avalues);
1738 return g_list_reverse (selected_plugins);
1741 enum {
1742 PIXBUF_COLUMN,
1743 PLUGIN_COLUMN,
1744 PLUGIN_DESCRIPTION_COLUMN,
1745 N_COLUMNS
1748 static void
1749 on_plugin_list_row_activated (GtkTreeView *tree_view,
1750 GtkTreePath *path,
1751 GtkTreeViewColumn *column,
1752 GtkDialog *dialog)
1754 gtk_dialog_response (dialog, GTK_RESPONSE_OK);
1757 AnjutaPluginDescription *
1758 anjuta_plugin_manager_select (AnjutaPluginManager *plugin_manager,
1759 gchar *title, gchar *description,
1760 GList *plugin_descriptions)
1762 AnjutaPluginDescription *desc;
1763 AnjutaPluginManagerPriv *priv;
1764 GtkWidget *dlg;
1765 GtkTreeModel *model;
1766 GtkWidget *view;
1767 GtkTreeViewColumn *column;
1768 GtkCellRenderer *renderer;
1769 GList *node;
1770 GtkWidget *label;
1771 GtkWidget *sc;
1772 GtkWidget *remember_checkbox;
1773 gint response;
1774 GtkTreeIter selected;
1775 GtkTreeSelection *selection;
1776 GtkTreeModel *store;
1777 GList *selection_ids = NULL;
1778 GString *remember_key = g_string_new ("");
1780 g_return_val_if_fail (title != NULL, NULL);
1781 g_return_val_if_fail (description != NULL, NULL);
1782 g_return_val_if_fail (plugin_descriptions != NULL, NULL);
1784 priv = plugin_manager->priv;
1786 if (g_list_length (plugin_descriptions) <= 0)
1787 return NULL;
1789 dlg = gtk_dialog_new_with_buttons (title, GTK_WINDOW (priv->shell),
1790 GTK_DIALOG_DESTROY_WITH_PARENT,
1791 GTK_STOCK_CANCEL,
1792 GTK_RESPONSE_CANCEL,
1793 GTK_STOCK_OK, GTK_RESPONSE_OK,
1794 NULL);
1795 gtk_widget_set_size_request (dlg, 400, 300);
1796 gtk_window_set_default_size (GTK_WINDOW (dlg), 400, 300);
1798 label = gtk_label_new (description);
1799 gtk_widget_show (label);
1800 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), label,
1801 FALSE, FALSE, 5);
1803 sc = gtk_scrolled_window_new (NULL, NULL);
1804 gtk_widget_show (sc);
1805 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sc),
1806 GTK_SHADOW_IN);
1807 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sc),
1808 GTK_POLICY_AUTOMATIC,
1809 GTK_POLICY_AUTOMATIC);
1811 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dlg)->vbox), sc,
1812 TRUE, TRUE, 5);
1814 model = GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS, GDK_TYPE_PIXBUF,
1815 G_TYPE_STRING, G_TYPE_POINTER));
1816 view = gtk_tree_view_new_with_model (model);
1817 gtk_widget_show (view);
1818 gtk_container_add (GTK_CONTAINER (sc), view);
1820 column = gtk_tree_view_column_new ();
1821 gtk_tree_view_column_set_sizing (column,
1822 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1823 gtk_tree_view_column_set_title (column, _("Available Plugins"));
1825 renderer = gtk_cell_renderer_pixbuf_new ();
1826 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1827 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
1828 PIXBUF_COLUMN);
1830 renderer = gtk_cell_renderer_text_new ();
1831 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1832 gtk_tree_view_column_add_attribute (column, renderer, "markup",
1833 PLUGIN_COLUMN);
1835 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
1836 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (view), column);
1838 g_signal_connect (view, "row-activated",
1839 G_CALLBACK (on_plugin_list_row_activated),
1840 GTK_DIALOG(dlg));
1841 remember_checkbox =
1842 gtk_check_button_new_with_label (_("Remember this selection"));
1843 gtk_container_set_border_width (GTK_CONTAINER (remember_checkbox), 10);
1844 gtk_widget_show (remember_checkbox);
1845 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dlg)->vbox), remember_checkbox,
1846 FALSE, FALSE, 0);
1848 node = plugin_descriptions;
1849 while (node)
1851 GdkPixbuf *icon_pixbuf = NULL;
1852 gchar *plugin_name = NULL;
1853 gchar *plugin_desc = NULL;
1854 gchar *icon_filename = NULL;
1855 gchar *location = NULL;
1857 desc = (AnjutaPluginDescription*)node->data;
1859 if (anjuta_plugin_description_get_string (desc,
1860 "Anjuta Plugin",
1861 "Icon",
1862 &icon_filename))
1864 gchar *icon_path = NULL;
1865 icon_path = g_strconcat (PACKAGE_PIXMAPS_DIR"/",
1866 icon_filename, NULL);
1867 /* DEBUG_PRINT ("Icon: %s", icon_path); */
1868 icon_pixbuf =
1869 gdk_pixbuf_new_from_file (icon_path, NULL);
1870 if (icon_pixbuf == NULL)
1872 g_warning ("Plugin pixmap not found: %s", plugin_name);
1874 g_free (icon_path);
1876 else
1878 g_warning ("Plugin does not define Icon attribute");
1880 if (!anjuta_plugin_description_get_string (desc,
1881 "Anjuta Plugin",
1882 "Name",
1883 &plugin_name))
1885 g_warning ("Plugin does not define Name attribute");
1887 if (!anjuta_plugin_description_get_string (desc,
1888 "Anjuta Plugin",
1889 "Description",
1890 &plugin_desc))
1892 g_warning ("Plugin does not define Description attribute");
1894 if (!anjuta_plugin_description_get_string (desc,
1895 "Anjuta Plugin",
1896 "Location",
1897 &location))
1899 g_warning ("Plugin does not define Location attribute");
1902 if (plugin_name && plugin_desc)
1904 GtkTreeIter iter;
1905 gchar *text;
1907 text = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s", plugin_name, plugin_desc);
1909 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1910 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1911 PLUGIN_COLUMN, text,
1912 PLUGIN_DESCRIPTION_COLUMN, desc, -1);
1913 if (icon_pixbuf) {
1914 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1915 PIXBUF_COLUMN, icon_pixbuf, -1);
1916 g_object_unref (icon_pixbuf);
1918 g_free (text);
1920 selection_ids = g_list_prepend (selection_ids, location);
1922 node = g_list_next (node);
1925 /* Prepare remembering key */
1926 selection_ids = g_list_sort (selection_ids,
1927 (GCompareFunc)strcmp);
1928 node = selection_ids;
1929 while (node)
1931 g_string_append (remember_key, (gchar*)node->data);
1932 g_string_append (remember_key, ",");
1933 node = g_list_next (node);
1935 g_list_foreach (selection_ids, (GFunc) g_free, NULL);
1936 g_list_free (selection_ids);
1938 /* Find if the selection is remembered */
1939 desc = g_hash_table_lookup (priv->remember_plugins, remember_key->str);
1940 if (desc)
1942 g_string_free (remember_key, TRUE);
1943 gtk_widget_destroy (dlg);
1944 return desc;
1947 /* Prompt dialog */
1948 response = gtk_dialog_run (GTK_DIALOG (dlg));
1949 switch (response)
1951 case GTK_RESPONSE_OK:
1952 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
1953 if (gtk_tree_selection_get_selected (selection, &store,
1954 &selected))
1956 gtk_tree_model_get (model, &selected,
1957 PLUGIN_DESCRIPTION_COLUMN, &desc, -1);
1958 if (desc)
1960 /* Remember selection */
1961 if (gtk_toggle_button_get_active
1962 (GTK_TOGGLE_BUTTON (remember_checkbox)))
1964 /* DEBUG_PRINT ("Remembering selection '%s'",
1965 remember_key->str);*/
1966 g_hash_table_insert (priv->remember_plugins,
1967 g_strdup (remember_key->str), desc);
1969 g_string_free (remember_key, TRUE);
1970 gtk_widget_destroy (dlg);
1971 return desc;
1974 break;
1976 g_string_free (remember_key, TRUE);
1977 gtk_widget_destroy (dlg);
1978 return NULL;
1981 GObject*
1982 anjuta_plugin_manager_select_and_activate (AnjutaPluginManager *plugin_manager,
1983 gchar *title,
1984 gchar *description,
1985 GList *plugin_descriptions)
1987 AnjutaPluginDescription *d;
1989 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1991 d = anjuta_plugin_manager_select (plugin_manager, title, description,
1992 plugin_descriptions);
1993 if (d)
1995 GObject *plugin = NULL;
1996 gchar *location = NULL;
1998 anjuta_plugin_description_get_string (d,
1999 "Anjuta Plugin",
2000 "Location",
2001 &location);
2002 g_return_val_if_fail (location != NULL, NULL);
2003 plugin =
2004 anjuta_plugin_manager_get_plugin_by_id (plugin_manager, location);
2005 g_free (location);
2006 return plugin;
2008 return NULL;
2011 /* Plugin manager */
2013 static void
2014 anjuta_plugin_manager_init (AnjutaPluginManager *object)
2016 object->priv = g_new0 (AnjutaPluginManagerPriv, 1);
2017 object->priv->plugins_by_name = g_hash_table_new (g_str_hash, g_str_equal);
2018 object->priv->plugins_by_interfaces = g_hash_table_new_full (g_str_hash,
2019 g_str_equal,
2020 NULL,
2021 (GDestroyNotify) g_list_free);
2022 object->priv->plugins_by_description = g_hash_table_new (g_direct_hash,
2023 g_direct_equal);
2024 object->priv->activated_plugins = g_hash_table_new (g_direct_hash,
2025 g_direct_equal);
2026 object->priv->plugins_cache = g_hash_table_new (g_direct_hash,
2027 g_direct_equal);
2028 object->priv->remember_plugins = g_hash_table_new_full (g_str_hash,
2029 g_str_equal,
2030 g_free, NULL);
2033 static void
2034 anjuta_plugin_manager_finalize (GObject *object)
2036 AnjutaPluginManagerPriv *priv;
2037 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2038 if (priv->available_plugins)
2040 /* anjuta_plugin_manager_unload_all_plugins (ANJUTA_PLUGIN_MANAGER (object)); */
2041 g_list_foreach (priv->available_plugins, (GFunc)g_object_unref, NULL);
2042 g_list_free (priv->available_plugins);
2043 priv->available_plugins = NULL;
2045 if (priv->activated_plugins)
2047 g_hash_table_destroy (priv->activated_plugins);
2048 priv->activated_plugins = NULL;
2050 if (priv->plugins_cache)
2052 g_hash_table_destroy (priv->plugins_cache);
2053 priv->plugins_cache = NULL;
2055 if (priv->plugins_by_name)
2057 g_hash_table_destroy (priv->plugins_by_name);
2058 priv->plugins_by_name = NULL;
2060 if (priv->plugins_by_description)
2062 g_hash_table_destroy (priv->plugins_by_description);
2063 priv->plugins_by_description = NULL;
2065 if (priv->plugins_by_interfaces)
2067 g_hash_table_destroy (priv->plugins_by_interfaces);
2068 priv->plugins_by_interfaces = NULL;
2070 if (priv->plugin_dirs)
2072 g_list_foreach (priv->plugin_dirs, (GFunc)g_free, NULL);
2073 g_list_free (priv->plugin_dirs);
2074 priv->plugin_dirs = NULL;
2076 #if 0
2077 if (anjuta_c_plugin_factory)
2079 g_object_unref (anjuta_c_plugin_factory);
2080 anjuta_c_plugin_factory = NULL;
2082 #endif
2083 G_OBJECT_CLASS (parent_class)->finalize (object);
2086 static void
2087 anjuta_plugin_manager_set_property (GObject *object, guint prop_id,
2088 const GValue *value, GParamSpec *pspec)
2090 AnjutaPluginManagerPriv *priv;
2092 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object));
2093 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2095 switch (prop_id)
2097 case PROP_STATUS:
2098 priv->status = g_value_get_object (value);
2099 break;
2100 case PROP_SHELL:
2101 priv->shell = g_value_get_object (value);
2102 break;
2103 default:
2104 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2105 break;
2109 static void
2110 anjuta_plugin_manager_get_property (GObject *object, guint prop_id,
2111 GValue *value, GParamSpec *pspec)
2113 AnjutaPluginManagerPriv *priv;
2115 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object));
2116 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2118 switch (prop_id)
2120 case PROP_SHELL:
2121 g_value_set_object (value, priv->shell);
2122 break;
2123 case PROP_STATUS:
2124 g_value_set_object (value, priv->status);
2125 break;
2126 case PROP_AVAILABLE_PLUGINS:
2127 g_value_set_pointer (value, priv->available_plugins);
2128 break;
2129 case PROP_ACTIVATED_PLUGINS:
2130 g_value_set_pointer (value, priv->activated_plugins);
2131 break;
2132 default:
2133 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2134 break;
2137 static void
2138 anjuta_plugin_manager_plugin_activated (AnjutaPluginManager *self,
2139 AnjutaPluginDescription* plugin_desc,
2140 GObject *plugin)
2142 /* TODO: Add default signal handler implementation here */
2145 static void
2146 anjuta_plugin_manager_plugin_deactivated (AnjutaPluginManager *self,
2147 AnjutaPluginDescription* plugin_desc,
2148 GObject *plugin)
2150 /* TODO: Add default signal handler implementation here */
2153 static void
2154 anjuta_plugin_manager_class_init (AnjutaPluginManagerClass *klass)
2156 GObjectClass* object_class = G_OBJECT_CLASS (klass);
2157 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
2159 object_class->finalize = anjuta_plugin_manager_finalize;
2160 object_class->set_property = anjuta_plugin_manager_set_property;
2161 object_class->get_property = anjuta_plugin_manager_get_property;
2163 klass->plugin_activated = anjuta_plugin_manager_plugin_activated;
2164 klass->plugin_deactivated = anjuta_plugin_manager_plugin_deactivated;
2166 g_object_class_install_property (object_class,
2167 PROP_PROFILES,
2168 g_param_spec_pointer ("profiles",
2169 _("Profiles"),
2170 _("Current stack of profiles"),
2171 G_PARAM_READABLE));
2172 g_object_class_install_property (object_class,
2173 PROP_AVAILABLE_PLUGINS,
2174 g_param_spec_pointer ("available-plugins",
2175 _("Available plugins"),
2176 _("Currently available plugins found in plugin paths"),
2177 G_PARAM_READABLE));
2179 g_object_class_install_property (object_class,
2180 PROP_ACTIVATED_PLUGINS,
2181 g_param_spec_pointer ("activated-plugins",
2182 _("Activated plugins"),
2183 _("Currently activated plugins"),
2184 G_PARAM_READABLE));
2185 g_object_class_install_property (object_class,
2186 PROP_SHELL,
2187 g_param_spec_object ("shell",
2188 _("Anjuta Shell"),
2189 _("Anjuta shell for which the plugins are"),
2190 G_TYPE_OBJECT,
2191 G_PARAM_READABLE |
2192 G_PARAM_WRITABLE |
2193 G_PARAM_CONSTRUCT));
2194 g_object_class_install_property (object_class,
2195 PROP_STATUS,
2196 g_param_spec_object ("status",
2197 _("Anjuta Status"),
2198 _("Anjuta status to use in loading and unloading of plugins"),
2199 ANJUTA_TYPE_STATUS,
2200 G_PARAM_READABLE |
2201 G_PARAM_WRITABLE |
2202 G_PARAM_CONSTRUCT));
2204 plugin_manager_signals[PLUGIN_ACTIVATED] =
2205 g_signal_new ("plugin-activated",
2206 G_OBJECT_CLASS_TYPE (klass),
2207 G_SIGNAL_RUN_FIRST,
2208 G_STRUCT_OFFSET (AnjutaPluginManagerClass,
2209 plugin_activated),
2210 NULL, NULL,
2211 anjuta_cclosure_marshal_VOID__POINTER_OBJECT,
2212 G_TYPE_NONE, 2,
2213 G_TYPE_POINTER, ANJUTA_TYPE_PLUGIN);
2215 plugin_manager_signals[PLUGIN_DEACTIVATED] =
2216 g_signal_new ("plugin-deactivated",
2217 G_OBJECT_CLASS_TYPE (klass),
2218 G_SIGNAL_RUN_FIRST,
2219 G_STRUCT_OFFSET (AnjutaPluginManagerClass,
2220 plugin_deactivated),
2221 NULL, NULL,
2222 anjuta_cclosure_marshal_VOID__POINTER_OBJECT,
2223 G_TYPE_NONE, 2,
2224 G_TYPE_POINTER, ANJUTA_TYPE_PLUGIN);
2227 GType
2228 anjuta_plugin_manager_get_type (void)
2230 static GType our_type = 0;
2232 if(our_type == 0)
2234 static const GTypeInfo our_info =
2236 sizeof (AnjutaPluginManagerClass), /* class_size */
2237 (GBaseInitFunc) NULL, /* base_init */
2238 (GBaseFinalizeFunc) NULL, /* base_finalize */
2239 (GClassInitFunc) anjuta_plugin_manager_class_init, /* class_init */
2240 (GClassFinalizeFunc) NULL, /* class_finalize */
2241 NULL /* class_data */,
2242 sizeof (AnjutaPluginManager), /* instance_size */
2243 0, /* n_preallocs */
2244 (GInstanceInitFunc) anjuta_plugin_manager_init, /* instance_init */
2245 NULL /* value_table */
2247 our_type = g_type_register_static (G_TYPE_OBJECT,
2248 "AnjutaPluginManager",
2249 &our_info, 0);
2252 return our_type;
2255 AnjutaPluginManager*
2256 anjuta_plugin_manager_new (GObject *shell, AnjutaStatus *status,
2257 GList* plugins_directories)
2259 GObject *manager_object;
2260 AnjutaPluginManager *plugin_manager;
2261 GList *cycles = NULL;
2262 const char *gnome2_path;
2263 char **pathv;
2264 char **p;
2265 GList *node;
2266 GList *plugin_dirs = NULL;
2268 /* Initialize the anjuta plugin system */
2269 manager_object = g_object_new (ANJUTA_TYPE_PLUGIN_MANAGER,
2270 "shell", shell, "status", status, NULL);
2271 plugin_manager = ANJUTA_PLUGIN_MANAGER (manager_object);
2273 if (anjuta_plugin_factory == NULL)
2275 anjuta_plugin_factory = anjuta_c_plugin_factory_new ();
2278 gnome2_path = g_getenv ("GNOME2_PATH");
2279 if (gnome2_path) {
2280 pathv = g_strsplit (gnome2_path, ":", 1);
2282 for (p = pathv; *p != NULL; p++) {
2283 char *path = g_strdup (*p);
2284 plugin_dirs = g_list_prepend (plugin_dirs, path);
2286 g_strfreev (pathv);
2289 node = plugins_directories;
2290 while (node) {
2291 if (!node->data)
2292 continue;
2293 char *path = g_strdup (node->data);
2294 plugin_dirs = g_list_prepend (plugin_dirs, path);
2295 node = g_list_next (node);
2297 plugin_dirs = g_list_reverse (plugin_dirs);
2298 /* load_plugins (); */
2300 node = plugin_dirs;
2301 while (node)
2303 load_plugins_from_directory (plugin_manager, (char*)node->data);
2304 node = g_list_next (node);
2306 resolve_dependencies (plugin_manager, &cycles);
2307 g_list_foreach(plugin_dirs, (GFunc) g_free, NULL);
2308 g_list_free(plugin_dirs);
2309 return plugin_manager;
2312 void
2313 anjuta_plugin_manager_activate_plugins (AnjutaPluginManager *plugin_manager,
2314 GList *plugins_to_activate)
2316 AnjutaPluginManagerPriv *priv;
2317 GdkPixbuf *icon_pixbuf;
2318 GList *node;
2320 priv = plugin_manager->priv;
2322 /* Freeze shell operations */
2323 anjuta_shell_freeze (ANJUTA_SHELL (priv->shell), NULL);
2324 if (plugins_to_activate)
2326 anjuta_status_progress_add_ticks (ANJUTA_STATUS (priv->status),
2327 g_list_length (plugins_to_activate));
2329 node = plugins_to_activate;
2330 while (node)
2332 AnjutaPluginDescription *d;
2333 gchar *plugin_id;
2334 gchar *icon_filename, *label;
2335 gchar *icon_path = NULL;
2337 d = node->data;
2339 icon_pixbuf = NULL;
2340 label = NULL;
2341 if (anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2342 "Icon",
2343 &icon_filename))
2345 gchar *title, *description;
2346 anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2347 "Name",
2348 &title);
2349 anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2350 "Description",
2351 &description);
2352 icon_path = g_strconcat (PACKAGE_PIXMAPS_DIR"/",
2353 icon_filename, NULL);
2354 /* DEBUG_PRINT ("Icon: %s", icon_path); */
2355 label = g_strconcat (_("Loaded: "), title, _("..."), NULL);
2356 icon_pixbuf = gdk_pixbuf_new_from_file (icon_path, NULL);
2357 if (!icon_pixbuf)
2358 g_warning ("Plugin does not define Icon: No such file %s",
2359 icon_path);
2360 g_free (icon_path);
2361 g_free (icon_filename);
2364 if (anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2365 "Location", &plugin_id))
2367 GObject *plugin_obj;
2369 plugin_obj =
2370 anjuta_plugin_manager_get_plugin_by_id (plugin_manager,
2371 plugin_id);
2372 g_free (plugin_id);
2374 anjuta_status_progress_tick (ANJUTA_STATUS (priv->status),
2375 icon_pixbuf, label);
2376 g_free (label);
2377 if (icon_pixbuf)
2378 g_object_unref (icon_pixbuf);
2380 node = g_list_next (node);
2383 /* Thaw shell operations */
2384 anjuta_shell_thaw (ANJUTA_SHELL (priv->shell), NULL);
2387 static void
2388 on_collect (gpointer key, gpointer value, gpointer user_data)
2390 gchar *id;
2391 gchar *query = (gchar*) key;
2392 AnjutaPluginDescription *desc = (AnjutaPluginDescription *) value;
2393 GString *write_buffer = (GString *) user_data;
2395 anjuta_plugin_description_get_string (desc, "Anjuta Plugin", "Location",
2396 &id);
2397 g_string_append_printf (write_buffer, "%s=%s;", query, id);
2398 g_free (id);
2401 gchar*
2402 anjuta_plugin_manager_get_remembered_plugins (AnjutaPluginManager *plugin_manager)
2404 AnjutaPluginManagerPriv *priv;
2405 GString *write_buffer = g_string_new ("");
2407 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
2409 priv = plugin_manager->priv;
2410 g_hash_table_foreach (priv->remember_plugins, on_collect,
2411 write_buffer);
2412 return g_string_free (write_buffer, FALSE);
2415 static gboolean
2416 on_foreach_remove_true (gpointer k, gpointer v, gpointer d)
2418 return TRUE;
2421 void
2422 anjuta_plugin_manager_set_remembered_plugins (AnjutaPluginManager *plugin_manager,
2423 const gchar *remembered_plugins)
2425 AnjutaPluginManagerPriv *priv;
2426 gchar **strv_lines, **line_idx;
2428 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager));
2429 g_return_if_fail (remembered_plugins != NULL);
2431 priv = plugin_manager->priv;
2433 g_hash_table_foreach_remove (priv->remember_plugins,
2434 on_foreach_remove_true, NULL);
2436 strv_lines = g_strsplit (remembered_plugins, ";", -1);
2437 line_idx = strv_lines;
2438 while (*line_idx)
2440 gchar **strv_keyvals;
2441 strv_keyvals = g_strsplit (*line_idx, "=", -1);
2442 if (strv_keyvals && strv_keyvals[0] && strv_keyvals[1])
2444 AnjutaPluginHandle *plugin;
2445 plugin = g_hash_table_lookup (priv->plugins_by_name,
2446 strv_keyvals[1]);
2447 if (plugin)
2449 AnjutaPluginDescription *desc;
2450 desc = anjuta_plugin_handle_get_description (plugin);
2452 DEBUG_PRINT ("Restoring remember plugin: %s=%s",
2453 strv_keyvals[0],
2454 strv_keyvals[1]);
2456 g_hash_table_insert (priv->remember_plugins,
2457 g_strdup (strv_keyvals[0]), desc);
2459 g_strfreev (strv_keyvals);
2461 line_idx++;
2463 g_strfreev (strv_lines);