Automatic callback prototyping when glade signal is dropped in a C source file.
[anjuta.git] / plugins / symbol-db / plugin.c
blob7e13a05b708f05a381894862ecf29b30c2280d95
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * plugin.c
4 * Copyright (C) Massimo Cora' 2007-2008 <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 <gio/gio.h>
27 #include <libanjuta/anjuta-shell.h>
28 #include <libanjuta/anjuta-debug.h>
29 #include <libanjuta/anjuta-utils.h>
30 #include <libanjuta/anjuta-tabber.h>
31 #include <libanjuta/anjuta-project.h>
32 #include <libanjuta/interfaces/ianjuta-document-manager.h>
33 #include <libanjuta/interfaces/ianjuta-symbol-manager.h>
34 #include <libanjuta/interfaces/ianjuta-symbol.h>
35 #include <libanjuta/interfaces/ianjuta-project-manager.h>
36 #include <libanjuta/interfaces/ianjuta-project.h>
37 #include <libanjuta/interfaces/ianjuta-file-manager.h>
38 #include <libanjuta/interfaces/ianjuta-file.h>
39 #include <libanjuta/interfaces/ianjuta-file-loader.h>
40 #include <libanjuta/interfaces/ianjuta-editor.h>
41 #include <libanjuta/interfaces/ianjuta-markable.h>
42 #include <libanjuta/interfaces/ianjuta-language.h>
43 #include <libanjuta/interfaces/ianjuta-iterable.h>
44 #include <libanjuta/interfaces/ianjuta-preferences.h>
46 #include "plugin.h"
47 #include "symbol-db-engine.h"
48 #include "symbol-db-views.h"
50 #define ICON_FILE "anjuta-symbol-db-plugin-48.png"
51 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta-symbol-db-plugin.xml"
53 #define BUILDER_FILE PACKAGE_DATA_DIR"/glade/anjuta-symbol-db.ui"
54 #define BUILDER_ROOT "symbol_prefs"
55 #define ICON_FILE "anjuta-symbol-db-plugin-48.png"
56 #define BUFFER_UPDATE "symboldb-buffer-update"
57 #define PARALLEL_SCAN "symboldb-parallel-scan"
58 #define PREFS_BUFFER_UPDATE "preferences_toggle:bool:1:1:symboldb-buffer-update"
59 #define PREFS_PARALLEL_SCAN "preferences_toggle:bool:1:1:symboldb-parallel-scan"
61 #define TIMEOUT_INTERVAL_SYMBOLS_UPDATE 10
62 #define TIMEOUT_SECONDS_AFTER_LAST_TIP 5
64 #define PROJECT_GLOBALS "/"
65 #define SESSION_SECTION "SymbolDB"
66 #define SESSION_KEY "SystemPackages"
68 #define ANJUTA_PIXMAP_GOTO_DECLARATION "element-interface"
69 #define ANJUTA_PIXMAP_GOTO_IMPLEMENTATION "element-method"
71 #define ANJUTA_STOCK_GOTO_DECLARATION "element-interface"
72 #define ANJUTA_STOCK_GOTO_IMPLEMENTATION "element-method"
74 #define PREF_SCHEMA "org.gnome.anjuta.symbol-db"
76 static gpointer parent_class;
78 /* signals */
79 enum
81 PROJECT_IMPORT_END,
82 GLOBALS_IMPORT_END,
83 LAST_SIGNAL
86 typedef enum
88 TASK_IMPORT_PROJECT = 1,
89 TASK_IMPORT_PROJECT_AFTER_ABORT,
90 TASK_BUFFER_UPDATE,
91 TASK_ELEMENT_ADDED,
92 TASK_OFFLINE_CHANGES,
93 TASK_PROJECT_UPDATE,
94 TASK_FILE_UPDATE
95 } ProcTask;
97 static unsigned int signals[LAST_SIGNAL] = { 0 };
99 static void
100 register_stock_icons (AnjutaPlugin *plugin)
102 static gboolean registered = FALSE;
104 if (registered)
105 return;
106 registered = TRUE;
108 /* Register stock icons */
109 BEGIN_REGISTER_ICON (plugin);
110 REGISTER_ICON (ICON_FILE, "symbol-db-plugin-icon");
111 REGISTER_ICON_FULL (ANJUTA_PIXMAP_GOTO_DECLARATION, ANJUTA_STOCK_GOTO_DECLARATION);
112 REGISTER_ICON_FULL (ANJUTA_PIXMAP_GOTO_IMPLEMENTATION, ANJUTA_STOCK_GOTO_IMPLEMENTATION);
113 END_REGISTER_ICON;
116 static void
117 goto_file_line (AnjutaPlugin *plugin, const gchar *filename, gint lineno)
119 IAnjutaDocumentManager *docman;
120 GFile* file;
122 g_return_if_fail (filename != NULL);
124 DEBUG_PRINT ("going to: file %s, line %d", filename, lineno);
126 /* Go to file and line number */
127 docman = anjuta_shell_get_interface (plugin->shell, IAnjutaDocumentManager,
128 NULL);
129 file = g_file_new_for_path (filename);
130 ianjuta_document_manager_goto_file_line (docman, file, lineno, NULL);
132 g_object_unref (file);
135 /* Find an implementation (if impl == TRUE) or declaration (if impl == FALSE)
136 * from the given symbol iterator.
137 * If current_document != NULL it prefers matches from the currently open document
139 static gchar *
140 find_file_line (IAnjutaIterable *iterator, gboolean impl, const gchar *current_document,
141 gint *line)
143 gchar *path = NULL;
144 gint _line = -1;
148 const gchar *symbol_kind;
149 gboolean is_decl;
150 IAnjutaSymbol *iter_node = IANJUTA_SYMBOL (iterator);
152 if (iter_node == NULL)
154 /* not found or some error occurred */
155 break;
158 symbol_kind = ianjuta_symbol_get_string (iter_node, IANJUTA_SYMBOL_FIELD_KIND, NULL);
159 is_decl = g_strcmp0 (symbol_kind, "prototype") == 0 ||
160 g_strcmp0 (symbol_kind, "interface") == 0;
162 if (is_decl == !impl)
164 GFile *file;
165 gchar *_path;
166 file = ianjuta_symbol_get_file (iter_node, NULL);
167 /* if the path matches the current document we return immidiately */
168 _path = g_file_get_path (file);
169 g_object_unref (file);
170 if (!current_document || g_strcmp0 (_path, current_document) == 0)
172 *line = ianjuta_symbol_get_int (iter_node,
173 IANJUTA_SYMBOL_FIELD_FILE_POS,
174 NULL);
175 g_free (path);
177 return _path;
179 /* we store the first match incase there is no match against the current document */
180 else if (_line == -1)
182 path = _path;
183 _line = ianjuta_symbol_get_int (iter_node,
184 IANJUTA_SYMBOL_FIELD_FILE_POS,
185 NULL);
187 else
189 g_free (_path);
192 } while (ianjuta_iterable_next (iterator, NULL) == TRUE);
194 if (_line != -1)
195 *line = _line;
197 return path;
200 static void
201 goto_file_tag (SymbolDBPlugin *sdb_plugin, const gchar *word,
202 gboolean prefer_implementation)
204 IAnjutaIterable *iterator;
205 gchar *path = NULL;
206 gint line;
207 gint i;
208 gboolean found = FALSE;
209 SymbolDBEngine *engine;
211 for (i = 0; i < 2; i++)
213 if (i == 0)
215 engine = sdb_plugin->sdbe_project;
217 else
219 engine = sdb_plugin->sdbe_globals;
222 iterator = NULL;
223 if (symbol_db_engine_is_connected (engine))
225 iterator = ianjuta_symbol_query_search (sdb_plugin->search_query,
226 word, NULL);
229 if (iterator != NULL && ianjuta_iterable_get_length (iterator, NULL) > 0)
231 gchar *current_document = NULL;
232 /* FIXME: namespaces are not handled here, but they should. */
234 if (IANJUTA_IS_FILE (sdb_plugin->current_editor))
236 GFile *file;
238 if ((file = ianjuta_file_get_file (IANJUTA_FILE (sdb_plugin->current_editor),
239 NULL)))
241 current_document = g_file_get_path (file);
242 g_object_unref (file);
246 path = find_file_line (iterator, prefer_implementation, current_document, &line);
247 if (!path)
249 /* reset iterator */
250 ianjuta_iterable_first (iterator, NULL);
251 path = find_file_line (iterator, !prefer_implementation, current_document,
252 &line);
255 if (path)
257 goto_file_line (ANJUTA_PLUGIN (sdb_plugin), path, line);
258 g_free (path);
259 found = TRUE;
262 g_free (current_document);
265 if (iterator)
266 g_object_unref (iterator);
268 /* have we found it in the project db? */
269 if (found)
270 break;
274 static void
275 on_goto_file_tag_impl_activate (GtkAction *action, SymbolDBPlugin *sdb_plugin)
277 IAnjutaEditor *ed;
278 gchar *word;
280 if (sdb_plugin->current_editor)
282 ed = IANJUTA_EDITOR (sdb_plugin->current_editor);
283 word = ianjuta_editor_get_current_word (ed, NULL);
284 if (word)
286 goto_file_tag (sdb_plugin, word, TRUE);
287 g_free (word);
292 static void
293 on_goto_file_tag_decl_activate (GtkAction *action, SymbolDBPlugin *sdb_plugin)
295 IAnjutaEditor *ed;
296 gchar *word;
298 if (sdb_plugin->current_editor)
300 ed = IANJUTA_EDITOR (sdb_plugin->current_editor);
301 word = ianjuta_editor_get_current_word (ed, NULL);
302 if (word)
304 goto_file_tag (sdb_plugin, word, FALSE);
305 g_free (word);
310 static void
311 on_find_symbol (GtkAction *action, SymbolDBPlugin *sdb_plugin)
313 anjuta_shell_present_widget(ANJUTA_PLUGIN(sdb_plugin)->shell,
314 sdb_plugin->dbv_main, NULL);
316 gtk_notebook_set_current_page (GTK_NOTEBOOK(sdb_plugin->dbv_notebook), 2);
317 gtk_widget_grab_focus (GTK_WIDGET (sdb_plugin->search_entry));
320 static GtkActionEntry actions[] =
322 { "ActionMenuGoto", NULL, N_("_Go to"), NULL, NULL, NULL},
324 "ActionSymbolDBGotoDecl",
325 ANJUTA_STOCK_GOTO_DECLARATION,
326 N_("Tag De_claration"),
327 "<shift><control>d",
328 N_("Go to symbol declaration"),
329 G_CALLBACK (on_goto_file_tag_decl_activate)
332 "ActionSymbolDBGotoImpl",
333 ANJUTA_STOCK_GOTO_IMPLEMENTATION,
334 /* Translators: Go to the line where the tag is implemented */
335 N_("Tag _Implementation"),
336 "<control>d",
337 N_("Go to symbol definition"),
338 G_CALLBACK (on_goto_file_tag_impl_activate)
342 static GtkActionEntry actions_search[] = {
344 "ActionEditSearchFindSymbol", GTK_STOCK_FIND, N_("_Find Symbol…"),
345 "<control>l", N_("Find Symbol"),
346 G_CALLBACK (on_find_symbol)
350 static gboolean
351 editor_buffer_symbols_update (IAnjutaEditor *editor, SymbolDBPlugin *sdb_plugin)
353 gchar *current_buffer = NULL;
354 gsize buffer_size = 0;
355 GFile* file;
356 gchar * local_path;
357 GPtrArray *real_files_list;
358 GPtrArray *text_buffers;
359 GPtrArray *buffer_sizes;
360 gint i;
361 gint proc_id ;
363 /* we won't proceed with the updating of the symbols if we didn't type in
364 anything */
365 if (sdb_plugin->need_symbols_update == FALSE)
366 return TRUE;
368 if (editor)
370 buffer_size = ianjuta_editor_get_length (editor, NULL);
371 current_buffer = ianjuta_editor_get_text_all (editor, NULL);
373 file = ianjuta_file_get_file (IANJUTA_FILE (editor), NULL);
375 else
376 return FALSE;
378 if (file == NULL)
379 return FALSE;
381 /* take the path reference */
382 local_path = g_file_get_path (file);
384 /* ok that's good. Let's have a last check: is the current file present
385 * on the buffer_update_files?
387 for (i = 0; i < sdb_plugin->buffer_update_files->len; i++)
389 if (g_strcmp0 (g_ptr_array_index (sdb_plugin->buffer_update_files, i),
390 local_path) == 0)
392 /* hey we found it */
393 /* something is already scanning this buffer file. Drop the procedure now. */
394 DEBUG_PRINT ("something is already scanning the file %s", local_path);
395 return FALSE;
399 real_files_list = g_ptr_array_new_with_free_func (g_free);
400 g_ptr_array_add (real_files_list, local_path);
402 text_buffers = g_ptr_array_new ();
403 g_ptr_array_add (text_buffers, current_buffer);
405 buffer_sizes = g_ptr_array_new ();
406 g_ptr_array_add (buffer_sizes, GINT_TO_POINTER (buffer_size));
409 proc_id = 0;
410 if (symbol_db_engine_is_connected (sdb_plugin->sdbe_project))
412 proc_id = symbol_db_engine_update_buffer_symbols (sdb_plugin->sdbe_project,
413 sdb_plugin->project_opened,
414 real_files_list,
415 text_buffers,
416 buffer_sizes);
419 if (proc_id > 0)
421 /* good. All is ready for a buffer scan. Add the file_scan into the arrays */
422 gchar * local_path_dup = g_strdup (local_path);
423 g_ptr_array_add (sdb_plugin->buffer_update_files, local_path_dup);
424 /* add the id too */
425 g_ptr_array_add (sdb_plugin->buffer_update_ids, GINT_TO_POINTER (proc_id));
427 /* add a task so that scan_end_manager can manage this */
428 g_tree_insert (sdb_plugin->proc_id_tree, GINT_TO_POINTER (proc_id),
429 GINT_TO_POINTER (TASK_BUFFER_UPDATE));
432 g_ptr_array_unref (real_files_list);
433 g_free (current_buffer);
434 g_object_unref (file);
436 /* no need to free local_path, it'll be automatically freed later by the buffer_update
437 * function */
439 sdb_plugin->need_symbols_update = FALSE;
441 return proc_id > 0 ? TRUE : FALSE;
443 static gboolean
444 on_editor_buffer_symbols_update_timeout (gpointer user_data)
446 SymbolDBPlugin *sdb_plugin;
447 gdouble seconds_elapsed;
449 g_return_val_if_fail (user_data != NULL, FALSE);
451 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (user_data);
453 if (sdb_plugin->current_editor == NULL)
454 return FALSE;
456 /* check the timer. If it's elapsed enought time since the last time the user
457 * typed in something, than proceed with updating, elsewhere don't do nothing
459 if (sdb_plugin->update_timer == NULL)
460 return TRUE;
462 seconds_elapsed = g_timer_elapsed (sdb_plugin->update_timer, NULL);
464 if (seconds_elapsed < TIMEOUT_SECONDS_AFTER_LAST_TIP)
465 return TRUE;
467 return editor_buffer_symbols_update (IANJUTA_EDITOR (sdb_plugin->current_editor),
468 sdb_plugin);
471 static void
472 on_editor_buffer_symbol_update_scan_end (SymbolDBEngine *dbe, gint process_id,
473 gpointer data)
475 SymbolDBPlugin *sdb_plugin;
476 gint i;
478 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (data);
480 /* search for the proc id */
481 for (i = 0; i < sdb_plugin->buffer_update_ids->len; i++)
483 if (g_ptr_array_index (sdb_plugin->buffer_update_ids, i) == GINT_TO_POINTER (process_id))
485 gchar *str;
486 /* hey we found it */
487 /* remove both the items */
488 g_ptr_array_remove_index (sdb_plugin->buffer_update_ids, i);
490 str = (gchar*)g_ptr_array_remove_index (sdb_plugin->buffer_update_files,
495 /* was the updating of view-locals symbols blocked while we were scanning?
496 * e.g. was the editor switched? */
497 if (sdb_plugin->buffer_update_semaphore == TRUE)
499 GFile *file;
500 gchar *local_path;
501 gboolean tags_update;
502 if (!IANJUTA_IS_EDITOR (sdb_plugin->current_editor))
503 return;
505 file = ianjuta_file_get_file (IANJUTA_FILE (sdb_plugin->current_editor),
506 NULL);
508 if (file == NULL)
509 return;
511 local_path = g_file_get_path (file);
513 if (local_path == NULL)
515 g_critical ("local_path == NULL");
516 return;
519 /* add a default timeout to the updating of buffer symbols */
520 tags_update = g_settings_get_boolean (sdb_plugin->settings, BUFFER_UPDATE);
522 if (tags_update)
524 sdb_plugin->buf_update_timeout_id =
525 g_timeout_add_seconds (TIMEOUT_INTERVAL_SYMBOLS_UPDATE,
526 on_editor_buffer_symbols_update_timeout,
527 sdb_plugin);
530 g_free (local_path);
531 sdb_plugin->buffer_update_semaphore = FALSE;
535 static void
536 on_editor_destroy (SymbolDBPlugin *sdb_plugin, IAnjutaEditor *editor)
538 const gchar *uri;
539 DEBUG_PRINT ("%s", "on_editor_destroy ()");
540 if (!sdb_plugin->editor_connected)
542 DEBUG_PRINT ("%s", "on_editor_destroy (): returning….");
543 return;
546 uri = g_hash_table_lookup (sdb_plugin->editor_connected, G_OBJECT (editor));
547 g_hash_table_remove (sdb_plugin->editor_connected, G_OBJECT (editor));
549 if (g_hash_table_size (sdb_plugin->editor_connected) <= 0)
551 DEBUG_PRINT ("%s", "displaying nothing…");
552 if (sdb_plugin->file_model)
553 g_object_set (sdb_plugin->file_model, "file-path", NULL, NULL);
557 static void
558 on_editor_update_ui (IAnjutaEditor *editor, SymbolDBPlugin *sdb_plugin)
560 g_timer_reset (sdb_plugin->update_timer);
563 static void
564 on_code_added (IAnjutaEditor *editor, IAnjutaIterable *position, gchar *code,
565 SymbolDBPlugin *sdb_plugin)
567 sdb_plugin->need_symbols_update = TRUE;
568 editor_buffer_symbols_update (editor, sdb_plugin);
571 static void
572 on_char_added (IAnjutaEditor *editor, IAnjutaIterable *position, gchar ch,
573 SymbolDBPlugin *sdb_plugin)
575 g_timer_reset (sdb_plugin->update_timer);
577 /* Update when the user enters a newline */
578 if (ch == '\n')
579 sdb_plugin->need_symbols_update = TRUE;
582 static void
583 on_editor_saved (IAnjutaEditor *editor, GFile* file,
584 SymbolDBPlugin *sdb_plugin)
586 const gchar *old_uri;
587 gchar *local_filename;
588 gchar *saved_uri;
589 GPtrArray *files_array;
590 gint proc_id;
591 gint i;
593 local_filename = g_file_get_path (file);
594 /* Verify that it's local file */
595 g_return_if_fail (local_filename != NULL);
597 saved_uri = g_file_get_uri (file);
599 for (i = 0; i < sdb_plugin->buffer_update_files->len; i++)
601 if (g_strcmp0 (g_ptr_array_index (sdb_plugin->buffer_update_files, i),
602 local_filename) == 0)
604 DEBUG_PRINT ("already scanning");
605 /* something is already scanning this buffer file. Drop the procedure now. */
606 return;
610 files_array = g_ptr_array_new();
611 g_ptr_array_add (files_array, local_filename);
612 /* no need to free local_filename now */
614 if (!sdb_plugin->editor_connected)
615 return;
617 old_uri = g_hash_table_lookup (sdb_plugin->editor_connected, editor);
619 if (old_uri && strlen (old_uri) <= 0)
620 old_uri = NULL;
622 /* files_array will be freed once updating has taken place */
623 proc_id = 0;
624 if (symbol_db_engine_is_connected (sdb_plugin->sdbe_project))
626 proc_id = symbol_db_engine_update_files_symbols (sdb_plugin->sdbe_project,
627 sdb_plugin->project_root_dir, files_array, TRUE);
630 if (proc_id > 0)
632 /* add a task so that scan_end_manager can manage this */
633 g_tree_insert (sdb_plugin->proc_id_tree, GINT_TO_POINTER (proc_id),
634 GINT_TO_POINTER (TASK_FILE_UPDATE));
637 g_hash_table_insert (sdb_plugin->editor_connected, editor,
638 g_strdup (saved_uri));
640 /* if we saved it we shouldn't update a second time */
641 sdb_plugin->need_symbols_update = FALSE;
643 on_editor_update_ui (editor, sdb_plugin);
644 g_free (saved_uri);
647 static void
648 value_added_current_editor (AnjutaPlugin *plugin, const char *name,
649 const GValue *value, gpointer data)
651 gchar *uri;
652 gboolean tags_update;
653 GFile* file;
654 gchar *local_path;
655 GObject *editor;
656 SymbolDBPlugin *sdb_plugin;
658 editor = g_value_get_object (value);
659 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
660 if (sdb_plugin->session_loading)
662 return;
664 else
665 DEBUG_PRINT ("%s", "Updating symbols");
667 if (!sdb_plugin->editor_connected)
669 sdb_plugin->editor_connected = g_hash_table_new_full (g_direct_hash,
670 g_direct_equal,
671 NULL, g_free);
673 sdb_plugin->current_editor = editor;
675 if (!IANJUTA_IS_EDITOR (editor))
676 return;
678 file = ianjuta_file_get_file (IANJUTA_FILE (editor), NULL);
680 if (file == NULL)
681 return;
683 local_path = g_file_get_path (file);
684 uri = g_file_get_uri (file);
686 if (local_path == NULL)
688 g_critical ("local_path == NULL");
689 return;
692 /* we can have a weird behaviour here if we're not paying the right attention:
693 * A timeout scan could have been launched and a millisecond later the user could
694 * have switched editor: we'll be getting the symbol inserted in the previous
695 * editor into the new one's view.
697 if (sdb_plugin->buffer_update_files->len > 0)
699 sdb_plugin->buffer_update_semaphore = TRUE;
701 else
703 g_object_set (sdb_plugin->file_model, "file-path", local_path, NULL);
705 /* add a default timeout to the updating of buffer symbols */
706 tags_update = g_settings_get_boolean (sdb_plugin->settings, BUFFER_UPDATE);
709 if (tags_update)
711 sdb_plugin->buf_update_timeout_id =
712 g_timeout_add_seconds (TIMEOUT_INTERVAL_SYMBOLS_UPDATE,
713 on_editor_buffer_symbols_update_timeout,
714 plugin);
718 if (g_hash_table_lookup (sdb_plugin->editor_connected, editor) == NULL)
720 g_object_weak_ref (G_OBJECT (editor),
721 (GWeakNotify) (on_editor_destroy),
722 sdb_plugin);
723 if (uri)
725 g_hash_table_insert (sdb_plugin->editor_connected, editor,
726 g_strdup (uri));
728 else
730 g_hash_table_insert (sdb_plugin->editor_connected, editor,
731 g_strdup (""));
734 g_signal_connect (G_OBJECT (editor), "saved",
735 G_CALLBACK (on_editor_saved),
736 sdb_plugin);
737 g_signal_connect (G_OBJECT (editor), "char-added",
738 G_CALLBACK (on_char_added),
739 sdb_plugin);
740 g_signal_connect (G_OBJECT (editor), "code-added",
741 G_CALLBACK (on_code_added),
742 sdb_plugin);
743 g_signal_connect (G_OBJECT(editor), "update_ui",
744 G_CALLBACK (on_editor_update_ui),
745 sdb_plugin);
747 g_free (uri);
748 g_free (local_path);
750 sdb_plugin->need_symbols_update = FALSE;
753 static void
754 on_editor_foreach_disconnect (gpointer key, gpointer value, gpointer user_data)
756 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
757 G_CALLBACK (on_editor_saved),
758 user_data);
759 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
760 G_CALLBACK (on_editor_update_ui),
761 user_data);
762 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
763 G_CALLBACK (on_char_added),
764 user_data);
765 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
766 G_CALLBACK (on_code_added),
767 user_data);
768 g_object_weak_unref (G_OBJECT(key),
769 (GWeakNotify) (on_editor_destroy),
770 user_data);
773 static void
774 value_removed_current_editor (AnjutaPlugin *plugin,
775 const char *name, gpointer data)
777 SymbolDBPlugin *sdb_plugin;
779 sdb_plugin = (SymbolDBPlugin *) plugin;
781 DEBUG_PRINT ("%s", "value_removed_current_editor ()");
782 /* let's remove the timeout for symbols refresh */
783 if (sdb_plugin->buf_update_timeout_id)
784 g_source_remove (sdb_plugin->buf_update_timeout_id);
785 sdb_plugin->buf_update_timeout_id = 0;
786 sdb_plugin->need_symbols_update = FALSE;
788 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
789 sdb_plugin->current_editor = NULL;
793 * Perform the real add to the db and also checks that no dups are inserted.
794 * Return the real number of files added.
796 static gint
797 do_add_new_files (SymbolDBPlugin *sdb_plugin, const GPtrArray *sources_array,
798 ProcTask task)
800 GPtrArray* languages_array = NULL;
801 GPtrArray* to_scan_array = NULL;
802 GHashTable* check_unique_file_hash = NULL;
803 IAnjutaLanguage* lang_manager;
804 AnjutaPlugin *plugin;
805 gint added_num;
806 gint i;
808 plugin = ANJUTA_PLUGIN (sdb_plugin);
810 /* create array of languages and the wannabe scanned files */
811 languages_array = g_ptr_array_new_with_free_func (g_free);
812 to_scan_array = g_ptr_array_new_with_free_func (g_free);
814 /* to speed the things up we must avoid the dups */
815 check_unique_file_hash = g_hash_table_new_full (g_str_hash,
816 g_str_equal, NULL, NULL);
818 lang_manager = anjuta_shell_get_interface (plugin->shell, IAnjutaLanguage,
819 NULL);
821 if (!lang_manager)
823 g_critical ("LanguageManager not found");
824 return -1;
827 for (i=0; i < sources_array->len; i++)
829 const gchar *file_mime;
830 const gchar *lang;
831 const gchar *local_filename;
832 GFile *gfile;
833 GFileInfo *gfile_info;
834 IAnjutaLanguageId lang_id;
836 if ( (local_filename = g_ptr_array_index (sources_array, i)) == NULL)
837 continue;
839 if ((gfile = g_file_new_for_path (local_filename)) == NULL)
840 continue;
842 gfile_info = g_file_query_info (gfile,
843 "standard::content-type",
844 G_FILE_QUERY_INFO_NONE,
845 NULL,
846 NULL);
847 if (gfile_info == NULL)
849 g_object_unref (gfile);
850 continue;
853 /* check if it's already present in the list. This avoids
854 * duplicates.
856 if (g_hash_table_lookup (check_unique_file_hash,
857 local_filename) == NULL)
859 g_hash_table_insert (check_unique_file_hash,
860 (gpointer)local_filename,
861 (gpointer)local_filename);
863 else
865 /* you're a dup! we don't want you */
866 continue;
869 file_mime = g_file_info_get_attribute_string (gfile_info,
870 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
872 lang_id = ianjuta_language_get_from_mime_type (lang_manager,
873 file_mime, NULL);
875 if (!lang_id)
877 g_object_unref (gfile);
878 g_object_unref (gfile_info);
879 continue;
882 lang = ianjuta_language_get_name (lang_manager, lang_id, NULL);
884 /* test its existence */
885 if (g_file_test (local_filename, G_FILE_TEST_EXISTS) == FALSE)
887 g_object_unref (gfile);
888 g_object_unref (gfile_info);
889 continue;
892 /* ok, we've just tested that the local_filename does exist.
893 * We can safely add it to the array.
895 g_ptr_array_add (languages_array, g_strdup (lang));
896 g_ptr_array_add (to_scan_array, g_strdup (local_filename));
897 g_object_unref (gfile);
898 g_object_unref (gfile_info);
901 /* last but not least check if we had some files in that GPtrArray. It that's not
902 * the case just pass over
904 if (to_scan_array->len > 0)
906 gint proc_id = symbol_db_engine_add_new_files_full_async (sdb_plugin->sdbe_project,
907 sdb_plugin->project_opened, "1.0", to_scan_array, languages_array,
908 TRUE);
910 /* insert the proc id associated within the task */
911 g_tree_insert (sdb_plugin->proc_id_tree, GINT_TO_POINTER (proc_id),
912 GINT_TO_POINTER (task));
915 /* get the real added number of files */
916 added_num = to_scan_array->len;
918 g_ptr_array_unref (languages_array);
919 g_ptr_array_unref (to_scan_array);
921 g_hash_table_destroy (check_unique_file_hash);
923 return added_num;
926 static void
927 on_project_element_added (IAnjutaProjectManager *pm, GFile *gfile,
928 SymbolDBPlugin *sdb_plugin)
930 gchar *filename;
931 gint real_added;
932 GPtrArray *files_array;
934 g_return_if_fail (sdb_plugin->project_root_uri != NULL);
935 g_return_if_fail (sdb_plugin->project_root_dir != NULL);
937 filename = g_file_get_path (gfile);
939 files_array = g_ptr_array_new_with_free_func (g_free);
940 g_ptr_array_add (files_array, filename);
942 sdb_plugin->is_adding_element = TRUE;
944 /* use a custom function to add the files to db */
945 real_added = do_add_new_files (sdb_plugin, files_array, TASK_ELEMENT_ADDED);
946 if (real_added <= 0)
948 sdb_plugin->is_adding_element = FALSE;
951 g_ptr_array_unref (files_array);
954 static void
955 on_project_element_removed (IAnjutaProjectManager *pm, GFile *gfile,
956 SymbolDBPlugin *sdb_plugin)
958 gchar *filename;
960 if (!sdb_plugin->project_root_uri)
961 return;
963 filename = g_file_get_path (gfile);
965 if (filename)
967 DEBUG_PRINT ("%s", "on_project_element_removed");
968 symbol_db_engine_remove_file (sdb_plugin->sdbe_project,
969 sdb_plugin->project_root_dir,
970 symbol_db_util_get_file_db_path (sdb_plugin->sdbe_project,
971 filename));
973 g_free (filename);
977 static void
978 on_system_scan_package_start (SymbolDBEngine *dbe, guint num_files,
979 const gchar *package, gpointer user_data)
981 SymbolDBPlugin *sdb_plugin;
982 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (user_data);
984 sdb_plugin->files_count_system_done = 0;
985 sdb_plugin->files_count_system += num_files;
988 /* show the global bar */
989 gtk_widget_show (sdb_plugin->progress_bar_system);
990 if (sdb_plugin->current_scanned_package != NULL)
991 g_free (sdb_plugin->current_scanned_package);
992 sdb_plugin->current_scanned_package = g_strdup (package);
994 DEBUG_PRINT ("********************* START [%s] with n %d files ", package, num_files);
997 static void
998 on_system_scan_package_end (SymbolDBEngine *dbe, const gchar *package,
999 gpointer user_data)
1001 SymbolDBPlugin *sdb_plugin;
1002 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (user_data);
1004 DEBUG_PRINT ("******************** END () [%s]", package);
1006 /* hide the progress bar */
1007 gtk_widget_hide (sdb_plugin->progress_bar_system);
1009 sdb_plugin->files_count_system_done = 0;
1010 sdb_plugin->files_count_system = 0;
1013 static void
1014 on_system_single_file_scan_end (SymbolDBEngine *dbe, gpointer data)
1016 AnjutaPlugin *plugin;
1017 SymbolDBPlugin *sdb_plugin;
1018 gchar *message;
1019 gdouble fraction = 0;
1021 plugin = ANJUTA_PLUGIN (data);
1022 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
1024 sdb_plugin->files_count_system_done++;
1025 if (sdb_plugin->files_count_system_done >= sdb_plugin->files_count_system)
1027 message = g_strdup_printf (_("%s: Generating inheritances…"),
1028 sdb_plugin->current_scanned_package);
1030 else
1032 message = g_strdup_printf (_("%s: %d files scanned out of %d"),
1033 sdb_plugin->current_scanned_package,
1034 sdb_plugin->files_count_system_done,
1035 sdb_plugin->files_count_system);
1038 if (sdb_plugin->files_count_system > 0)
1040 fraction = (gdouble) sdb_plugin->files_count_system_done /
1041 (gdouble) sdb_plugin->files_count_system;
1043 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_system),
1044 fraction);
1045 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_system), message);
1047 g_free (message);
1050 static void
1051 on_project_single_file_scan_end (SymbolDBEngine *dbe, gpointer data)
1053 AnjutaPlugin *plugin;
1054 SymbolDBPlugin *sdb_plugin;
1055 gchar *message;
1056 gdouble fraction = 0;
1058 plugin = ANJUTA_PLUGIN (data);
1059 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
1061 sdb_plugin->files_count_project_done++;
1062 if (sdb_plugin->files_count_project_done >= sdb_plugin->files_count_project)
1063 message = g_strdup_printf (_("Generating inheritances…"));
1064 else
1065 message = g_strdup_printf (_("%d files scanned out of %d"),
1066 sdb_plugin->files_count_project_done, sdb_plugin->files_count_project);
1068 if (sdb_plugin->files_count_project > 0)
1070 fraction = (gdouble) sdb_plugin->files_count_project_done /
1071 (gdouble) sdb_plugin->files_count_project;
1072 if (fraction > 1.0)
1073 fraction = 1.0;
1075 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_project),
1076 fraction);
1077 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_project), message);
1078 gtk_widget_show (sdb_plugin->progress_bar_project);
1079 g_free (message);
1082 static void
1083 clear_project_progress_bar (SymbolDBEngine *dbe, gpointer data)
1085 SymbolDBPlugin *sdb_plugin;
1087 g_return_if_fail (data != NULL);
1089 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (data);
1091 /* hide the progress bar */
1092 gtk_widget_hide (sdb_plugin->progress_bar_project);
1095 static void
1096 on_check_offline_single_file_scan_end (SymbolDBEngine *dbe, gpointer data)
1098 on_project_single_file_scan_end (dbe, data);
1101 /* note the *system* word in the function */
1102 static void
1103 do_import_system_sources_after_abort (SymbolDBPlugin *sdb_plugin,
1104 const GPtrArray *sources_array)
1106 AnjutaPlugin *plugin;
1107 GPtrArray* languages_array = NULL;
1108 GPtrArray *to_scan_array = NULL;
1109 IAnjutaLanguage* lang_manager;
1110 gint i;
1112 plugin = ANJUTA_PLUGIN (sdb_plugin);
1114 lang_manager = anjuta_shell_get_interface (plugin->shell, IAnjutaLanguage,
1115 NULL);
1117 /* create array of languages */
1118 languages_array = g_ptr_array_new ();
1119 to_scan_array = g_ptr_array_new ();
1121 if (!lang_manager)
1123 g_critical ("LanguageManager not found");
1124 return;
1127 for (i=0; i < sources_array->len; i++)
1129 const gchar *file_mime;
1130 const gchar *lang;
1131 const gchar *local_filename;
1132 GFile *gfile;
1133 GFileInfo *gfile_info;
1134 IAnjutaLanguageId lang_id;
1136 local_filename = g_ptr_array_index (sources_array, i);
1138 if (local_filename == NULL)
1139 continue;
1141 gfile = g_file_new_for_path (local_filename);
1142 if (gfile == NULL)
1143 continue;
1145 gfile_info = g_file_query_info (gfile,
1146 "*",
1147 G_FILE_QUERY_INFO_NONE,
1148 NULL,
1149 NULL);
1150 if (gfile_info == NULL)
1152 g_object_unref (gfile);
1153 continue;
1156 file_mime = g_file_info_get_attribute_string (gfile_info,
1157 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1159 lang_id = ianjuta_language_get_from_mime_type (lang_manager,
1160 file_mime, NULL);
1162 if (!lang_id)
1164 g_object_unref (gfile);
1165 g_object_unref (gfile_info);
1166 continue;
1169 lang = ianjuta_language_get_name (lang_manager, lang_id, NULL);
1171 /* test its existence */
1172 if (g_file_test (local_filename, G_FILE_TEST_EXISTS) == FALSE)
1174 g_object_unref (gfile);
1175 g_object_unref (gfile_info);
1176 continue;
1179 g_ptr_array_add (languages_array, g_strdup (lang));
1180 g_ptr_array_add (to_scan_array, g_strdup (local_filename));
1181 g_object_unref (gfile);
1182 g_object_unref (gfile_info);
1185 symbol_db_system_parse_aborted_package (sdb_plugin->sdbs,
1186 to_scan_array,
1187 languages_array);
1189 /* no need to free the GPtrArray, Huston. They'll be auto-destroyed in that
1190 * function
1194 /* we assume that sources_array has already unique elements */
1195 /* note the *project* word in the function */
1196 static void
1197 do_import_project_sources_after_abort (SymbolDBPlugin *sdb_plugin,
1198 const GPtrArray *sources_array)
1200 gint real_added;
1202 sdb_plugin->is_project_importing = TRUE;
1204 /* connect to receive signals on single file scan complete. We'll
1205 * update a status bar notifying the user about the status
1207 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_project), "single-file-scan-end",
1208 G_CALLBACK (on_project_single_file_scan_end), sdb_plugin);
1210 real_added = do_add_new_files (sdb_plugin, sources_array,
1211 TASK_IMPORT_PROJECT_AFTER_ABORT);
1212 if (real_added <= 0)
1214 sdb_plugin->is_project_importing = FALSE;
1216 else
1218 sdb_plugin->files_count_project += real_added;
1222 static void
1223 do_import_project_sources (SymbolDBPlugin *sdb_plugin, IAnjutaProjectManager *pm,
1224 const gchar *root_dir)
1226 GList* prj_elements_list;
1227 GPtrArray* sources_array;
1228 gint i;
1229 gint real_added;
1231 prj_elements_list = ianjuta_project_manager_get_elements (pm,
1232 ANJUTA_PROJECT_SOURCE | ANJUTA_PROJECT_PROJECT,
1233 NULL);
1235 if (prj_elements_list == NULL)
1237 g_warning ("No sources found within this project");
1238 return;
1241 /* if we're importing first shut off the signal receiving.
1242 * We'll re-enable that on scan-end
1244 sdb_plugin->is_project_importing = TRUE;
1245 DEBUG_PRINT ("Retrieving %d gbf sources of the project…",
1246 g_list_length (prj_elements_list));
1248 /* create the storage array. The file names will be strdup'd and put here.
1249 * This is just a sort of GList -> GPtrArray conversion.
1251 sources_array = g_ptr_array_new_with_free_func (g_free);
1252 for (i=0; i < g_list_length (prj_elements_list); i++)
1254 gchar *local_filename;
1255 GFile *gfile = NULL;
1257 gfile = g_list_nth_data (prj_elements_list, i);
1259 if ((local_filename = g_file_get_path (gfile)) == NULL)
1261 continue;
1264 g_ptr_array_add (sources_array, local_filename);
1267 /* connect to receive signals on single file scan complete. We'll
1268 * update a status bar notifying the user about the status
1270 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_project), "single-file-scan-end",
1271 G_CALLBACK (on_project_single_file_scan_end), sdb_plugin);
1273 real_added = do_add_new_files (sdb_plugin, sources_array, TASK_IMPORT_PROJECT);
1274 if (real_added <= 0)
1276 sdb_plugin->is_project_importing = FALSE;
1278 sdb_plugin->files_count_project += real_added;
1281 /* free the ptr array */
1282 g_ptr_array_unref (sources_array);
1284 /* and the list of project files */
1285 g_list_foreach (prj_elements_list, (GFunc) g_object_unref, NULL);
1286 g_list_free (prj_elements_list);
1290 * This function will call do_import_project_sources_after_abort ().
1291 * The list of files for sysstem packages enqueued on the first scan aren't
1292 * persisted on session for later retrieval. So we can only rely
1293 * on fixing the zero-symbols file.
1295 static void
1296 do_import_system_sources (SymbolDBPlugin *sdb_plugin)
1298 /* the resume thing */
1299 GPtrArray *sys_src_array = NULL;
1300 sys_src_array =
1301 symbol_db_util_get_files_with_zero_symbols (sdb_plugin->sdbe_globals);
1303 if (sys_src_array != NULL && sys_src_array->len > 0)
1305 do_import_system_sources_after_abort (sdb_plugin, sys_src_array);
1307 g_ptr_array_unref (sys_src_array);
1312 * @return TRUE if a scan is in progress, FALSE elsewhere.
1314 static gboolean
1315 do_update_project_symbols (SymbolDBPlugin *sdb_plugin, const gchar *root_dir)
1317 gint proc_id;
1318 /* Update the symbols */
1319 proc_id = symbol_db_engine_update_project_symbols (sdb_plugin->sdbe_project,
1320 root_dir, FALSE);
1321 if (proc_id > 0)
1323 sdb_plugin->is_project_updating = TRUE;
1325 /* insert the proc id associated within the task */
1326 g_tree_insert (sdb_plugin->proc_id_tree, GINT_TO_POINTER (proc_id),
1327 GINT_TO_POINTER (TASK_PROJECT_UPDATE));
1328 return TRUE;
1331 return FALSE;
1335 * @return TRUE is a scan process is started, FALSE elsewhere.
1337 static gboolean
1338 do_check_offline_files_changed (SymbolDBPlugin *sdb_plugin)
1340 GList * prj_elements_list;
1341 IAnjutaProjectManager *pm;
1342 GHashTable *prj_elements_hash;
1343 GPtrArray *to_add_files = NULL;
1344 gint i;
1345 gint real_added = 0;
1347 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
1348 IAnjutaProjectManager, NULL);
1350 prj_elements_list = ianjuta_project_manager_get_elements (pm,
1351 ANJUTA_PROJECT_SOURCE | ANJUTA_PROJECT_PROJECT,
1352 NULL);
1354 /* fill an hash table with all the items of the list just taken.
1355 * We won't g_strdup () the elements because they'll be freed later
1357 prj_elements_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
1358 NULL, g_free);
1360 for (i = 0; i < g_list_length (prj_elements_list); i++)
1362 GFile *gfile;
1363 gchar *filename;
1365 gfile = (GFile *)g_list_nth_data (prj_elements_list, i);
1367 if ((filename = g_file_get_path (gfile)) == NULL ||
1368 g_strcmp0 (filename, "") == 0)
1370 if (gfile)
1371 g_object_unref (gfile);
1372 continue;
1375 /* test its existence */
1376 if (g_file_query_exists (gfile, NULL) == FALSE)
1378 if (gfile)
1379 g_object_unref (gfile);
1380 continue;
1383 /* Use g_hash_table_replace instead of g_hash_table_insert because the key
1384 * and the value use the same block of memory, both must be changed at
1385 * the same time. */
1386 g_hash_table_replace (prj_elements_hash,
1387 (gpointer) symbol_db_util_get_file_db_path
1388 (sdb_plugin->sdbe_project,
1389 filename),
1390 filename);
1391 g_object_unref (gfile);
1395 /* some files may have added/removed editing Makefile.am while
1396 * Anjuta was offline. Check this case too.
1397 * FIXME: Get rid of data model here.
1399 GdaDataModel *model =
1400 symbol_db_engine_get_files_for_project (sdb_plugin->sdbe_project);
1401 GdaDataModelIter *it =
1402 gda_data_model_create_iter (model);
1404 if (it && gda_data_model_iter_move_to_row (it, 0))
1406 GPtrArray *remove_array;
1407 remove_array = g_ptr_array_new_with_free_func (g_free);
1408 do {
1409 const GValue *val = gda_data_model_iter_get_value_at (it, 0);
1410 const gchar * file = g_value_get_string (val);
1412 if (file && g_hash_table_remove (prj_elements_hash, file) == FALSE)
1413 g_ptr_array_add (remove_array, g_strdup (file));
1415 } while (gda_data_model_iter_move_next (it));
1417 symbol_db_engine_remove_files (sdb_plugin->sdbe_project,
1418 sdb_plugin->project_opened,
1419 remove_array);
1420 g_ptr_array_unref (remove_array);
1423 /* great, at this point we should have this situation:
1424 * remove array = files to remove, remaining items in the hash_table = files
1425 * to add.
1427 to_add_files = g_ptr_array_new ();
1428 if (g_hash_table_size (prj_elements_hash) > 0)
1430 gint i;
1431 GList *keys = g_hash_table_get_keys (prj_elements_hash);
1433 /* get all the nodes from the hash table and add them to the wannabe-added
1434 * array
1436 for (i = 0; i < g_hash_table_size (prj_elements_hash); i++)
1438 /*DEBUG_PRINT ("ARRAY ADD %s", (gchar*)g_list_nth_data (keys, i));*/
1439 g_ptr_array_add (to_add_files,
1440 g_hash_table_lookup (prj_elements_hash,
1441 g_list_nth_data (keys, i)));
1445 /* good. Let's go on with add of new files. */
1446 if (to_add_files->len > 0)
1448 /* block the signals spreading from engine to local-view tab */
1449 sdb_plugin->is_offline_scanning = TRUE;
1450 real_added = do_add_new_files (sdb_plugin, to_add_files,
1451 TASK_OFFLINE_CHANGES);
1453 DEBUG_PRINT ("going to do add %d files with TASK_OFFLINE_CHANGES",
1454 real_added);
1456 if (real_added <= 0)
1458 sdb_plugin->is_offline_scanning = FALSE;
1460 else {
1461 /* connect to receive signals on single file scan complete. We'll
1462 * update a status bar notifying the user about the status
1464 sdb_plugin->files_count_project += real_added;
1466 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_project), "single-file-scan-end",
1467 G_CALLBACK (on_check_offline_single_file_scan_end), ANJUTA_PLUGIN (sdb_plugin));
1471 /*if (it != NULL) g_object_unref (it);*/
1472 g_object_unref (it);
1473 g_object_unref (model);
1474 g_ptr_array_unref (to_add_files);
1475 g_hash_table_destroy (prj_elements_hash);
1477 return real_added > 0 ? TRUE : FALSE;
1481 * Session saved string will have the form:
1482 * pkg_name1:version1:version2:version3
1484 static GList *
1485 save_session_packages (SymbolDBPlugin *sdb_plugin)
1487 GHashTableIter iter;
1488 gpointer key, versions;
1489 GList *pkg_list;
1491 pkg_list = NULL;
1493 g_return_val_if_fail (sdb_plugin->session_packages != NULL, NULL);
1495 g_hash_table_iter_init (&iter, sdb_plugin->session_packages);
1496 while (g_hash_table_iter_next (&iter, &key, &versions))
1498 GList *node;
1499 GString *result;
1501 result = g_string_new (key);
1503 node = versions;
1504 while (node != NULL)
1506 result = g_string_append (result, ":");
1507 result = g_string_append (result, node->data);
1509 node = g_list_next (node);
1512 pkg_list = g_list_prepend (pkg_list, g_strdup (result->str));
1513 g_string_free (result, TRUE);
1516 return pkg_list;
1519 static void
1520 on_session_save (AnjutaShell *shell, AnjutaSessionPhase phase,
1521 AnjutaSession *session,
1522 SymbolDBPlugin *sdb_plugin)
1524 GList *pkgs;
1525 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
1526 return;
1528 DEBUG_PRINT ("%s", "SymbolDB: session_save");
1530 pkgs = save_session_packages (sdb_plugin);
1532 anjuta_session_set_string_list (session,
1533 SESSION_SECTION,
1534 SESSION_KEY,
1535 pkgs);
1538 static void
1539 load_session_packages (SymbolDBPlugin *sdb_plugin, GList *hash_glist)
1541 GList *node;
1543 node = hash_glist;
1544 while (node != NULL)
1546 if (node->data != NULL)
1548 gchar **split;
1549 gint i;
1550 gint len;
1551 GList *versions;
1552 split = g_strsplit (node->data, ":", 0);
1554 len = g_strv_length (split);
1555 if (len <= 1)
1557 g_strfreev(split);
1558 node = g_list_next (node);
1559 continue;
1562 /* add items to glist, skipping first splitted item (the pkg name) */
1563 for (i = 1; i < len; i++)
1565 versions = g_list_prepend (versions, strdup (split[i]));
1568 /* finally add key and value to hash table */
1569 g_hash_table_insert (sdb_plugin->session_packages,
1570 g_strdup (split[0]), versions);
1573 node = g_list_next (node);
1577 static void
1578 on_session_load (AnjutaShell *shell, AnjutaSessionPhase phase,
1579 AnjutaSession *session,
1580 SymbolDBPlugin *sdb_plugin)
1582 IAnjutaProjectManager *pm;
1583 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
1584 IAnjutaProjectManager, NULL);
1586 if (phase == ANJUTA_SESSION_PHASE_START)
1588 GList *hash_glist = anjuta_session_get_string_list (session,
1589 SESSION_SECTION,
1590 SESSION_KEY);
1592 load_session_packages (sdb_plugin, hash_glist);
1594 anjuta_util_glist_strings_free (hash_glist);
1596 DEBUG_PRINT ("SymbolDB: session_loading started. Getting info from %s",
1597 anjuta_session_get_session_directory (session));
1598 sdb_plugin->session_loading = TRUE;
1600 /* get preferences about the parallel scan */
1601 gboolean parallel_scan = g_settings_get_boolean (sdb_plugin->settings,
1602 PARALLEL_SCAN);
1604 if (parallel_scan == TRUE &&
1605 symbol_db_engine_is_connected (sdb_plugin->sdbe_globals) == TRUE)
1607 /* we simulate a project-import-end signal received */
1608 do_import_system_sources (sdb_plugin);
1611 else if (phase == ANJUTA_SESSION_PHASE_END)
1613 IAnjutaDocumentManager* docman;
1614 sdb_plugin->session_loading = FALSE;
1615 DEBUG_PRINT ("SymbolDB: session_loading finished");
1617 /* Show the symbols for the current editor */
1618 docman = anjuta_shell_get_interface (shell, IAnjutaDocumentManager, NULL);
1619 if (docman)
1621 IAnjutaDocument* cur_doc =
1622 ianjuta_document_manager_get_current_document (docman, NULL);
1623 if (cur_doc)
1625 GValue value = {0, };
1626 g_value_init (&value, G_TYPE_OBJECT);
1627 g_value_set_object (&value, cur_doc);
1628 value_added_current_editor (ANJUTA_PLUGIN (sdb_plugin),
1629 "document_manager_current_document",
1630 &value, NULL);
1631 g_value_unset(&value);
1635 if (sdb_plugin->project_opened == NULL)
1637 gtk_widget_hide (sdb_plugin->progress_bar_project);
1638 gtk_widget_hide (sdb_plugin->progress_bar_system);
1643 static void
1644 on_project_loaded (IAnjutaProjectManager *pm, GError *error,
1645 SymbolDBPlugin *sdb_plugin)
1647 g_return_if_fail (sdb_plugin->project_root_uri != NULL);
1648 g_return_if_fail (sdb_plugin->project_root_dir != NULL);
1650 /* Malformed project abort */
1651 if (error != NULL) return;
1654 * we need an initial import
1656 if (sdb_plugin->needs_sources_scan == TRUE)
1658 DEBUG_PRINT ("Importing sources.");
1659 do_import_project_sources (sdb_plugin, pm, sdb_plugin->project_root_dir);
1661 else
1664 * no import needed. But we may have aborted the scan of sources in
1665 * a previous session..
1667 GPtrArray *sources_array = NULL;
1668 gboolean flag_offline;
1669 gboolean flag_update;
1671 DEBUG_PRINT ("Checking for files with zero symbols.");
1672 sources_array =
1673 symbol_db_util_get_files_with_zero_symbols (sdb_plugin->sdbe_project);
1675 if (sources_array != NULL && sources_array->len > 0)
1677 DEBUG_PRINT ("Importing files after abort.");
1678 do_import_project_sources_after_abort (sdb_plugin, sources_array);
1680 g_ptr_array_unref (sources_array);
1683 DEBUG_PRINT ("Checking for offline changes.");
1684 /* check for offline changes */
1685 flag_offline = do_check_offline_files_changed (sdb_plugin);
1687 DEBUG_PRINT ("Updating project symbols.");
1688 /* update any files of the project which isn't up-to-date */
1689 flag_update = do_update_project_symbols (sdb_plugin, sdb_plugin->project_root_dir);
1693 /* add a new project */
1694 static void
1695 on_project_root_added (AnjutaPlugin *plugin, const gchar *name,
1696 const GValue *value, gpointer user_data)
1698 IAnjutaProjectManager *pm;
1699 SymbolDBPlugin *sdb_plugin;
1700 const gchar *root_uri;
1701 gchar *root_dir;
1702 GFile *gfile;
1703 IAnjutaProject *project;
1704 AnjutaProjectNode *root;
1705 const gchar *root_name;
1707 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
1710 * The Global System symbols thing
1713 /* is the global db connected? */
1714 if (symbol_db_engine_is_connected (sdb_plugin->sdbe_globals) == FALSE)
1716 gchar *anjuta_cache_path;
1717 /* open the connection to global db */
1718 anjuta_cache_path = anjuta_util_get_user_cache_file_path (".", NULL);
1719 if (symbol_db_engine_open_db (sdb_plugin->sdbe_globals,
1720 anjuta_cache_path,
1721 PROJECT_GLOBALS) == DB_OPEN_STATUS_FATAL)
1723 g_error ("Opening global project under %s", anjuta_cache_path);
1725 g_free (anjuta_cache_path);
1727 /* unref and recreate the sdbs object */
1728 if (sdb_plugin->sdbs != NULL)
1729 g_object_unref (sdb_plugin->sdbs);
1731 sdb_plugin->sdbs = symbol_db_system_new (sdb_plugin,
1732 sdb_plugin->sdbe_globals);
1735 /* Hide the progress bar. Default system tags thing: we'll import after abort even
1736 * if the preferences says not to automatically scan the packages.
1738 gtk_widget_hide (sdb_plugin->progress_bar_system);
1740 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
1741 IAnjutaProjectManager, NULL);
1744 * The Project thing
1747 g_free (sdb_plugin->project_root_uri);
1748 sdb_plugin->project_root_uri = NULL;
1749 if ((root_uri = g_value_get_string (value)) == NULL)
1751 DEBUG_PRINT ("Warning, root_uri for project is NULL");
1752 return;
1756 gfile = g_file_new_for_uri (root_uri);
1758 root_dir = g_file_get_path (gfile);
1759 DEBUG_PRINT ("Symbol-DB: added project root_dir %s, name %s", root_dir,
1760 name);
1762 g_object_unref (gfile);
1764 project = ianjuta_project_manager_get_current_project (pm, NULL);
1765 root = ianjuta_project_get_root (project, NULL);
1766 root_name = anjuta_project_node_get_name (root);
1768 sdb_plugin->project_opened = g_strdup (root_name);
1770 if (root_dir)
1772 gboolean project_exist = FALSE;
1773 guint id;
1775 /* we'll use the same values for db_directory and project_directory */
1776 DEBUG_PRINT ("Opening db %s and project_dir %s", root_dir, root_dir);
1777 gint open_status = symbol_db_engine_open_db (sdb_plugin->sdbe_project, root_dir,
1778 root_dir);
1780 /* is it a fresh-new project? is it an imported project with
1781 * no 'new' symbol-db database but the 'old' one symbol-browser?
1783 sdb_plugin->needs_sources_scan = FALSE;
1784 switch (open_status)
1786 case DB_OPEN_STATUS_FATAL:
1787 g_warning ("*** Error in opening db ***");
1788 return;
1790 case DB_OPEN_STATUS_NORMAL:
1791 project_exist = TRUE;
1792 break;
1794 case DB_OPEN_STATUS_CREATE:
1795 case DB_OPEN_STATUS_UPGRADE:
1796 sdb_plugin->needs_sources_scan = TRUE;
1797 project_exist = FALSE;
1798 break;
1800 default:
1801 break;
1804 /* if project did not exist add a new project */
1805 if (project_exist == FALSE)
1807 DEBUG_PRINT ("Creating new project.");
1808 symbol_db_engine_add_new_project (sdb_plugin->sdbe_project,
1809 NULL, /* still no workspace logic */
1810 sdb_plugin->project_opened,
1811 "1.0");
1814 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_project),
1815 _("Populating symbol database…"));
1816 id = g_idle_add ((GSourceFunc) gtk_progress_bar_pulse,
1817 sdb_plugin->progress_bar_project);
1818 gtk_widget_show (sdb_plugin->progress_bar_project);
1819 g_source_remove (id);
1820 gtk_widget_hide (sdb_plugin->progress_bar_project);
1822 /* root dir */
1823 sdb_plugin->project_root_dir = root_dir;
1825 /* this is uri */
1826 sdb_plugin->project_root_uri = g_strdup (root_uri);
1829 static void
1830 on_project_root_removed (AnjutaPlugin *plugin, const gchar *name,
1831 gpointer user_data)
1833 IAnjutaProjectManager *pm;
1834 SymbolDBPlugin *sdb_plugin;
1836 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
1837 DEBUG_PRINT ("%s", "project_root_removed ()");
1838 /* Disconnect events from project manager */
1840 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
1841 IAnjutaProjectManager, NULL);
1842 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
1843 on_project_element_added,
1844 sdb_plugin);
1845 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
1846 on_project_element_removed,
1847 sdb_plugin);
1849 /* don't forget to close the project */
1850 symbol_db_engine_close_db (sdb_plugin->sdbe_project);
1852 /* and the globals one */
1853 symbol_db_engine_close_db (sdb_plugin->sdbe_globals);
1855 /* stop any opened scanning process */
1856 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_system), "");
1857 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_project), "");
1858 gtk_widget_hide (sdb_plugin->progress_bar_system);
1859 gtk_widget_hide (sdb_plugin->progress_bar_project);
1861 sdb_plugin->files_count_system_done = 0;
1862 sdb_plugin->files_count_system = 0;
1864 sdb_plugin->files_count_project_done = 0;
1865 sdb_plugin->files_count_project = 0;
1868 g_free (sdb_plugin->project_root_uri);
1869 g_free (sdb_plugin->project_root_dir);
1870 g_free (sdb_plugin->project_opened);
1871 sdb_plugin->project_root_uri = NULL;
1872 sdb_plugin->project_root_dir = NULL;
1873 sdb_plugin->project_opened = NULL;
1876 static void
1877 on_scan_end_manager (SymbolDBEngine *dbe, gint process_id,
1878 gpointer data)
1880 SymbolDBPlugin *sdb_plugin;
1881 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (data);
1882 gint task_registered;
1884 task_registered = GPOINTER_TO_INT (g_tree_lookup (sdb_plugin->proc_id_tree,
1885 GINT_TO_POINTER (process_id)));
1886 /* hey, we haven't find anything */
1887 if (task_registered <= 0)
1889 DEBUG_PRINT ("No task found, proc id was %d", process_id);
1890 return;
1893 switch (task_registered)
1895 case TASK_IMPORT_PROJECT:
1896 case TASK_IMPORT_PROJECT_AFTER_ABORT:
1898 DEBUG_PRINT ("received TASK_IMPORT_PROJECT (AFTER_ABORT)");
1900 /* re-enable signals receiving on local-view */
1901 sdb_plugin->is_project_importing = FALSE;
1903 /* disconnect this coz it's not important after the process of importing */
1904 g_signal_handlers_disconnect_by_func (dbe, on_project_single_file_scan_end,
1905 sdb_plugin);
1907 /* get preferences about the parallel scan */
1908 gboolean parallel_scan = g_settings_get_boolean (sdb_plugin->settings,
1909 PARALLEL_SCAN);
1912 /* check the system population has a parallel fashion or not. */
1913 if (parallel_scan == FALSE)
1914 do_import_system_sources (sdb_plugin);
1916 break;
1918 case TASK_BUFFER_UPDATE:
1919 DEBUG_PRINT ("received TASK_BUFFER_UPDATE");
1920 on_editor_buffer_symbol_update_scan_end (dbe, process_id, sdb_plugin);
1921 break;
1923 case TASK_ELEMENT_ADDED:
1924 DEBUG_PRINT ("received TASK_ELEMENT_ADDED");
1925 sdb_plugin->is_adding_element = FALSE;
1926 break;
1928 case TASK_OFFLINE_CHANGES:
1929 DEBUG_PRINT ("received TASK_OFFLINE_CHANGES");
1931 /* disconnect this coz it's not important after the process of importing */
1932 g_signal_handlers_disconnect_by_func (dbe, on_check_offline_single_file_scan_end,
1933 sdb_plugin);
1935 sdb_plugin->is_offline_scanning = FALSE;
1936 break;
1938 case TASK_PROJECT_UPDATE:
1939 DEBUG_PRINT ("received TASK_PROJECT_UPDATE");
1940 sdb_plugin->is_project_updating = FALSE;
1941 break;
1943 case TASK_FILE_UPDATE:
1944 DEBUG_PRINT ("received TASK_FILE_UPDATE");
1945 break;
1947 default:
1948 DEBUG_PRINT ("Don't know what to to with task_registered %d",
1949 task_registered);
1952 /* ok, we're done. Remove the proc_id from the GTree coz we won't use it anymore */
1953 if (g_tree_remove (sdb_plugin->proc_id_tree, GINT_TO_POINTER (process_id)) == FALSE)
1954 g_warning ("Cannot remove proc_id from GTree");
1956 DEBUG_PRINT ("is_offline_scanning %d, is_project_importing %d, is_project_updating %d, "
1957 "is_adding_element %d", sdb_plugin->is_offline_scanning,
1958 sdb_plugin->is_project_importing, sdb_plugin->is_project_updating,
1959 sdb_plugin->is_adding_element);
1961 /* is the project still opened? */
1962 if (sdb_plugin->project_opened == NULL)
1964 /* just return, the project may have been closed while we were waiting for the
1965 * scanning to finish
1967 return;
1971 * perform some checks on some booleans. If they're all successfully passed
1972 * then activate the display of local view
1974 if (sdb_plugin->is_offline_scanning == FALSE &&
1975 sdb_plugin->is_project_importing == FALSE &&
1976 sdb_plugin->is_project_updating == FALSE &&
1977 sdb_plugin->is_adding_element == FALSE)
1979 sdb_plugin->files_count_project_done = 0;
1980 sdb_plugin->files_count_project = 0;
1981 clear_project_progress_bar (dbe, sdb_plugin);
1985 static void
1986 on_isymbol_manager_prj_scan_end (SymbolDBEngine *dbe,
1987 gint process_id,
1988 IAnjutaSymbolManager *sm)
1990 g_signal_emit_by_name (sm, "prj-scan-end", process_id);
1993 static void
1994 on_isymbol_manager_sys_scan_end (SymbolDBEngine *dbe,
1995 gint process_id,
1996 IAnjutaSymbolManager *sm)
1998 g_signal_emit_by_name (sm, "sys-scan-end", process_id);
2001 static gboolean
2002 symbol_db_activate (AnjutaPlugin *plugin)
2004 IAnjutaProjectManager *pm;
2005 SymbolDBPlugin *sdb_plugin;
2006 gchar *anjuta_cache_path;
2007 gchar *ctags_path;
2008 GtkWidget *view, *label;
2010 DEBUG_PRINT ("SymbolDBPlugin: Activating SymbolDBPlugin plugin …");
2012 /* Initialize gda library. */
2013 gda_init ();
2015 register_stock_icons (plugin);
2017 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
2018 sdb_plugin->ui = anjuta_shell_get_ui (plugin->shell, NULL);
2019 sdb_plugin->project_opened = NULL;
2021 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
2022 IAnjutaProjectManager, NULL);
2024 ctags_path = NULL;
2026 /* leaving here this code. Maybe in future ctags-devs will include our patches
2027 * upstream and this can be useful again.
2029 if (ctags_path == NULL)
2031 DEBUG_PRINT ("ctags is not in preferences. Trying a default one %s",
2032 CTAGS_PATH);
2033 ctags_path = g_strdup (CTAGS_PATH);
2036 /* initialize the session packages. We'll store there the user
2037 * preferences for the session about global-system packages
2039 sdb_plugin->session_packages = g_hash_table_new_full (g_str_hash,
2040 g_str_equal, g_free, (GDestroyNotify)anjuta_util_glist_strings_free);
2042 sdb_plugin->buf_update_timeout_id = 0;
2043 sdb_plugin->need_symbols_update = FALSE;
2044 /* creates and start a new timer. */
2045 sdb_plugin->update_timer = g_timer_new ();
2047 /* these two arrays will maintain the same number of objects,
2048 * so that if you search, say on the first, an occurrence of a file,
2049 * you'll be able to get in O(1) the _index in the second array, where the
2050 * scan process ids are stored. This is true in the other way too.
2052 sdb_plugin->buffer_update_files = g_ptr_array_new_with_free_func (g_free);
2053 sdb_plugin->buffer_update_ids = g_ptr_array_new ();
2054 sdb_plugin->buffer_update_semaphore = FALSE;
2056 sdb_plugin->is_offline_scanning = FALSE;
2057 sdb_plugin->is_project_importing = FALSE;
2058 sdb_plugin->is_project_updating = FALSE;
2059 sdb_plugin->is_adding_element = FALSE;
2061 DEBUG_PRINT ("SymbolDBPlugin: Initializing engines with %s", ctags_path);
2062 /* create SymbolDBEngine(s) */
2063 sdb_plugin->sdbe_project = symbol_db_engine_new (ctags_path);
2064 if (sdb_plugin->sdbe_project == NULL)
2066 g_critical ("sdbe_project == NULL");
2067 return FALSE;
2070 /* the globals one too */
2071 sdb_plugin->sdbe_globals = symbol_db_engine_new (ctags_path);
2072 if (sdb_plugin->sdbe_globals == NULL)
2074 g_critical ("sdbe_globals == NULL");
2075 return FALSE;
2078 g_free (ctags_path);
2080 /* open it */
2081 anjuta_cache_path = anjuta_util_get_user_cache_file_path (".", NULL);
2082 if (symbol_db_engine_open_db (sdb_plugin->sdbe_globals,
2083 anjuta_cache_path,
2084 PROJECT_GLOBALS) == DB_OPEN_STATUS_FATAL)
2086 g_error ("Opening global project under %s", anjuta_cache_path);
2089 g_free (anjuta_cache_path);
2091 /* create the object that'll manage the globals population */
2092 sdb_plugin->sdbs = symbol_db_system_new (sdb_plugin, sdb_plugin->sdbe_globals);
2094 g_signal_connect (G_OBJECT (sdb_plugin->sdbs), "scan-package-start",
2095 G_CALLBACK (on_system_scan_package_start), plugin);
2097 g_signal_connect (G_OBJECT (sdb_plugin->sdbs), "scan-package-end",
2098 G_CALLBACK (on_system_scan_package_end), plugin);
2100 g_signal_connect (G_OBJECT (sdb_plugin->sdbs), "single-file-scan-end",
2101 G_CALLBACK (on_system_single_file_scan_end), plugin);
2103 /* beign necessary to listen to many scan-end signals, we'll build up a method
2104 * to manage them with just one signal connection
2106 sdb_plugin->proc_id_tree = g_tree_new_full ((GCompareDataFunc)&symbol_db_gtree_compare_func,
2107 NULL,
2108 NULL,
2109 NULL);
2111 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_project), "scan-end",
2112 G_CALLBACK (on_scan_end_manager), sdb_plugin);
2114 /* connect signals for interface to receive them */
2115 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_globals), "scan-end",
2116 G_CALLBACK (on_isymbol_manager_sys_scan_end), sdb_plugin);
2118 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_project), "scan-end",
2119 G_CALLBACK (on_isymbol_manager_prj_scan_end), sdb_plugin);
2121 /* connect signals for project loading and element adding */
2122 g_signal_connect (G_OBJECT (pm), "element-added",
2123 G_CALLBACK (on_project_element_added), sdb_plugin);
2124 g_signal_connect (G_OBJECT (pm), "element-removed",
2125 G_CALLBACK (on_project_element_removed), sdb_plugin);
2126 g_signal_connect (G_OBJECT (pm), "project-loaded",
2127 G_CALLBACK (on_project_loaded), sdb_plugin);
2129 /* Create widgets */
2130 sdb_plugin->dbv_main = gtk_vbox_new(FALSE, 5);
2131 sdb_plugin->dbv_notebook = gtk_notebook_new();
2132 gtk_notebook_set_show_border (GTK_NOTEBOOK (sdb_plugin->dbv_notebook), FALSE);
2133 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (sdb_plugin->dbv_notebook), FALSE);
2134 sdb_plugin->dbv_hbox = gtk_hbox_new (FALSE, 1);
2136 label = gtk_label_new (_("Symbols"));
2137 gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f);
2138 gtk_box_pack_start (GTK_BOX(sdb_plugin->dbv_hbox),
2139 gtk_image_new_from_stock ("symbol-db-plugin-icon",
2140 GTK_ICON_SIZE_MENU),
2141 FALSE, FALSE, 0);
2142 gtk_box_pack_start (GTK_BOX(sdb_plugin->dbv_hbox), label,
2143 FALSE, FALSE, 0);
2145 sdb_plugin->tabber = anjuta_tabber_new (GTK_NOTEBOOK (sdb_plugin->dbv_notebook));
2146 label = gtk_label_new (_("File"));
2147 gtk_label_set_ellipsize (GTK_LABEL (label),
2148 PANGO_ELLIPSIZE_END);
2149 anjuta_tabber_add_tab (ANJUTA_TABBER (sdb_plugin->tabber),
2150 label);
2151 label = gtk_label_new (_("Project"));
2152 gtk_label_set_ellipsize (GTK_LABEL (label),
2153 PANGO_ELLIPSIZE_END);
2154 anjuta_tabber_add_tab (ANJUTA_TABBER (sdb_plugin->tabber),
2155 label);
2156 label = gtk_label_new (_("Search"));
2157 gtk_label_set_ellipsize (GTK_LABEL (label),
2158 PANGO_ELLIPSIZE_END);
2159 anjuta_tabber_add_tab (ANJUTA_TABBER (sdb_plugin->tabber),
2160 label);
2161 gtk_box_pack_end (GTK_BOX(sdb_plugin->dbv_hbox), sdb_plugin->tabber,
2162 TRUE, TRUE, 5);
2164 gtk_widget_show_all (sdb_plugin->dbv_hbox);
2166 sdb_plugin->progress_bar_project = gtk_progress_bar_new();
2167 gtk_progress_bar_set_ellipsize (GTK_PROGRESS_BAR(sdb_plugin->progress_bar_project),
2168 PANGO_ELLIPSIZE_MIDDLE);
2169 g_object_ref (sdb_plugin->progress_bar_project);
2171 sdb_plugin->progress_bar_system = gtk_progress_bar_new();
2172 gtk_progress_bar_set_ellipsize (GTK_PROGRESS_BAR(sdb_plugin->progress_bar_system),
2173 PANGO_ELLIPSIZE_MIDDLE);
2174 g_object_ref (sdb_plugin->progress_bar_system);
2176 gtk_box_pack_start (GTK_BOX (sdb_plugin->dbv_main), sdb_plugin->dbv_notebook,
2177 TRUE, TRUE, 0);
2178 gtk_box_pack_start (GTK_BOX (sdb_plugin->dbv_main), sdb_plugin->progress_bar_project,
2179 FALSE, FALSE, 0);
2180 gtk_box_pack_start (GTK_BOX (sdb_plugin->dbv_main), sdb_plugin->progress_bar_system,
2181 FALSE, FALSE, 0);
2182 gtk_widget_show_all (sdb_plugin->dbv_main);
2184 /* Local symbols */
2185 view = symbol_db_view_new (SYMBOL_DB_VIEW_FILE, sdb_plugin->sdbe_project,
2186 sdb_plugin);
2187 gtk_notebook_append_page (GTK_NOTEBOOK (sdb_plugin->dbv_notebook),
2188 view, gtk_label_new (_("Local")));
2189 sdb_plugin->file_model =
2190 gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_bin_get_child (GTK_BIN(view))));
2192 g_object_add_weak_pointer (G_OBJECT (sdb_plugin->file_model),
2193 (gpointer)&sdb_plugin->file_model);
2195 /* Global symbols */
2196 view = symbol_db_view_new (SYMBOL_DB_VIEW_PROJECT,
2197 sdb_plugin->sdbe_project,
2198 sdb_plugin);
2199 gtk_notebook_append_page (GTK_NOTEBOOK (sdb_plugin->dbv_notebook),
2200 view, gtk_label_new (_("Global" )));
2202 /* Search symbols */
2203 view = symbol_db_view_new (SYMBOL_DB_VIEW_SEARCH,
2204 sdb_plugin->sdbe_project,
2205 sdb_plugin);
2206 sdb_plugin->search_entry = symbol_db_view_get_search_entry (view);
2207 gtk_notebook_append_page (GTK_NOTEBOOK (sdb_plugin->dbv_notebook),
2208 view, gtk_label_new (_("Search" )));
2210 gtk_widget_show_all (sdb_plugin->dbv_notebook);
2212 /* setting focus to the tree_view*/
2213 gtk_notebook_set_current_page (GTK_NOTEBOOK (sdb_plugin->dbv_notebook), 0);
2215 sdb_plugin->editor_watch_id =
2216 anjuta_plugin_add_watch (plugin, IANJUTA_DOCUMENT_MANAGER_CURRENT_DOCUMENT,
2217 value_added_current_editor,
2218 value_removed_current_editor, NULL);
2219 /* Added widgets */
2220 anjuta_shell_add_widget_custom (plugin->shell, sdb_plugin->dbv_main,
2221 "AnjutaSymbolDB", _("Symbols"),
2222 "symbol-db-plugin-icon",
2223 sdb_plugin->dbv_hbox,
2224 ANJUTA_SHELL_PLACEMENT_LEFT, NULL);
2226 /* Add action group */
2227 sdb_plugin->popup_action_group =
2228 anjuta_ui_add_action_group_entries (sdb_plugin->ui,
2229 "ActionGroupPopupSymbolDB",
2230 _("SymbolDb popup actions"),
2231 actions,
2232 G_N_ELEMENTS (actions),
2233 GETTEXT_PACKAGE, FALSE, plugin);
2235 sdb_plugin->menu_action_group =
2236 anjuta_ui_add_action_group_entries (sdb_plugin->ui,
2237 "ActionGroupEditSearchSymbolDB",
2238 _("SymbolDb menu actions"),
2239 actions_search,
2240 G_N_ELEMENTS (actions_search),
2241 GETTEXT_PACKAGE, FALSE, plugin);
2243 /* Add UI */
2244 sdb_plugin->merge_id =
2245 anjuta_ui_merge (sdb_plugin->ui, UI_FILE);
2247 /* set up project directory watch */
2248 sdb_plugin->root_watch_id = anjuta_plugin_add_watch (plugin,
2249 IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI,
2250 on_project_root_added,
2251 on_project_root_removed, NULL);
2253 /* Determine session state */
2254 g_signal_connect (plugin->shell, "load-session",
2255 G_CALLBACK (on_session_load), plugin);
2257 g_signal_connect (plugin->shell, "save-session",
2258 G_CALLBACK (on_session_save), plugin);
2260 /* be sure to hide the progress bars in case no project has been opened. */
2261 gtk_widget_hide (sdb_plugin->progress_bar_project);
2262 gtk_widget_hide (sdb_plugin->progress_bar_system);
2264 static IAnjutaSymbolField search_fields[] =
2266 IANJUTA_SYMBOL_FIELD_KIND,
2267 IANJUTA_SYMBOL_FIELD_FILE_PATH,
2268 IANJUTA_SYMBOL_FIELD_FILE_POS
2270 sdb_plugin->search_query =
2271 ianjuta_symbol_manager_create_query (IANJUTA_SYMBOL_MANAGER (sdb_plugin),
2272 IANJUTA_SYMBOL_QUERY_SEARCH,
2273 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
2274 NULL);
2275 ianjuta_symbol_query_set_fields (sdb_plugin->search_query,
2276 G_N_ELEMENTS (search_fields),
2277 search_fields, NULL);
2278 return TRUE;
2281 static gboolean
2282 symbol_db_deactivate (AnjutaPlugin *plugin)
2284 SymbolDBPlugin *sdb_plugin;
2285 IAnjutaProjectManager *pm;
2287 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
2289 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
2290 IAnjutaProjectManager, NULL);
2294 DEBUG_PRINT ("%s", "SymbolDBPlugin: Dectivating SymbolDBPlugin plugin …");
2296 /* Unmerge UI */
2297 gtk_ui_manager_remove_ui (GTK_UI_MANAGER (sdb_plugin->ui),
2298 sdb_plugin->merge_id);
2299 gtk_ui_manager_remove_action_group (GTK_UI_MANAGER (sdb_plugin->ui),
2300 sdb_plugin->popup_action_group);
2301 gtk_ui_manager_remove_action_group (GTK_UI_MANAGER (sdb_plugin->ui),
2302 sdb_plugin->menu_action_group);
2303 g_signal_handlers_disconnect_by_func (G_OBJECT (plugin->shell),
2304 on_session_load,
2305 plugin);
2307 g_signal_handlers_disconnect_by_func (G_OBJECT (plugin->shell),
2308 on_session_save,
2309 plugin);
2311 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbs),
2312 on_system_scan_package_start,
2313 plugin);
2315 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbs),
2316 on_system_scan_package_end,
2317 plugin);
2319 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbs),
2320 on_system_single_file_scan_end,
2321 plugin);
2323 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbs),
2324 on_scan_end_manager,
2325 plugin);
2327 /* disconnect the interface ones */
2328 /* connect signals for interface to receive them */
2329 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbe_globals),
2330 G_CALLBACK (on_isymbol_manager_sys_scan_end), plugin);
2332 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbe_project),
2333 G_CALLBACK (on_isymbol_manager_prj_scan_end), plugin);
2335 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
2336 G_CALLBACK (on_project_element_added), plugin);
2338 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
2339 G_CALLBACK (on_project_element_removed), plugin);
2341 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
2342 G_CALLBACK (on_project_loaded), plugin);
2344 if (sdb_plugin->update_timer)
2346 g_timer_destroy (sdb_plugin->update_timer);
2347 sdb_plugin->update_timer = NULL;
2350 /* destroy search query */
2351 if (sdb_plugin->search_query)
2353 g_object_unref (sdb_plugin->search_query);
2355 sdb_plugin->search_query = NULL;
2357 /* destroy objects */
2358 if (sdb_plugin->sdbe_project)
2360 DEBUG_PRINT ("Destroying project engine object. ");
2361 g_object_unref (sdb_plugin->sdbe_project);
2363 sdb_plugin->sdbe_project = NULL;
2365 /* this must be done *before* destroying sdbe_globals */
2366 g_object_unref (sdb_plugin->sdbs);
2367 sdb_plugin->sdbs = NULL;
2369 g_free (sdb_plugin->current_scanned_package);
2370 sdb_plugin->current_scanned_package = NULL;
2372 DEBUG_PRINT ("Destroying global engine object. ");
2373 g_object_unref (sdb_plugin->sdbe_globals);
2374 sdb_plugin->sdbe_globals = NULL;
2376 g_free (sdb_plugin->project_opened);
2377 sdb_plugin->project_opened = NULL;
2379 if (sdb_plugin->buffer_update_files)
2381 g_ptr_array_unref (sdb_plugin->buffer_update_files);
2382 sdb_plugin->buffer_update_files = NULL;
2385 if (sdb_plugin->buffer_update_ids)
2387 g_ptr_array_unref (sdb_plugin->buffer_update_ids);
2388 sdb_plugin->buffer_update_ids = NULL;
2391 if (sdb_plugin->session_packages)
2393 g_hash_table_destroy (sdb_plugin->session_packages);
2394 sdb_plugin->session_packages = NULL;
2397 /* Ensure all editor cached info are released */
2398 if (sdb_plugin->editor_connected)
2400 g_hash_table_foreach (sdb_plugin->editor_connected,
2401 on_editor_foreach_disconnect, plugin);
2402 g_hash_table_destroy (sdb_plugin->editor_connected);
2403 sdb_plugin->editor_connected = NULL;
2406 // FIXME
2407 g_tree_destroy (sdb_plugin->proc_id_tree);
2409 /* Remove watches */
2410 anjuta_plugin_remove_watch (plugin, sdb_plugin->root_watch_id, FALSE);
2411 anjuta_plugin_remove_watch (plugin, sdb_plugin->editor_watch_id, TRUE);
2413 /* Remove UI */
2414 anjuta_ui_unmerge (sdb_plugin->ui, sdb_plugin->merge_id);
2416 /* Remove widgets: Widgets will be destroyed when dbv_main is removed */
2417 anjuta_shell_remove_widget (plugin->shell, sdb_plugin->dbv_main, NULL);
2419 sdb_plugin->root_watch_id = 0;
2420 sdb_plugin->editor_watch_id = 0;
2421 sdb_plugin->merge_id = 0;
2422 sdb_plugin->dbv_notebook = NULL;
2423 sdb_plugin->progress_bar_project = NULL;
2424 sdb_plugin->progress_bar_system = NULL;
2425 return TRUE;
2428 static void
2429 symbol_db_finalize (GObject *obj)
2431 DEBUG_PRINT ("Symbol-DB finalize");
2432 /* Finalization codes here */
2433 G_OBJECT_CLASS (parent_class)->finalize (obj);
2436 static void
2437 symbol_db_dispose (GObject *obj)
2439 SymbolDBPlugin *plugin = (SymbolDBPlugin*)obj;
2440 DEBUG_PRINT ("Symbol-DB dispose");
2441 /* Disposition codes */
2442 g_object_unref (plugin->settings);
2445 G_OBJECT_CLASS (parent_class)->dispose (obj);
2448 static void
2449 symbol_db_instance_init (GObject *obj)
2451 SymbolDBPlugin *plugin = (SymbolDBPlugin*)obj;
2453 plugin->files_count_project_done = 0;
2454 plugin->files_count_project = 0;
2456 plugin->files_count_system_done = 0;
2457 plugin->files_count_system = 0;
2458 plugin->current_scanned_package = NULL;
2459 plugin->settings = g_settings_new (PREF_SCHEMA);
2462 static void
2463 symbol_db_class_init (GObjectClass *klass)
2465 AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
2467 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2468 parent_class = g_type_class_peek_parent (klass);
2470 plugin_class->activate = symbol_db_activate;
2471 plugin_class->deactivate = symbol_db_deactivate;
2472 klass->finalize = symbol_db_finalize;
2473 klass->dispose = symbol_db_dispose;
2475 signals[PROJECT_IMPORT_END]
2476 = g_signal_new ("project-import-end",
2477 G_OBJECT_CLASS_TYPE (object_class),
2478 G_SIGNAL_RUN_FIRST,
2479 G_STRUCT_OFFSET (SymbolDBPluginClass, project_import_end),
2480 NULL, NULL,
2481 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2483 signals[GLOBALS_IMPORT_END]
2484 = g_signal_new ("globals-import-end",
2485 G_OBJECT_CLASS_TYPE (object_class),
2486 G_SIGNAL_RUN_FIRST,
2487 G_STRUCT_OFFSET (SymbolDBPluginClass, globals_import_end),
2488 NULL, NULL,
2489 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2492 static void
2493 on_prefs_buffer_update_toggled (GtkToggleButton* button,
2494 gpointer user_data)
2496 SymbolDBPlugin *sdb_plugin;
2497 gboolean sensitive;
2499 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (user_data);
2501 sensitive = gtk_toggle_button_get_active (button);
2503 DEBUG_PRINT ("on_prefs_buffer_update_toggled () %d", sensitive);
2505 if (sensitive == FALSE)
2507 if (sdb_plugin->buf_update_timeout_id)
2508 g_source_remove (sdb_plugin->buf_update_timeout_id);
2509 sdb_plugin->buf_update_timeout_id = 0;
2511 else
2513 if (sdb_plugin->buf_update_timeout_id == 0)
2514 sdb_plugin->buf_update_timeout_id =
2515 g_timeout_add_seconds (TIMEOUT_INTERVAL_SYMBOLS_UPDATE,
2516 on_editor_buffer_symbols_update_timeout,
2517 sdb_plugin);
2521 static void
2522 ipreferences_merge(IAnjutaPreferences* ipref, AnjutaPreferences* prefs, GError** e)
2524 DEBUG_PRINT ("%s", "SymbolDB: ipreferences_merge");
2525 SymbolDBPlugin *sdb_plugin;
2526 GtkWidget *buf_up_widget;
2527 GError* error = NULL;
2529 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (ipref);
2531 if (sdb_plugin->prefs_bxml == NULL)
2533 /* Create the preferences page */
2534 sdb_plugin->prefs_bxml = gtk_builder_new ();
2535 if (!gtk_builder_add_from_file (sdb_plugin->prefs_bxml, BUILDER_FILE, &error))
2537 g_warning ("Couldn't load builder file: %s", error->message);
2538 g_error_free(error);
2542 anjuta_preferences_add_from_builder (prefs,
2543 sdb_plugin->prefs_bxml,
2544 sdb_plugin->settings,
2545 BUILDER_ROOT,
2546 _("Symbol Database"),
2547 ICON_FILE);
2549 buf_up_widget = GTK_WIDGET (gtk_builder_get_object (sdb_plugin->prefs_bxml,
2550 PREFS_BUFFER_UPDATE));
2552 g_signal_connect (buf_up_widget, "toggled",
2553 G_CALLBACK (on_prefs_buffer_update_toggled),
2554 sdb_plugin);
2557 static void
2558 ipreferences_unmerge(IAnjutaPreferences* ipref, AnjutaPreferences* prefs, GError** e)
2560 SymbolDBPlugin *sdb_plugin;
2562 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (ipref);
2564 anjuta_preferences_remove_page(prefs, _("Symbol Database"));
2565 g_object_unref (sdb_plugin->prefs_bxml);
2566 sdb_plugin->prefs_bxml = NULL;
2569 static void
2570 ipreferences_iface_init(IAnjutaPreferencesIface* iface)
2572 DEBUG_PRINT ("%s", "SymbolDB: ipreferences_iface_init");
2573 iface->merge = ipreferences_merge;
2574 iface->unmerge = ipreferences_unmerge;
2577 /* IAnjutaSymbolManager implementation */
2578 static IAnjutaSymbolQuery*
2579 isymbol_manager_create_query (IAnjutaSymbolManager *isymbol_manager,
2580 IAnjutaSymbolQueryName query_name,
2581 IAnjutaSymbolQueryDb db,
2582 GError **err)
2584 SymbolDBPlugin *sdb_plugin;
2585 SymbolDBQuery *query;
2587 g_return_val_if_fail (isymbol_manager != NULL, NULL);
2589 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (isymbol_manager);
2591 query = symbol_db_query_new (sdb_plugin->sdbe_globals,
2592 sdb_plugin->sdbe_project, query_name, db);
2593 return IANJUTA_SYMBOL_QUERY (query);
2596 static gboolean
2597 isymbol_manager_add_package (IAnjutaSymbolManager *isymbol_manager,
2598 const gchar* pkg_name,
2599 const gchar* pkg_version,
2600 GList* files,
2601 GError *err)
2603 SymbolDBPlugin *sdb_plugin;
2604 IAnjutaLanguage *lang_manager;
2605 GPtrArray *files_array;
2606 GList *node;
2608 g_return_val_if_fail (isymbol_manager != NULL, FALSE);
2610 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (isymbol_manager);
2611 lang_manager = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell, IAnjutaLanguage,
2612 NULL);
2614 if (symbol_db_engine_add_new_project (sdb_plugin->sdbe_globals, NULL, pkg_name,
2615 pkg_version) == FALSE)
2617 return FALSE;
2620 files_array = g_ptr_array_sized_new (g_list_length (files));
2621 g_ptr_array_set_free_func (files_array, g_free);
2623 node = files;
2624 while (node != NULL)
2626 g_ptr_array_add (files_array, g_strdup (node->data));
2628 node = node->next;
2631 symbol_db_engine_add_new_files_async (sdb_plugin->sdbe_globals, lang_manager,
2632 pkg_name, pkg_version, files_array);
2634 g_ptr_array_unref (files_array);
2636 return TRUE;
2639 static gboolean
2640 isymbol_manager_activate_package (IAnjutaSymbolManager *isymbol_manager,
2641 const gchar *pkg_name,
2642 const gchar *pkg_version,
2643 GError *err)
2645 SymbolDBPlugin *sdb_plugin;
2646 GList *versions;
2648 g_return_val_if_fail (isymbol_manager != NULL, FALSE);
2650 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (isymbol_manager);
2652 /* check whether the package already exists in the session packages. */
2653 if ((versions = g_hash_table_lookup (sdb_plugin->session_packages, pkg_name)) != NULL)
2655 GList *node;
2657 /* if the package is already activated return true */
2658 node = versions;
2659 while (node != NULL)
2661 if (g_strcmp0 (node->data, pkg_version) == 0)
2662 return TRUE;
2664 node = g_list_next (node);
2667 /* check in the db: it may have a different version from the one already activated */
2668 if (symbol_db_engine_project_exists (sdb_plugin->sdbe_globals, pkg_name,
2669 pkg_version) == TRUE)
2671 GList *new_versions;
2673 /* this is a rare case so the performance playing with glist should not be
2674 taken into consideration */
2675 new_versions = anjuta_util_glist_strings_dup (versions);
2677 /* ok, the package version exists in db. Append it to the versions glist */
2678 new_versions = g_list_prepend (new_versions, g_strdup (pkg_version));
2680 /* go ahead and insert it, replacing the old one */
2681 g_hash_table_insert (sdb_plugin->session_packages, g_strdup (pkg_name),
2682 new_versions);
2684 return TRUE;
2687 /* nothing found on db. This is hopeless */
2688 return FALSE;
2691 if (symbol_db_engine_project_exists (sdb_plugin->sdbe_globals, pkg_name,
2692 pkg_version) == TRUE)
2694 GList *versions = NULL;
2696 versions = g_list_append (versions, g_strdup (pkg_version));
2697 /* ok, package exists in db. Add it to session packages */
2698 g_hash_table_insert (sdb_plugin->session_packages,
2699 g_strdup (pkg_name),
2700 versions);
2701 return TRUE;
2704 /* user should add a package before activating it. */
2705 return FALSE;
2708 static void
2709 isymbol_manager_iface_init (IAnjutaSymbolManagerIface *iface)
2711 iface->create_query = isymbol_manager_create_query;
2714 ANJUTA_PLUGIN_BEGIN (SymbolDBPlugin, symbol_db);
2715 ANJUTA_PLUGIN_ADD_INTERFACE (isymbol_manager, IANJUTA_TYPE_SYMBOL_MANAGER);
2716 ANJUTA_PLUGIN_ADD_INTERFACE(ipreferences, IANJUTA_TYPE_PREFERENCES);
2717 ANJUTA_PLUGIN_END;
2719 ANJUTA_SIMPLE_PLUGIN (SymbolDBPlugin, symbol_db);