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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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-48.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
, IAnjutaIterable
*position
, gchar ch
,
69 SymbolBrowserPlugin
*sv_plugin
);
72 register_stock_icons (AnjutaPlugin
*plugin
)
74 static gboolean registered
= FALSE
;
80 /* Register stock icons */
81 BEGIN_REGISTER_ICON (plugin
);
82 REGISTER_ICON (ICON_FILE
, "symbol-browser-plugin-icon");
87 goto_file_line (AnjutaPlugin
*plugin
, const gchar
*filename
, gint lineno
)
90 IAnjutaDocumentManager
*docman
;
92 g_return_if_fail (filename
!= NULL
);
94 /* Go to file and line number */
95 docman
= anjuta_shell_get_interface (plugin
->shell
, IAnjutaDocumentManager
,
98 uri
= gnome_vfs_get_uri_from_local_path (filename
);
99 ianjuta_document_manager_goto_file_line (docman
, uri
, lineno
, NULL
);
104 goto_file_tag (SymbolBrowserPlugin
*sv_plugin
, const char *symbol
,
105 gboolean prefer_definition
)
111 ret
= anjuta_symbol_view_get_file_symbol (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
112 symbol
, prefer_definition
,
116 goto_file_line (ANJUTA_PLUGIN (sv_plugin
), file
, line
);
121 on_goto_def_activate (GtkAction
*action
, SymbolBrowserPlugin
*sv_plugin
)
127 ret
= anjuta_symbol_view_get_current_symbol_def (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
131 goto_file_line (ANJUTA_PLUGIN (sv_plugin
), file
, line
);
137 on_goto_decl_activate (GtkAction
*action
, SymbolBrowserPlugin
*sv_plugin
)
143 ret
= anjuta_symbol_view_get_current_symbol_decl (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
147 goto_file_line (ANJUTA_PLUGIN (sv_plugin
), file
, line
);
153 on_goto_file_tag_decl_activate (GtkAction
* action
,
154 SymbolBrowserPlugin
*sv_plugin
)
159 if (sv_plugin
->current_editor
)
161 ed
= IANJUTA_EDITOR (sv_plugin
->current_editor
);
162 word
= ianjuta_editor_get_current_word (ed
, NULL
);
165 goto_file_tag (sv_plugin
, word
, FALSE
);
172 on_goto_file_tag_def_activate (GtkAction
* action
,
173 SymbolBrowserPlugin
*sv_plugin
)
178 if (sv_plugin
->current_editor
)
180 ed
= IANJUTA_EDITOR (sv_plugin
->current_editor
);
181 word
= ianjuta_editor_get_current_word (ed
, NULL
);
184 goto_file_tag (sv_plugin
, word
, TRUE
);
191 on_find_activate (GtkAction
*action
, SymbolBrowserPlugin
*sv_plugin
)
194 symbol
= anjuta_symbol_view_get_current_symbol (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
));
197 g_warning ("TODO: Unimplemented");
203 on_refresh_idle (gpointer user_data
)
205 IAnjutaProjectManager
*pm
;
208 AnjutaStatus
*status
;
209 SymbolBrowserPlugin
*sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (user_data
);
211 /* FIXME: There should be a way to ensure that this project manager
212 * is indeed the one that has opened the project_uri
214 pm
= anjuta_shell_get_interface (ANJUTA_PLUGIN (sv_plugin
)->shell
,
215 IAnjutaProjectManager
, NULL
);
216 g_return_val_if_fail (pm
!= NULL
, FALSE
);
218 status
= anjuta_shell_get_status (ANJUTA_PLUGIN (sv_plugin
)->shell
, NULL
);
219 anjuta_status_push (status
, "Refreshing symbol tree...");
220 anjuta_status_busy_push (status
);
222 source_uris
= source_files
= NULL
;
223 source_uris
= ianjuta_project_manager_get_elements (pm
,
224 IANJUTA_PROJECT_MANAGER_SOURCE
,
236 uri
= (const gchar
*)node
->data
;
237 file_path
= gnome_vfs_get_local_path_from_uri (uri
);
239 source_files
= g_list_prepend (source_files
, file_path
);
240 node
= g_list_next (node
);
242 source_files
= g_list_reverse (source_files
);
244 anjuta_symbol_view_update (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
246 g_list_foreach (source_files
, (GFunc
)g_free
, NULL
);
247 g_list_foreach (source_uris
, (GFunc
)g_free
, NULL
);
248 g_list_free (source_files
);
249 g_list_free (source_uris
);
251 /* Current editor symbol model may have changed */
252 update_editor_symbol_model (sv_plugin
);
254 anjuta_status_busy_pop (status
);
255 anjuta_status_pop (status
);
260 on_refresh_activate (GtkAction
*action
, SymbolBrowserPlugin
*sv_plugin
)
262 if (!sv_plugin
->project_root_uri
)
264 g_idle_add (on_refresh_idle
, sv_plugin
);
267 static GtkActionEntry actions
[] =
269 { "ActionMenuGoto", NULL
, N_("_Goto"), NULL
, NULL
, NULL
},
271 "ActionSymbolBrowserGotoDef",
273 N_("Tag _Definition"),
275 N_("Goto symbol definition"),
276 G_CALLBACK (on_goto_file_tag_def_activate
)
279 "ActionSymbolBrowserGotoDecl",
281 N_("Tag De_claration"),
283 N_("Goto symbol declaration"),
284 G_CALLBACK (on_goto_file_tag_decl_activate
)
288 static GtkActionEntry popup_actions
[] =
291 "ActionPopupSymbolBrowserGotoDef",
293 N_("Goto _Definition"),
295 N_("Goto symbol definition"),
296 G_CALLBACK (on_goto_def_activate
)
299 "ActionPopupSymbolBrowserGotoDecl",
301 N_("Goto De_claration"),
303 N_("Goto symbol declaration"),
304 G_CALLBACK (on_goto_decl_activate
)
307 "ActionPopupSymbolBrowserFind",
311 N_("Find usage of symbol in project"),
312 G_CALLBACK (on_find_activate
)
315 "ActionPopupSymbolBrowserRefresh",
319 N_("Refresh symbol browser tree"),
320 G_CALLBACK (on_refresh_activate
)
325 on_project_element_added (IAnjutaProjectManager
*pm
, const gchar
*uri
,
326 SymbolBrowserPlugin
*sv_plugin
)
330 if (!sv_plugin
->project_root_uri
)
333 filename
= gnome_vfs_get_local_path_from_uri (uri
);
336 anjuta_symbol_view_add_source (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
343 on_project_element_removed (IAnjutaProjectManager
*pm
, const gchar
*uri
,
344 SymbolBrowserPlugin
*sv_plugin
)
348 if (!sv_plugin
->project_root_uri
)
351 filename
= gnome_vfs_get_local_path_from_uri (uri
);
354 anjuta_symbol_view_remove_source (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
362 project_root_added (AnjutaPlugin
*plugin
, const gchar
*name
,
363 const GValue
*value
, gpointer user_data
)
365 AnjutaStatus
*status
;
366 IAnjutaProjectManager
*pm
;
367 SymbolBrowserPlugin
*sv_plugin
;
368 const gchar
*root_uri
;
370 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
372 g_free (sv_plugin
->project_root_uri
);
373 sv_plugin
->project_root_uri
= NULL
;
374 root_uri
= g_value_get_string (value
);
377 gchar
*root_dir
= gnome_vfs_get_local_path_from_uri (root_uri
);
380 status
= anjuta_shell_get_status (plugin
->shell
, NULL
);
381 anjuta_status_progress_add_ticks (status
, 1);
382 trees_signals_block (sv_plugin
);
383 anjuta_symbol_view_open (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
386 /* Current editor symbol model may have changed */
387 update_editor_symbol_model (sv_plugin
);
388 anjuta_status_progress_tick (status
, NULL
, _("Created symbols..."));
389 trees_signals_unblock (sv_plugin
);
392 sv_plugin
->project_root_uri
= g_strdup (root_uri
);
394 /* FIXME: There should be a way to ensure that this project manager
395 * is indeed the one that has opened the project_uri
397 pm
= anjuta_shell_get_interface (ANJUTA_PLUGIN (sv_plugin
)->shell
,
398 IAnjutaProjectManager
, NULL
);
399 g_signal_connect (G_OBJECT (pm
), "element_added",
400 G_CALLBACK (on_project_element_added
), sv_plugin
);
401 g_signal_connect (G_OBJECT (pm
), "element_removed",
402 G_CALLBACK (on_project_element_removed
), sv_plugin
);
406 project_root_removed (AnjutaPlugin
*plugin
, const gchar
*name
,
409 IAnjutaProjectManager
*pm
;
410 SymbolBrowserPlugin
*sv_plugin
;
412 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
414 /* Disconnect events from project manager */
416 /* FIXME: There should be a way to ensure that this project manager
417 * is indeed the one that has opened the project_uri
419 pm
= anjuta_shell_get_interface (ANJUTA_PLUGIN (sv_plugin
)->shell
,
420 IAnjutaProjectManager
, NULL
);
421 g_signal_handlers_disconnect_by_func (G_OBJECT (pm
),
422 on_project_element_added
,
424 g_signal_handlers_disconnect_by_func (G_OBJECT (pm
),
425 on_project_element_removed
,
428 /* clear anjuta_symbol_search side */
429 anjuta_symbol_search_clear(ANJUTA_SYMBOL_SEARCH(sv_plugin
->ss
));
431 /* clear glist's sfiles */
432 anjuta_symbol_view_clear (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
));
434 g_free (sv_plugin
->project_root_uri
);
435 sv_plugin
->project_root_uri
= NULL
;
439 on_treeview_event (GtkWidget
*widget
,
441 SymbolBrowserPlugin
*sv_plugin
)
445 GtkTreeSelection
*selection
;
447 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget
), FALSE
);
449 view
= GTK_TREE_VIEW (widget
);
450 model
= gtk_tree_view_get_model (view
);
451 selection
= gtk_tree_view_get_selection (view
);
456 if (event
->type
== GDK_BUTTON_PRESS
) {
457 GdkEventButton
*e
= (GdkEventButton
*) event
;
459 if (e
->button
== 3) {
462 /* Popup project menu */
463 menu
= gtk_ui_manager_get_widget (GTK_UI_MANAGER (sv_plugin
->ui
),
464 "/PopupSymbolBrowser");
465 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
,
466 NULL
, NULL
, e
->button
, e
->time
);
469 } else if (event
->type
== GDK_KEY_PRESS
) {
470 GdkEventKey
*e
= (GdkEventKey
*) event
;
474 anjuta_ui_activate_action_by_group (sv_plugin
->ui
,
475 sv_plugin
->popup_action_group
,
476 "ActionPopupSymbolBrowserGotoDef");
486 on_treeview_row_activated (GtkTreeView
*view
, GtkTreePath
*arg1
,
487 GtkTreeViewColumn
*arg2
,
488 SymbolBrowserPlugin
*sv_plugin
)
491 GtkTreeSelection
*selection
;
494 selection
= gtk_tree_view_get_selection (view
);
495 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
497 anjuta_ui_activate_action_by_group (sv_plugin
->ui
,
498 sv_plugin
->popup_action_group
,
499 "ActionPopupSymbolBrowserGotoDef");
503 trees_signals_block (SymbolBrowserPlugin
*sv_plugin
)
505 g_signal_handlers_block_by_func (G_OBJECT (sv_plugin
->sv_tree
),
506 G_CALLBACK (on_treeview_event
), NULL
);
508 g_signal_handlers_block_by_func (G_OBJECT (sv_plugin
->ss
),
509 G_CALLBACK (on_treesearch_symbol_selected_event
),
515 trees_signals_unblock (SymbolBrowserPlugin
*sv_plugin
)
517 g_signal_handlers_unblock_by_func (G_OBJECT (sv_plugin
->sv_tree
),
518 G_CALLBACK (on_treeview_event
), NULL
);
520 g_signal_handlers_unblock_by_func (G_OBJECT (sv_plugin
->ss
),
521 G_CALLBACK (on_treesearch_symbol_selected_event
),
526 goto_tree_iter (SymbolBrowserPlugin
*sv_plugin
, GtkTreeIter
*iter
)
531 line
= anjuta_symbol_view_workspace_get_line (ANJUTA_SYMBOL_VIEW
532 (sv_plugin
->sv_tree
),
535 if (line
> 0 && sv_plugin
->current_editor
)
537 /* Goto line number */
538 ianjuta_editor_goto_line (IANJUTA_EDITOR (sv_plugin
->current_editor
),
540 if (IANJUTA_IS_MARKABLE (sv_plugin
->current_editor
))
542 ianjuta_markable_delete_all_markers (IANJUTA_MARKABLE (sv_plugin
->current_editor
),
543 IANJUTA_MARKABLE_LINEMARKER
,
546 ianjuta_markable_mark (IANJUTA_MARKABLE (sv_plugin
->current_editor
),
547 line
, IANJUTA_MARKABLE_LINEMARKER
, NULL
);
553 on_symbol_selected (GtkAction
*action
, SymbolBrowserPlugin
*sv_plugin
)
557 if (egg_combo_action_get_active_iter (EGG_COMBO_ACTION (action
), &iter
))
559 goto_tree_iter (sv_plugin
, &iter
);
564 on_local_treeview_row_activated (GtkTreeView
*view
, GtkTreePath
*arg1
,
565 GtkTreeViewColumn
*arg2
,
566 SymbolBrowserPlugin
*sv_plugin
)
569 GtkTreeSelection
*selection
;
572 selection
= gtk_tree_view_get_selection (view
);
573 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
575 goto_tree_iter (sv_plugin
, &iter
);
578 /* -----------------------------------------------------------------------------
579 * will manage the click of mouse and other events on search->hitlist treeview
582 on_treesearch_symbol_selected_event (AnjutaSymbolSearch
*search
,
583 AnjutaSymbolInfo
*sym
,
584 SymbolBrowserPlugin
*sv_plugin
) {
589 ret
= anjuta_symbol_view_get_file_symbol (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
594 goto_file_line (ANJUTA_PLUGIN (sv_plugin
), file
, line
);
599 on_editor_destroy (SymbolBrowserPlugin
*sv_plugin
, IAnjutaEditor
*editor
)
603 if (!sv_plugin
->editor_connected
|| !sv_plugin
->sv_tree
)
605 uri
= g_hash_table_lookup (sv_plugin
->editor_connected
, G_OBJECT (editor
));
606 if (uri
&& strlen (uri
) > 0)
608 DEBUG_PRINT ("Removing file tags of %s", uri
);
609 anjuta_symbol_view_workspace_remove_file (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
612 g_hash_table_remove (sv_plugin
->editor_connected
, G_OBJECT (editor
));
616 on_editor_saved (IAnjutaEditor
*editor
, const gchar
*saved_uri
,
617 SymbolBrowserPlugin
*sv_plugin
)
619 const gchar
*old_uri
;
620 gboolean tags_update
;
621 GtkTreeModel
*file_symbol_model
;
625 /* FIXME: Do this only if automatic tags update is enabled */
627 anjuta_preferences_get_int (te->preferences, AUTOMATIC_TAGS_UPDATE);
632 gchar
*local_filename
;
634 /* Verify that it's local file */
635 local_filename
= gnome_vfs_get_local_path_from_uri (saved_uri
);
636 g_return_if_fail (local_filename
!= NULL
);
637 g_free (local_filename
);
639 if (!sv_plugin
->editor_connected
)
642 old_uri
= g_hash_table_lookup (sv_plugin
->editor_connected
, editor
);
644 if (old_uri
&& strlen (old_uri
) <= 0)
646 anjuta_symbol_view_workspace_update_file (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
648 g_hash_table_insert (sv_plugin
->editor_connected
, editor
,
649 g_strdup (saved_uri
));
651 /* Update File symbol view */
652 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN (sv_plugin
)->shell
, NULL
);
653 action
= anjuta_ui_get_action (ui
, "ActionGroupSymbolNavigation",
658 anjuta_symbol_view_get_file_symbol_model (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
));
659 g_object_set_data (G_OBJECT (editor
), "tm_file",
660 g_object_get_data (G_OBJECT (file_symbol_model
),
662 /* Set toolbar version */
663 egg_combo_action_set_model (EGG_COMBO_ACTION (action
), file_symbol_model
);
664 /* Set local view version */
665 gtk_tree_view_set_model (GTK_TREE_VIEW (sv_plugin
->sl_tree
),
667 sv_plugin
->locals_line_number
= 0;
668 on_editor_update_ui (editor
, sv_plugin
);
670 if (gtk_tree_model_iter_n_children (file_symbol_model
, NULL
) > 0)
671 g_object_set (G_OBJECT (action
), "sensitive", TRUE
, NULL
);
673 g_object_set (G_OBJECT (action
), "sensitive", FALSE
, NULL
);
676 /* FIXME: Re-hilite all editors on tags update */
679 for (tmp
= app
->text_editor_list
; tmp
; tmp
= g_list_next(tmp
))
681 te1
= TEXT_EDITOR (tmp
->data
);
682 text_editor_set_hilite_type(te1
);
690 on_editor_foreach_disconnect (gpointer key
, gpointer value
, gpointer user_data
)
692 g_signal_handlers_disconnect_by_func (G_OBJECT(key
),
693 G_CALLBACK (on_editor_saved
),
695 g_signal_handlers_disconnect_by_func (G_OBJECT(key
),
696 G_CALLBACK (on_editor_update_ui
),
698 g_signal_handlers_disconnect_by_func (G_OBJECT(key
),
699 G_CALLBACK (on_char_added
),
701 g_object_weak_unref (G_OBJECT(key
),
702 (GWeakNotify
) (on_editor_destroy
),
707 on_editor_foreach_clear (gpointer key
, gpointer value
, gpointer user_data
)
710 SymbolBrowserPlugin
*sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (user_data
);
712 uri
= (const gchar
*)value
;
713 if (uri
&& strlen (uri
) > 0)
715 DEBUG_PRINT ("Removing file tags of %s", uri
);
716 anjuta_symbol_view_workspace_remove_file (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
),
722 update_editor_symbol_model (SymbolBrowserPlugin
*sv_plugin
)
726 GObject
*editor
= sv_plugin
->current_editor
;
731 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN (sv_plugin
)->shell
, NULL
);
732 uri
= ianjuta_file_get_uri (IANJUTA_FILE (editor
), NULL
);
735 gchar
*local_filename
;
736 GtkTreeModel
*file_symbol_model
;
739 /* Verify that it's local file */
740 local_filename
= gnome_vfs_get_local_path_from_uri (uri
);
741 g_return_if_fail (local_filename
!= NULL
);
742 g_free (local_filename
);
744 anjuta_symbol_view_workspace_add_file (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
), uri
);
745 action
= anjuta_ui_get_action (ui
, "ActionGroupSymbolNavigation",
750 anjuta_symbol_view_get_file_symbol_model (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
));
751 if (file_symbol_model
)
753 g_object_set_data (G_OBJECT (editor
), "tm_file",
754 g_object_get_data (G_OBJECT (file_symbol_model
),
756 /* Set toolbar version */
757 egg_combo_action_set_model (EGG_COMBO_ACTION (action
), file_symbol_model
);
759 /* Set local view version */
760 gtk_tree_view_set_model (GTK_TREE_VIEW (sv_plugin
->sl_tree
),
762 sv_plugin
->locals_line_number
= 0;
763 on_editor_update_ui (IANJUTA_EDITOR (editor
), sv_plugin
);
765 if (gtk_tree_model_iter_n_children (file_symbol_model
, NULL
) > 0)
766 g_object_set (G_OBJECT (action
), "sensitive", TRUE
, NULL
);
768 g_object_set (G_OBJECT (action
), "sensitive", FALSE
, NULL
);
774 on_editor_buffer_symbols_update_timeout (gpointer user_data
)
776 SymbolBrowserPlugin
*sv_plugin
;
778 gchar
*current_buffer
= NULL
;
779 gint buffer_size
= 0;
782 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (user_data
);
784 if (sv_plugin
->current_editor
== NULL
)
787 /* we won't proceed with the updating of the symbols if we didn't type in
789 if (!need_symbols_update
)
792 if (sv_plugin
->current_editor
) {
793 ed
= IANJUTA_EDITOR (sv_plugin
->current_editor
);
795 buffer_size
= ianjuta_editor_get_length (ed
, NULL
);
796 current_buffer
= ianjuta_editor_get_text_all (ed
, NULL
);
798 uri
= ianjuta_file_get_uri (IANJUTA_FILE (ed
), NULL
);
805 /* FIXME: Only uncomment after investigating bug 395362 */
807 anjuta_symbol_view_update_source_from_buffer (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
808 uri, current_buffer, buffer_size);
814 g_free (current_buffer
);
816 need_symbols_update
= FALSE
;
822 iter_matches (SymbolBrowserPlugin
*sv_plugin
, GtkTreeIter
* iter
,
823 GtkTreeModel
* model
, gint lineno
)
826 gtk_tree_model_get (model
, iter
, COL_LINE
, &line
, -1);
829 GtkTreePath
* path
= gtk_tree_model_get_path (model
, iter
);
830 GtkAction
* action
= anjuta_ui_get_action (sv_plugin
->ui
,
831 "ActionGroupSymbolNavigation",
834 egg_combo_action_set_active_iter (EGG_COMBO_ACTION (action
), iter
);
835 gtk_tree_view_set_cursor (GTK_TREE_VIEW (sv_plugin
->sl_tree
), path
, NULL
,
837 gtk_tree_path_free (path
);
844 on_editor_update_ui (IAnjutaEditor
*editor
, SymbolBrowserPlugin
*sv_plugin
)
846 gint lineno
= ianjuta_editor_get_lineno (editor
, NULL
);
848 GtkTreeModel
* model
= anjuta_symbol_view_get_file_symbol_model
849 (ANJUTA_SYMBOL_VIEW(sv_plugin
->sv_tree
));
851 gboolean found
= FALSE
;
853 if (sv_plugin
->locals_line_number
== lineno
)
855 sv_plugin
->locals_line_number
= lineno
;
857 if (!gtk_tree_model_get_iter_first (model
, &iter
))
859 while (!found
&& lineno
>= 0)
861 gtk_tree_model_get_iter_first (model
, &iter
);
864 found
= iter_matches (sv_plugin
, &iter
, model
, lineno
);
868 while (gtk_tree_model_iter_next (model
, &iter
));
874 on_char_added (IAnjutaEditor
*editor
, IAnjutaIterable
*position
, gchar ch
,
875 SymbolBrowserPlugin
*sv_plugin
)
877 DEBUG_PRINT ("char added: %c [int %d]", ch
, ch
);
879 /* try to force the update if a "." or a "->" is pressed */
880 if ((ch
== '.') || (prev_char_added
== '-' && ch
== '>'))
881 on_editor_buffer_symbols_update_timeout (sv_plugin
);
883 need_symbols_update
= TRUE
;
885 prev_char_added
= ch
;
889 value_added_current_editor (AnjutaPlugin
*plugin
, const char *name
,
890 const GValue
*value
, gpointer data
)
894 SymbolBrowserPlugin
*sv_plugin
;
896 editor
= g_value_get_object (value
);
898 if (!IANJUTA_IS_EDITOR(editor
))
901 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
903 if (!sv_plugin
->editor_connected
)
905 sv_plugin
->editor_connected
= g_hash_table_new_full (g_direct_hash
,
909 sv_plugin
->current_editor
= editor
;
911 update_editor_symbol_model (sv_plugin
);
913 uri
= ianjuta_file_get_uri (IANJUTA_FILE (editor
), NULL
);
914 if (g_hash_table_lookup (sv_plugin
->editor_connected
, editor
) == NULL
)
916 g_object_weak_ref (G_OBJECT (editor
),
917 (GWeakNotify
) (on_editor_destroy
),
921 g_hash_table_insert (sv_plugin
->editor_connected
, editor
, uri
); //g_strdup (uri));
926 g_hash_table_insert (sv_plugin
->editor_connected
, editor
,
929 g_signal_connect (G_OBJECT (editor
), "saved",
930 G_CALLBACK (on_editor_saved
),
933 g_signal_connect (G_OBJECT (editor
), "char-added",
934 G_CALLBACK (on_char_added
),
936 g_signal_connect (G_OBJECT(editor
), "update_ui",
937 G_CALLBACK (on_editor_update_ui
),
941 /* add a default timeout to the updating of buffer symbols */
942 timeout_id
= g_timeout_add (TIMEOUT_INTERVAL_SYMBOLS_UPDATE
,
943 on_editor_buffer_symbols_update_timeout
,
945 need_symbols_update
= FALSE
;
950 value_removed_current_editor (AnjutaPlugin
*plugin
,
951 const char *name
, gpointer data
)
954 SymbolBrowserPlugin
*sv_plugin
;
957 /* let's remove the timeout for symbols refresh */
958 g_source_remove (timeout_id
);
959 need_symbols_update
= FALSE
;
961 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
962 ui
= anjuta_shell_get_ui (plugin
->shell
, NULL
);
963 action
= anjuta_ui_get_action (ui
, "ActionGroupSymbolNavigation",
965 g_object_set (G_OBJECT (action
), "sensitive", FALSE
, NULL
);
966 sv_plugin
->current_editor
= NULL
;
970 activate_plugin (AnjutaPlugin
*plugin
)
972 GtkActionGroup
*group
;
974 SymbolBrowserPlugin
*sv_plugin
;
976 DEBUG_PRINT ("SymbolBrowserPlugin: Activating Symbol Manager plugin...");
978 register_stock_icons (plugin
);
980 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
981 sv_plugin
->ui
= anjuta_shell_get_ui (plugin
->shell
, NULL
);
982 sv_plugin
->prefs
= anjuta_shell_get_preferences (plugin
->shell
, NULL
);
985 sv_plugin
->sw
= gtk_notebook_new();
988 sv_plugin
->sl
= gtk_scrolled_window_new (NULL
, NULL
);
989 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sv_plugin
->sl
),
991 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sv_plugin
->sl
),
992 GTK_POLICY_AUTOMATIC
,
993 GTK_POLICY_AUTOMATIC
);
995 sv_plugin
->sl_tab_label
= gtk_label_new (_("Local" ));
996 sv_plugin
->sl_tree
= anjuta_symbol_locals_new ();
997 g_object_add_weak_pointer (G_OBJECT (sv_plugin
->sl_tree
),
998 (gpointer
)&sv_plugin
->sl_tree
);
999 g_signal_connect (G_OBJECT (sv_plugin
->sl_tree
), "row_activated",
1000 G_CALLBACK (on_local_treeview_row_activated
), plugin
);
1001 gtk_container_add (GTK_CONTAINER(sv_plugin
->sl
), sv_plugin
->sl_tree
);
1003 /* add the scrolled window to the notebook */
1004 gtk_notebook_append_page (GTK_NOTEBOOK(sv_plugin
->sw
),
1005 sv_plugin
->sl
, sv_plugin
->sl_tab_label
);
1007 /* Global symbols */
1008 sv_plugin
->sv
= gtk_scrolled_window_new (NULL
, NULL
);
1009 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sv_plugin
->sv
),
1011 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sv_plugin
->sv
),
1012 GTK_POLICY_AUTOMATIC
,
1013 GTK_POLICY_AUTOMATIC
);
1015 sv_plugin
->sv_tab_label
= gtk_label_new (_("Global" ));
1016 sv_plugin
->sv_tree
= anjuta_symbol_view_new ();
1017 symbol_browser_load_global_tags (plugin
);
1019 g_object_add_weak_pointer (G_OBJECT (sv_plugin
->sv_tree
),
1020 (gpointer
)&sv_plugin
->sv_tree
);
1022 g_signal_connect (G_OBJECT (sv_plugin
->sv_tree
), "event-after",
1023 G_CALLBACK (on_treeview_event
), plugin
);
1024 g_signal_connect (G_OBJECT (sv_plugin
->sv_tree
), "row_activated",
1025 G_CALLBACK (on_treeview_row_activated
), plugin
);
1027 gtk_container_add (GTK_CONTAINER(sv_plugin
->sv
), sv_plugin
->sv_tree
);
1029 /* add the scrolled window to the notebook */
1030 gtk_notebook_append_page (GTK_NOTEBOOK(sv_plugin
->sw
),
1031 sv_plugin
->sv
, sv_plugin
->sv_tab_label
);
1033 /* anjuta symbol search */
1035 anjuta_symbol_search_new (ANJUTA_SYMBOL_VIEW (sv_plugin
->sv_tree
));
1036 sv_plugin
->ss_tab_label
= gtk_label_new (_("Search" ));
1038 g_object_add_weak_pointer (G_OBJECT (sv_plugin
->ss
),
1039 (gpointer
)&sv_plugin
->ss
);
1041 gtk_notebook_append_page (GTK_NOTEBOOK(sv_plugin
->sw
), sv_plugin
->ss
,
1042 sv_plugin
->ss_tab_label
);
1044 gtk_widget_show_all (sv_plugin
->sw
);
1046 /* connect some signals */
1047 g_signal_connect (G_OBJECT (sv_plugin
->ss
), "symbol_selected",
1048 G_CALLBACK (on_treesearch_symbol_selected_event
),
1052 /* setting focus to the tree_view*/
1053 gtk_notebook_set_current_page (GTK_NOTEBOOK (sv_plugin
->sw
), 0);
1055 /* Add action group */
1056 sv_plugin
->action_group
=
1057 anjuta_ui_add_action_group_entries (sv_plugin
->ui
,
1058 "ActionGroupSymbolBrowser",
1059 _("Symbol browser actions"),
1061 G_N_ELEMENTS (actions
),
1062 GETTEXT_PACKAGE
, TRUE
, plugin
);
1063 sv_plugin
->popup_action_group
=
1064 anjuta_ui_add_action_group_entries (sv_plugin
->ui
,
1065 "ActionGroupPopupSymbolBrowser",
1066 _("Symbol browser popup actions"),
1068 G_N_ELEMENTS (popup_actions
),
1069 GETTEXT_PACKAGE
, FALSE
, plugin
);
1070 group
= gtk_action_group_new ("ActionGroupSymbolNavigation");
1072 /* create a new combobox in style of libegg... */
1073 action
= g_object_new (EGG_TYPE_COMBO_ACTION
,
1074 "name", "ActionGotoSymbol",
1075 "label", _("Goto symbol"),
1076 "tooltip", _("Select the symbol to go"),
1077 "stock_id", GTK_STOCK_JUMP_TO
,
1080 g_object_set (G_OBJECT (action
), "sensitive", FALSE
, NULL
);
1081 g_signal_connect (action
, "activate",
1082 G_CALLBACK (on_symbol_selected
), sv_plugin
);
1083 gtk_action_group_add_action (group
, action
);
1084 anjuta_ui_add_action_group (sv_plugin
->ui
, "ActionGroupSymbolNavigation",
1085 N_("Symbol navigations"), group
, FALSE
);
1086 sv_plugin
->action_group_nav
= group
;
1089 sv_plugin
->merge_id
=
1090 anjuta_ui_merge (sv_plugin
->ui
, UI_FILE
);
1093 anjuta_shell_add_widget (plugin
->shell
, sv_plugin
->sw
,
1094 "AnjutaSymbolBrowser", _("Symbols"),
1095 "symbol-browser-plugin-icon",
1096 ANJUTA_SHELL_PLACEMENT_LEFT
, NULL
);
1098 /* set up project directory watch */
1099 sv_plugin
->root_watch_id
= anjuta_plugin_add_watch (plugin
,
1102 project_root_removed
, NULL
);
1103 sv_plugin
->editor_watch_id
=
1104 anjuta_plugin_add_watch (plugin
, "document_manager_current_editor",
1105 value_added_current_editor
,
1106 value_removed_current_editor
, NULL
);
1111 deactivate_plugin (AnjutaPlugin
*plugin
)
1113 SymbolBrowserPlugin
*sv_plugin
;
1114 sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (plugin
);
1116 /* Ensure all editor cached info are released */
1117 if (sv_plugin
->editor_connected
)
1119 g_hash_table_foreach (sv_plugin
->editor_connected
,
1120 on_editor_foreach_disconnect
, plugin
);
1121 g_hash_table_foreach (sv_plugin
->editor_connected
,
1122 on_editor_foreach_clear
, plugin
);
1123 g_hash_table_destroy (sv_plugin
->editor_connected
);
1124 sv_plugin
->editor_connected
= NULL
;
1126 /* Remove watches */
1127 anjuta_plugin_remove_watch (plugin
, sv_plugin
->root_watch_id
, FALSE
);
1128 anjuta_plugin_remove_watch (plugin
, sv_plugin
->editor_watch_id
, TRUE
);
1130 /* Remove widgets: Widgets will be destroyed when sw is removed */
1131 anjuta_shell_remove_widget (plugin
->shell
, sv_plugin
->sw
, NULL
);
1134 anjuta_ui_unmerge (sv_plugin
->ui
, sv_plugin
->merge_id
);
1136 /* Remove action group */
1137 anjuta_ui_remove_action_group (sv_plugin
->ui
, sv_plugin
->action_group
);
1138 anjuta_ui_remove_action_group (sv_plugin
->ui
, sv_plugin
->popup_action_group
);
1139 anjuta_ui_remove_action_group (sv_plugin
->ui
, sv_plugin
->action_group_nav
);
1141 sv_plugin
->root_watch_id
= 0;
1142 sv_plugin
->editor_watch_id
= 0;
1143 sv_plugin
->merge_id
= 0;
1144 sv_plugin
->sw
= NULL
;
1145 sv_plugin
->sl
= NULL
;
1146 sv_plugin
->sl_tree
= NULL
;
1147 sv_plugin
->sv
= NULL
;
1148 sv_plugin
->sv_tree
= NULL
;
1149 sv_plugin
->ss
= NULL
;
1154 dispose (GObject
*obj
)
1156 SymbolBrowserPlugin
*sv_plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (obj
);
1157 /* Ensure all editors are disconnected */
1158 if (sv_plugin
->editor_connected
)
1160 g_hash_table_foreach (sv_plugin
->editor_connected
,
1161 on_editor_foreach_disconnect
,
1163 g_hash_table_destroy (sv_plugin
->editor_connected
);
1164 sv_plugin
->editor_connected
= NULL
;
1169 g_object_unref (G_OBJECT (plugin->sw));
1174 g_object_remove_weak_pointer (G_OBJECT (sv_plugin
->ss
),
1175 (gpointer
)&sv_plugin
->ss
);
1178 GNOME_CALL_PARENT (G_OBJECT_CLASS
, dispose
, (obj
));
1182 finalize (GObject
*obj
)
1184 /* SymbolBrowserPlugin *plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (obj); */
1185 GNOME_CALL_PARENT (G_OBJECT_CLASS
, finalize
, (obj
));
1189 symbol_browser_plugin_instance_init (GObject
*obj
)
1191 SymbolBrowserPlugin
*plugin
= ANJUTA_PLUGIN_SYMBOL_BROWSER (obj
);
1192 plugin
->current_editor
= NULL
;
1193 plugin
->editor_connected
= NULL
;
1196 plugin
->gconf_notify_ids
= NULL
;
1197 plugin
->locals_line_number
= 0;
1198 plugin
->launcher
= NULL
;
1202 symbol_browser_plugin_class_init (SymbolBrowserPluginClass
*klass
)
1204 GObjectClass
*object_class
;
1205 AnjutaPluginClass
*plugin_class
;
1207 parent_class
= g_type_class_peek_parent (klass
);
1208 object_class
= G_OBJECT_CLASS (klass
);
1209 plugin_class
= ANJUTA_PLUGIN_CLASS (klass
);
1211 plugin_class
->activate
= activate_plugin
;
1212 plugin_class
->deactivate
= deactivate_plugin
;
1214 object_class
->dispose
= dispose
;
1215 object_class
->finalize
= finalize
;
1218 static IAnjutaIterable
*
1219 isymbol_manager_search (IAnjutaSymbolManager
*sm
,
1220 IAnjutaSymbolType match_types
,
1221 const gchar
*match_name
,
1222 gboolean partial_name_match
,
1223 gboolean global_search
,
1226 const GPtrArray
*tags_array
;
1227 AnjutaSymbolIter
*iter
= NULL
;
1230 if (match_name
&& strlen (match_name
) > 0)
1235 tags_array
= tm_workspace_find (name
, match_types
, NULL
,
1236 partial_name_match
, global_search
);
1237 if (tags_array
&& tags_array
->len
)
1239 iter
= anjuta_symbol_iter_new (tags_array
);
1240 return IANJUTA_ITERABLE (iter
);
1245 static IAnjutaIterable
*
1246 isymbol_manager_get_members (IAnjutaSymbolManager
*sm
,
1247 const gchar
*symbol_name
,
1248 gboolean global_search
,
1251 const GPtrArray
*tags_array
;
1252 AnjutaSymbolIter
*iter
= NULL
;
1254 tags_array
= tm_workspace_find_scope_members (NULL
, symbol_name
,
1255 global_search
, TRUE
);
1258 if (tags_array
&& tags_array
->len
)
1260 iter
= anjuta_symbol_iter_new (tags_array
);
1261 return IANJUTA_ITERABLE (iter
);
1266 static IAnjutaIterable
*
1267 isymbol_manager_get_parents (IAnjutaSymbolManager
*sm
,
1268 const gchar
*symbol_name
,
1271 const GPtrArray
*tags_array
;
1272 AnjutaSymbolIter
*iter
= NULL
;
1274 tags_array
= tm_workspace_get_parents (symbol_name
);
1275 if (tags_array
&& tags_array
->len
)
1277 iter
= anjuta_symbol_iter_new (tags_array
);
1278 return IANJUTA_ITERABLE (iter
);
1284 isymbol_manager_iface_init (IAnjutaSymbolManagerIface
*iface
)
1286 iface
->search
= isymbol_manager_search
;
1287 iface
->get_members
= isymbol_manager_get_members
;
1288 iface
->get_parents
= isymbol_manager_get_parents
;
1292 ipreferences_merge(IAnjutaPreferences
* ipref
, AnjutaPreferences
* prefs
, GError
** e
)
1294 symbol_browser_prefs_init(ANJUTA_PLUGIN_SYMBOL_BROWSER (ipref
));
1298 ipreferences_unmerge(IAnjutaPreferences
* ipref
, AnjutaPreferences
* prefs
, GError
** e
)
1300 symbol_browser_prefs_finalize (ANJUTA_PLUGIN_SYMBOL_BROWSER (ipref
));
1304 ipreferences_iface_init(IAnjutaPreferencesIface
* iface
)
1306 iface
->merge
= ipreferences_merge
;
1307 iface
->unmerge
= ipreferences_unmerge
;
1310 ANJUTA_PLUGIN_BEGIN (SymbolBrowserPlugin
, symbol_browser_plugin
);
1311 ANJUTA_PLUGIN_ADD_INTERFACE (isymbol_manager
, IANJUTA_TYPE_SYMBOL_MANAGER
);
1312 ANJUTA_PLUGIN_ADD_INTERFACE (ipreferences
, IANJUTA_TYPE_PREFERENCES
);
1315 ANJUTA_SIMPLE_PLUGIN (SymbolBrowserPlugin
, symbol_browser_plugin
);