2007-10-13 Johannes Schmid <jhs@gnome.org>
[anjuta-git-plugin.git] / plugins / symbol-db / plugin.c
blob04d1ce2c745e8750f54513c7006e856c1936b7c0
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * plugin.c
4 * Copyright (C) Massimo Cora' 2007 <maxcvs@email.it>
5 *
6 * plugin.c is free software.
7 *
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
11 * any later version.
13 * plugin.c is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 * See the GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with plugin.c. If not, write to:
20 * The Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301, USA.
25 #include <config.h>
26 #include <libgnomevfs/gnome-vfs-utils.h>
27 #include <libgnomevfs/gnome-vfs-mime-utils.h>
28 #include <libanjuta/anjuta-shell.h>
29 #include <libanjuta/anjuta-debug.h>
30 #include <libanjuta/interfaces/ianjuta-document-manager.h>
31 #include <libanjuta/interfaces/ianjuta-symbol-manager.h>
32 #include <libanjuta/interfaces/ianjuta-project-manager.h>
33 #include <libanjuta/interfaces/ianjuta-file-manager.h>
34 #include <libanjuta/interfaces/ianjuta-file.h>
35 #include <libanjuta/interfaces/ianjuta-file-loader.h>
36 #include <libanjuta/interfaces/ianjuta-editor.h>
37 #include <libanjuta/interfaces/ianjuta-markable.h>
38 #include <libanjuta/interfaces/ianjuta-language.h>
39 #include <libanjuta/interfaces/ianjuta-iterable.h>
41 #include <libegg/menu/egg-combo-action.h>
43 #include "plugin.h"
44 #include "symbol-db-view.h"
45 #include "symbol-db-view-locals.h"
46 #include "symbol-db-view-search.h"
47 #include "symbol-db-engine.h"
48 #include "symbol-db-engine-iterator.h"
50 #define UI_FILE ANJUTA_DATA_DIR"/ui/symbol-db.ui"
52 #define GLADE_FILE ANJUTA_DATA_DIR"/glade/symbol-db.glade"
53 #define ICON_FILE "symbol-db.png"
55 #define TIMEOUT_INTERVAL_SYMBOLS_UPDATE 60000
56 #define TIMEOUT_SECONDS_AFTER_LAST_TIP 5
58 static gpointer parent_class;
59 static gboolean need_symbols_update = FALSE;
60 static gchar prev_char_added = ' ';
61 static gint timeout_id = 0;
62 static GTimer *timer = NULL;
64 #define REGISTER_ICON(icon, stock_id) \
65 pixbuf = gdk_pixbuf_new_from_file (icon, NULL); \
66 icon_set = gtk_icon_set_new_from_pixbuf (pixbuf); \
67 gtk_icon_factory_add (icon_factory, stock_id, icon_set); \
68 g_object_unref (pixbuf);
70 static void
71 register_stock_icons (AnjutaPlugin *plugin)
73 AnjutaUI *ui;
74 GtkIconFactory *icon_factory;
75 GtkIconSet *icon_set;
76 GdkPixbuf *pixbuf;
77 static gboolean registered = FALSE;
79 if (registered)
80 return;
81 registered = TRUE;
83 /* Register stock icons */
84 ui = anjuta_shell_get_ui (plugin->shell, NULL);
85 icon_factory = anjuta_ui_get_icon_factory (ui);
86 REGISTER_ICON (PACKAGE_PIXMAPS_DIR"/"ICON_FILE, "symbol-db-plugin-icon");
89 static GtkActionEntry actions[] =
91 { "ActionMenuGoto", NULL, N_("_Goto"), NULL, NULL, NULL},
93 "ActionSymbolBrowserGotoDef",
94 NULL,
95 N_("Tag _Definition"),
96 "<control>d",
97 N_("Goto symbol definition"),
98 G_CALLBACK (on_goto_file_tag_def_activate)
101 "ActionSymbolBrowserGotoDecl",
102 NULL,
103 N_("Tag De_claration"),
104 "<shift><control>d",
105 N_("Goto symbol declaration"),
106 G_CALLBACK (on_goto_file_tag_decl_activate)
111 static gboolean
112 on_editor_buffer_symbols_update_timeout (gpointer user_data)
114 SymbolDBPlugin *sdb_plugin;
115 IAnjutaEditor *ed;
116 gchar *current_buffer = NULL;
117 gint buffer_size = 0;
118 gchar *uri = NULL;
119 gdouble seconds_elapsed;
121 g_return_val_if_fail (user_data != NULL, FALSE);
123 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (user_data);
125 if (sdb_plugin->current_editor == NULL)
126 return FALSE;
128 /* check the timer. If it's elapsed enought time since the last time the user
129 * typed in something, than proceed with updating, elsewhere don't do nothing
131 if (timer == NULL)
132 return TRUE;
134 seconds_elapsed = g_timer_elapsed (timer, NULL);
136 /* DEBUG_PRINT ("seconds_elapsed %f", seconds_elapsed ); */
137 if (seconds_elapsed < TIMEOUT_SECONDS_AFTER_LAST_TIP)
138 return TRUE;
141 /* we won't proceed with the updating of the symbols if we didn't type in
142 anything */
143 if (!need_symbols_update)
144 return TRUE;
146 DEBUG_PRINT ("on_editor_buffer_symbols_update_timeout()");
148 if (sdb_plugin->current_editor)
150 ed = IANJUTA_EDITOR (sdb_plugin->current_editor);
152 buffer_size = ianjuta_editor_get_length (ed, NULL);
153 current_buffer = ianjuta_editor_get_text (ed, 0, -1, NULL);
155 uri = ianjuta_file_get_uri (IANJUTA_FILE (ed), NULL);
157 else
158 return FALSE;
160 if (uri)
162 DEBUG_PRINT ("uri for buffer updating: %s", uri);
164 GPtrArray *real_files_list;
165 GPtrArray *text_buffers;
166 GPtrArray *buffer_sizes;
167 gchar *project_name;
169 gchar * local_path = gnome_vfs_get_local_path_from_uri (uri);
171 real_files_list = g_ptr_array_new ();
172 g_ptr_array_add (real_files_list, local_path);
174 text_buffers = g_ptr_array_new ();
175 g_ptr_array_add (text_buffers, current_buffer);
177 buffer_sizes = g_ptr_array_new ();
178 g_ptr_array_add (buffer_sizes, (gpointer)buffer_size);
180 project_name = symbol_db_engine_get_opened_project_name (sdb_plugin->sdbe);
182 symbol_db_engine_update_buffer_symbols (sdb_plugin->sdbe,
183 project_name,
184 real_files_list,
185 text_buffers,
186 buffer_sizes);
187 g_free (project_name);
189 g_free (uri);
192 g_free (current_buffer);
194 need_symbols_update = FALSE;
196 return TRUE;
199 static void
200 on_editor_destroy (SymbolDBPlugin *sdb_plugin, IAnjutaEditor *editor)
202 const gchar *uri;
204 if (!sdb_plugin->editor_connected || !sdb_plugin->dbv_view_tree)
205 return;
207 uri = g_hash_table_lookup (sdb_plugin->editor_connected, G_OBJECT (editor));
208 if (uri && strlen (uri) > 0)
210 DEBUG_PRINT ("Removing file tags of %s", uri);
212 anjuta_symbol_view_workspace_remove_file (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
213 uri);
216 g_hash_table_remove (sdb_plugin->editor_connected, G_OBJECT (editor));
219 static void
220 on_editor_update_ui (IAnjutaEditor *editor, SymbolDBPlugin *sdb_plugin)
222 #if 0
223 gint lineno = ianjuta_editor_get_lineno (editor, NULL);
225 GtkTreeModel* model = anjuta_symbol_view_get_file_symbol_model
226 (ANJUTA_SYMBOL_VIEW(sv_plugin->sv_tree));
227 GtkTreeIter iter;
228 gboolean found = FALSE;
230 if (sv_plugin->locals_line_number == lineno)
231 return;
232 sv_plugin->locals_line_number = lineno;
234 if (!gtk_tree_model_get_iter_first (model, &iter))
235 return;
236 while (!found && lineno >= 0)
238 gtk_tree_model_get_iter_first (model, &iter);
241 found = iter_matches (sv_plugin, &iter, model, lineno);
242 if (found)
243 break;
245 while (gtk_tree_model_iter_next (model, &iter));
246 lineno--;
248 #endif
251 static void
252 on_char_added (IAnjutaEditor *editor, gint position, gchar ch,
253 SymbolDBPlugin *sdb_plugin)
255 DEBUG_PRINT ("char added @ %d : %c [int %d]", position, ch, ch);
257 if (timer == NULL)
259 /* creates and start a new timer. */
260 timer = g_timer_new ();
262 else
264 g_timer_reset (timer);
268 /* try to force the update if a "." or a "->" is pressed */
269 if ((ch == '.') || (prev_char_added == '-' && ch == '>'))
270 on_editor_buffer_symbols_update_timeout (sdb_plugin);
272 need_symbols_update = TRUE;
274 prev_char_added = ch;
278 static void
279 on_editor_saved (IAnjutaEditor *editor, const gchar *saved_uri,
280 SymbolDBPlugin *sdb_plugin)
282 const gchar *old_uri;
283 gboolean tags_update;
285 /* FIXME: Do this only if automatic tags update is enabled */
286 /* tags_update =
287 anjuta_preferences_get_int (te->preferences, AUTOMATIC_TAGS_UPDATE);
289 tags_update = TRUE;
290 if (tags_update)
292 gchar *local_filename;
293 GPtrArray *files_array;
295 /* Verify that it's local file */
296 local_filename = gnome_vfs_get_local_path_from_uri (saved_uri);
297 g_return_if_fail (local_filename != NULL);
299 files_array = g_ptr_array_new();
300 DEBUG_PRINT ("local_filename saved is %s", local_filename);
301 g_ptr_array_add (files_array, local_filename);
302 /* no need to free local_filename now */
304 if (!sdb_plugin->editor_connected)
305 return;
307 old_uri = g_hash_table_lookup (sdb_plugin->editor_connected, editor);
309 if (old_uri && strlen (old_uri) <= 0)
310 old_uri = NULL;
312 /* files_array will be freed once updating has taken place */
313 symbol_db_engine_update_files_symbols (sdb_plugin->sdbe,
314 sdb_plugin->project_root_dir, files_array, TRUE);
315 g_hash_table_insert (sdb_plugin->editor_connected, editor,
316 g_strdup (saved_uri));
318 on_editor_update_ui (editor, sdb_plugin);
323 static void
324 value_added_current_editor (AnjutaPlugin *plugin, const char *name,
325 const GValue *value, gpointer data)
327 gchar *uri;
328 gchar *local_path;
329 GObject *editor;
330 SymbolDBPlugin *sdb_plugin;
332 editor = g_value_get_object (value);
333 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
335 if (!sdb_plugin->editor_connected)
337 sdb_plugin->editor_connected = g_hash_table_new_full (g_direct_hash,
338 g_direct_equal,
339 NULL, g_free);
341 sdb_plugin->current_editor = editor;
343 uri = ianjuta_file_get_uri (IANJUTA_FILE (editor), NULL);
345 if (uri == NULL)
346 return;
348 local_path = gnome_vfs_get_local_path_from_uri (uri);
350 symbol_db_view_locals_update_list (
351 SYMBOL_DB_VIEW_LOCALS (sdb_plugin->dbv_view_tree_locals),
352 sdb_plugin->sdbe, local_path);
354 if (g_hash_table_lookup (sdb_plugin->editor_connected, editor) == NULL)
356 g_object_weak_ref (G_OBJECT (editor),
357 (GWeakNotify) (on_editor_destroy),
358 sdb_plugin);
359 // if (uri)
360 // {
361 g_hash_table_insert (sdb_plugin->editor_connected, editor,
362 g_strdup (uri));
363 /* }
364 else
366 g_hash_table_insert (sdb_plugin->editor_connected, editor,
367 g_strdup (""));
370 g_signal_connect (G_OBJECT (editor), "saved",
371 G_CALLBACK (on_editor_saved),
372 sdb_plugin);
374 g_signal_connect (G_OBJECT (editor), "char-added",
375 G_CALLBACK (on_char_added),
376 sdb_plugin);
377 g_signal_connect (G_OBJECT(editor), "update_ui",
378 G_CALLBACK (on_editor_update_ui),
379 sdb_plugin);
381 g_free (uri);
382 g_free (local_path);
384 /* add a default timeout to the updating of buffer symbols */
385 timeout_id = g_timeout_add (TIMEOUT_INTERVAL_SYMBOLS_UPDATE,
386 on_editor_buffer_symbols_update_timeout,
387 plugin);
388 need_symbols_update = FALSE;
391 static void
392 on_editor_foreach_disconnect (gpointer key, gpointer value, gpointer user_data)
394 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
395 G_CALLBACK (on_editor_saved),
396 user_data);
397 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
398 G_CALLBACK (on_editor_update_ui),
399 user_data);
400 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
401 G_CALLBACK (on_char_added),
402 user_data);
403 g_object_weak_unref (G_OBJECT(key),
404 (GWeakNotify) (on_editor_destroy),
405 user_data);
408 static void
409 goto_file_line (AnjutaPlugin *plugin, const gchar *filename, gint lineno)
411 gchar *uri;
412 IAnjutaFileLoader *loader;
414 g_return_if_fail (filename != NULL);
416 /* Go to file and line number */
417 loader = anjuta_shell_get_interface (plugin->shell, IAnjutaFileLoader,
418 NULL);
420 uri = g_strdup_printf ("file:///%s#%d", filename, lineno);
421 ianjuta_file_loader_load (loader, uri, FALSE, NULL);
422 g_free (uri);
426 static void
427 goto_tree_iter (SymbolDBPlugin *sdb_plugin, GtkTreeIter *iter)
429 gint line;
431 line = symbol_db_view_locals_get_line (SYMBOL_DB_VIEW_LOCALS (
432 sdb_plugin->dbv_view_tree_locals), iter);
434 DEBUG_PRINT ("got line %d", line);
436 if (line > 0 && sdb_plugin->current_editor)
438 /* Goto line number */
439 ianjuta_editor_goto_line (IANJUTA_EDITOR (sdb_plugin->current_editor),
440 line, NULL);
441 if (IANJUTA_IS_MARKABLE (sdb_plugin->current_editor))
443 ianjuta_markable_delete_all_markers (IANJUTA_MARKABLE (sdb_plugin->current_editor),
444 IANJUTA_MARKABLE_LINEMARKER,
445 NULL);
447 ianjuta_markable_mark (IANJUTA_MARKABLE (sdb_plugin->current_editor),
448 line, IANJUTA_MARKABLE_LINEMARKER, NULL);
454 * will manage the click of mouse and other events on search->hitlist treeview
456 static void
457 on_treesearch_symbol_selected_event (SymbolDBViewSearch *search,
458 gint line,
459 gchar* file,
460 SymbolDBPlugin *sdb_plugin) {
462 DEBUG_PRINT ("on_treesearch_symbol_selected_event (), %s %d", file, line);
463 goto_file_line (ANJUTA_PLUGIN (sdb_plugin), file, line);
467 static void
468 on_local_treeview_row_activated (GtkTreeView *view, GtkTreePath *arg1,
469 GtkTreeViewColumn *arg2,
470 SymbolDBPlugin *sdb_plugin)
472 GtkTreeModel *model;
473 GtkTreeSelection *selection;
474 GtkTreeIter iter;
476 DEBUG_PRINT ("on_local_treeview_row_activated ()");
477 selection = gtk_tree_view_get_selection (view);
478 if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
479 return;
481 goto_tree_iter (sdb_plugin, &iter);
485 static void
486 on_editor_foreach_clear (gpointer key, gpointer value, gpointer user_data)
488 const gchar *uri;
490 uri = (const gchar *)value;
491 if (uri && strlen (uri) > 0)
493 #if 0
494 /* FIXME ?! */
495 DEBUG_PRINT ("Removing file tags of %s", uri);
496 anjuta_symbol_view_workspace_remove_file (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
497 uri);
498 #endif
502 static void
503 value_removed_current_editor (AnjutaPlugin *plugin,
504 const char *name, gpointer data)
506 SymbolDBPlugin *sdb_plugin;
508 /* let's remove the timeout for symbols refresh */
509 g_source_remove (timeout_id);
510 need_symbols_update = FALSE;
512 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
513 /* FIXME
514 ui = anjuta_shell_get_ui (plugin->shell, NULL);
515 action = anjuta_ui_get_action (ui, "ActionGroupSymbolNavigation",
516 "ActionGotoSymbol");
517 g_object_set (G_OBJECT (action), "sensitive", FALSE, NULL);
519 sdb_plugin->current_editor = NULL;
523 static void
524 on_project_element_added (IAnjutaProjectManager *pm, const gchar *uri,
525 SymbolDBPlugin *sv_plugin)
527 gchar *filename;
529 g_return_if_fail (sv_plugin->project_root_uri != NULL);
530 g_return_if_fail (sv_plugin->project_root_dir != NULL);
532 DEBUG_PRINT ("on_project_element_added");
534 filename = gnome_vfs_get_local_path_from_uri (uri);
535 if (filename)
537 GPtrArray *files_array;
538 const gchar* file_mime;
539 IAnjutaLanguageId lang_id;
540 const gchar* lang;
541 IAnjutaLanguage* lang_manager =
542 anjuta_shell_get_interface (ANJUTA_PLUGIN(sv_plugin)->shell, IAnjutaLanguage, NULL);
543 file_mime = gnome_vfs_get_mime_type_for_name (filename);
545 lang_id = ianjuta_language_get_from_mime_type (lang_manager, file_mime, NULL);
547 /* No supported language... */
548 if (!lang_id)
550 g_free (filename);
551 return;
554 lang = ianjuta_language_get_name (lang_manager, lang_id, NULL);
555 files_array = g_ptr_array_new();
556 g_ptr_array_add (files_array, filename);
557 DEBUG_PRINT ("gonna opening %s",
558 filename + strlen(sv_plugin->project_root_dir) );
559 DEBUG_PRINT ("poject_root_dir %s", sv_plugin->project_root_dir );
561 symbol_db_engine_add_new_files (sv_plugin->sdbe,
562 sv_plugin->project_root_dir, files_array, lang, TRUE);
564 g_free (filename);
565 g_ptr_array_free (files_array, TRUE);
569 static void
570 on_project_element_removed (IAnjutaProjectManager *pm, const gchar *uri,
571 SymbolDBPlugin *sv_plugin)
573 gchar *filename;
575 if (!sv_plugin->project_root_uri)
576 return;
578 filename = gnome_vfs_get_local_path_from_uri (uri);
579 if (filename)
581 DEBUG_PRINT ("on_project_element_removed");
582 DEBUG_PRINT ("gonna removing %s",
583 filename + strlen(sv_plugin->project_root_dir));
584 DEBUG_PRINT ("poject_root_dir %s", sv_plugin->project_root_dir );
585 symbol_db_engine_remove_file (sv_plugin->sdbe,
586 sv_plugin->project_root_dir, filename);
588 g_free (filename);
592 static void
593 sources_array_free (gpointer data)
595 GPtrArray* sources = (GPtrArray*) data;
596 g_ptr_array_foreach (sources, (GFunc)g_free, NULL);
597 g_ptr_array_free (sources, TRUE);
600 typedef struct
602 SymbolDBEngine* sdbe;
603 const gchar* root_dir;
604 } SourcesForeachData;
606 static void
607 sources_array_add_foreach (gpointer key, gpointer value, gpointer user_data)
609 const gchar* lang = (const gchar*) key;
610 GPtrArray* sources_array = (GPtrArray*) value;
611 SourcesForeachData* data = (SourcesForeachData*) user_data;
613 if (symbol_db_engine_add_new_files (data->sdbe, data->root_dir,
614 sources_array, lang, TRUE) == FALSE)
616 DEBUG_PRINT ("__FUNCTION__ failed for lang %s, root_dir %s",
617 lang, data->root_dir);
621 /* add a new project */
622 static void
623 project_root_added (AnjutaPlugin *plugin, const gchar *name,
624 const GValue *value, gpointer user_data)
626 AnjutaStatus *status;
627 IAnjutaProjectManager *pm;
628 SymbolDBPlugin *sdb_plugin;
629 const gchar *root_uri;
631 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
633 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
634 IAnjutaProjectManager, NULL);
636 g_free (sdb_plugin->project_root_uri);
637 sdb_plugin->project_root_uri = NULL;
638 root_uri = g_value_get_string (value);
639 if (root_uri)
641 gchar *root_dir = gnome_vfs_get_local_path_from_uri (root_uri);
642 DEBUG_PRINT ("Symbol-DB: added project %s", root_dir);
643 if (root_dir)
645 gboolean needs_sources_scan = FALSE;
646 gint i;
647 GHashTable* lang_hash =
648 g_hash_table_new_full (g_str_hash, g_str_equal, NULL, sources_array_free);
650 status = anjuta_shell_get_status (plugin->shell, NULL);
651 anjuta_status_progress_add_ticks (status, 1);
653 DEBUG_PRINT ("Symbol-DB: creating new project.");
655 /* is it a fresh-new project? is it an imported project with
656 * no 'new' symbol-db database but the 'old' one symbol-browser?
658 if (symbol_db_engine_db_exists (sdb_plugin->sdbe, root_dir) == FALSE)
660 needs_sources_scan = TRUE;
663 if (symbol_db_engine_open_db (sdb_plugin->sdbe, root_dir) == FALSE)
664 g_error ("error in opening db");
666 symbol_db_engine_add_new_project (sdb_plugin->sdbe,
667 NULL, /* still no workspace */
668 root_dir);
670 /* open the project. we can do this only if the db was loaded */
671 if (symbol_db_engine_open_project (sdb_plugin->sdbe, root_dir) == FALSE)
672 g_warning ("error in opening project");
674 if (needs_sources_scan == TRUE)
676 GList* prj_elements_list;
678 DEBUG_PRINT ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
679 DEBUG_PRINT ("Retrieving gbf sources of the project...");
681 prj_elements_list = ianjuta_project_manager_get_elements (pm,
682 IANJUTA_PROJECT_MANAGER_SOURCE,
683 NULL);
685 GPtrArray* sources_array;
687 for (i=0; i < g_list_length (prj_elements_list); i++)
689 gchar *local_filename;
690 const gchar *file_mime;
691 const gchar *lang;
692 IAnjutaLanguageId lang_id;
693 IAnjutaLanguage* lang_manager =
694 anjuta_shell_get_interface (plugin->shell, IAnjutaLanguage, NULL);
696 if (!lang_manager)
698 g_critical ("LanguageManager not found");
699 return;
702 local_filename =
703 gnome_vfs_get_local_path_from_uri (g_list_nth_data (
704 prj_elements_list, i));
705 file_mime = gnome_vfs_get_mime_type_for_name (local_filename);
707 lang_id = ianjuta_language_get_from_mime_type (lang_manager, file_mime, NULL);
709 if (!lang_id)
711 g_free (local_filename);
712 continue;
715 lang = ianjuta_language_get_name (lang_manager, lang_id, NULL);
716 DEBUG_PRINT ("Language of %s is %s", local_filename, file_mime);
717 /* test its existence */
718 if (g_file_test (local_filename, G_FILE_TEST_EXISTS) == FALSE)
720 g_free (local_filename);
721 continue;
724 sources_array = g_hash_table_lookup (lang_hash, lang);
725 if (!sources_array)
727 sources_array = g_ptr_array_new ();
728 g_hash_table_insert (lang_hash, (gpointer) lang, sources_array);
731 g_ptr_array_add (sources_array, local_filename);
734 DEBUG_PRINT ("calling symbol_db_engine_add_new_files with root_dir %s",
735 root_dir);
737 SourcesForeachData* data = g_new0 (SourcesForeachData, 1);
738 data->sdbe = sdb_plugin->sdbe;
739 data->root_dir = root_dir;
741 g_hash_table_foreach (lang_hash, (GHFunc) sources_array_add_foreach,
742 data);
744 g_free (data);
745 g_hash_table_unref (lang_hash);
748 anjuta_status_progress_tick (status, NULL, _("Created symbols..."));
750 symbol_db_view_open (SYMBOL_DB_VIEW (sdb_plugin->dbv_view_tree),
751 sdb_plugin->sdbe);
753 /* root dir */
754 sdb_plugin->project_root_dir = root_dir;
756 /* this is uri */
757 sdb_plugin->project_root_uri = g_strdup (root_uri);
760 g_signal_connect (G_OBJECT (pm), "element_added",
761 G_CALLBACK (on_project_element_added), sdb_plugin);
762 g_signal_connect (G_OBJECT (pm), "element_removed",
763 G_CALLBACK (on_project_element_removed), sdb_plugin);
766 static void
767 project_root_removed (AnjutaPlugin *plugin, const gchar *name,
768 gpointer user_data)
770 IAnjutaProjectManager *pm;
771 SymbolDBPlugin *sdb_plugin;
773 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
775 /* Disconnect events from project manager */
777 /* FIXME: There should be a way to ensure that this project manager
778 * is indeed the one that has opened the project_uri
780 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
781 IAnjutaProjectManager, NULL);
782 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
783 on_project_element_added,
784 sdb_plugin);
785 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
786 on_project_element_removed,
787 sdb_plugin);
789 /* don't forget to close the project */
790 symbol_db_engine_close_project (sdb_plugin->sdbe,
791 sdb_plugin->project_root_dir);
793 g_free (sdb_plugin->project_root_uri);
794 g_free (sdb_plugin->project_root_dir);
795 sdb_plugin->project_root_uri = NULL;
796 sdb_plugin->project_root_dir = NULL;
799 static gboolean
800 symbol_db_activate (AnjutaPlugin *plugin)
802 SymbolDBPlugin *symbol_db;
804 DEBUG_PRINT ("SymbolDBPlugin: Activating SymbolDBPlugin plugin ...");
807 register_stock_icons (plugin);
809 symbol_db = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
810 symbol_db->ui = anjuta_shell_get_ui (plugin->shell, NULL);
812 /* create SymbolDBEngine */
813 symbol_db->sdbe = symbol_db_engine_new ();
815 /* Create widgets */
816 symbol_db->dbv_notebook = gtk_notebook_new();
818 /* Local symbols */
819 symbol_db->scrolled_locals = gtk_scrolled_window_new (NULL, NULL);
820 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (symbol_db->scrolled_locals),
821 GTK_SHADOW_IN);
822 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (symbol_db->scrolled_locals),
823 GTK_POLICY_AUTOMATIC,
824 GTK_POLICY_AUTOMATIC);
826 symbol_db->dbv_view_locals_tab_label = gtk_label_new (_("Local" ));
827 symbol_db->dbv_view_tree_locals = symbol_db_view_locals_new ();
829 g_object_add_weak_pointer (G_OBJECT (symbol_db->dbv_view_tree_locals),
830 (gpointer)&symbol_db->dbv_view_tree_locals);
831 g_signal_connect (G_OBJECT (symbol_db->dbv_view_tree_locals), "row_activated",
832 G_CALLBACK (on_local_treeview_row_activated), plugin);
834 gtk_container_add (GTK_CONTAINER(symbol_db->scrolled_locals),
835 symbol_db->dbv_view_tree_locals);
838 /* Global symbols */
839 symbol_db->scrolled_global = gtk_scrolled_window_new (NULL, NULL);
840 gtk_scrolled_window_set_shadow_type (
841 GTK_SCROLLED_WINDOW (symbol_db->scrolled_global),
842 GTK_SHADOW_IN);
843 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (symbol_db->scrolled_global),
844 GTK_POLICY_AUTOMATIC,
845 GTK_POLICY_AUTOMATIC);
847 symbol_db->dbv_view_tab_label = gtk_label_new (_("Global" ));
848 symbol_db->dbv_view_tree = symbol_db_view_new ();
849 g_object_add_weak_pointer (G_OBJECT (symbol_db->dbv_view_tree),
850 (gpointer)&symbol_db->dbv_view_tree);
851 #if 0
852 g_signal_connect (G_OBJECT (symbol_db->dbv_view_tree), "event-after",
853 G_CALLBACK (on_treeview_event), plugin);
855 g_signal_connect (G_OBJECT (symbol_db->dbv_view_tree), "row_activated",
856 G_CALLBACK (on_treeview_row_activated), plugin);
857 #endif
858 gtk_container_add (GTK_CONTAINER(symbol_db->scrolled_global),
859 symbol_db->dbv_view_tree);
861 /* Search symbols */
862 symbol_db->dbv_view_tree_search =
863 (GtkWidget*) symbol_db_view_search_new (symbol_db->sdbe);
864 symbol_db->dbv_view_search_tab_label = gtk_label_new (_("Search" ));
866 g_signal_connect (G_OBJECT (symbol_db->dbv_view_tree_search), "symbol_selected",
867 G_CALLBACK (on_treesearch_symbol_selected_event),
868 plugin);
870 g_object_add_weak_pointer (G_OBJECT (symbol_db->dbv_view_tree_search),
871 (gpointer)&symbol_db->dbv_view_tree_search);
873 /* add the scrolled windows to the notebook */
874 gtk_notebook_append_page (GTK_NOTEBOOK (symbol_db->dbv_notebook),
875 symbol_db->scrolled_locals,
876 symbol_db->dbv_view_locals_tab_label);
878 gtk_notebook_append_page (GTK_NOTEBOOK (symbol_db->dbv_notebook),
879 symbol_db->scrolled_global,
880 symbol_db->dbv_view_tab_label);
882 gtk_notebook_append_page (GTK_NOTEBOOK (symbol_db->dbv_notebook),
883 symbol_db->dbv_view_tree_search,
884 symbol_db->dbv_view_search_tab_label);
886 gtk_widget_show_all (symbol_db->dbv_notebook);
888 /* setting focus to the tree_view*/
889 gtk_notebook_set_current_page (GTK_NOTEBOOK (symbol_db->dbv_notebook), 0);
891 symbol_db->editor_watch_id =
892 anjuta_plugin_add_watch (plugin, "document_manager_current_editor",
893 value_added_current_editor,
894 value_removed_current_editor, NULL);
895 #if 0
896 /* Add UI */
897 symbol_db->merge_id =
898 anjuta_ui_merge (symbol_db->ui, UI_FILE);
899 #endif
900 /* Added widgets */
901 anjuta_shell_add_widget (plugin->shell, symbol_db->dbv_notebook,
902 "SymbolDBView", _("Symbols"),
903 "symbol-db-plugin-icon",
904 ANJUTA_SHELL_PLACEMENT_LEFT, NULL);
906 /* set up project directory watch */
907 symbol_db->root_watch_id = anjuta_plugin_add_watch (plugin,
908 "project_root_uri",
909 project_root_added,
910 project_root_removed, NULL);
912 return TRUE;
915 static gboolean
916 symbol_db_deactivate (AnjutaPlugin *plugin)
918 SymbolDBPlugin *sdb_plugin;
920 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
922 DEBUG_PRINT ("SymbolDBPlugin: Dectivating SymbolDBPlugin plugin ...");
924 DEBUG_PRINT ("SymbolDBPlugin: destroying engine ...");
925 g_object_unref (sdb_plugin->sdbe);
926 sdb_plugin->sdbe = NULL;
928 /* disconnect some signals */
929 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->dbv_view_tree_locals),
930 on_local_treeview_row_activated,
931 plugin);
933 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->dbv_view_tree_search),
934 on_treesearch_symbol_selected_event,
935 plugin);
938 DEBUG_PRINT ("SymbolDBPlugin: destroying locals view ...");
939 g_object_unref (sdb_plugin->dbv_view_tree_locals);
941 DEBUG_PRINT ("SymbolDBPlugin: destroying globals view ...");
942 g_object_unref (sdb_plugin->dbv_view_tree);
944 DEBUG_PRINT ("SymbolDBPlugin: destroying search ...");
945 g_object_unref (sdb_plugin->dbv_view_tree_search);
948 /* Ensure all editor cached info are released */
949 if (sdb_plugin->editor_connected)
951 g_hash_table_foreach (sdb_plugin->editor_connected,
952 on_editor_foreach_disconnect, plugin);
953 g_hash_table_foreach (sdb_plugin->editor_connected,
954 on_editor_foreach_clear, plugin);
955 g_hash_table_destroy (sdb_plugin->editor_connected);
956 sdb_plugin->editor_connected = NULL;
959 /* Remove watches */
960 anjuta_plugin_remove_watch (plugin, sdb_plugin->root_watch_id, FALSE);
961 anjuta_plugin_remove_watch (plugin, sdb_plugin->editor_watch_id, TRUE);
963 /* Remove widgets: Widgets will be destroyed when dbv_notebook is removed */
964 anjuta_shell_remove_widget (plugin->shell, sdb_plugin->dbv_notebook, NULL);
966 #if 0
967 /* Remove UI */
968 anjuta_ui_unmerge (sdb_plugin->ui, sdb_plugin->merge_id);
970 /* Remove action group */
971 anjuta_ui_remove_action_group (sv_plugin->ui, sv_plugin->action_group);
972 anjuta_ui_remove_action_group (sv_plugin->ui, sv_plugin->popup_action_group);
973 anjuta_ui_remove_action_group (sdb_plugin->ui, sdb_plugin->action_group_nav);
974 ui = anjuta_shell_get_ui (plugin->shell, NULL);
975 /* anjuta_ui_remove_action_group (ui, ((SymbolDBPlugin*)plugin)->action_group); */
976 anjuta_ui_unmerge (ui, ((SymbolDBPlugin*)plugin)->uiid);
977 #endif
979 sdb_plugin->root_watch_id = 0;
980 sdb_plugin->editor_watch_id = 0;
981 sdb_plugin->dbv_notebook = NULL;
982 sdb_plugin->scrolled_global = NULL;
983 sdb_plugin->scrolled_locals = NULL;
984 sdb_plugin->dbv_view_tree = NULL;
985 sdb_plugin->dbv_view_tab_label = NULL;
986 sdb_plugin->dbv_view_tree_locals = NULL;
987 sdb_plugin->dbv_view_locals_tab_label = NULL;
988 sdb_plugin->dbv_view_tree_search = NULL;
989 sdb_plugin->dbv_view_search_tab_label = NULL;
990 return TRUE;
993 static void
994 symbol_db_finalize (GObject *obj)
996 /* Finalization codes here */
997 GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (obj));
1000 static void
1001 symbol_db_dispose (GObject *obj)
1003 /* Disposition codes */
1004 GNOME_CALL_PARENT (G_OBJECT_CLASS, dispose, (obj));
1007 static void
1008 symbol_db_instance_init (GObject *obj)
1010 SymbolDBPlugin *plugin = (SymbolDBPlugin*)obj;
1012 plugin->uiid = 0;
1013 plugin->widget = NULL;
1016 static void
1017 symbol_db_class_init (GObjectClass *klass)
1019 AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
1021 parent_class = g_type_class_peek_parent (klass);
1023 plugin_class->activate = symbol_db_activate;
1024 plugin_class->deactivate = symbol_db_deactivate;
1025 klass->finalize = symbol_db_finalize;
1026 klass->dispose = symbol_db_dispose;
1029 static IAnjutaIterable*
1030 isymbol_manager_search (IAnjutaSymbolManager *sm,
1031 IAnjutaSymbolType match_types,
1032 const gchar *match_name,
1033 gboolean partial_name_match,
1034 gboolean global_search,
1035 GError **err)
1037 SymbolDBEngineIterator *iterator = NULL;
1038 SymbolDBPlugin *sdb_plugin;
1039 SymbolDBEngine *dbe;
1040 const gchar* name;
1042 DEBUG_PRINT ("called isymbol_manager_search()! %s", match_name);
1044 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (sm);
1045 dbe = SYMBOL_DB_ENGINE (sdb_plugin->sdbe);
1048 if (match_name && strlen (match_name) > 0)
1049 name = match_name;
1050 else
1051 name = NULL;
1054 iterator =
1055 symbol_db_engine_find_symbol_by_name_pattern (dbe,
1056 name, SYMINFO_SIMPLE |
1057 SYMINFO_FILE_PATH |
1058 SYMINFO_IMPLEMENTATION |
1059 SYMINFO_ACCESS |
1060 SYMINFO_KIND |
1061 SYMINFO_TYPE |
1062 SYMINFO_TYPE_NAME |
1063 SYMINFO_LANGUAGE |
1064 SYMINFO_FILE_IGNORE |
1065 SYMINFO_FILE_INCLUDE |
1066 SYMINFO_PROJECT_NAME |
1067 SYMINFO_WORKSPACE_NAME );
1069 return IANJUTA_ITERABLE (iterator);
1072 static IAnjutaIterable*
1073 isymbol_manager_get_members (IAnjutaSymbolManager *sm,
1074 const gchar *symbol_name,
1075 gboolean global_search,
1076 GError **err)
1078 #if 0
1079 const GPtrArray *tags_array;
1080 AnjutaSymbolIter *iter = NULL;
1082 tags_array = tm_workspace_find_scope_members (NULL, symbol_name,
1083 global_search, TRUE);
1086 if (tags_array)
1088 iter = anjuta_symbol_iter_new (tags_array);
1089 return IANJUTA_ITERABLE (iter);
1091 #endif
1092 return NULL;
1095 static IAnjutaIterable*
1096 isymbol_manager_get_parents (IAnjutaSymbolManager *sm,
1097 const gchar *symbol_name,
1098 GError **err)
1100 #if 0
1101 const GPtrArray *tags_array;
1102 AnjutaSymbolIter *iter = NULL;
1104 tags_array = tm_workspace_get_parents (symbol_name);
1105 if (tags_array)
1107 iter = anjuta_symbol_iter_new (tags_array);
1108 return IANJUTA_ITERABLE (iter);
1110 #endif
1111 return NULL;
1114 static IAnjutaIterable*
1115 isymbol_manager_get_completions_at_position (IAnjutaSymbolManager *sm,
1116 const gchar *file_uri,
1117 const gchar *text_buffer,
1118 gint text_length,
1119 gint text_pos,
1120 GError **err)
1122 #if 0
1123 SymbolBrowserPlugin *sv_plugin;
1124 const TMTag *func_scope_tag;
1125 TMSourceFile *tm_file;
1126 IAnjutaEditor *ed;
1127 AnjutaSymbolView *symbol_view;
1128 gulong line;
1129 gulong scope_position;
1130 gchar *needed_text = NULL;
1131 gint access_method;
1132 GPtrArray * completable_tags_array;
1133 AnjutaSymbolIter *iter = NULL;
1135 sv_plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (sm);
1136 ed = IANJUTA_EDITOR (sv_plugin->current_editor);
1137 symbol_view = ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree);
1139 line = ianjuta_editor_get_line_from_position (ed, text_pos, NULL);
1141 /* get the function scope */
1142 tm_file = anjuta_symbol_view_get_tm_file (symbol_view, file_uri);
1144 /* check whether the current file_uri is listed in the tm_workspace or not... */
1145 if (tm_file == NULL)
1146 return NULL;
1149 // FIXME: remove DEBUG_PRINT
1151 DEBUG_PRINT ("tags in file &s\n");
1152 if (tm_file->work_object.tags_array != NULL) {
1153 int i;
1154 for (i=0; i < tm_file->work_object.tags_array->len; i++) {
1155 TMTag *cur_tag;
1157 cur_tag = (TMTag*)g_ptr_array_index (tm_file->work_object.tags_array, i);
1158 tm_tag_print (cur_tag, stdout);
1163 func_scope_tag = tm_get_current_function (tm_file->work_object.tags_array, line);
1165 if (func_scope_tag == NULL) {
1166 DEBUG_PRINT ("func_scope_tag is NULL, seems like it's a completion on a global scope");
1167 return NULL;
1170 DEBUG_PRINT ("current expression scope: %s", func_scope_tag->name);
1173 scope_position = ianjuta_editor_get_line_begin_position (ed, func_scope_tag->atts.entry.line, NULL);
1174 needed_text = ianjuta_editor_get_text (ed, scope_position,
1175 text_pos - scope_position, NULL);
1177 if (needed_text == NULL)
1178 DEBUG_PRINT ("needed_text is null");
1179 DEBUG_PRINT ("text needed is %s", needed_text );
1182 /* we'll pass only the text of the current scope: i.e. only the current function
1183 * in which we request the completion. */
1184 TMTag * found_type = anjuta_symbol_view_get_type_of_expression (symbol_view,
1185 needed_text, text_pos - scope_position, func_scope_tag, &access_method);
1188 if (found_type == NULL) {
1189 DEBUG_PRINT ("type not found.");
1190 return NULL;
1193 /* get the completable memebers. If the access is COMPLETION_ACCESS_STATIC we don't
1194 * want to know the parents members of the class.
1196 if (access_method == COMPLETION_ACCESS_STATIC)
1197 completable_tags_array = anjuta_symbol_view_get_completable_members (found_type, FALSE);
1198 else
1199 completable_tags_array = anjuta_symbol_view_get_completable_members (found_type, TRUE);
1201 if (completable_tags_array)
1203 iter = anjuta_symbol_iter_new (completable_tags_array);
1204 return IANJUTA_ITERABLE (iter);
1206 #endif
1207 return NULL;
1211 static void
1212 isymbol_manager_iface_init (IAnjutaSymbolManagerIface *iface)
1214 iface->search = isymbol_manager_search;
1215 iface->get_members = isymbol_manager_get_members;
1216 iface->get_parents = isymbol_manager_get_parents;
1217 iface->get_completions_at_position = isymbol_manager_get_completions_at_position;
1220 ANJUTA_PLUGIN_BEGIN (SymbolDBPlugin, symbol_db);
1221 ANJUTA_PLUGIN_ADD_INTERFACE (isymbol_manager, IANJUTA_TYPE_SYMBOL_MANAGER);
1222 ANJUTA_PLUGIN_END;
1224 ANJUTA_SIMPLE_PLUGIN (SymbolDBPlugin, symbol_db);