1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <libgnomevfs/gnome-vfs-utils.h>
23 #include <libanjuta/anjuta-shell.h>
24 #include <libanjuta/anjuta-debug.h>
25 #include <libanjuta/interfaces/ianjuta-help.h>
26 #include <libanjuta/interfaces/ianjuta-document-manager.h>
27 #include <libanjuta/interfaces/ianjuta-project-manager.h>
28 #include <libanjuta/interfaces/ianjuta-file-manager.h>
29 #include <libanjuta/interfaces/ianjuta-file.h>
30 #include <libanjuta/interfaces/ianjuta-file-loader.h>
31 #include <libanjuta/interfaces/ianjuta-editor.h>
32 #include <libanjuta/interfaces/ianjuta-markable.h>
33 #include <libanjuta/interfaces/ianjuta-symbol-manager.h>
34 #include <libanjuta/interfaces/ianjuta-preferences.h>
35 #include <libegg/menu/egg-combo-action.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"
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.png"
50 #define TIMEOUT_INTERVAL_SYMBOLS_UPDATE 10000
52 static gpointer parent_class
= NULL
;
53 static gboolean need_symbols_update
;
54 static gint timeout_id
;
55 static gchar prev_char_added
= ' ';
57 /* these will block signals on treeview and treesearch callbacks functions */
58 static void trees_signals_block (SymbolBrowserPlugin
*sv_plugin
);
59 static void trees_signals_unblock (SymbolBrowserPlugin
*sv_plugin
);
61 static void on_treesearch_symbol_selected_event (AnjutaSymbolSearch
*search
,
62 AnjutaSymbolInfo
*sym
,
63 SymbolBrowserPlugin
*sv_plugin
);
64 static void update_editor_symbol_model (SymbolBrowserPlugin
*sv_plugin
);
66 static void on_editor_update_ui (IAnjutaEditor
*editor
,
67 SymbolBrowserPlugin
*sv_plugin
);
68 static void on_char_added (IAnjutaEditor
*editor
, gint position
, gchar ch
,
69 SymbolBrowserPlugin
*sv_plugin
);
71 #define REGISTER_ICON(icon, stock_id) \
72 pixbuf = gdk_pixbuf_new_from_file (icon, NULL); \
73 icon_set = gtk_icon_set_new_from_pixbuf (pixbuf); \
74 gtk_icon_factory_add (icon_factory, stock_id, icon_set); \
75 g_object_unref (pixbuf);
78 register_stock_icons (AnjutaPlugin
*plugin
)
81 GtkIconFactory
*icon_factory
;
84 static gboolean registered
= FALSE
;
90 /* Register stock icons */
91 ui
= anjuta_shell_get_ui (plugin
->shell
, NULL
);
92 icon_factory
= anjuta_ui_get_icon_factory (ui
);
93 REGISTER_ICON (PACKAGE_PIXMAPS_DIR
"/"ICON_FILE
, "symbol-browser-plugin-icon");
97 goto_file_line (AnjutaPlugin
*plugin
, const gchar
*filename
, gint lineno
)
100 IAnjutaFileLoader
*loader
;
102 g_return_if_fail (filename
!= NULL
);
104 /* Go to file and line number */
105 loader
= anjuta_shell_get_interface (plugin
->shell
, IAnjutaFileLoader
,
108 uri
= g_strdup_printf ("file:///%s#%d", filename
, lineno
);
109 ianjuta_file_loader_load (loader
, uri
, FALSE
, NULL
);
114 goto_file_tag (SymbolBrowserPlugin
*sv_plugin
, const char *symbol
,
115 gboolean prefer_definition
)
121 ret
= anjuta_symbol_view_get_file_symbol (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
122 symbol
, prefer_definition
,
126 goto_file_line (ANJUTA_PLUGIN (sv_plugin
), file
, line
);
131 on_goto_def_activate (GtkAction
*action
, SymbolBrowserPlugin
*sv_plugin
)
137 ret
= anjuta_symbol_view_get_current_symbol_def (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
141 goto_file_line (ANJUTA_PLUGIN (sv_plugin
), file
, line
);
147 on_goto_decl_activate (GtkAction
*action
, SymbolBrowserPlugin
*sv_plugin
)
153 ret
= anjuta_symbol_view_get_current_symbol_decl (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
157 goto_file_line (ANJUTA_PLUGIN (sv_plugin
), file
, line
);
163 on_goto_file_tag_decl_activate (GtkAction
* action
,
164 SymbolBrowserPlugin
*sv_plugin
)
169 if (sv_plugin
->current_editor
)
171 ed
= IANJUTA_EDITOR (sv_plugin
->current_editor
);
172 word
= ianjuta_editor_get_current_word (ed
, NULL
);
175 goto_file_tag (sv_plugin
, word
, FALSE
);
182 on_goto_file_tag_def_activate (GtkAction
* action
,
183 SymbolBrowserPlugin
*sv_plugin
)
188 if (sv_plugin
->current_editor
)
190 ed
= IANJUTA_EDITOR (sv_plugin
->current_editor
);
191 word
= ianjuta_editor_get_current_word (ed
, NULL
);
194 goto_file_tag (sv_plugin
, word
, TRUE
);
201 on_find_activate (GtkAction
*action
, SymbolBrowserPlugin
*sv_plugin
)
204 symbol
= anjuta_symbol_view_get_current_symbol (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
));
207 g_warning ("TODO: Unimplemented");
213 on_refresh_idle (gpointer user_data
)
215 IAnjutaProjectManager
*pm
;
218 AnjutaStatus
*status
;
219 SymbolBrowserPlugin
*sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (user_data
);
221 /* FIXME: There should be a way to ensure that this project manager
222 * is indeed the one that has opened the project_uri
224 pm
= anjuta_shell_get_interface (ANJUTA_PLUGIN (sv_plugin
)->shell
,
225 IAnjutaProjectManager
, NULL
);
226 g_return_val_if_fail (pm
!= NULL
, FALSE
);
228 status
= anjuta_shell_get_status (ANJUTA_PLUGIN (sv_plugin
)->shell
, NULL
);
229 anjuta_status_push (status
, "Refreshing symbol tree...");
230 anjuta_status_busy_push (status
);
232 source_uris
= source_files
= NULL
;
233 source_uris
= ianjuta_project_manager_get_elements (pm
,
234 IANJUTA_PROJECT_MANAGER_SOURCE
,
246 uri
= (const gchar
*)node
->data
;
247 file_path
= gnome_vfs_get_local_path_from_uri (uri
);
249 source_files
= g_list_prepend (source_files
, file_path
);
250 node
= g_list_next (node
);
252 source_files
= g_list_reverse (source_files
);
254 anjuta_symbol_view_update (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
256 g_list_foreach (source_files
, (GFunc
)g_free
, NULL
);
257 g_list_foreach (source_uris
, (GFunc
)g_free
, NULL
);
258 g_list_free (source_files
);
259 g_list_free (source_uris
);
261 /* Current editor symbol model may have changed */
262 update_editor_symbol_model (sv_plugin
);
264 anjuta_status_busy_pop (status
);
265 anjuta_status_pop (status
);
270 on_refresh_activate (GtkAction
*action
, SymbolBrowserPlugin
*sv_plugin
)
272 if (!sv_plugin
->project_root_uri
)
274 g_idle_add (on_refresh_idle
, sv_plugin
);
277 static GtkActionEntry actions
[] =
279 { "ActionMenuGoto", NULL
, N_("_Goto"), NULL
, NULL
, NULL
},
281 "ActionSymbolBrowserGotoDef",
283 N_("Tag _Definition"),
285 N_("Goto symbol definition"),
286 G_CALLBACK (on_goto_file_tag_def_activate
)
289 "ActionSymbolBrowserGotoDecl",
291 N_("Tag De_claration"),
293 N_("Goto symbol declaration"),
294 G_CALLBACK (on_goto_file_tag_decl_activate
)
298 static GtkActionEntry popup_actions
[] =
301 "ActionPopupSymbolBrowserGotoDef",
303 N_("Goto _Definition"),
305 N_("Goto symbol definition"),
306 G_CALLBACK (on_goto_def_activate
)
309 "ActionPopupSymbolBrowserGotoDecl",
311 N_("Goto De_claration"),
313 N_("Goto symbol declaration"),
314 G_CALLBACK (on_goto_decl_activate
)
317 "ActionPopupSymbolBrowserFind",
321 N_("Find usage of symbol in project"),
322 G_CALLBACK (on_find_activate
)
325 "ActionPopupSymbolBrowserRefresh",
329 N_("Refresh symbol browser tree"),
330 G_CALLBACK (on_refresh_activate
)
335 on_project_element_added (IAnjutaProjectManager
*pm
, const gchar
*uri
,
336 SymbolBrowserPlugin
*sv_plugin
)
340 if (!sv_plugin
->project_root_uri
)
343 filename
= gnome_vfs_get_local_path_from_uri (uri
);
346 anjuta_symbol_view_add_source (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
353 on_project_element_removed (IAnjutaProjectManager
*pm
, const gchar
*uri
,
354 SymbolBrowserPlugin
*sv_plugin
)
358 if (!sv_plugin
->project_root_uri
)
361 filename
= gnome_vfs_get_local_path_from_uri (uri
);
364 anjuta_symbol_view_remove_source (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
372 project_root_added (AnjutaPlugin
*plugin
, const gchar
*name
,
373 const GValue
*value
, gpointer user_data
)
375 AnjutaStatus
*status
;
376 IAnjutaProjectManager
*pm
;
377 SymbolBrowserPlugin
*sv_plugin
;
378 const gchar
*root_uri
;
380 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
382 g_free (sv_plugin
->project_root_uri
);
383 sv_plugin
->project_root_uri
= NULL
;
384 root_uri
= g_value_get_string (value
);
387 gchar
*root_dir
= gnome_vfs_get_local_path_from_uri (root_uri
);
390 status
= anjuta_shell_get_status (plugin
->shell
, NULL
);
391 anjuta_status_progress_add_ticks (status
, 1);
392 trees_signals_block (sv_plugin
);
393 anjuta_symbol_view_open (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
396 /* Current editor symbol model may have changed */
397 update_editor_symbol_model (sv_plugin
);
398 anjuta_status_progress_tick (status
, NULL
, _("Created symbols..."));
399 trees_signals_unblock (sv_plugin
);
402 sv_plugin
->project_root_uri
= g_strdup (root_uri
);
404 /* FIXME: There should be a way to ensure that this project manager
405 * is indeed the one that has opened the project_uri
407 pm
= anjuta_shell_get_interface (ANJUTA_PLUGIN (sv_plugin
)->shell
,
408 IAnjutaProjectManager
, NULL
);
409 g_signal_connect (G_OBJECT (pm
), "element_added",
410 G_CALLBACK (on_project_element_added
), sv_plugin
);
411 g_signal_connect (G_OBJECT (pm
), "element_removed",
412 G_CALLBACK (on_project_element_removed
), sv_plugin
);
416 project_root_removed (AnjutaPlugin
*plugin
, const gchar
*name
,
419 IAnjutaProjectManager
*pm
;
420 SymbolBrowserPlugin
*sv_plugin
;
422 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
424 /* Disconnect events from project manager */
426 /* FIXME: There should be a way to ensure that this project manager
427 * is indeed the one that has opened the project_uri
429 pm
= anjuta_shell_get_interface (ANJUTA_PLUGIN (sv_plugin
)->shell
,
430 IAnjutaProjectManager
, NULL
);
431 g_signal_handlers_disconnect_by_func (G_OBJECT (pm
),
432 on_project_element_added
,
434 g_signal_handlers_disconnect_by_func (G_OBJECT (pm
),
435 on_project_element_removed
,
438 /* clear anjuta_symbol_search side */
439 anjuta_symbol_search_clear(ANJUTA_SYMBOL_SEARCH(sv_plugin
->ss
));
441 /* clear glist's sfiles */
442 anjuta_symbol_view_clear (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
));
444 g_free (sv_plugin
->project_root_uri
);
445 sv_plugin
->project_root_uri
= NULL
;
449 on_treeview_event (GtkWidget
*widget
,
451 SymbolBrowserPlugin
*sv_plugin
)
455 GtkTreeSelection
*selection
;
457 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget
), FALSE
);
459 view
= GTK_TREE_VIEW (widget
);
460 model
= gtk_tree_view_get_model (view
);
461 selection
= gtk_tree_view_get_selection (view
);
466 if (event
->type
== GDK_BUTTON_PRESS
) {
467 GdkEventButton
*e
= (GdkEventButton
*) event
;
469 if (e
->button
== 3) {
472 /* Popup project menu */
473 menu
= gtk_ui_manager_get_widget (GTK_UI_MANAGER (sv_plugin
->ui
),
474 "/PopupSymbolBrowser");
475 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
,
476 NULL
, NULL
, e
->button
, e
->time
);
479 } else if (event
->type
== GDK_KEY_PRESS
) {
480 GdkEventKey
*e
= (GdkEventKey
*) event
;
484 anjuta_ui_activate_action_by_group (sv_plugin
->ui
,
485 sv_plugin
->popup_action_group
,
486 "ActionPopupSymbolBrowserGotoDef");
496 on_treeview_row_activated (GtkTreeView
*view
, GtkTreePath
*arg1
,
497 GtkTreeViewColumn
*arg2
,
498 SymbolBrowserPlugin
*sv_plugin
)
501 GtkTreeSelection
*selection
;
504 selection
= gtk_tree_view_get_selection (view
);
505 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
507 anjuta_ui_activate_action_by_group (sv_plugin
->ui
,
508 sv_plugin
->popup_action_group
,
509 "ActionPopupSymbolBrowserGotoDef");
513 trees_signals_block (SymbolBrowserPlugin
*sv_plugin
)
515 g_signal_handlers_block_by_func (G_OBJECT (sv_plugin
->sv_tree
),
516 G_CALLBACK (on_treeview_event
), NULL
);
518 g_signal_handlers_block_by_func (G_OBJECT (sv_plugin
->ss
),
519 G_CALLBACK (on_treesearch_symbol_selected_event
),
525 trees_signals_unblock (SymbolBrowserPlugin
*sv_plugin
)
527 g_signal_handlers_unblock_by_func (G_OBJECT (sv_plugin
->sv_tree
),
528 G_CALLBACK (on_treeview_event
), NULL
);
530 g_signal_handlers_unblock_by_func (G_OBJECT (sv_plugin
->ss
),
531 G_CALLBACK (on_treesearch_symbol_selected_event
),
536 goto_tree_iter (SymbolBrowserPlugin
*sv_plugin
, GtkTreeIter
*iter
)
541 line
= anjuta_symbol_view_workspace_get_line (ANJUTA_SYMBOL_VIEW
542 (sv_plugin
->sv_tree
),
545 if (line
> 0 && sv_plugin
->current_editor
)
547 /* Goto line number */
548 ianjuta_editor_goto_line (IANJUTA_EDITOR (sv_plugin
->current_editor
),
550 if (IANJUTA_IS_MARKABLE (sv_plugin
->current_editor
))
552 ianjuta_markable_delete_all_markers (IANJUTA_MARKABLE (sv_plugin
->current_editor
),
553 IANJUTA_MARKABLE_LINEMARKER
,
556 ianjuta_markable_mark (IANJUTA_MARKABLE (sv_plugin
->current_editor
),
557 line
, IANJUTA_MARKABLE_LINEMARKER
, NULL
);
563 on_symbol_selected (GtkAction
*action
, SymbolBrowserPlugin
*sv_plugin
)
567 if (egg_combo_action_get_active_iter (EGG_COMBO_ACTION (action
), &iter
))
569 goto_tree_iter (sv_plugin
, &iter
);
574 on_local_treeview_row_activated (GtkTreeView
*view
, GtkTreePath
*arg1
,
575 GtkTreeViewColumn
*arg2
,
576 SymbolBrowserPlugin
*sv_plugin
)
579 GtkTreeSelection
*selection
;
582 selection
= gtk_tree_view_get_selection (view
);
583 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
585 goto_tree_iter (sv_plugin
, &iter
);
588 /* -----------------------------------------------------------------------------
589 * will manage the click of mouse and other events on search->hitlist treeview
592 on_treesearch_symbol_selected_event (AnjutaSymbolSearch
*search
,
593 AnjutaSymbolInfo
*sym
,
594 SymbolBrowserPlugin
*sv_plugin
) {
599 ret
= anjuta_symbol_view_get_file_symbol (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
604 goto_file_line (ANJUTA_PLUGIN (sv_plugin
), file
, line
);
609 on_editor_destroy (SymbolBrowserPlugin
*sv_plugin
, IAnjutaEditor
*editor
)
613 if (!sv_plugin
->editor_connected
|| !sv_plugin
->sv_tree
)
615 uri
= g_hash_table_lookup (sv_plugin
->editor_connected
, G_OBJECT (editor
));
616 if (uri
&& strlen (uri
) > 0)
618 DEBUG_PRINT ("Removing file tags of %s", uri
);
619 anjuta_symbol_view_workspace_remove_file (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
622 g_hash_table_remove (sv_plugin
->editor_connected
, G_OBJECT (editor
));
626 on_editor_saved (IAnjutaEditor
*editor
, const gchar
*saved_uri
,
627 SymbolBrowserPlugin
*sv_plugin
)
629 const gchar
*old_uri
;
630 gboolean tags_update
;
631 GtkTreeModel
*file_symbol_model
;
635 /* FIXME: Do this only if automatic tags update is enabled */
637 anjuta_preferences_get_int (te->preferences, AUTOMATIC_TAGS_UPDATE);
642 gchar
*local_filename
;
644 /* Verify that it's local file */
645 local_filename
= gnome_vfs_get_local_path_from_uri (saved_uri
);
646 g_return_if_fail (local_filename
!= NULL
);
647 g_free (local_filename
);
649 if (!sv_plugin
->editor_connected
)
652 old_uri
= g_hash_table_lookup (sv_plugin
->editor_connected
, editor
);
654 if (old_uri
&& strlen (old_uri
) <= 0)
656 anjuta_symbol_view_workspace_update_file (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
658 g_hash_table_insert (sv_plugin
->editor_connected
, editor
,
659 g_strdup (saved_uri
));
661 /* Update File symbol view */
662 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN (sv_plugin
)->shell
, NULL
);
663 action
= anjuta_ui_get_action (ui
, "ActionGroupSymbolNavigation",
668 anjuta_symbol_view_get_file_symbol_model (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
));
669 g_object_set_data (G_OBJECT (editor
), "tm_file",
670 g_object_get_data (G_OBJECT (file_symbol_model
),
672 /* Set toolbar version */
673 egg_combo_action_set_model (EGG_COMBO_ACTION (action
), file_symbol_model
);
674 /* Set local view version */
675 gtk_tree_view_set_model (GTK_TREE_VIEW (sv_plugin
->sl_tree
),
677 sv_plugin
->locals_line_number
= 0;
678 on_editor_update_ui (editor
, sv_plugin
);
680 if (gtk_tree_model_iter_n_children (file_symbol_model
, NULL
) > 0)
681 g_object_set (G_OBJECT (action
), "sensitive", TRUE
, NULL
);
683 g_object_set (G_OBJECT (action
), "sensitive", FALSE
, NULL
);
686 /* FIXME: Re-hilite all editors on tags update */
689 for (tmp
= app
->text_editor_list
; tmp
; tmp
= g_list_next(tmp
))
691 te1
= TEXT_EDITOR (tmp
->data
);
692 text_editor_set_hilite_type(te1
);
700 on_editor_foreach_disconnect (gpointer key
, gpointer value
, gpointer user_data
)
702 g_signal_handlers_disconnect_by_func (G_OBJECT(key
),
703 G_CALLBACK (on_editor_saved
),
705 g_signal_handlers_disconnect_by_func (G_OBJECT(key
),
706 G_CALLBACK (on_editor_update_ui
),
708 g_signal_handlers_disconnect_by_func (G_OBJECT(key
),
709 G_CALLBACK (on_char_added
),
711 g_object_weak_unref (G_OBJECT(key
),
712 (GWeakNotify
) (on_editor_destroy
),
717 on_editor_foreach_clear (gpointer key
, gpointer value
, gpointer user_data
)
720 SymbolBrowserPlugin
*sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (user_data
);
722 uri
= (const gchar
*)value
;
723 if (uri
&& strlen (uri
) > 0)
725 DEBUG_PRINT ("Removing file tags of %s", uri
);
726 anjuta_symbol_view_workspace_remove_file (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
732 update_editor_symbol_model (SymbolBrowserPlugin
*sv_plugin
)
736 GObject
*editor
= sv_plugin
->current_editor
;
741 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN (sv_plugin
)->shell
, NULL
);
742 uri
= ianjuta_file_get_uri (IANJUTA_FILE (editor
), NULL
);
745 gchar
*local_filename
;
746 GtkTreeModel
*file_symbol_model
;
749 /* Verify that it's local file */
750 local_filename
= gnome_vfs_get_local_path_from_uri (uri
);
751 g_return_if_fail (local_filename
!= NULL
);
752 g_free (local_filename
);
754 anjuta_symbol_view_workspace_add_file (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
), uri
);
755 action
= anjuta_ui_get_action (ui
, "ActionGroupSymbolNavigation",
759 anjuta_symbol_view_get_file_symbol_model (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
));
760 if (file_symbol_model
)
762 g_object_set_data (G_OBJECT (editor
), "tm_file",
763 g_object_get_data (G_OBJECT (file_symbol_model
),
765 /* Set toolbar version */
766 egg_combo_action_set_model (EGG_COMBO_ACTION (action
), file_symbol_model
);
768 /* Set local view version */
769 gtk_tree_view_set_model (GTK_TREE_VIEW (sv_plugin
->sl_tree
),
771 sv_plugin
->locals_line_number
= 0;
772 on_editor_update_ui (IANJUTA_EDITOR (editor
), sv_plugin
);
774 if (gtk_tree_model_iter_n_children (file_symbol_model
, NULL
) > 0)
775 g_object_set (G_OBJECT (action
), "sensitive", TRUE
, NULL
);
777 g_object_set (G_OBJECT (action
), "sensitive", FALSE
, NULL
);
785 on_editor_buffer_symbols_update_timeout (gpointer user_data
)
787 SymbolBrowserPlugin
*sv_plugin
;
789 gchar
*current_buffer
= NULL
;
790 gint buffer_size
= 0;
793 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (user_data
);
795 if (sv_plugin
->current_editor
== NULL
)
798 /* we won't proceed with the updating of the symbols if we didn't type in
800 if (!need_symbols_update
)
803 if (sv_plugin
->current_editor
) {
804 ed
= IANJUTA_EDITOR (sv_plugin
->current_editor
);
806 buffer_size
= ianjuta_editor_get_length (ed
, NULL
);
807 current_buffer
= ianjuta_editor_get_text (ed
, 0, -1, NULL
);
809 uri
= ianjuta_file_get_uri (IANJUTA_FILE (ed
), NULL
);
816 /* FIXME: Only uncomment after investigating bug 395362 */
818 anjuta_symbol_view_update_source_from_buffer (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
819 uri, current_buffer, buffer_size);
825 g_free (current_buffer
);
827 need_symbols_update
= FALSE
;
833 iter_matches (SymbolBrowserPlugin
*sv_plugin
, GtkTreeIter
* iter
,
834 GtkTreeModel
* model
, gint lineno
)
837 gtk_tree_model_get (model
, iter
, COL_LINE
, &line
, -1);
840 GtkTreePath
* path
= gtk_tree_model_get_path (model
, iter
);
841 GtkAction
* action
= anjuta_ui_get_action (sv_plugin
->ui
,
842 "ActionGroupSymbolNavigation",
845 egg_combo_action_set_active_iter (EGG_COMBO_ACTION (action
), iter
);
846 gtk_tree_view_set_cursor (GTK_TREE_VIEW (sv_plugin
->sl_tree
), path
, NULL
,
848 gtk_tree_path_free (path
);
855 on_editor_update_ui (IAnjutaEditor
*editor
, SymbolBrowserPlugin
*sv_plugin
)
857 gint lineno
= ianjuta_editor_get_lineno (editor
, NULL
);
859 GtkTreeModel
* model
= anjuta_symbol_view_get_file_symbol_model
860 (ANJUTA_SYMBOL_VIEW(sv_plugin
->sv_tree
));
862 gboolean found
= FALSE
;
864 if (sv_plugin
->locals_line_number
== lineno
)
866 sv_plugin
->locals_line_number
= lineno
;
868 if (!gtk_tree_model_get_iter_first (model
, &iter
))
870 while (!found
&& lineno
>= 0)
872 gtk_tree_model_get_iter_first (model
, &iter
);
875 found
= iter_matches (sv_plugin
, &iter
, model
, lineno
);
879 while (gtk_tree_model_iter_next (model
, &iter
));
885 on_char_added (IAnjutaEditor
*editor
, gint position
, gchar ch
,
886 SymbolBrowserPlugin
*sv_plugin
)
888 DEBUG_PRINT ("char added @ %d : %c [int %d]", position
, ch
, ch
);
890 /* try to force the update if a "." or a "->" is pressed */
891 if ((ch
== '.') || (prev_char_added
== '-' && ch
== '>'))
892 on_editor_buffer_symbols_update_timeout (sv_plugin
);
894 need_symbols_update
= TRUE
;
896 prev_char_added
= ch
;
900 value_added_current_editor (AnjutaPlugin
*plugin
, const char *name
,
901 const GValue
*value
, gpointer data
)
905 SymbolBrowserPlugin
*sv_plugin
;
907 editor
= g_value_get_object (value
);
909 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
911 if (!sv_plugin
->editor_connected
)
913 sv_plugin
->editor_connected
= g_hash_table_new_full (g_direct_hash
,
917 sv_plugin
->current_editor
= editor
;
919 update_editor_symbol_model (sv_plugin
);
921 uri
= ianjuta_file_get_uri (IANJUTA_FILE (editor
), NULL
);
922 if (g_hash_table_lookup (sv_plugin
->editor_connected
, editor
) == NULL
)
924 g_object_weak_ref (G_OBJECT (editor
),
925 (GWeakNotify
) (on_editor_destroy
),
929 g_hash_table_insert (sv_plugin
->editor_connected
, editor
,
934 g_hash_table_insert (sv_plugin
->editor_connected
, editor
,
937 g_signal_connect (G_OBJECT (editor
), "saved",
938 G_CALLBACK (on_editor_saved
),
941 g_signal_connect (G_OBJECT (editor
), "char-added",
942 G_CALLBACK (on_char_added
),
944 g_signal_connect (G_OBJECT(editor
), "update_ui",
945 G_CALLBACK (on_editor_update_ui
),
950 /* add a default timeout to the updating of buffer symbols */
951 timeout_id
= g_timeout_add (TIMEOUT_INTERVAL_SYMBOLS_UPDATE
,
952 on_editor_buffer_symbols_update_timeout
,
954 need_symbols_update
= FALSE
;
959 value_removed_current_editor (AnjutaPlugin
*plugin
,
960 const char *name
, gpointer data
)
963 SymbolBrowserPlugin
*sv_plugin
;
966 /* let's remove the timeout for symbols refresh */
967 g_source_remove (timeout_id
);
968 need_symbols_update
= FALSE
;
970 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
971 ui
= anjuta_shell_get_ui (plugin
->shell
, NULL
);
972 action
= anjuta_ui_get_action (ui
, "ActionGroupSymbolNavigation",
974 g_object_set (G_OBJECT (action
), "sensitive", FALSE
, NULL
);
975 sv_plugin
->current_editor
= NULL
;
979 activate_plugin (AnjutaPlugin
*plugin
)
981 GtkActionGroup
*group
;
983 SymbolBrowserPlugin
*sv_plugin
;
985 DEBUG_PRINT ("SymbolBrowserPlugin: Activating Symbol Manager plugin...");
987 register_stock_icons (plugin
);
989 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
990 sv_plugin
->ui
= anjuta_shell_get_ui (plugin
->shell
, NULL
);
991 sv_plugin
->prefs
= anjuta_shell_get_preferences (plugin
->shell
, NULL
);
994 sv_plugin
->sw
= gtk_notebook_new();
997 sv_plugin
->sl
= gtk_scrolled_window_new (NULL
, NULL
);
998 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sv_plugin
->sl
),
1000 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sv_plugin
->sl
),
1001 GTK_POLICY_AUTOMATIC
,
1002 GTK_POLICY_AUTOMATIC
);
1004 sv_plugin
->sl_tab_label
= gtk_label_new (_("Local" ));
1005 sv_plugin
->sl_tree
= anjuta_symbol_locals_new ();
1006 g_object_add_weak_pointer (G_OBJECT (sv_plugin
->sl_tree
),
1007 (gpointer
)&sv_plugin
->sl_tree
);
1008 g_signal_connect (G_OBJECT (sv_plugin
->sl_tree
), "row_activated",
1009 G_CALLBACK (on_local_treeview_row_activated
), plugin
);
1010 gtk_container_add (GTK_CONTAINER(sv_plugin
->sl
), sv_plugin
->sl_tree
);
1012 /* add the scrolled window to the notebook */
1013 gtk_notebook_append_page (GTK_NOTEBOOK(sv_plugin
->sw
),
1014 sv_plugin
->sl
, sv_plugin
->sl_tab_label
);
1016 /* Global symbols */
1017 sv_plugin
->sv
= gtk_scrolled_window_new (NULL
, NULL
);
1018 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sv_plugin
->sv
),
1020 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sv_plugin
->sv
),
1021 GTK_POLICY_AUTOMATIC
,
1022 GTK_POLICY_AUTOMATIC
);
1024 sv_plugin
->sv_tab_label
= gtk_label_new (_("Global" ));
1025 sv_plugin
->sv_tree
= anjuta_symbol_view_new ();
1026 g_object_add_weak_pointer (G_OBJECT (sv_plugin
->sv_tree
),
1027 (gpointer
)&sv_plugin
->sv_tree
);
1029 g_signal_connect (G_OBJECT (sv_plugin
->sv_tree
), "event-after",
1030 G_CALLBACK (on_treeview_event
), plugin
);
1031 g_signal_connect (G_OBJECT (sv_plugin
->sv_tree
), "row_activated",
1032 G_CALLBACK (on_treeview_row_activated
), plugin
);
1034 gtk_container_add (GTK_CONTAINER(sv_plugin
->sv
), sv_plugin
->sv_tree
);
1036 /* add the scrolled window to the notebook */
1037 gtk_notebook_append_page (GTK_NOTEBOOK(sv_plugin
->sw
),
1038 sv_plugin
->sv
, sv_plugin
->sv_tab_label
);
1040 /* anjuta symbol search */
1042 anjuta_symbol_search_new (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
));
1043 sv_plugin
->ss_tab_label
= gtk_label_new (_("Search" ));
1045 g_object_add_weak_pointer (G_OBJECT (sv_plugin
->ss
),
1046 (gpointer
)&sv_plugin
->ss
);
1048 gtk_notebook_append_page (GTK_NOTEBOOK(sv_plugin
->sw
), sv_plugin
->ss
,
1049 sv_plugin
->ss_tab_label
);
1051 gtk_widget_show_all (sv_plugin
->sw
);
1053 /* connect some signals */
1054 g_signal_connect (G_OBJECT (sv_plugin
->ss
), "symbol_selected",
1055 G_CALLBACK (on_treesearch_symbol_selected_event
),
1059 /* setting focus to the tree_view*/
1060 gtk_notebook_set_current_page (GTK_NOTEBOOK (sv_plugin
->sw
), 0);
1062 /* Add action group */
1063 sv_plugin
->action_group
=
1064 anjuta_ui_add_action_group_entries (sv_plugin
->ui
,
1065 "ActionGroupSymbolBrowser",
1066 _("Symbol browser actions"),
1068 G_N_ELEMENTS (actions
),
1069 GETTEXT_PACKAGE
, TRUE
, plugin
);
1070 sv_plugin
->popup_action_group
=
1071 anjuta_ui_add_action_group_entries (sv_plugin
->ui
,
1072 "ActionGroupPopupSymbolBrowser",
1073 _("Symbol browser popup actions"),
1075 G_N_ELEMENTS (popup_actions
),
1076 GETTEXT_PACKAGE
, FALSE
, plugin
);
1077 group
= gtk_action_group_new ("ActionGroupSymbolNavigation");
1079 /* create a new combobox in style of libegg... */
1080 action
= g_object_new (EGG_TYPE_COMBO_ACTION
,
1081 "name", "ActionGotoSymbol",
1082 "label", _("Goto symbol"),
1083 "tooltip", _("Select the symbol to go"),
1084 "stock_id", GTK_STOCK_JUMP_TO
,
1087 g_object_set (G_OBJECT (action
), "sensitive", FALSE
, NULL
);
1088 g_signal_connect (action
, "activate",
1089 G_CALLBACK (on_symbol_selected
), sv_plugin
);
1090 gtk_action_group_add_action (group
, action
);
1091 anjuta_ui_add_action_group (sv_plugin
->ui
, "ActionGroupSymbolNavigation",
1092 N_("Symbol navigations"), group
, FALSE
);
1093 sv_plugin
->action_group_nav
= group
;
1096 sv_plugin
->merge_id
=
1097 anjuta_ui_merge (sv_plugin
->ui
, UI_FILE
);
1100 anjuta_shell_add_widget (plugin
->shell
, sv_plugin
->sw
,
1101 "AnjutaSymbolBrowser", _("Symbols"),
1102 "symbol-browser-plugin-icon",
1103 ANJUTA_SHELL_PLACEMENT_LEFT
, NULL
);
1105 /* set up project directory watch */
1106 sv_plugin
->root_watch_id
= anjuta_plugin_add_watch (plugin
,
1109 project_root_removed
, NULL
);
1110 sv_plugin
->editor_watch_id
=
1111 anjuta_plugin_add_watch (plugin
, "document_manager_current_editor",
1112 value_added_current_editor
,
1113 value_removed_current_editor
, NULL
);
1119 deactivate_plugin (AnjutaPlugin
*plugin
)
1121 SymbolBrowserPlugin
*sv_plugin
;
1122 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
1124 /* Ensure all editor cached info are released */
1125 if (sv_plugin
->editor_connected
)
1127 g_hash_table_foreach (sv_plugin
->editor_connected
,
1128 on_editor_foreach_disconnect
, plugin
);
1129 g_hash_table_foreach (sv_plugin
->editor_connected
,
1130 on_editor_foreach_clear
, plugin
);
1131 g_hash_table_destroy (sv_plugin
->editor_connected
);
1132 sv_plugin
->editor_connected
= NULL
;
1134 /* Remove watches */
1135 anjuta_plugin_remove_watch (plugin
, sv_plugin
->root_watch_id
, FALSE
);
1136 anjuta_plugin_remove_watch (plugin
, sv_plugin
->editor_watch_id
, TRUE
);
1138 /* Remove widgets: Widgets will be destroyed when sw is removed */
1139 anjuta_shell_remove_widget (plugin
->shell
, sv_plugin
->sw
, NULL
);
1142 anjuta_ui_unmerge (sv_plugin
->ui
, sv_plugin
->merge_id
);
1144 /* Remove action group */
1145 anjuta_ui_remove_action_group (sv_plugin
->ui
, sv_plugin
->action_group
);
1146 anjuta_ui_remove_action_group (sv_plugin
->ui
, sv_plugin
->popup_action_group
);
1147 anjuta_ui_remove_action_group (sv_plugin
->ui
, sv_plugin
->action_group_nav
);
1149 sv_plugin
->root_watch_id
= 0;
1150 sv_plugin
->editor_watch_id
= 0;
1151 sv_plugin
->merge_id
= 0;
1152 sv_plugin
->sw
= NULL
;
1153 sv_plugin
->sl
= NULL
;
1154 sv_plugin
->sl_tree
= NULL
;
1155 sv_plugin
->sv
= NULL
;
1156 sv_plugin
->sv_tree
= NULL
;
1157 sv_plugin
->ss
= NULL
;
1162 dispose (GObject
*obj
)
1164 SymbolBrowserPlugin
*sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (obj
);
1165 /* Ensure all editors are disconnected */
1166 if (sv_plugin
->editor_connected
)
1168 g_hash_table_foreach (sv_plugin
->editor_connected
,
1169 on_editor_foreach_disconnect
,
1171 g_hash_table_destroy (sv_plugin
->editor_connected
);
1172 sv_plugin
->editor_connected
= NULL
;
1177 g_object_unref (G_OBJECT (plugin->sw));
1182 g_object_remove_weak_pointer (G_OBJECT (sv_plugin
->ss
),
1183 (gpointer
)&sv_plugin
->ss
);
1186 GNOME_CALL_PARENT (G_OBJECT_CLASS
, dispose
, (obj
));
1190 finalize (GObject
*obj
)
1192 /* SymbolBrowserPlugin *plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (obj); */
1193 GNOME_CALL_PARENT (G_OBJECT_CLASS
, finalize
, (obj
));
1197 symbol_browser_plugin_instance_init (GObject
*obj
)
1199 SymbolBrowserPlugin
*plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (obj
);
1200 plugin
->current_editor
= NULL
;
1201 plugin
->editor_connected
= NULL
;
1204 plugin
->gconf_notify_ids
= NULL
;
1205 plugin
->locals_line_number
= 0;
1206 plugin
->launcher
= NULL
;
1210 symbol_browser_plugin_class_init (SymbolBrowserPluginClass
*klass
)
1212 GObjectClass
*object_class
;
1213 AnjutaPluginClass
*plugin_class
;
1215 parent_class
= g_type_class_peek_parent (klass
);
1216 object_class
= G_OBJECT_CLASS (klass
);
1217 plugin_class
= ANJUTA_PLUGIN_CLASS (klass
);
1219 plugin_class
->activate
= activate_plugin
;
1220 plugin_class
->deactivate
= deactivate_plugin
;
1222 object_class
->dispose
= dispose
;
1223 object_class
->finalize
= finalize
;
1226 static IAnjutaIterable
*
1227 isymbol_manager_search (IAnjutaSymbolManager
*sm
,
1228 IAnjutaSymbolType match_types
,
1229 const gchar
*match_name
,
1230 gboolean partial_name_match
,
1231 gboolean global_search
,
1234 const GPtrArray
*tags_array
;
1235 AnjutaSymbolIter
*iter
= NULL
;
1238 if (match_name
&& strlen (match_name
) > 0)
1243 tags_array
= tm_workspace_find (name
, match_types
, NULL
,
1244 partial_name_match
, global_search
);
1247 iter
= anjuta_symbol_iter_new (tags_array
);
1248 return IANJUTA_ITERABLE (iter
);
1253 static IAnjutaIterable
*
1254 isymbol_manager_get_members (IAnjutaSymbolManager
*sm
,
1255 const gchar
*symbol_name
,
1256 gboolean global_search
,
1259 const GPtrArray
*tags_array
;
1260 AnjutaSymbolIter
*iter
= NULL
;
1262 tags_array
= tm_workspace_find_scope_members (NULL
, symbol_name
,
1263 global_search
, TRUE
);
1268 iter
= anjuta_symbol_iter_new (tags_array
);
1269 return IANJUTA_ITERABLE (iter
);
1274 static IAnjutaIterable
*
1275 isymbol_manager_get_parents (IAnjutaSymbolManager
*sm
,
1276 const gchar
*symbol_name
,
1279 const GPtrArray
*tags_array
;
1280 AnjutaSymbolIter
*iter
= NULL
;
1282 tags_array
= tm_workspace_get_parents (symbol_name
);
1285 iter
= anjuta_symbol_iter_new (tags_array
);
1286 return IANJUTA_ITERABLE (iter
);
1291 static IAnjutaIterable
*
1292 isymbol_manager_get_completions_at_position (IAnjutaSymbolManager
*sm
,
1293 const gchar
*file_uri
,
1294 const gchar
*text_buffer
,
1299 SymbolBrowserPlugin
*sv_plugin
;
1300 const TMTag
*func_scope_tag
;
1301 TMSourceFile
*tm_file
;
1303 AnjutaSymbolView
*symbol_view
;
1305 gulong scope_position
;
1306 gchar
*needed_text
= NULL
;
1308 GPtrArray
* completable_tags_array
;
1309 AnjutaSymbolIter
*iter
= NULL
;
1311 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (sm
);
1312 ed
= IANJUTA_EDITOR (sv_plugin
->current_editor
);
1313 symbol_view
= ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
);
1315 line
= ianjuta_editor_get_line_from_position (ed
, text_pos
, NULL
);
1317 /* get the function scope */
1318 tm_file
= anjuta_symbol_view_get_tm_file (symbol_view
, file_uri
);
1320 /* check whether the current file_uri is listed in the tm_workspace or not... */
1321 if (tm_file
== NULL
)
1325 // FIXME: remove DEBUG_PRINT
1327 DEBUG_PRINT ("tags in file &s\n");
1328 if (tm_file->work_object.tags_array != NULL) {
1330 for (i=0; i < tm_file->work_object.tags_array->len; i++) {
1333 cur_tag = (TMTag*)g_ptr_array_index (tm_file->work_object.tags_array, i);
1334 tm_tag_print (cur_tag, stdout);
1339 func_scope_tag = tm_get_current_function (tm_file->work_object.tags_array, line);
1341 if (func_scope_tag == NULL) {
1342 DEBUG_PRINT ("func_scope_tag is NULL, seems like it's a completion on a global scope");
1346 DEBUG_PRINT ("current expression scope: %s", func_scope_tag->name);
1349 scope_position = ianjuta_editor_get_line_begin_position (ed, func_scope_tag->atts.entry.line, NULL);
1350 needed_text = ianjuta_editor_get_text (ed, scope_position,
1351 text_pos - scope_position, NULL);
1353 if (needed_text == NULL)
1354 DEBUG_PRINT ("needed_text is null");
1355 DEBUG_PRINT ("text needed is %s", needed_text );
1358 /* we'll pass only the text of the current scope: i.e. only the current function
1359 * in which we request the completion. */
1360 TMTag
* found_type
= anjuta_symbol_view_get_type_of_expression (symbol_view
,
1361 needed_text
, text_pos
- scope_position
, func_scope_tag
, &access_method
);
1364 if (found_type
== NULL
) {
1365 DEBUG_PRINT ("type not found.");
1369 /* get the completable memebers. If the access is COMPLETION_ACCESS_STATIC we don't
1370 * want to know the parents members of the class.
1372 if (access_method
== COMPLETION_ACCESS_STATIC
)
1373 completable_tags_array
= anjuta_symbol_view_get_completable_members (found_type
, FALSE
);
1375 completable_tags_array
= anjuta_symbol_view_get_completable_members (found_type
, TRUE
);
1377 if (completable_tags_array
)
1379 iter
= anjuta_symbol_iter_new (completable_tags_array
);
1380 return IANJUTA_ITERABLE (iter
);
1387 isymbol_manager_iface_init (IAnjutaSymbolManagerIface
*iface
)
1389 iface
->search
= isymbol_manager_search
;
1390 iface
->get_members
= isymbol_manager_get_members
;
1391 iface
->get_parents
= isymbol_manager_get_parents
;
1392 iface
->get_completions_at_position
= isymbol_manager_get_completions_at_position
;
1396 ipreferences_merge(IAnjutaPreferences
* ipref
, AnjutaPreferences
* prefs
, GError
** e
)
1398 symbol_browser_prefs_init(ANJUTA_PLUGIN_SYMBOL_BROWSER (ipref
));
1402 ipreferences_unmerge(IAnjutaPreferences
* ipref
, AnjutaPreferences
* prefs
, GError
** e
)
1404 symbol_browser_prefs_finalize (ANJUTA_PLUGIN_SYMBOL_BROWSER (ipref
));
1408 ipreferences_iface_init(IAnjutaPreferencesIface
* iface
)
1410 iface
->merge
= ipreferences_merge
;
1411 iface
->unmerge
= ipreferences_unmerge
;
1414 ANJUTA_PLUGIN_BEGIN (SymbolBrowserPlugin
, symbol_browser_plugin
);
1415 ANJUTA_PLUGIN_ADD_INTERFACE (isymbol_manager
, IANJUTA_TYPE_SYMBOL_MANAGER
);
1416 ANJUTA_PLUGIN_ADD_INTERFACE (ipreferences
, IANJUTA_TYPE_PREFERENCES
);
1419 ANJUTA_SIMPLE_PLUGIN (SymbolBrowserPlugin
, symbol_browser_plugin
);