2007-10-28 Johannes Schmid <jhs@gnome.org>
[anjuta-git-plugin.git] / plugins / symbol-db / plugin.c
blob85010a8c991d442adb901356309b089dc7358e65
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 15000
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 static void
65 register_stock_icons (AnjutaPlugin *plugin)
67 static gboolean registered = FALSE;
69 if (registered)
70 return;
71 registered = TRUE;
73 /* Register stock icons */
74 BEGIN_REGISTER_ICON (plugin);
75 REGISTER_ICON (ICON_FILE, "symbol-db-plugin-icon");
76 END_REGISTER_ICON;
79 static GtkActionEntry actions[] =
81 { "ActionMenuGoto", NULL, N_("_Goto"), NULL, NULL, NULL},
83 "ActionSymbolBrowserGotoDef",
84 NULL,
85 N_("Tag _Definition"),
86 "<control>d",
87 N_("Goto symbol definition"),
88 G_CALLBACK (on_goto_file_tag_def_activate)
91 "ActionSymbolBrowserGotoDecl",
92 NULL,
93 N_("Tag De_claration"),
94 "<shift><control>d",
95 N_("Goto symbol declaration"),
96 G_CALLBACK (on_goto_file_tag_decl_activate)
101 static gboolean
102 on_editor_buffer_symbols_update_timeout (gpointer user_data)
104 SymbolDBPlugin *sdb_plugin;
105 IAnjutaEditor *ed;
106 gchar *current_buffer = NULL;
107 gint buffer_size = 0;
108 gchar *uri = NULL;
109 gdouble seconds_elapsed;
111 g_return_val_if_fail (user_data != NULL, FALSE);
113 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (user_data);
115 if (sdb_plugin->current_editor == NULL)
116 return FALSE;
118 /* check the timer. If it's elapsed enought time since the last time the user
119 * typed in something, than proceed with updating, elsewhere don't do nothing
121 if (timer == NULL)
122 return TRUE;
124 seconds_elapsed = g_timer_elapsed (timer, NULL);
126 /* DEBUG_PRINT ("seconds_elapsed %f", seconds_elapsed ); */
127 if (seconds_elapsed < TIMEOUT_SECONDS_AFTER_LAST_TIP)
128 return TRUE;
131 /* we won't proceed with the updating of the symbols if we didn't type in
132 anything */
133 if (!need_symbols_update)
134 return TRUE;
136 DEBUG_PRINT ("on_editor_buffer_symbols_update_timeout()");
138 if (sdb_plugin->current_editor)
140 ed = IANJUTA_EDITOR (sdb_plugin->current_editor);
142 buffer_size = ianjuta_editor_get_length (ed, NULL);
143 current_buffer = ianjuta_editor_get_text (ed, 0, -1, NULL);
145 uri = ianjuta_file_get_uri (IANJUTA_FILE (ed), NULL);
147 else
148 return FALSE;
150 if (uri)
152 DEBUG_PRINT ("uri for buffer updating: %s", uri);
154 GPtrArray *real_files_list;
155 GPtrArray *text_buffers;
156 GPtrArray *buffer_sizes;
157 gchar *project_name;
159 gchar * local_path = gnome_vfs_get_local_path_from_uri (uri);
161 real_files_list = g_ptr_array_new ();
162 g_ptr_array_add (real_files_list, local_path);
164 text_buffers = g_ptr_array_new ();
165 g_ptr_array_add (text_buffers, current_buffer);
167 buffer_sizes = g_ptr_array_new ();
168 g_ptr_array_add (buffer_sizes, (gpointer)buffer_size);
170 project_name = symbol_db_engine_get_opened_project_name (sdb_plugin->sdbe);
172 symbol_db_engine_update_buffer_symbols (sdb_plugin->sdbe,
173 project_name,
174 real_files_list,
175 text_buffers,
176 buffer_sizes);
177 g_free (project_name);
179 g_free (uri);
182 g_free (current_buffer);
184 need_symbols_update = FALSE;
186 return TRUE;
189 static void
190 on_editor_destroy (SymbolDBPlugin *sdb_plugin, IAnjutaEditor *editor)
192 const gchar *uri;
194 if (!sdb_plugin->editor_connected || !sdb_plugin->dbv_view_tree)
195 return;
197 uri = g_hash_table_lookup (sdb_plugin->editor_connected, G_OBJECT (editor));
198 if (uri && strlen (uri) > 0)
200 DEBUG_PRINT ("Removing file tags of %s", uri);
202 anjuta_symbol_view_workspace_remove_file (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
203 uri);
206 g_hash_table_remove (sdb_plugin->editor_connected, G_OBJECT (editor));
209 static void
210 on_editor_update_ui (IAnjutaEditor *editor, SymbolDBPlugin *sdb_plugin)
212 #if 0
213 gint lineno = ianjuta_editor_get_lineno (editor, NULL);
215 GtkTreeModel* model = anjuta_symbol_view_get_file_symbol_model
216 (ANJUTA_SYMBOL_VIEW(sv_plugin->sv_tree));
217 GtkTreeIter iter;
218 gboolean found = FALSE;
220 if (sv_plugin->locals_line_number == lineno)
221 return;
222 sv_plugin->locals_line_number = lineno;
224 if (!gtk_tree_model_get_iter_first (model, &iter))
225 return;
226 while (!found && lineno >= 0)
228 gtk_tree_model_get_iter_first (model, &iter);
231 found = iter_matches (sv_plugin, &iter, model, lineno);
232 if (found)
233 break;
235 while (gtk_tree_model_iter_next (model, &iter));
236 lineno--;
238 #endif
241 static void
242 on_char_added (IAnjutaEditor *editor, gint position, gchar ch,
243 SymbolDBPlugin *sdb_plugin)
245 DEBUG_PRINT ("char added @ %d : %c [int %d]", position, ch, ch);
247 if (timer == NULL)
249 /* creates and start a new timer. */
250 timer = g_timer_new ();
252 else
254 g_timer_reset (timer);
258 /* try to force the update if a "." or a "->" is pressed */
259 if ((ch == '.') || (prev_char_added == '-' && ch == '>'))
260 on_editor_buffer_symbols_update_timeout (sdb_plugin);
262 need_symbols_update = TRUE;
264 prev_char_added = ch;
268 static void
269 on_editor_saved (IAnjutaEditor *editor, const gchar *saved_uri,
270 SymbolDBPlugin *sdb_plugin)
272 const gchar *old_uri;
273 gboolean tags_update;
275 /* FIXME: Do this only if automatic tags update is enabled */
276 /* tags_update =
277 anjuta_preferences_get_int (te->preferences, AUTOMATIC_TAGS_UPDATE);
279 tags_update = TRUE;
280 if (tags_update)
282 gchar *local_filename;
283 GPtrArray *files_array;
285 /* Verify that it's local file */
286 local_filename = gnome_vfs_get_local_path_from_uri (saved_uri);
287 g_return_if_fail (local_filename != NULL);
289 files_array = g_ptr_array_new();
290 DEBUG_PRINT ("local_filename saved is %s", local_filename);
291 g_ptr_array_add (files_array, local_filename);
292 /* no need to free local_filename now */
294 if (!sdb_plugin->editor_connected)
295 return;
297 old_uri = g_hash_table_lookup (sdb_plugin->editor_connected, editor);
299 if (old_uri && strlen (old_uri) <= 0)
300 old_uri = NULL;
302 /* files_array will be freed once updating has taken place */
303 symbol_db_engine_update_files_symbols (sdb_plugin->sdbe,
304 sdb_plugin->project_root_dir, files_array, TRUE);
305 g_hash_table_insert (sdb_plugin->editor_connected, editor,
306 g_strdup (saved_uri));
308 on_editor_update_ui (editor, sdb_plugin);
313 //files = anjuta_session_get_string_list (session, "File Loader", "Files");
314 static void
315 value_added_current_editor (AnjutaPlugin *plugin, const char *name,
316 const GValue *value, gpointer data)
318 gchar *uri;
319 gchar *local_path;
320 GObject *editor;
321 SymbolDBPlugin *sdb_plugin;
323 editor = g_value_get_object (value);
324 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
326 if (!sdb_plugin->editor_connected)
328 sdb_plugin->editor_connected = g_hash_table_new_full (g_direct_hash,
329 g_direct_equal,
330 NULL, g_free);
332 sdb_plugin->current_editor = editor;
334 uri = ianjuta_file_get_uri (IANJUTA_FILE (editor), NULL);
336 if (uri == NULL)
337 return;
339 local_path = gnome_vfs_get_local_path_from_uri (uri);
340 symbol_db_view_locals_update_list (
341 SYMBOL_DB_VIEW_LOCALS (sdb_plugin->dbv_view_tree_locals),
342 sdb_plugin->sdbe, local_path);
344 if (g_hash_table_lookup (sdb_plugin->editor_connected, editor) == NULL)
346 g_object_weak_ref (G_OBJECT (editor),
347 (GWeakNotify) (on_editor_destroy),
348 sdb_plugin);
349 if (uri)
351 g_hash_table_insert (sdb_plugin->editor_connected, editor,
352 g_strdup (uri));
354 else
356 g_hash_table_insert (sdb_plugin->editor_connected, editor,
357 g_strdup (""));
360 g_signal_connect (G_OBJECT (editor), "saved",
361 G_CALLBACK (on_editor_saved),
362 sdb_plugin);
364 g_signal_connect (G_OBJECT (editor), "char-added",
365 G_CALLBACK (on_char_added),
366 sdb_plugin);
367 g_signal_connect (G_OBJECT(editor), "update_ui",
368 G_CALLBACK (on_editor_update_ui),
369 sdb_plugin);
371 g_free (uri);
372 g_free (local_path);
374 /* add a default timeout to the updating of buffer symbols */
375 timeout_id = g_timeout_add (TIMEOUT_INTERVAL_SYMBOLS_UPDATE,
376 on_editor_buffer_symbols_update_timeout,
377 plugin);
378 need_symbols_update = FALSE;
381 static void
382 on_editor_foreach_disconnect (gpointer key, gpointer value, gpointer user_data)
384 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
385 G_CALLBACK (on_editor_saved),
386 user_data);
387 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
388 G_CALLBACK (on_editor_update_ui),
389 user_data);
390 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
391 G_CALLBACK (on_char_added),
392 user_data);
393 g_object_weak_unref (G_OBJECT(key),
394 (GWeakNotify) (on_editor_destroy),
395 user_data);
398 static void
399 goto_file_line (AnjutaPlugin *plugin, const gchar *filename, gint lineno)
401 gchar *uri;
402 IAnjutaFileLoader *loader;
404 g_return_if_fail (filename != NULL);
406 /* Go to file and line number */
407 loader = anjuta_shell_get_interface (plugin->shell, IAnjutaFileLoader,
408 NULL);
410 uri = g_strdup_printf ("file:///%s#%d", filename, lineno);
411 ianjuta_file_loader_load (loader, uri, FALSE, NULL);
412 g_free (uri);
416 static void
417 goto_tree_iter (SymbolDBPlugin *sdb_plugin, GtkTreeIter *iter)
419 gint line;
421 line = symbol_db_view_locals_get_line (SYMBOL_DB_VIEW_LOCALS (
422 sdb_plugin->dbv_view_tree_locals),
423 sdb_plugin->sdbe,
424 iter);
426 DEBUG_PRINT ("got line %d", line);
428 if (line > 0 && sdb_plugin->current_editor)
430 /* Goto line number */
431 ianjuta_editor_goto_line (IANJUTA_EDITOR (sdb_plugin->current_editor),
432 line, NULL);
433 if (IANJUTA_IS_MARKABLE (sdb_plugin->current_editor))
435 ianjuta_markable_delete_all_markers (IANJUTA_MARKABLE (sdb_plugin->current_editor),
436 IANJUTA_MARKABLE_LINEMARKER,
437 NULL);
439 ianjuta_markable_mark (IANJUTA_MARKABLE (sdb_plugin->current_editor),
440 line, IANJUTA_MARKABLE_LINEMARKER, NULL);
446 * will manage the click of mouse and other events on search->hitlist treeview
448 static void
449 on_treesearch_symbol_selected_event (SymbolDBViewSearch *search,
450 gint line,
451 gchar* file,
452 SymbolDBPlugin *sdb_plugin) {
454 DEBUG_PRINT ("on_treesearch_symbol_selected_event (), %s %d", file, line);
455 goto_file_line (ANJUTA_PLUGIN (sdb_plugin), file, line);
459 static void
460 on_local_treeview_row_activated (GtkTreeView *view, GtkTreePath *arg1,
461 GtkTreeViewColumn *arg2,
462 SymbolDBPlugin *sdb_plugin)
464 GtkTreeModel *model;
465 GtkTreeSelection *selection;
466 GtkTreeIter iter;
468 DEBUG_PRINT ("on_local_treeview_row_activated ()");
469 selection = gtk_tree_view_get_selection (view);
470 if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
471 return;
473 goto_tree_iter (sdb_plugin, &iter);
477 static void
478 on_editor_foreach_clear (gpointer key, gpointer value, gpointer user_data)
480 const gchar *uri;
482 uri = (const gchar *)value;
483 if (uri && strlen (uri) > 0)
485 #if 0
486 /* FIXME ?! */
487 DEBUG_PRINT ("Removing file tags of %s", uri);
488 anjuta_symbol_view_workspace_remove_file (ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree),
489 uri);
490 #endif
494 static void
495 value_removed_current_editor (AnjutaPlugin *plugin,
496 const char *name, gpointer data)
498 SymbolDBPlugin *sdb_plugin;
500 /* let's remove the timeout for symbols refresh */
501 g_source_remove (timeout_id);
502 need_symbols_update = FALSE;
504 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
505 /* FIXME
506 ui = anjuta_shell_get_ui (plugin->shell, NULL);
507 action = anjuta_ui_get_action (ui, "ActionGroupSymbolNavigation",
508 "ActionGotoSymbol");
509 g_object_set (G_OBJECT (action), "sensitive", FALSE, NULL);
511 sdb_plugin->current_editor = NULL;
515 static void
516 on_project_element_added (IAnjutaProjectManager *pm, const gchar *uri,
517 SymbolDBPlugin *sv_plugin)
519 gchar *filename;
521 g_return_if_fail (sv_plugin->project_root_uri != NULL);
522 g_return_if_fail (sv_plugin->project_root_dir != NULL);
524 DEBUG_PRINT ("on_project_element_added");
526 filename = gnome_vfs_get_local_path_from_uri (uri);
527 if (filename)
529 GPtrArray *files_array;
530 const gchar* file_mime;
531 IAnjutaLanguageId lang_id;
532 const gchar* lang;
533 IAnjutaLanguage* lang_manager =
534 anjuta_shell_get_interface (ANJUTA_PLUGIN(sv_plugin)->shell, IAnjutaLanguage, NULL);
535 file_mime = gnome_vfs_get_mime_type_for_name (filename);
537 lang_id = ianjuta_language_get_from_mime_type (lang_manager, file_mime, NULL);
539 /* No supported language... */
540 if (!lang_id)
542 g_free (filename);
543 return;
546 lang = ianjuta_language_get_name (lang_manager, lang_id, NULL);
547 files_array = g_ptr_array_new();
548 g_ptr_array_add (files_array, filename);
549 DEBUG_PRINT ("gonna opening %s",
550 filename + strlen(sv_plugin->project_root_dir) );
551 DEBUG_PRINT ("poject_root_dir %s", sv_plugin->project_root_dir );
553 symbol_db_engine_add_new_files (sv_plugin->sdbe,
554 sv_plugin->project_root_dir, files_array, lang, TRUE);
556 g_free (filename);
557 g_ptr_array_free (files_array, TRUE);
561 static void
562 on_project_element_removed (IAnjutaProjectManager *pm, const gchar *uri,
563 SymbolDBPlugin *sv_plugin)
565 gchar *filename;
567 if (!sv_plugin->project_root_uri)
568 return;
570 filename = gnome_vfs_get_local_path_from_uri (uri);
571 if (filename)
573 DEBUG_PRINT ("on_project_element_removed");
574 DEBUG_PRINT ("gonna removing %s",
575 filename + strlen(sv_plugin->project_root_dir));
576 DEBUG_PRINT ("poject_root_dir %s", sv_plugin->project_root_dir );
577 symbol_db_engine_remove_file (sv_plugin->sdbe,
578 sv_plugin->project_root_dir, filename);
580 g_free (filename);
584 static void
585 sources_array_free (gpointer data)
587 GPtrArray* sources = (GPtrArray*) data;
588 g_ptr_array_foreach (sources, (GFunc)g_free, NULL);
589 g_ptr_array_free (sources, TRUE);
592 typedef struct
594 SymbolDBEngine* sdbe;
595 const gchar* root_dir;
596 } SourcesForeachData;
598 static void
599 sources_array_add_foreach (gpointer key, gpointer value, gpointer user_data)
601 const gchar* lang = (const gchar*) key;
602 GPtrArray* sources_array = (GPtrArray*) value;
603 SourcesForeachData* data = (SourcesForeachData*) user_data;
605 if (symbol_db_engine_add_new_files (data->sdbe, data->root_dir,
606 sources_array, lang, TRUE) == FALSE)
608 DEBUG_PRINT ("__FUNCTION__ failed for lang %s, root_dir %s",
609 lang, data->root_dir);
613 /* add a new project */
614 static void
615 project_root_added (AnjutaPlugin *plugin, const gchar *name,
616 const GValue *value, gpointer user_data)
618 AnjutaStatus *status;
619 IAnjutaProjectManager *pm;
620 SymbolDBPlugin *sdb_plugin;
621 const gchar *root_uri;
623 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
625 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
626 IAnjutaProjectManager, NULL);
628 g_free (sdb_plugin->project_root_uri);
629 sdb_plugin->project_root_uri = NULL;
630 root_uri = g_value_get_string (value);
631 if (root_uri)
633 gchar *root_dir = gnome_vfs_get_local_path_from_uri (root_uri);
634 DEBUG_PRINT ("Symbol-DB: added project %s", root_dir);
635 if (root_dir)
637 gboolean needs_sources_scan = FALSE;
638 gint i;
639 GHashTable* lang_hash =
640 g_hash_table_new_full (g_str_hash, g_str_equal, NULL, sources_array_free);
642 status = anjuta_shell_get_status (plugin->shell, NULL);
643 anjuta_status_progress_add_ticks (status, 1);
645 DEBUG_PRINT ("Symbol-DB: creating new project.");
647 /* is it a fresh-new project? is it an imported project with
648 * no 'new' symbol-db database but the 'old' one symbol-browser?
650 if (symbol_db_engine_db_exists (sdb_plugin->sdbe, root_dir) == FALSE)
652 needs_sources_scan = TRUE;
655 if (symbol_db_engine_open_db (sdb_plugin->sdbe, root_dir) == FALSE)
656 g_error ("error in opening db");
658 symbol_db_engine_add_new_project (sdb_plugin->sdbe,
659 NULL, /* still no workspace */
660 root_dir);
662 /* open the project. we can do this only if the db was loaded */
663 if (symbol_db_engine_open_project (sdb_plugin->sdbe, root_dir) == FALSE)
664 g_warning ("error in opening project");
666 if (needs_sources_scan == TRUE)
668 GList* prj_elements_list;
670 DEBUG_PRINT ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
671 DEBUG_PRINT ("Retrieving gbf sources of the project...");
673 prj_elements_list = ianjuta_project_manager_get_elements (pm,
674 IANJUTA_PROJECT_MANAGER_SOURCE,
675 NULL);
677 GPtrArray* sources_array;
679 for (i=0; i < g_list_length (prj_elements_list); i++)
681 gchar *local_filename;
682 const gchar *file_mime;
683 const gchar *lang;
684 IAnjutaLanguageId lang_id;
685 IAnjutaLanguage* lang_manager =
686 anjuta_shell_get_interface (plugin->shell, IAnjutaLanguage, NULL);
688 if (!lang_manager)
690 g_critical ("LanguageManager not found");
691 return;
694 local_filename =
695 gnome_vfs_get_local_path_from_uri (g_list_nth_data (
696 prj_elements_list, i));
697 file_mime = gnome_vfs_get_mime_type_for_name (local_filename);
699 lang_id = ianjuta_language_get_from_mime_type (lang_manager, file_mime, NULL);
701 if (!lang_id)
703 g_free (local_filename);
704 continue;
707 lang = ianjuta_language_get_name (lang_manager, lang_id, NULL);
708 DEBUG_PRINT ("Language of %s is %s", local_filename, file_mime);
709 /* test its existence */
710 if (g_file_test (local_filename, G_FILE_TEST_EXISTS) == FALSE)
712 g_free (local_filename);
713 continue;
716 sources_array = g_hash_table_lookup (lang_hash, lang);
717 if (!sources_array)
719 sources_array = g_ptr_array_new ();
720 g_hash_table_insert (lang_hash, (gpointer) lang, sources_array);
723 g_ptr_array_add (sources_array, local_filename);
726 DEBUG_PRINT ("calling symbol_db_engine_add_new_files with root_dir %s",
727 root_dir);
729 SourcesForeachData* data = g_new0 (SourcesForeachData, 1);
730 data->sdbe = sdb_plugin->sdbe;
731 data->root_dir = root_dir;
733 g_hash_table_foreach (lang_hash, (GHFunc) sources_array_add_foreach,
734 data);
736 g_free (data);
737 g_hash_table_unref (lang_hash);
740 anjuta_status_progress_tick (status, NULL, _("Created symbols..."));
742 symbol_db_view_open (SYMBOL_DB_VIEW (sdb_plugin->dbv_view_tree),
743 sdb_plugin->sdbe);
745 /* root dir */
746 sdb_plugin->project_root_dir = root_dir;
748 /* this is uri */
749 sdb_plugin->project_root_uri = g_strdup (root_uri);
752 g_signal_connect (G_OBJECT (pm), "element_added",
753 G_CALLBACK (on_project_element_added), sdb_plugin);
754 g_signal_connect (G_OBJECT (pm), "element_removed",
755 G_CALLBACK (on_project_element_removed), sdb_plugin);
758 static void
759 project_root_removed (AnjutaPlugin *plugin, const gchar *name,
760 gpointer user_data)
762 IAnjutaProjectManager *pm;
763 SymbolDBPlugin *sdb_plugin;
765 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
767 /* Disconnect events from project manager */
769 /* FIXME: There should be a way to ensure that this project manager
770 * is indeed the one that has opened the project_uri
772 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
773 IAnjutaProjectManager, NULL);
774 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
775 on_project_element_added,
776 sdb_plugin);
777 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
778 on_project_element_removed,
779 sdb_plugin);
781 /* don't forget to close the project */
782 symbol_db_engine_close_project (sdb_plugin->sdbe,
783 sdb_plugin->project_root_dir);
785 g_free (sdb_plugin->project_root_uri);
786 g_free (sdb_plugin->project_root_dir);
787 sdb_plugin->project_root_uri = NULL;
788 sdb_plugin->project_root_dir = NULL;
791 static void
792 on_session_load (AnjutaShell *shell, AnjutaSessionPhase phase,
793 AnjutaSession *session, SymbolDBPlugin *plugin)
795 GList *files;
796 gint i;
797 DEBUG_PRINT ("on_session_load ()");
799 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
800 return;
802 files = anjuta_session_get_string_list (session, "File Loader", "Files");
804 for (i=0; i < g_list_length (files); i++)
806 gchar * node = g_list_nth_data (files, i);
807 DEBUG_PRINT ("file %s", node);
812 g_list_foreach (files, (GFunc)g_free, NULL);
813 g_list_free (files);
817 static gboolean
818 symbol_db_activate (AnjutaPlugin *plugin)
820 SymbolDBPlugin *symbol_db;
822 DEBUG_PRINT ("SymbolDBPlugin: Activating SymbolDBPlugin plugin ...");
824 register_stock_icons (plugin);
826 symbol_db = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
827 symbol_db->ui = anjuta_shell_get_ui (plugin->shell, NULL);
829 /* connect for session load event
830 g_signal_connect (plugin->shell, "load-session",
831 G_CALLBACK (on_session_load),
832 plugin);
836 /* create SymbolDBEngine */
837 symbol_db->sdbe = symbol_db_engine_new ();
839 /* Create widgets */
840 symbol_db->dbv_notebook = gtk_notebook_new();
842 /* Local symbols */
843 symbol_db->scrolled_locals = gtk_scrolled_window_new (NULL, NULL);
844 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (symbol_db->scrolled_locals),
845 GTK_SHADOW_IN);
846 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (symbol_db->scrolled_locals),
847 GTK_POLICY_AUTOMATIC,
848 GTK_POLICY_AUTOMATIC);
850 symbol_db->dbv_view_locals_tab_label = gtk_label_new (_("Local" ));
851 symbol_db->dbv_view_tree_locals = symbol_db_view_locals_new ();
853 g_object_add_weak_pointer (G_OBJECT (symbol_db->dbv_view_tree_locals),
854 (gpointer)&symbol_db->dbv_view_tree_locals);
855 g_signal_connect (G_OBJECT (symbol_db->dbv_view_tree_locals), "row_activated",
856 G_CALLBACK (on_local_treeview_row_activated), plugin);
858 gtk_container_add (GTK_CONTAINER(symbol_db->scrolled_locals),
859 symbol_db->dbv_view_tree_locals);
862 /* Global symbols */
863 symbol_db->scrolled_global = gtk_scrolled_window_new (NULL, NULL);
864 gtk_scrolled_window_set_shadow_type (
865 GTK_SCROLLED_WINDOW (symbol_db->scrolled_global),
866 GTK_SHADOW_IN);
867 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (symbol_db->scrolled_global),
868 GTK_POLICY_AUTOMATIC,
869 GTK_POLICY_AUTOMATIC);
871 symbol_db->dbv_view_tab_label = gtk_label_new (_("Global" ));
872 symbol_db->dbv_view_tree = symbol_db_view_new ();
873 g_object_add_weak_pointer (G_OBJECT (symbol_db->dbv_view_tree),
874 (gpointer)&symbol_db->dbv_view_tree);
875 #if 0
876 g_signal_connect (G_OBJECT (symbol_db->dbv_view_tree), "event-after",
877 G_CALLBACK (on_treeview_event), plugin);
879 g_signal_connect (G_OBJECT (symbol_db->dbv_view_tree), "row_activated",
880 G_CALLBACK (on_treeview_row_activated), plugin);
881 #endif
882 gtk_container_add (GTK_CONTAINER(symbol_db->scrolled_global),
883 symbol_db->dbv_view_tree);
885 /* Search symbols */
886 symbol_db->dbv_view_tree_search =
887 (GtkWidget*) symbol_db_view_search_new (symbol_db->sdbe);
888 symbol_db->dbv_view_search_tab_label = gtk_label_new (_("Search" ));
890 g_signal_connect (G_OBJECT (symbol_db->dbv_view_tree_search), "symbol_selected",
891 G_CALLBACK (on_treesearch_symbol_selected_event),
892 plugin);
894 g_object_add_weak_pointer (G_OBJECT (symbol_db->dbv_view_tree_search),
895 (gpointer)&symbol_db->dbv_view_tree_search);
897 /* add the scrolled windows to the notebook */
898 gtk_notebook_append_page (GTK_NOTEBOOK (symbol_db->dbv_notebook),
899 symbol_db->scrolled_locals,
900 symbol_db->dbv_view_locals_tab_label);
902 gtk_notebook_append_page (GTK_NOTEBOOK (symbol_db->dbv_notebook),
903 symbol_db->scrolled_global,
904 symbol_db->dbv_view_tab_label);
906 gtk_notebook_append_page (GTK_NOTEBOOK (symbol_db->dbv_notebook),
907 symbol_db->dbv_view_tree_search,
908 symbol_db->dbv_view_search_tab_label);
910 gtk_widget_show_all (symbol_db->dbv_notebook);
912 /* setting focus to the tree_view*/
913 gtk_notebook_set_current_page (GTK_NOTEBOOK (symbol_db->dbv_notebook), 0);
915 symbol_db->editor_watch_id =
916 anjuta_plugin_add_watch (plugin, "document_manager_current_editor",
917 value_added_current_editor,
918 value_removed_current_editor, NULL);
919 #if 0
920 /* Add UI */
921 symbol_db->merge_id =
922 anjuta_ui_merge (symbol_db->ui, UI_FILE);
923 #endif
924 /* Added widgets */
925 anjuta_shell_add_widget (plugin->shell, symbol_db->dbv_notebook,
926 "SymbolDBView", _("Symbols"),
927 "symbol-db-plugin-icon",
928 ANJUTA_SHELL_PLACEMENT_LEFT, NULL);
930 /* set up project directory watch */
931 symbol_db->root_watch_id = anjuta_plugin_add_watch (plugin,
932 "project_root_uri",
933 project_root_added,
934 project_root_removed, NULL);
937 return TRUE;
940 static gboolean
941 symbol_db_deactivate (AnjutaPlugin *plugin)
943 SymbolDBPlugin *sdb_plugin;
945 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
947 DEBUG_PRINT ("SymbolDBPlugin: Dectivating SymbolDBPlugin plugin ...");
949 DEBUG_PRINT ("SymbolDBPlugin: destroying engine ...");
950 g_object_unref (sdb_plugin->sdbe);
951 sdb_plugin->sdbe = NULL;
953 /* disconnect some signals */
954 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->dbv_view_tree_locals),
955 on_local_treeview_row_activated,
956 plugin);
958 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->dbv_view_tree_search),
959 on_treesearch_symbol_selected_event,
960 plugin);
963 DEBUG_PRINT ("SymbolDBPlugin: destroying locals view ...");
964 g_object_unref (sdb_plugin->dbv_view_tree_locals);
966 DEBUG_PRINT ("SymbolDBPlugin: destroying globals view ...");
967 g_object_unref (sdb_plugin->dbv_view_tree);
969 DEBUG_PRINT ("SymbolDBPlugin: destroying search ...");
970 g_object_unref (sdb_plugin->dbv_view_tree_search);
973 /* Ensure all editor cached info are released */
974 if (sdb_plugin->editor_connected)
976 g_hash_table_foreach (sdb_plugin->editor_connected,
977 on_editor_foreach_disconnect, plugin);
978 g_hash_table_foreach (sdb_plugin->editor_connected,
979 on_editor_foreach_clear, plugin);
980 g_hash_table_destroy (sdb_plugin->editor_connected);
981 sdb_plugin->editor_connected = NULL;
984 /* Remove watches */
985 anjuta_plugin_remove_watch (plugin, sdb_plugin->root_watch_id, FALSE);
986 anjuta_plugin_remove_watch (plugin, sdb_plugin->editor_watch_id, TRUE);
988 /* Remove widgets: Widgets will be destroyed when dbv_notebook is removed */
989 anjuta_shell_remove_widget (plugin->shell, sdb_plugin->dbv_notebook, NULL);
991 #if 0
992 /* Remove UI */
993 anjuta_ui_unmerge (sdb_plugin->ui, sdb_plugin->merge_id);
995 /* Remove action group */
996 anjuta_ui_remove_action_group (sv_plugin->ui, sv_plugin->action_group);
997 anjuta_ui_remove_action_group (sv_plugin->ui, sv_plugin->popup_action_group);
998 anjuta_ui_remove_action_group (sdb_plugin->ui, sdb_plugin->action_group_nav);
999 ui = anjuta_shell_get_ui (plugin->shell, NULL);
1000 /* anjuta_ui_remove_action_group (ui, ((SymbolDBPlugin*)plugin)->action_group); */
1001 anjuta_ui_unmerge (ui, ((SymbolDBPlugin*)plugin)->uiid);
1002 #endif
1004 sdb_plugin->root_watch_id = 0;
1005 sdb_plugin->editor_watch_id = 0;
1006 sdb_plugin->dbv_notebook = NULL;
1007 sdb_plugin->scrolled_global = NULL;
1008 sdb_plugin->scrolled_locals = NULL;
1009 sdb_plugin->dbv_view_tree = NULL;
1010 sdb_plugin->dbv_view_tab_label = NULL;
1011 sdb_plugin->dbv_view_tree_locals = NULL;
1012 sdb_plugin->dbv_view_locals_tab_label = NULL;
1013 sdb_plugin->dbv_view_tree_search = NULL;
1014 sdb_plugin->dbv_view_search_tab_label = NULL;
1015 return TRUE;
1018 static void
1019 symbol_db_finalize (GObject *obj)
1021 /* Finalization codes here */
1022 GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (obj));
1025 static void
1026 symbol_db_dispose (GObject *obj)
1028 /* Disposition codes */
1029 GNOME_CALL_PARENT (G_OBJECT_CLASS, dispose, (obj));
1032 static void
1033 symbol_db_instance_init (GObject *obj)
1035 SymbolDBPlugin *plugin = (SymbolDBPlugin*)obj;
1037 plugin->uiid = 0;
1038 plugin->widget = NULL;
1041 static void
1042 symbol_db_class_init (GObjectClass *klass)
1044 AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
1046 parent_class = g_type_class_peek_parent (klass);
1048 plugin_class->activate = symbol_db_activate;
1049 plugin_class->deactivate = symbol_db_deactivate;
1050 klass->finalize = symbol_db_finalize;
1051 klass->dispose = symbol_db_dispose;
1054 static IAnjutaIterable*
1055 isymbol_manager_search (IAnjutaSymbolManager *sm,
1056 IAnjutaSymbolType match_types,
1057 const gchar *match_name,
1058 gboolean partial_name_match,
1059 gboolean global_search,
1060 GError **err)
1062 SymbolDBEngineIterator *iterator = NULL;
1063 SymbolDBPlugin *sdb_plugin;
1064 SymbolDBEngine *dbe;
1065 const gchar* name;
1067 DEBUG_PRINT ("called isymbol_manager_search()! %s", match_name);
1069 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (sm);
1070 dbe = SYMBOL_DB_ENGINE (sdb_plugin->sdbe);
1073 if (match_name && strlen (match_name) > 0)
1074 name = match_name;
1075 else
1076 name = NULL;
1079 iterator =
1080 symbol_db_engine_find_symbol_by_name_pattern (dbe,
1081 name, SYMINFO_SIMPLE |
1082 SYMINFO_FILE_PATH |
1083 SYMINFO_IMPLEMENTATION |
1084 SYMINFO_ACCESS |
1085 SYMINFO_KIND |
1086 SYMINFO_TYPE |
1087 SYMINFO_TYPE_NAME |
1088 SYMINFO_LANGUAGE |
1089 SYMINFO_FILE_IGNORE |
1090 SYMINFO_FILE_INCLUDE |
1091 SYMINFO_PROJECT_NAME |
1092 SYMINFO_WORKSPACE_NAME );
1094 return IANJUTA_ITERABLE (iterator);
1097 static IAnjutaIterable*
1098 isymbol_manager_get_members (IAnjutaSymbolManager *sm,
1099 const gchar *symbol_name,
1100 gboolean global_search,
1101 GError **err)
1103 #if 0
1104 const GPtrArray *tags_array;
1105 AnjutaSymbolIter *iter = NULL;
1107 tags_array = tm_workspace_find_scope_members (NULL, symbol_name,
1108 global_search, TRUE);
1111 if (tags_array)
1113 iter = anjuta_symbol_iter_new (tags_array);
1114 return IANJUTA_ITERABLE (iter);
1116 #endif
1117 return NULL;
1120 static IAnjutaIterable*
1121 isymbol_manager_get_parents (IAnjutaSymbolManager *sm,
1122 const gchar *symbol_name,
1123 GError **err)
1125 #if 0
1126 const GPtrArray *tags_array;
1127 AnjutaSymbolIter *iter = NULL;
1129 tags_array = tm_workspace_get_parents (symbol_name);
1130 if (tags_array)
1132 iter = anjuta_symbol_iter_new (tags_array);
1133 return IANJUTA_ITERABLE (iter);
1135 #endif
1136 return NULL;
1139 static IAnjutaIterable*
1140 isymbol_manager_get_completions_at_position (IAnjutaSymbolManager *sm,
1141 const gchar *file_uri,
1142 const gchar *text_buffer,
1143 gint text_length,
1144 gint text_pos,
1145 GError **err)
1147 #if 0
1148 SymbolBrowserPlugin *sv_plugin;
1149 const TMTag *func_scope_tag;
1150 TMSourceFile *tm_file;
1151 IAnjutaEditor *ed;
1152 AnjutaSymbolView *symbol_view;
1153 gulong line;
1154 gulong scope_position;
1155 gchar *needed_text = NULL;
1156 gint access_method;
1157 GPtrArray * completable_tags_array;
1158 AnjutaSymbolIter *iter = NULL;
1160 sv_plugin = ANJUTA_PLUGIN_SYMBOL_BROWSER (sm);
1161 ed = IANJUTA_EDITOR (sv_plugin->current_editor);
1162 symbol_view = ANJUTA_SYMBOL_VIEW (sv_plugin->sv_tree);
1164 line = ianjuta_editor_get_line_from_position (ed, text_pos, NULL);
1166 /* get the function scope */
1167 tm_file = anjuta_symbol_view_get_tm_file (symbol_view, file_uri);
1169 /* check whether the current file_uri is listed in the tm_workspace or not... */
1170 if (tm_file == NULL)
1171 return NULL;
1174 // FIXME: remove DEBUG_PRINT
1176 DEBUG_PRINT ("tags in file &s\n");
1177 if (tm_file->work_object.tags_array != NULL) {
1178 int i;
1179 for (i=0; i < tm_file->work_object.tags_array->len; i++) {
1180 TMTag *cur_tag;
1182 cur_tag = (TMTag*)g_ptr_array_index (tm_file->work_object.tags_array, i);
1183 tm_tag_print (cur_tag, stdout);
1188 func_scope_tag = tm_get_current_function (tm_file->work_object.tags_array, line);
1190 if (func_scope_tag == NULL) {
1191 DEBUG_PRINT ("func_scope_tag is NULL, seems like it's a completion on a global scope");
1192 return NULL;
1195 DEBUG_PRINT ("current expression scope: %s", func_scope_tag->name);
1198 scope_position = ianjuta_editor_get_line_begin_position (ed, func_scope_tag->atts.entry.line, NULL);
1199 needed_text = ianjuta_editor_get_text (ed, scope_position,
1200 text_pos - scope_position, NULL);
1202 if (needed_text == NULL)
1203 DEBUG_PRINT ("needed_text is null");
1204 DEBUG_PRINT ("text needed is %s", needed_text );
1207 /* we'll pass only the text of the current scope: i.e. only the current function
1208 * in which we request the completion. */
1209 TMTag * found_type = anjuta_symbol_view_get_type_of_expression (symbol_view,
1210 needed_text, text_pos - scope_position, func_scope_tag, &access_method);
1213 if (found_type == NULL) {
1214 DEBUG_PRINT ("type not found.");
1215 return NULL;
1218 /* get the completable memebers. If the access is COMPLETION_ACCESS_STATIC we don't
1219 * want to know the parents members of the class.
1221 if (access_method == COMPLETION_ACCESS_STATIC)
1222 completable_tags_array = anjuta_symbol_view_get_completable_members (found_type, FALSE);
1223 else
1224 completable_tags_array = anjuta_symbol_view_get_completable_members (found_type, TRUE);
1226 if (completable_tags_array)
1228 iter = anjuta_symbol_iter_new (completable_tags_array);
1229 return IANJUTA_ITERABLE (iter);
1231 #endif
1232 return NULL;
1236 static void
1237 isymbol_manager_iface_init (IAnjutaSymbolManagerIface *iface)
1239 iface->search = isymbol_manager_search;
1240 iface->get_members = isymbol_manager_get_members;
1241 iface->get_parents = isymbol_manager_get_parents;
1242 iface->get_completions_at_position = isymbol_manager_get_completions_at_position;
1245 ANJUTA_PLUGIN_BEGIN (SymbolDBPlugin, symbol_db);
1246 ANJUTA_PLUGIN_ADD_INTERFACE (isymbol_manager, IANJUTA_TYPE_SYMBOL_MANAGER);
1247 ANJUTA_PLUGIN_END;
1249 ANJUTA_SIMPLE_PLUGIN (SymbolDBPlugin, symbol_db);