Fix a Gtk warning when checking path input in the log viewer.
[anjuta-git-plugin.git] / plugins / symbol-browser / plugin.c
blob0d824eadf382a61b2bb3c9c624bac160f823de74
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 plugin.c
4 Copyright (C) Naba Kumar <naba@gnome.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <config.h>
22 #include <libgnomevfs/gnome-vfs-utils.h>
23 #include <libanjuta/anjuta-shell.h>
24 #include <libanjuta/anjuta-debug.h>
25 #include <libanjuta/anjuta-utils.h>
26 #include <libanjuta/interfaces/ianjuta-help.h>
27 #include <libanjuta/interfaces/ianjuta-document-manager.h>
28 #include <libanjuta/interfaces/ianjuta-project-manager.h>
29 #include <libanjuta/interfaces/ianjuta-file-manager.h>
30 #include <libanjuta/interfaces/ianjuta-file.h>
31 #include <libanjuta/interfaces/ianjuta-file-loader.h>
32 #include <libanjuta/interfaces/ianjuta-editor.h>
33 #include <libanjuta/interfaces/ianjuta-markable.h>
34 #include <libanjuta/interfaces/ianjuta-symbol-manager.h>
35 #include <libanjuta/interfaces/ianjuta-preferences.h>
37 #include <tm_tagmanager.h>
38 #include "an_symbol_view.h"
39 #include "an_symbol_search.h"
40 #include "anjuta-symbol-locals.h"
41 #include "an_symbol_info.h"
42 #include "an_symbol_prefs.h"
43 #include "an_symbol_iter.h"
44 #include "plugin.h"
46 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta-symbol-browser-plugin.ui"
47 #define PREFS_GLADE PACKAGE_DATA_DIR"/glade/anjuta-symbol-browser-plugin.glade"
48 #define ICON_FILE "anjuta-symbol-browser-plugin-48.png"
49 #define SYMBOL_BROWSER_TAGS "symbol.browser.tags"
51 #define TIMEOUT_INTERVAL_SYMBOLS_UPDATE 10000
53 static gpointer parent_class = NULL;
55 /* these will block signals on treeview and treesearch callbacks functions */
56 static void trees_signals_block (SymbolBrowserPlugin *sv_plugin);
57 static void trees_signals_unblock (SymbolBrowserPlugin *sv_plugin);
59 static void on_treesearch_symbol_selected_event (AnjutaSymbolSearch *search,
60 AnjutaSymbolInfo *sym,
61 SymbolBrowserPlugin *sv_plugin);
62 static void update_editor_symbol_model (SymbolBrowserPlugin *sv_plugin);
64 static void on_editor_update_ui (IAnjutaEditor *editor,
65 SymbolBrowserPlugin *sv_plugin);
66 static void
67 register_stock_icons (AnjutaPlugin *plugin)
69 static gboolean registered = FALSE;
71 if (registered)
72 return;
73 registered = TRUE;
75 /* Register stock icons */
76 BEGIN_REGISTER_ICON (plugin);
77 REGISTER_ICON (ICON_FILE, "symbol-browser-plugin-icon");
78 END_REGISTER_ICON;
81 static void
82 goto_file_line (AnjutaPlugin *plugin, const gchar *filename, gint lineno)
84 GFile* file;
85 IAnjutaDocumentManager *docman;
87 g_return_if_fail (filename != NULL);
89 /* Go to file and line number */
90 docman = anjuta_shell_get_interface (plugin->shell, IAnjutaDocumentManager,
91 NULL);
93 file = g_file_new_for_path (filename);
94 ianjuta_document_manager_goto_file_line (docman, file, lineno, NULL);
95 g_object_unref (file);
98 static void
99 goto_file_tag (SymbolBrowserPlugin *sv_plugin, const char *symbol,
100 gboolean prefer_definition)
102 const gchar *file;
103 gint line;
104 gboolean ret;
106 ret = anjuta_symbol_view_get_file_symbol (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
107 symbol, prefer_definition,
108 &file, &line);
109 if (ret)
111 goto_file_line (ANJUTA_PLUGIN (sv_plugin), file, line);
115 static void
116 on_goto_def_activate (GtkAction *action, SymbolBrowserPlugin *sv_plugin)
118 gchar *file;
119 gint line;
120 gboolean ret;
122 ret = anjuta_symbol_view_get_current_symbol_def (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
123 &file, &line);
124 if (ret)
126 goto_file_line (ANJUTA_PLUGIN (sv_plugin), file, line);
127 g_free (file);
131 static void
132 on_goto_decl_activate (GtkAction *action, SymbolBrowserPlugin *sv_plugin)
134 gchar *file;
135 gint line;
136 gboolean ret;
138 ret = anjuta_symbol_view_get_current_symbol_decl (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
139 &file, &line);
140 if (ret)
142 goto_file_line (ANJUTA_PLUGIN (sv_plugin), file, line);
143 g_free (file);
147 static void
148 on_goto_file_tag_decl_activate (GtkAction * action,
149 SymbolBrowserPlugin *sv_plugin)
151 IAnjutaEditor *ed;
152 gchar *word;
154 if (sv_plugin->current_editor)
156 ed = IANJUTA_EDITOR (sv_plugin->current_editor);
157 word = ianjuta_editor_get_current_word (ed, NULL);
158 if (word)
160 goto_file_tag (sv_plugin, word, FALSE);
161 g_free (word);
166 static void
167 on_goto_file_tag_def_activate (GtkAction * action,
168 SymbolBrowserPlugin *sv_plugin)
170 IAnjutaEditor *ed;
171 gchar *word;
173 if (sv_plugin->current_editor)
175 ed = IANJUTA_EDITOR (sv_plugin->current_editor);
176 word = ianjuta_editor_get_current_word (ed, NULL);
177 if (word)
179 goto_file_tag (sv_plugin, word, TRUE);
180 g_free (word);
185 static void
186 on_find_activate (GtkAction *action, SymbolBrowserPlugin *sv_plugin)
188 gchar *symbol;
189 symbol = anjuta_symbol_view_get_current_symbol (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree));
190 if (symbol)
192 g_warning ("TODO: Unimplemented");
193 g_free (symbol);
197 static gboolean
198 on_refresh_idle (gpointer user_data)
200 IAnjutaProjectManager *pm;
201 GList *source_uris;
202 GList *source_files;
203 AnjutaStatus *status;
204 SymbolBrowserPlugin *sv_plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (user_data);
206 /* FIXME: There should be a way to ensure that this project manager
207 * is indeed the one that has opened the project_uri
209 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sv_plugin)->shell,
210 IAnjutaProjectManager, NULL);
211 g_return_val_if_fail (pm != NULL, FALSE);
213 status = anjuta_shell_get_status (ANJUTA_PLUGIN (sv_plugin)->shell, NULL);
214 anjuta_status_push (status, "Refreshing symbol tree...");
215 anjuta_status_busy_push (status);
217 source_uris = source_files = NULL;
218 source_uris = ianjuta_project_manager_get_elements (pm,
219 IANJUTA_PROJECT_MANAGER_SOURCE,
220 NULL);
221 if (source_uris)
223 const gchar *uri;
224 GList *node;
225 node = source_uris;
227 while (node)
229 gchar *file_path;
231 uri = (const gchar *)node->data;
232 file_path = gnome_vfs_get_local_path_from_uri (uri);
233 if (file_path)
234 source_files = g_list_prepend (source_files, file_path);
235 node = g_list_next (node);
237 source_files = g_list_reverse (source_files);
239 anjuta_symbol_view_update (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
240 source_files);
241 g_list_foreach (source_files, (GFunc)g_free, NULL);
242 g_list_foreach (source_uris, (GFunc)g_free, NULL);
243 g_list_free (source_files);
244 g_list_free (source_uris);
246 /* Current editor symbol model may have changed */
247 update_editor_symbol_model (sv_plugin);
249 anjuta_status_busy_pop (status);
250 anjuta_status_pop (status);
251 return FALSE;
254 static void
255 on_refresh_activate (GtkAction *action, SymbolBrowserPlugin *sv_plugin)
257 if (!sv_plugin->project_root_uri)
258 return;
259 g_idle_add (on_refresh_idle, sv_plugin);
262 static GtkActionEntry actions[] =
264 { "ActionMenuGoto", NULL, N_("_Goto"), NULL, NULL, NULL},
266 "ActionSymbolBrowserGotoDef",
267 NULL,
268 N_("Tag _Definition"),
269 "<control>d",
270 N_("Goto symbol definition"),
271 G_CALLBACK (on_goto_file_tag_def_activate)
274 "ActionSymbolBrowserGotoDecl",
275 NULL,
276 N_("Tag De_claration"),
277 "<shift><control>d",
278 N_("Goto symbol declaration"),
279 G_CALLBACK (on_goto_file_tag_decl_activate)
283 static GtkActionEntry popup_actions[] =
286 "ActionPopupSymbolBrowserGotoDef",
287 NULL,
288 N_("Goto _Definition"),
289 NULL,
290 N_("Goto symbol definition"),
291 G_CALLBACK (on_goto_def_activate)
294 "ActionPopupSymbolBrowserGotoDecl",
295 NULL,
296 N_("Goto De_claration"),
297 NULL,
298 N_("Goto symbol declaration"),
299 G_CALLBACK (on_goto_decl_activate)
302 "ActionPopupSymbolBrowserFind",
303 GTK_STOCK_FIND,
304 N_("_Find Usage"),
305 NULL,
306 N_("Find usage of symbol in project"),
307 G_CALLBACK (on_find_activate)
310 "ActionPopupSymbolBrowserRefresh",
311 GTK_STOCK_REFRESH,
312 N_("_Refresh"),
313 NULL,
314 N_("Refresh symbol browser tree"),
315 G_CALLBACK (on_refresh_activate)
319 static void
320 on_project_element_added (IAnjutaProjectManager *pm, const gchar *uri,
321 SymbolBrowserPlugin *sv_plugin)
323 gchar *filename;
325 if (!sv_plugin->project_root_uri)
326 return;
328 filename = gnome_vfs_get_local_path_from_uri (uri);
329 if (filename)
331 anjuta_symbol_view_add_source (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
332 filename);
333 g_free (filename);
337 static void
338 on_project_element_removed (IAnjutaProjectManager *pm, const gchar *uri,
339 SymbolBrowserPlugin *sv_plugin)
341 gchar *filename;
343 if (!sv_plugin->project_root_uri)
344 return;
346 filename = gnome_vfs_get_local_path_from_uri (uri);
347 if (filename)
349 anjuta_symbol_view_remove_source (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
350 filename);
351 g_free (filename);
355 #define LOCAL_TAGS_SUBDIR "tags/"
357 // add a new project
358 static void
359 project_root_added (AnjutaPlugin *plugin, const gchar *name,
360 const GValue *value, gpointer user_data)
362 AnjutaStatus *status;
363 IAnjutaProjectManager *pm;
364 SymbolBrowserPlugin *sv_plugin;
365 const gchar *root_uri;
366 gchar* tags;
368 sv_plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin);
370 g_free (sv_plugin->project_root_uri);
371 sv_plugin->project_root_uri = NULL;
372 root_uri = g_value_get_string (value);
373 if (root_uri)
375 gchar *root_dir = gnome_vfs_get_local_path_from_uri (root_uri);
376 if (root_dir)
378 status = anjuta_shell_get_status (plugin->shell, NULL);
379 anjuta_status_progress_add_ticks (status, 1);
380 trees_signals_block (sv_plugin);
381 anjuta_symbol_view_open (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
382 root_dir);
384 /* Current editor symbol model may have changed */
385 update_editor_symbol_model (sv_plugin);
386 anjuta_status_progress_tick (status, NULL, _("Created symbols..."));
387 trees_signals_unblock (sv_plugin);
388 g_free (root_dir);
390 sv_plugin->project_root_uri = g_strdup (root_uri);
392 /* FIXME: There should be a way to ensure that this project manager
393 * is indeed the one that has opened the project_uri
395 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sv_plugin)->shell,
396 IAnjutaProjectManager, NULL);
397 g_signal_connect (G_OBJECT (pm), "element_added",
398 G_CALLBACK (on_project_element_added), sv_plugin);
399 g_signal_connect (G_OBJECT (pm), "element_removed",
400 G_CALLBACK (on_project_element_removed), sv_plugin);
401 /* Load from project */
402 if (anjuta_preferences_get_int (sv_plugin->prefs,
403 "symbol_browser.tags_auto_load"))
405 gchar* pref_symbols = anjuta_preferences_get (sv_plugin->prefs, SYMBOL_BROWSER_TAGS);
406 gchar* dirname = anjuta_util_get_user_cache_file_path (LOCAL_TAGS_SUBDIR,NULL);
407 GList* packages = ianjuta_project_manager_get_packages (pm, NULL);
408 GList* node;
409 GString* str = g_string_new (pref_symbols);
410 g_free (pref_symbols);
411 for (node = packages; node != NULL; node = g_list_next (node))
413 gchar* pathname = g_build_filename (dirname, node->data, NULL);
414 if (!strstr (str->str, pathname))
416 if (str->len)
417 g_string_append_c (str, ':');
418 g_string_append (str, pathname);
419 g_string_append (str, ".anjutatags.gz");
421 g_free (pathname);
423 g_list_foreach (packages, (GFunc) g_free, NULL);
424 g_list_free (packages);
425 anjuta_preferences_set (sv_plugin->prefs, SYMBOL_BROWSER_TAGS, str->str);
426 g_string_free (str, TRUE);
427 g_free (dirname);
431 static void
432 project_root_removed (AnjutaPlugin *plugin, const gchar *name,
433 gpointer user_data)
435 IAnjutaProjectManager *pm;
436 SymbolBrowserPlugin *sv_plugin;
438 sv_plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin);
440 /* Disconnect events from project manager */
442 /* FIXME: There should be a way to ensure that this project manager
443 * is indeed the one that has opened the project_uri
445 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sv_plugin)->shell,
446 IAnjutaProjectManager, NULL);
447 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
448 on_project_element_added,
449 sv_plugin);
450 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
451 on_project_element_removed,
452 sv_plugin);
454 /* clear anjuta_symbol_search side */
455 if (sv_plugin->ss)
456 anjuta_symbol_search_clear(ANJUTA_SYMBOL_SEARCH(sv_plugin->ss));
458 /* clear glist's sfiles */
459 if (sv_plugin->sv_tree)
460 anjuta_symbol_view_clear (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree));
462 g_free (sv_plugin->project_root_uri);
463 sv_plugin->project_root_uri = NULL;
466 static gboolean
467 on_treeview_event (GtkWidget *widget,
468 GdkEvent *event,
469 SymbolBrowserPlugin *sv_plugin)
471 GtkTreeView *view;
472 GtkTreeModel *model;
473 GtkTreeSelection *selection;
475 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
477 view = GTK_TREE_VIEW (widget);
478 model = gtk_tree_view_get_model (view);
479 selection = gtk_tree_view_get_selection (view);
481 if (!event)
482 return FALSE;
484 if (event->type == GDK_BUTTON_PRESS) {
485 GdkEventButton *e = (GdkEventButton *) event;
487 if (e->button == 3) {
488 GtkWidget *menu;
490 /* Popup project menu */
491 menu = gtk_ui_manager_get_widget (GTK_UI_MANAGER (sv_plugin->ui),
492 "/PopupSymbolBrowser");
493 gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
494 NULL, NULL, e->button, e->time);
495 return TRUE;
497 } else if (event->type == GDK_KEY_PRESS) {
498 GdkEventKey *e = (GdkEventKey *) event;
500 switch (e->keyval) {
501 case GDK_Return:
502 anjuta_ui_activate_action_by_group (sv_plugin->ui,
503 sv_plugin->popup_action_group,
504 "ActionPopupSymbolBrowserGotoDef");
505 return TRUE;
506 default:
507 return FALSE;
510 return FALSE;
513 static void
514 on_treeview_row_activated (GtkTreeView *view, GtkTreePath *arg1,
515 GtkTreeViewColumn *arg2,
516 SymbolBrowserPlugin *sv_plugin)
518 GtkTreeModel *model;
519 GtkTreeSelection *selection;
520 GtkTreeIter iter;
522 selection = gtk_tree_view_get_selection (view);
523 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
524 return;
525 anjuta_ui_activate_action_by_group (sv_plugin->ui,
526 sv_plugin->popup_action_group,
527 "ActionPopupSymbolBrowserGotoDef");
530 static void
531 trees_signals_block (SymbolBrowserPlugin *sv_plugin)
533 g_signal_handlers_block_by_func (G_OBJECT (sv_plugin->sv_tree),
534 G_CALLBACK (on_treeview_event), NULL);
536 g_signal_handlers_block_by_func (G_OBJECT (sv_plugin->ss),
537 G_CALLBACK (on_treesearch_symbol_selected_event),
538 NULL);
542 static void
543 trees_signals_unblock (SymbolBrowserPlugin *sv_plugin)
545 g_signal_handlers_unblock_by_func (G_OBJECT (sv_plugin->sv_tree),
546 G_CALLBACK (on_treeview_event), NULL);
548 g_signal_handlers_unblock_by_func (G_OBJECT (sv_plugin->ss),
549 G_CALLBACK (on_treesearch_symbol_selected_event),
550 NULL);
553 static void
554 goto_tree_iter (SymbolBrowserPlugin *sv_plugin, GtkTreeIter *iter)
556 gint line;
558 /* FIXME: */
559 line = anjuta_symbol_view_workspace_get_line (ANJUTA_SYMBOL_VIEW
560 (sv_plugin->sv_tree),
561 iter);
563 if (line > 0 && sv_plugin->current_editor)
565 /* Goto line number */
566 ianjuta_editor_goto_line (IANJUTA_EDITOR (sv_plugin->current_editor),
567 line, NULL);
568 if (IANJUTA_IS_MARKABLE (sv_plugin->current_editor))
570 ianjuta_markable_delete_all_markers (IANJUTA_MARKABLE (sv_plugin->current_editor),
571 IANJUTA_MARKABLE_LINEMARKER,
572 NULL);
574 ianjuta_markable_mark (IANJUTA_MARKABLE (sv_plugin->current_editor),
575 line, IANJUTA_MARKABLE_LINEMARKER, NULL);
580 static void
581 on_local_treeview_row_activated (GtkTreeView *view, GtkTreePath *arg1,
582 GtkTreeViewColumn *arg2,
583 SymbolBrowserPlugin *sv_plugin)
585 GtkTreeModel *model;
586 GtkTreeSelection *selection;
587 GtkTreeIter iter;
589 selection = gtk_tree_view_get_selection (view);
590 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
591 return;
592 goto_tree_iter (sv_plugin, &iter);
595 /* -----------------------------------------------------------------------------
596 * will manage the click of mouse and other events on search->hitlist treeview
598 static void
599 on_treesearch_symbol_selected_event (AnjutaSymbolSearch *search,
600 AnjutaSymbolInfo *sym,
601 SymbolBrowserPlugin *sv_plugin) {
602 gboolean ret;
603 gint line;
604 const gchar *file;
606 ret = anjuta_symbol_view_get_file_symbol (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
607 sym->sym_name, TRUE,
608 &file, &line);
609 if (ret)
611 goto_file_line (ANJUTA_PLUGIN (sv_plugin), file, line);
615 static void
616 on_editor_destroy (SymbolBrowserPlugin *sv_plugin, IAnjutaEditor *editor)
618 const gchar *uri;
620 if (!sv_plugin->editor_connected || !sv_plugin->sv_tree)
621 return;
622 uri = g_hash_table_lookup (sv_plugin->editor_connected, G_OBJECT (editor));
623 if (uri && strlen (uri) > 0)
625 DEBUG_PRINT ("Removing file tags of %s", uri);
626 anjuta_symbol_view_workspace_remove_file (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
627 uri);
629 g_hash_table_remove (sv_plugin->editor_connected, G_OBJECT (editor));
632 static void
633 on_editor_saved (IAnjutaEditor *editor, GFile* file,
634 SymbolBrowserPlugin *sv_plugin)
636 const gchar *old_uri;
637 gboolean tags_update;
638 GtkTreeModel *file_symbol_model;
639 GtkAction *action;
640 AnjutaUI *ui;
642 /* FIXME: Do this only if automatic tags update is enabled */
643 /* tags_update =
644 anjuta_preferences_get_int (te->preferences, AUTOMATIC_TAGS_UPDATE);
647 if (!file)
648 return;
650 tags_update = TRUE;
651 if (tags_update)
653 gchar *local_filename;
654 gchar *saved_uri = g_file_get_uri (file);
656 /* Verify that it's local file */
657 local_filename = g_file_get_path (file);
658 g_return_if_fail (local_filename != NULL);
659 g_free (local_filename);
661 if (!sv_plugin->editor_connected)
662 return;
664 old_uri = g_hash_table_lookup (sv_plugin->editor_connected, editor);
666 if (old_uri && strlen (old_uri) <= 0)
667 old_uri = NULL;
668 anjuta_symbol_view_workspace_update_file (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
669 old_uri, saved_uri);
670 g_hash_table_insert (sv_plugin->editor_connected, editor,
671 g_strdup (saved_uri));
673 /* Update File symbol view */
674 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN (sv_plugin)->shell, NULL);
677 file_symbol_model =
678 anjuta_symbol_view_get_file_symbol_model (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree));
679 g_object_set_data (G_OBJECT (editor), "tm_file",
680 g_object_get_data (G_OBJECT (file_symbol_model),
681 "tm_file"));
682 /* Set local view version */
683 gtk_tree_view_set_model (GTK_TREE_VIEW (sv_plugin->sl_tree),
684 file_symbol_model);
685 sv_plugin->locals_line_number = 0;
686 on_editor_update_ui (editor, sv_plugin);
687 g_free (saved_uri);
689 #if 0
690 /* FIXME: Re-hilite all editors on tags update */
691 if(update)
693 for (tmp = app->text_editor_list; tmp; tmp = g_list_next(tmp))
695 te1 = TEXT_EDITOR (tmp->data);
696 text_editor_set_hilite_type(te1);
699 #endif
703 static void
704 on_editor_foreach_disconnect (gpointer key, gpointer value, gpointer user_data)
706 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
707 G_CALLBACK (on_editor_saved),
708 user_data);
709 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
710 G_CALLBACK (on_editor_update_ui),
711 user_data);
712 g_object_weak_unref (G_OBJECT(key),
713 (GWeakNotify) (on_editor_destroy),
714 user_data);
717 static void
718 on_editor_foreach_clear (gpointer key, gpointer value, gpointer user_data)
720 const gchar *uri;
721 SymbolBrowserPlugin *sv_plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (user_data);
723 uri = (const gchar *)value;
724 if (uri && strlen (uri) > 0)
726 DEBUG_PRINT ("Removing file tags of %s", uri);
727 anjuta_symbol_view_workspace_remove_file (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
728 uri);
732 static void
733 update_editor_symbol_model (SymbolBrowserPlugin *sv_plugin)
735 AnjutaUI *ui;
736 gchar *uri;
737 GFile* file;
738 GObject *editor = sv_plugin->current_editor;
740 if (!editor)
741 return;
743 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN (sv_plugin)->shell, NULL);
744 file = ianjuta_file_get_file (IANJUTA_FILE (editor), NULL);
745 uri = g_file_get_uri (file);
746 g_object_unref (file);
747 if (uri)
749 gchar *local_filename;
750 GtkTreeModel *file_symbol_model;
751 GtkAction *action;
753 /* Verify that it's local file */
754 local_filename = gnome_vfs_get_local_path_from_uri (uri);
755 g_return_if_fail (local_filename != NULL);
756 g_free (local_filename);
758 anjuta_symbol_view_workspace_add_file (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree), uri);
759 g_free (uri);
761 file_symbol_model =
762 anjuta_symbol_view_get_file_symbol_model (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree));
763 if (file_symbol_model)
765 g_object_set_data (G_OBJECT (editor), "tm_file",
766 g_object_get_data (G_OBJECT (file_symbol_model),
767 "tm_file"));
769 /* Set local view version */
770 gtk_tree_view_set_model (GTK_TREE_VIEW (sv_plugin->sl_tree),
771 file_symbol_model);
772 sv_plugin->locals_line_number = 0;
773 on_editor_update_ui (IANJUTA_EDITOR (editor), sv_plugin);
778 static gboolean
779 iter_matches (SymbolBrowserPlugin *sv_plugin, GtkTreeIter* iter,
780 GtkTreeModel* model, gint lineno)
782 gint line;
783 gtk_tree_model_get (model, iter, COL_LINE, &line, -1);
784 if (line == lineno)
786 GtkTreePath* path = gtk_tree_model_get_path (model, iter);
788 gtk_tree_view_set_cursor (GTK_TREE_VIEW (sv_plugin->sl_tree), path, NULL,
789 FALSE);
790 gtk_tree_path_free (path);
791 return TRUE;
793 return FALSE;
796 static void
797 on_editor_update_ui (IAnjutaEditor *editor, SymbolBrowserPlugin *sv_plugin)
799 gint lineno = ianjuta_editor_get_lineno (editor, NULL);
801 GtkTreeModel* model = anjuta_symbol_view_get_file_symbol_model
802 (ANJUTA_SYMBOL_VIEW(sv_plugin->sv_tree));
803 GtkTreeIter iter;
804 gboolean found = FALSE;
806 if (sv_plugin->locals_line_number == lineno)
807 return;
808 sv_plugin->locals_line_number = lineno;
810 if (!gtk_tree_model_get_iter_first (model, &iter))
811 return;
812 while (!found && lineno >= 0)
814 gtk_tree_model_get_iter_first (model, &iter);
817 found = iter_matches (sv_plugin, &iter, model, lineno);
818 if (found)
819 break;
821 while (gtk_tree_model_iter_next (model, &iter));
822 lineno--;
826 static void
827 value_added_current_editor (AnjutaPlugin *plugin, const char *name,
828 const GValue *value, gpointer data)
830 gchar *uri;
831 GObject *editor;
832 SymbolBrowserPlugin *sv_plugin;
833 GFile* file;
835 editor = g_value_get_object (value);
837 if (!IANJUTA_IS_EDITOR(editor))
838 return;
840 sv_plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin);
842 if (!sv_plugin->editor_connected)
844 sv_plugin->editor_connected = g_hash_table_new_full (g_direct_hash,
845 g_direct_equal,
846 NULL, g_free);
848 sv_plugin->current_editor = editor;
850 update_editor_symbol_model (sv_plugin);
852 file = ianjuta_file_get_file (IANJUTA_FILE (editor), NULL);
853 uri = file ? g_file_get_uri (file) : NULL;
854 if (file)
855 g_object_unref (file);
856 if (g_hash_table_lookup (sv_plugin->editor_connected, editor) == NULL)
858 g_object_weak_ref (G_OBJECT (editor),
859 (GWeakNotify) (on_editor_destroy),
860 sv_plugin);
861 if (uri)
863 g_hash_table_insert (sv_plugin->editor_connected, editor, uri); //g_strdup (uri));
864 //g_free (uri);
866 else
868 g_hash_table_insert (sv_plugin->editor_connected, editor,
869 g_strdup (""));
871 g_signal_connect (G_OBJECT (editor), "saved",
872 G_CALLBACK (on_editor_saved),
873 sv_plugin);
874 g_signal_connect (G_OBJECT(editor), "update_ui",
875 G_CALLBACK (on_editor_update_ui),
876 sv_plugin);
880 static void
881 value_removed_current_editor (AnjutaPlugin *plugin,
882 const char *name, gpointer data)
884 AnjutaUI *ui;
885 SymbolBrowserPlugin *sv_plugin;
886 GtkAction *action;
888 /* let's remove the timeout for symbols refresh */
890 sv_plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin);
891 ui = anjuta_shell_get_ui (plugin->shell, NULL);
892 sv_plugin->current_editor = NULL;
895 static gboolean
896 activate_plugin (AnjutaPlugin *plugin)
898 GtkActionGroup *group;
899 SymbolBrowserPlugin *sv_plugin;
901 DEBUG_PRINT ("SymbolBrowserPlugin: Activating Symbol Manager plugin...");
903 register_stock_icons (plugin);
905 sv_plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin);
906 sv_plugin->ui = anjuta_shell_get_ui (plugin->shell, NULL);
907 sv_plugin->prefs = anjuta_shell_get_preferences (plugin->shell, NULL);
909 /* Create widgets */
910 sv_plugin->sw = gtk_notebook_new();
912 /* Local symbols */
913 sv_plugin->sl = gtk_scrolled_window_new (NULL, NULL);
914 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sv_plugin->sl),
915 GTK_SHADOW_IN);
916 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sv_plugin->sl),
917 GTK_POLICY_AUTOMATIC,
918 GTK_POLICY_AUTOMATIC);
919 /* Local symbols of the file */
920 sv_plugin->sl_tab_label = gtk_label_new (_("Local" ));
921 sv_plugin->sl_tree = anjuta_symbol_locals_new ();
922 g_object_add_weak_pointer (G_OBJECT (sv_plugin->sl_tree),
923 (gpointer)&sv_plugin->sl_tree);
924 g_signal_connect (G_OBJECT (sv_plugin->sl_tree), "row_activated",
925 G_CALLBACK (on_local_treeview_row_activated), plugin);
926 gtk_container_add (GTK_CONTAINER(sv_plugin->sl), sv_plugin->sl_tree);
928 /* add the scrolled window to the notebook */
929 gtk_notebook_append_page (GTK_NOTEBOOK(sv_plugin->sw),
930 sv_plugin->sl, sv_plugin->sl_tab_label );
932 /* Global symbols */
933 sv_plugin->sv = gtk_scrolled_window_new (NULL, NULL);
934 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sv_plugin->sv),
935 GTK_SHADOW_IN);
936 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sv_plugin->sv),
937 GTK_POLICY_AUTOMATIC,
938 GTK_POLICY_AUTOMATIC);
939 /* Global project-wide symbols */
940 sv_plugin->sv_tab_label = gtk_label_new (_("Global" ));
941 sv_plugin->sv_tree = anjuta_symbol_view_new ();
942 symbol_browser_load_global_tags (plugin);
944 g_object_add_weak_pointer (G_OBJECT (sv_plugin->sv_tree),
945 (gpointer)&sv_plugin->sv_tree);
947 g_signal_connect (G_OBJECT (sv_plugin->sv_tree), "event-after",
948 G_CALLBACK (on_treeview_event), plugin);
949 g_signal_connect (G_OBJECT (sv_plugin->sv_tree), "row_activated",
950 G_CALLBACK (on_treeview_row_activated), plugin);
952 gtk_container_add (GTK_CONTAINER(sv_plugin->sv), sv_plugin->sv_tree);
954 /* add the scrolled window to the notebook */
955 gtk_notebook_append_page (GTK_NOTEBOOK(sv_plugin->sw),
956 sv_plugin->sv, sv_plugin->sv_tab_label );
958 /* anjuta symbol search */
959 sv_plugin->ss =
960 anjuta_symbol_search_new (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree));
961 sv_plugin->ss_tab_label = gtk_label_new (_("Search" ));
963 g_object_add_weak_pointer (G_OBJECT (sv_plugin->ss),
964 (gpointer)&sv_plugin->ss);
966 gtk_notebook_append_page (GTK_NOTEBOOK(sv_plugin->sw), sv_plugin->ss,
967 sv_plugin->ss_tab_label );
969 gtk_widget_show_all (sv_plugin->sw);
971 /* connect some signals */
972 g_signal_connect (G_OBJECT (sv_plugin->ss), "symbol_selected",
973 G_CALLBACK (on_treesearch_symbol_selected_event),
974 plugin);
977 /* setting focus to the tree_view*/
978 gtk_notebook_set_current_page (GTK_NOTEBOOK (sv_plugin->sw), 0);
980 /* Add action group */
981 sv_plugin->action_group =
982 anjuta_ui_add_action_group_entries (sv_plugin->ui,
983 "ActionGroupSymbolBrowser",
984 _("Symbol browser actions"),
985 actions,
986 G_N_ELEMENTS (actions),
987 GETTEXT_PACKAGE, TRUE, plugin);
988 sv_plugin->popup_action_group =
989 anjuta_ui_add_action_group_entries (sv_plugin->ui,
990 "ActionGroupPopupSymbolBrowser",
991 _("Symbol browser popup actions"),
992 popup_actions,
993 G_N_ELEMENTS (popup_actions),
994 GETTEXT_PACKAGE, FALSE, plugin);
995 group = gtk_action_group_new ("ActionGroupSymbolNavigation");
997 anjuta_ui_add_action_group (sv_plugin->ui, "ActionGroupSymbolNavigation",
998 N_("Symbol navigations"), group, FALSE);
999 sv_plugin->action_group_nav = group;
1001 /* Add UI */
1002 sv_plugin->merge_id =
1003 anjuta_ui_merge (sv_plugin->ui, UI_FILE);
1005 /* Added widgets */
1006 anjuta_shell_add_widget (plugin->shell, sv_plugin->sw,
1007 "AnjutaSymbolBrowser", _("Symbols"),
1008 "symbol-browser-plugin-icon",
1009 ANJUTA_SHELL_PLACEMENT_LEFT, NULL);
1011 /* set up project directory watch */
1012 sv_plugin->root_watch_id = anjuta_plugin_add_watch (plugin,
1013 IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI,
1014 project_root_added,
1015 project_root_removed, NULL);
1016 sv_plugin->editor_watch_id =
1017 anjuta_plugin_add_watch (plugin, IANJUTA_DOCUMENT_MANAGER_CURRENT_DOCUMENT,
1018 value_added_current_editor,
1019 value_removed_current_editor, NULL);
1020 return TRUE;
1023 static gboolean
1024 deactivate_plugin (AnjutaPlugin *plugin)
1026 SymbolBrowserPlugin *sv_plugin;
1027 sv_plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin);
1029 /* Ensure all editor cached info are released */
1030 if (sv_plugin->editor_connected)
1032 g_hash_table_foreach (sv_plugin->editor_connected,
1033 on_editor_foreach_disconnect, plugin);
1034 g_hash_table_foreach (sv_plugin->editor_connected,
1035 on_editor_foreach_clear, plugin);
1036 g_hash_table_destroy (sv_plugin->editor_connected);
1037 sv_plugin->editor_connected = NULL;
1039 /* Remove watches */
1040 anjuta_plugin_remove_watch (plugin, sv_plugin->root_watch_id, FALSE);
1041 anjuta_plugin_remove_watch (plugin, sv_plugin->editor_watch_id, TRUE);
1043 /* Remove widgets: Widgets will be destroyed when sw is removed */
1044 anjuta_shell_remove_widget (plugin->shell, sv_plugin->sw, NULL);
1046 /* Remove UI */
1047 anjuta_ui_unmerge (sv_plugin->ui, sv_plugin->merge_id);
1049 /* Remove action group */
1050 anjuta_ui_remove_action_group (sv_plugin->ui, sv_plugin->action_group);
1051 anjuta_ui_remove_action_group (sv_plugin->ui, sv_plugin->popup_action_group);
1052 anjuta_ui_remove_action_group (sv_plugin->ui, sv_plugin->action_group_nav);
1054 sv_plugin->root_watch_id = 0;
1055 sv_plugin->editor_watch_id = 0;
1056 sv_plugin->merge_id = 0;
1057 sv_plugin->sw = NULL;
1058 sv_plugin->sl = NULL;
1059 sv_plugin->sl_tree = NULL;
1060 sv_plugin->sv = NULL;
1061 sv_plugin->sv_tree = NULL;
1062 sv_plugin->ss = NULL;
1063 return TRUE;
1066 static void
1067 dispose (GObject *obj)
1069 SymbolBrowserPlugin *sv_plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (obj);
1070 /* Ensure all editors are disconnected */
1071 if (sv_plugin->editor_connected)
1073 g_hash_table_foreach (sv_plugin->editor_connected,
1074 on_editor_foreach_disconnect,
1075 sv_plugin);
1076 g_hash_table_destroy (sv_plugin->editor_connected);
1077 sv_plugin->editor_connected = NULL;
1080 if (plugin->sw)
1082 g_object_unref (G_OBJECT (plugin->sw));
1083 plugin->sw = NULL;
1087 g_object_remove_weak_pointer (G_OBJECT (sv_plugin->ss),
1088 (gpointer)&sv_plugin->ss);
1091 G_OBJECT_CLASS (parent_class)->dispose (obj);
1094 static void
1095 finalize (GObject *obj)
1097 /* SymbolBrowserPlugin *plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (obj); */
1098 G_OBJECT_CLASS (parent_class)->finalize (obj);
1101 static void
1102 symbol_browser_plugin_instance_init (GObject *obj)
1104 SymbolBrowserPlugin *plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (obj);
1105 plugin->current_editor = NULL;
1106 plugin->editor_connected = NULL;
1107 plugin->sw = NULL;
1108 plugin->sv = NULL;
1109 plugin->gconf_notify_ids = NULL;
1110 plugin->locals_line_number = 0;
1111 plugin->launcher = NULL;
1114 static void
1115 symbol_browser_plugin_class_init (SymbolBrowserPluginClass *klass)
1117 GObjectClass *object_class;
1118 AnjutaPluginClass *plugin_class;
1120 parent_class = g_type_class_peek_parent (klass);
1121 object_class = G_OBJECT_CLASS (klass);
1122 plugin_class = ANJUTA_PLUGIN_CLASS (klass);
1124 plugin_class->activate = activate_plugin;
1125 plugin_class->deactivate = deactivate_plugin;
1127 object_class->dispose = dispose;
1128 object_class->finalize = finalize;
1131 static IAnjutaIterable*
1132 isymbol_manager_search (IAnjutaSymbolManager *sm,
1133 IAnjutaSymbolType match_types,
1134 gboolean include_types,
1135 IAnjutaSymbolField info_fields,
1136 const gchar *match_name,
1137 gboolean partial_name_match,
1138 gboolean global_symbols_search,
1139 gboolean global_tags_search, /* unused */
1140 gint results_limit, /* unused */
1141 gint results_offset, /* unused */
1142 GError **err)
1144 const GPtrArray *tags_array;
1145 AnjutaSymbolIter *iter = NULL;
1146 const gchar *name;
1148 if (match_name && strlen (match_name) > 0)
1149 name = match_name;
1150 else
1151 name = NULL;
1153 tags_array = tm_workspace_find (name, match_types, NULL,
1154 partial_name_match, global_symbols_search);
1155 if (tags_array && tags_array->len)
1157 iter = anjuta_symbol_iter_new (tags_array);
1158 return IANJUTA_ITERABLE (iter);
1160 return NULL;
1163 static IAnjutaIterable*
1164 isymbol_manager_get_members (IAnjutaSymbolManager *sm,
1165 IAnjutaSymbol *symbol,
1166 IAnjutaSymbolField info_fields,
1167 gboolean global_search,
1168 GError **err)
1170 const GPtrArray *tags_array;
1171 AnjutaSymbolIter *iter = NULL;
1172 AnjutaSymbol *s;
1174 s = ANJUTA_SYMBOL (symbol);
1176 tags_array = tm_workspace_find_scope_members (NULL, anjuta_symbol_get_name (s),
1177 global_search, TRUE);
1180 if (tags_array && tags_array->len)
1182 iter = anjuta_symbol_iter_new (tags_array);
1183 return IANJUTA_ITERABLE (iter);
1185 return NULL;
1188 static IAnjutaIterable*
1189 isymbol_manager_get_class_parents (IAnjutaSymbolManager *sm,
1190 IAnjutaSymbol *symbol,
1191 IAnjutaSymbolField info_fields,
1192 GError **err)
1194 const GPtrArray *tags_array;
1195 AnjutaSymbolIter *iter = NULL;
1196 AnjutaSymbol *s;
1198 s = ANJUTA_SYMBOL (symbol);
1200 tags_array = tm_workspace_get_parents (anjuta_symbol_get_name (s));
1201 if (tags_array && tags_array->len)
1203 iter = anjuta_symbol_iter_new (tags_array);
1204 return IANJUTA_ITERABLE (iter);
1206 return NULL;
1209 static void
1210 isymbol_manager_iface_init (IAnjutaSymbolManagerIface *iface)
1212 iface->search = isymbol_manager_search;
1213 iface->get_members = isymbol_manager_get_members;
1214 iface->get_class_parents = isymbol_manager_get_class_parents;
1217 static void
1218 ipreferences_merge(IAnjutaPreferences* ipref, AnjutaPreferences* prefs, GError** e)
1220 symbol_browser_prefs_init(ANJUTA_PLUGIN_SYMBOL_BROWSER (ipref));
1223 static void
1224 ipreferences_unmerge(IAnjutaPreferences* ipref, AnjutaPreferences* prefs, GError** e)
1226 symbol_browser_prefs_finalize (ANJUTA_PLUGIN_SYMBOL_BROWSER (ipref));
1229 static void
1230 ipreferences_iface_init(IAnjutaPreferencesIface* iface)
1232 iface->merge = ipreferences_merge;
1233 iface->unmerge = ipreferences_unmerge;
1236 ANJUTA_PLUGIN_BEGIN (SymbolBrowserPlugin, symbol_browser_plugin);
1237 ANJUTA_PLUGIN_ADD_INTERFACE (isymbol_manager, IANJUTA_TYPE_SYMBOL_MANAGER);
1238 ANJUTA_PLUGIN_ADD_INTERFACE (ipreferences, IANJUTA_TYPE_PREFERENCES);
1239 ANJUTA_PLUGIN_END;
1241 ANJUTA_SIMPLE_PLUGIN (SymbolBrowserPlugin, symbol_browser_plugin);