code-analyzer: Fixed bgo#667903 - Code Analyzer Crashes
[anjuta.git] / plugins / symbol-db / plugin.c
blobb714e5eb942af80b6ee728d82feb8daa9d24cdb9
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 /* hey we found it */
486 /* remove both the items */
487 g_ptr_array_remove_index (sdb_plugin->buffer_update_ids, i);
489 g_ptr_array_remove_index (sdb_plugin->buffer_update_files, i);
491 /* no need to free the string coz the g_ptr_array is built with
492 * g_ptr_array_new_with_free_func (g_free)
497 /* was the updating of view-locals symbols blocked while we were scanning?
498 * e.g. was the editor switched? */
499 if (sdb_plugin->buffer_update_semaphore == TRUE)
501 GFile *file;
502 gchar *local_path;
503 gboolean tags_update;
504 if (!IANJUTA_IS_EDITOR (sdb_plugin->current_editor))
505 return;
507 file = ianjuta_file_get_file (IANJUTA_FILE (sdb_plugin->current_editor),
508 NULL);
510 if (file == NULL)
511 return;
513 local_path = g_file_get_path (file);
515 if (local_path == NULL)
517 g_critical ("local_path == NULL");
518 return;
521 /* add a default timeout to the updating of buffer symbols */
522 tags_update = g_settings_get_boolean (sdb_plugin->settings, BUFFER_UPDATE);
524 if (tags_update)
526 sdb_plugin->buf_update_timeout_id =
527 g_timeout_add_seconds (TIMEOUT_INTERVAL_SYMBOLS_UPDATE,
528 on_editor_buffer_symbols_update_timeout,
529 sdb_plugin);
532 g_free (local_path);
533 sdb_plugin->buffer_update_semaphore = FALSE;
537 static void
538 on_editor_destroy (SymbolDBPlugin *sdb_plugin, IAnjutaEditor *editor)
540 if (!sdb_plugin->editor_connected)
542 DEBUG_PRINT ("%s", "on_editor_destroy (): returning….");
543 return;
546 g_hash_table_remove (sdb_plugin->editor_connected, G_OBJECT (editor));
548 if (g_hash_table_size (sdb_plugin->editor_connected) <= 0)
550 DEBUG_PRINT ("%s", "displaying nothing…");
551 if (sdb_plugin->file_model)
552 g_object_set (sdb_plugin->file_model, "file-path", NULL, NULL);
556 static void
557 on_editor_update_ui (IAnjutaEditor *editor, SymbolDBPlugin *sdb_plugin)
559 g_timer_reset (sdb_plugin->update_timer);
562 static void
563 on_code_added (IAnjutaEditor *editor, IAnjutaIterable *position, gchar *code,
564 SymbolDBPlugin *sdb_plugin)
566 sdb_plugin->need_symbols_update = TRUE;
567 editor_buffer_symbols_update (editor, sdb_plugin);
570 static void
571 on_char_added (IAnjutaEditor *editor, IAnjutaIterable *position, gchar ch,
572 SymbolDBPlugin *sdb_plugin)
574 g_timer_reset (sdb_plugin->update_timer);
576 /* Update when the user enters a newline */
577 if (ch == '\n')
578 sdb_plugin->need_symbols_update = TRUE;
581 static void
582 on_editor_saved (IAnjutaEditor *editor, GFile* file,
583 SymbolDBPlugin *sdb_plugin)
585 const gchar *old_uri;
586 gchar *local_filename;
587 gchar *saved_uri;
588 GPtrArray *files_array;
589 gint proc_id;
590 gint i;
592 local_filename = g_file_get_path (file);
593 /* Verify that it's local file */
594 g_return_if_fail (local_filename != NULL);
596 saved_uri = g_file_get_uri (file);
598 for (i = 0; i < sdb_plugin->buffer_update_files->len; i++)
600 if (g_strcmp0 (g_ptr_array_index (sdb_plugin->buffer_update_files, i),
601 local_filename) == 0)
603 DEBUG_PRINT ("already scanning");
604 /* something is already scanning this buffer file. Drop the procedure now. */
605 return;
609 files_array = g_ptr_array_new();
610 g_ptr_array_add (files_array, local_filename);
611 /* no need to free local_filename now */
613 if (!sdb_plugin->editor_connected)
614 return;
616 old_uri = g_hash_table_lookup (sdb_plugin->editor_connected, editor);
618 if (old_uri && strlen (old_uri) <= 0)
619 old_uri = NULL;
621 /* files_array will be freed once updating has taken place */
622 proc_id = 0;
623 if (symbol_db_engine_is_connected (sdb_plugin->sdbe_project))
625 proc_id = symbol_db_engine_update_files_symbols (sdb_plugin->sdbe_project,
626 sdb_plugin->project_root_dir, files_array, TRUE);
629 if (proc_id > 0)
631 /* add a task so that scan_end_manager can manage this */
632 g_tree_insert (sdb_plugin->proc_id_tree, GINT_TO_POINTER (proc_id),
633 GINT_TO_POINTER (TASK_FILE_UPDATE));
636 g_hash_table_insert (sdb_plugin->editor_connected, editor,
637 g_strdup (saved_uri));
639 /* if we saved it we shouldn't update a second time */
640 sdb_plugin->need_symbols_update = FALSE;
642 on_editor_update_ui (editor, sdb_plugin);
643 g_free (saved_uri);
646 static void
647 value_added_current_editor (AnjutaPlugin *plugin, const char *name,
648 const GValue *value, gpointer data)
650 gchar *uri;
651 gboolean tags_update;
652 GFile* file;
653 gchar *local_path;
654 GObject *editor;
655 SymbolDBPlugin *sdb_plugin;
657 editor = g_value_get_object (value);
658 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
659 if (sdb_plugin->session_loading)
661 return;
663 else
664 DEBUG_PRINT ("%s", "Updating symbols");
666 if (!sdb_plugin->editor_connected)
668 sdb_plugin->editor_connected = g_hash_table_new_full (g_direct_hash,
669 g_direct_equal,
670 NULL, g_free);
672 sdb_plugin->current_editor = editor;
674 if (!IANJUTA_IS_EDITOR (editor))
675 return;
677 file = ianjuta_file_get_file (IANJUTA_FILE (editor), NULL);
679 if (file == NULL)
680 return;
682 local_path = g_file_get_path (file);
683 uri = g_file_get_uri (file);
685 if (local_path == NULL)
687 g_critical ("local_path == NULL");
688 return;
691 /* we can have a weird behaviour here if we're not paying the right attention:
692 * A timeout scan could have been launched and a millisecond later the user could
693 * have switched editor: we'll be getting the symbol inserted in the previous
694 * editor into the new one's view.
696 if (sdb_plugin->buffer_update_files->len > 0)
698 sdb_plugin->buffer_update_semaphore = TRUE;
700 else
702 g_object_set (sdb_plugin->file_model, "file-path", local_path, NULL);
704 /* add a default timeout to the updating of buffer symbols */
705 tags_update = g_settings_get_boolean (sdb_plugin->settings, BUFFER_UPDATE);
708 if (tags_update)
710 sdb_plugin->buf_update_timeout_id =
711 g_timeout_add_seconds (TIMEOUT_INTERVAL_SYMBOLS_UPDATE,
712 on_editor_buffer_symbols_update_timeout,
713 plugin);
717 if (g_hash_table_lookup (sdb_plugin->editor_connected, editor) == NULL)
719 g_object_weak_ref (G_OBJECT (editor),
720 (GWeakNotify) (on_editor_destroy),
721 sdb_plugin);
722 if (uri)
724 g_hash_table_insert (sdb_plugin->editor_connected, editor,
725 g_strdup (uri));
727 else
729 g_hash_table_insert (sdb_plugin->editor_connected, editor,
730 g_strdup (""));
733 g_signal_connect (G_OBJECT (editor), "saved",
734 G_CALLBACK (on_editor_saved),
735 sdb_plugin);
736 g_signal_connect (G_OBJECT (editor), "char-added",
737 G_CALLBACK (on_char_added),
738 sdb_plugin);
739 g_signal_connect (G_OBJECT (editor), "code-added",
740 G_CALLBACK (on_code_added),
741 sdb_plugin);
742 g_signal_connect (G_OBJECT(editor), "update_ui",
743 G_CALLBACK (on_editor_update_ui),
744 sdb_plugin);
746 g_free (uri);
747 g_free (local_path);
749 sdb_plugin->need_symbols_update = FALSE;
752 static void
753 on_editor_foreach_disconnect (gpointer key, gpointer value, gpointer user_data)
755 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
756 G_CALLBACK (on_editor_saved),
757 user_data);
758 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
759 G_CALLBACK (on_editor_update_ui),
760 user_data);
761 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
762 G_CALLBACK (on_char_added),
763 user_data);
764 g_signal_handlers_disconnect_by_func (G_OBJECT(key),
765 G_CALLBACK (on_code_added),
766 user_data);
767 g_object_weak_unref (G_OBJECT(key),
768 (GWeakNotify) (on_editor_destroy),
769 user_data);
772 static void
773 value_removed_current_editor (AnjutaPlugin *plugin,
774 const char *name, gpointer data)
776 SymbolDBPlugin *sdb_plugin;
778 sdb_plugin = (SymbolDBPlugin *) plugin;
780 DEBUG_PRINT ("%s", "value_removed_current_editor ()");
781 /* let's remove the timeout for symbols refresh */
782 if (sdb_plugin->buf_update_timeout_id)
783 g_source_remove (sdb_plugin->buf_update_timeout_id);
784 sdb_plugin->buf_update_timeout_id = 0;
785 sdb_plugin->need_symbols_update = FALSE;
787 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
788 sdb_plugin->current_editor = NULL;
792 * Perform the real add to the db and also checks that no dups are inserted.
793 * Return the real number of files added or -1 on error.
795 static gint
796 do_add_new_files (SymbolDBPlugin *sdb_plugin, const GPtrArray *sources_array,
797 ProcTask task)
799 GPtrArray* languages_array = NULL;
800 GPtrArray* to_scan_array = NULL;
801 GHashTable* check_unique_file_hash = NULL;
802 IAnjutaLanguage* lang_manager;
803 AnjutaPlugin *plugin;
804 gint added_num;
805 gint i;
806 gint proc_id;
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 proc_id = 0;
905 if (to_scan_array->len > 0)
907 proc_id = symbol_db_engine_add_new_files_full_async (sdb_plugin->sdbe_project,
908 sdb_plugin->project_opened, "1.0", to_scan_array, languages_array,
909 TRUE);
912 if (proc_id > 0)
914 /* insert the proc id associated within the task */
915 g_tree_insert (sdb_plugin->proc_id_tree, GINT_TO_POINTER (proc_id),
916 GINT_TO_POINTER (task));
919 /* get the real added number of files */
920 added_num = to_scan_array->len;
922 g_ptr_array_unref (languages_array);
923 g_ptr_array_unref (to_scan_array);
925 g_hash_table_destroy (check_unique_file_hash);
927 return proc_id > 0 ? added_num : -1;
930 static void
931 on_project_element_added (IAnjutaProjectManager *pm, GFile *gfile,
932 SymbolDBPlugin *sdb_plugin)
934 gchar *filename;
935 gint real_added;
936 GPtrArray *files_array;
938 g_return_if_fail (sdb_plugin->project_root_uri != NULL);
939 g_return_if_fail (sdb_plugin->project_root_dir != NULL);
941 filename = g_file_get_path (gfile);
943 files_array = g_ptr_array_new_with_free_func (g_free);
944 g_ptr_array_add (files_array, filename);
946 sdb_plugin->is_adding_element = TRUE;
948 /* use a custom function to add the files to db */
949 real_added = do_add_new_files (sdb_plugin, files_array, TASK_ELEMENT_ADDED);
950 if (real_added <= 0)
952 sdb_plugin->is_adding_element = FALSE;
955 g_ptr_array_unref (files_array);
958 static void
959 on_project_element_removed (IAnjutaProjectManager *pm, GFile *gfile,
960 SymbolDBPlugin *sdb_plugin)
962 gchar *filename;
964 if (!sdb_plugin->project_root_uri)
965 return;
967 filename = g_file_get_path (gfile);
969 if (filename)
971 DEBUG_PRINT ("%s", "on_project_element_removed");
972 symbol_db_engine_remove_file (sdb_plugin->sdbe_project,
973 sdb_plugin->project_root_dir,
974 symbol_db_util_get_file_db_path (sdb_plugin->sdbe_project,
975 filename));
977 g_free (filename);
981 static void
982 on_system_scan_package_start (SymbolDBEngine *dbe, guint num_files,
983 const gchar *package, gpointer user_data)
985 SymbolDBPlugin *sdb_plugin;
986 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (user_data);
988 sdb_plugin->files_count_system_done = 0;
989 sdb_plugin->files_count_system += num_files;
992 /* show the global bar */
993 gtk_widget_show (sdb_plugin->progress_bar_system);
994 if (sdb_plugin->current_scanned_package != NULL)
995 g_free (sdb_plugin->current_scanned_package);
996 sdb_plugin->current_scanned_package = g_strdup (package);
998 DEBUG_PRINT ("********************* START [%s] with n %d files ", package, num_files);
1001 static void
1002 on_system_scan_package_end (SymbolDBEngine *dbe, const gchar *package,
1003 gpointer user_data)
1005 SymbolDBPlugin *sdb_plugin;
1006 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (user_data);
1008 DEBUG_PRINT ("******************** END () [%s]", package);
1010 /* hide the progress bar */
1011 gtk_widget_hide (sdb_plugin->progress_bar_system);
1013 sdb_plugin->files_count_system_done = 0;
1014 sdb_plugin->files_count_system = 0;
1017 static void
1018 on_system_single_file_scan_end (SymbolDBEngine *dbe, gpointer data)
1020 AnjutaPlugin *plugin;
1021 SymbolDBPlugin *sdb_plugin;
1022 gchar *message;
1023 gdouble fraction = 0;
1025 plugin = ANJUTA_PLUGIN (data);
1026 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
1028 sdb_plugin->files_count_system_done++;
1029 if (sdb_plugin->files_count_system_done >= sdb_plugin->files_count_system)
1031 message = g_strdup_printf (_("%s: Generating inheritances…"),
1032 sdb_plugin->current_scanned_package);
1034 else
1036 /* Translators: %s is the name of a system library */
1037 message = g_strdup_printf (ngettext ("%s: %d file scanned out of %d", "%s: %d files scanned out of %d", sdb_plugin->files_count_system_done),
1038 sdb_plugin->current_scanned_package,
1039 sdb_plugin->files_count_system_done,
1040 sdb_plugin->files_count_system);
1043 if (sdb_plugin->files_count_system > 0)
1045 fraction = (gdouble) sdb_plugin->files_count_system_done /
1046 (gdouble) sdb_plugin->files_count_system;
1048 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_system),
1049 fraction);
1050 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_system), message);
1052 g_free (message);
1055 static void
1056 on_project_single_file_scan_end (SymbolDBEngine *dbe, gpointer data)
1058 AnjutaPlugin *plugin;
1059 SymbolDBPlugin *sdb_plugin;
1060 gchar *message;
1061 gdouble fraction = 0;
1063 plugin = ANJUTA_PLUGIN (data);
1064 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
1066 sdb_plugin->files_count_project_done++;
1067 if (sdb_plugin->files_count_project_done >= sdb_plugin->files_count_project)
1068 message = g_strdup_printf (_("Generating inheritances…"));
1069 else
1070 message = g_strdup_printf (ngettext ("%d file scanned out of %d", "%d files scanned out of %d", sdb_plugin->files_count_project_done),
1071 sdb_plugin->files_count_project_done, sdb_plugin->files_count_project);
1073 if (sdb_plugin->files_count_project > 0)
1075 fraction = (gdouble) sdb_plugin->files_count_project_done /
1076 (gdouble) sdb_plugin->files_count_project;
1077 if (fraction > 1.0)
1078 fraction = 1.0;
1080 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_project),
1081 fraction);
1082 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_project), message);
1083 gtk_widget_show (sdb_plugin->progress_bar_project);
1084 g_free (message);
1087 static void
1088 clear_project_progress_bar (SymbolDBEngine *dbe, gpointer data)
1090 SymbolDBPlugin *sdb_plugin;
1092 g_return_if_fail (data != NULL);
1094 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (data);
1096 /* hide the progress bar */
1097 gtk_widget_hide (sdb_plugin->progress_bar_project);
1100 static void
1101 on_check_offline_single_file_scan_end (SymbolDBEngine *dbe, gpointer data)
1103 on_project_single_file_scan_end (dbe, data);
1106 /* note the *system* word in the function */
1107 static void
1108 do_import_system_sources_after_abort (SymbolDBPlugin *sdb_plugin,
1109 const GPtrArray *sources_array)
1111 AnjutaPlugin *plugin;
1112 GPtrArray* languages_array = NULL;
1113 GPtrArray *to_scan_array = NULL;
1114 IAnjutaLanguage* lang_manager;
1115 gint i;
1117 plugin = ANJUTA_PLUGIN (sdb_plugin);
1119 lang_manager = anjuta_shell_get_interface (plugin->shell, IAnjutaLanguage,
1120 NULL);
1122 /* create array of languages */
1123 languages_array = g_ptr_array_new ();
1124 to_scan_array = g_ptr_array_new ();
1126 if (!lang_manager)
1128 g_critical ("LanguageManager not found");
1129 return;
1132 for (i=0; i < sources_array->len; i++)
1134 const gchar *file_mime;
1135 const gchar *lang;
1136 const gchar *local_filename;
1137 GFile *gfile;
1138 GFileInfo *gfile_info;
1139 IAnjutaLanguageId lang_id;
1141 local_filename = g_ptr_array_index (sources_array, i);
1143 if (local_filename == NULL)
1144 continue;
1146 gfile = g_file_new_for_path (local_filename);
1147 if (gfile == NULL)
1148 continue;
1150 gfile_info = g_file_query_info (gfile,
1151 "*",
1152 G_FILE_QUERY_INFO_NONE,
1153 NULL,
1154 NULL);
1155 if (gfile_info == NULL)
1157 g_object_unref (gfile);
1158 continue;
1161 file_mime = g_file_info_get_attribute_string (gfile_info,
1162 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1164 lang_id = ianjuta_language_get_from_mime_type (lang_manager,
1165 file_mime, NULL);
1167 if (!lang_id)
1169 g_object_unref (gfile);
1170 g_object_unref (gfile_info);
1171 continue;
1174 lang = ianjuta_language_get_name (lang_manager, lang_id, NULL);
1176 /* test its existence */
1177 if (g_file_test (local_filename, G_FILE_TEST_EXISTS) == FALSE)
1179 g_object_unref (gfile);
1180 g_object_unref (gfile_info);
1181 continue;
1184 g_ptr_array_add (languages_array, g_strdup (lang));
1185 g_ptr_array_add (to_scan_array, g_strdup (local_filename));
1186 g_object_unref (gfile);
1187 g_object_unref (gfile_info);
1190 /* FIXME HERE currently disabled */
1191 #if 0
1192 symbol_db_system_parse_aborted_package (sdb_plugin->sdbs,
1193 to_scan_array,
1194 languages_array);
1195 #endif
1196 /* no need to free the GPtrArray, Huston. They'll be auto-destroyed in that
1197 * function
1201 /* we assume that sources_array has already unique elements */
1202 /* note the *project* word in the function */
1203 static void
1204 do_import_project_sources_after_abort (SymbolDBPlugin *sdb_plugin,
1205 const GPtrArray *sources_array)
1207 gint real_added;
1209 sdb_plugin->is_project_importing = TRUE;
1211 /* connect to receive signals on single file scan complete. We'll
1212 * update a status bar notifying the user about the status
1214 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_project), "single-file-scan-end",
1215 G_CALLBACK (on_project_single_file_scan_end), sdb_plugin);
1217 real_added = do_add_new_files (sdb_plugin, sources_array,
1218 TASK_IMPORT_PROJECT_AFTER_ABORT);
1219 if (real_added <= 0)
1221 sdb_plugin->is_project_importing = FALSE;
1223 else
1225 sdb_plugin->files_count_project += real_added;
1229 static void
1230 do_import_project_sources (SymbolDBPlugin *sdb_plugin, IAnjutaProjectManager *pm,
1231 const gchar *root_dir)
1233 GList* prj_elements_list;
1234 GPtrArray* sources_array;
1235 gint i;
1236 gint real_added;
1238 prj_elements_list = ianjuta_project_manager_get_elements (pm,
1239 ANJUTA_PROJECT_SOURCE | ANJUTA_PROJECT_PROJECT,
1240 NULL);
1242 if (prj_elements_list == NULL)
1244 g_warning ("No sources found within this project");
1245 return;
1248 /* if we're importing first shut off the signal receiving.
1249 * We'll re-enable that on scan-end
1251 sdb_plugin->is_project_importing = TRUE;
1252 DEBUG_PRINT ("Retrieving %d gbf sources of the project…",
1253 g_list_length (prj_elements_list));
1255 /* create the storage array. The file names will be strdup'd and put here.
1256 * This is just a sort of GList -> GPtrArray conversion.
1258 sources_array = g_ptr_array_new_with_free_func (g_free);
1259 for (i=0; i < g_list_length (prj_elements_list); i++)
1261 gchar *local_filename;
1262 GFile *gfile = NULL;
1264 gfile = g_list_nth_data (prj_elements_list, i);
1266 if ((local_filename = g_file_get_path (gfile)) == NULL)
1268 continue;
1271 g_ptr_array_add (sources_array, local_filename);
1274 /* connect to receive signals on single file scan complete. We'll
1275 * update a status bar notifying the user about the status
1277 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_project), "single-file-scan-end",
1278 G_CALLBACK (on_project_single_file_scan_end), sdb_plugin);
1280 real_added = do_add_new_files (sdb_plugin, sources_array, TASK_IMPORT_PROJECT);
1281 if (real_added <= 0)
1283 sdb_plugin->is_project_importing = FALSE;
1285 sdb_plugin->files_count_project += real_added;
1288 /* free the ptr array */
1289 g_ptr_array_unref (sources_array);
1291 /* and the list of project files */
1292 g_list_foreach (prj_elements_list, (GFunc) g_object_unref, NULL);
1293 g_list_free (prj_elements_list);
1297 * This function will call do_import_project_sources_after_abort ().
1298 * The list of files for sysstem packages enqueued on the first scan aren't
1299 * persisted on session for later retrieval. So we can only rely
1300 * on fixing the zero-symbols file.
1302 static void
1303 do_import_system_sources (SymbolDBPlugin *sdb_plugin)
1305 /* the resume thing */
1306 GPtrArray *sys_src_array = NULL;
1307 sys_src_array =
1308 symbol_db_util_get_files_with_zero_symbols (sdb_plugin->sdbe_globals);
1310 if (sys_src_array != NULL && sys_src_array->len > 0)
1312 do_import_system_sources_after_abort (sdb_plugin, sys_src_array);
1314 g_ptr_array_unref (sys_src_array);
1319 * @return TRUE if a scan is in progress, FALSE elsewhere.
1321 static gboolean
1322 do_update_project_symbols (SymbolDBPlugin *sdb_plugin, const gchar *root_dir)
1324 gint proc_id;
1325 /* Update the symbols */
1326 proc_id = symbol_db_engine_update_project_symbols (sdb_plugin->sdbe_project,
1327 root_dir, FALSE);
1328 if (proc_id > 0)
1330 sdb_plugin->is_project_updating = TRUE;
1332 /* insert the proc id associated within the task */
1333 g_tree_insert (sdb_plugin->proc_id_tree, GINT_TO_POINTER (proc_id),
1334 GINT_TO_POINTER (TASK_PROJECT_UPDATE));
1335 return TRUE;
1338 return FALSE;
1342 * do_check_offline_files_changed:
1343 * @sdb_plugin: self
1345 * Returns: TRUE if a scan process is started, FALSE elsewhere.
1347 static gboolean
1348 do_check_offline_files_changed (SymbolDBPlugin *sdb_plugin)
1350 GList * prj_elements_list;
1351 GList *node;
1352 IAnjutaProjectManager *pm;
1353 GHashTable *prj_elements_hash;
1354 GPtrArray *to_add_files = NULL;
1355 gint real_added = 0;
1357 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
1358 IAnjutaProjectManager, NULL);
1360 prj_elements_list = ianjuta_project_manager_get_elements (pm,
1361 ANJUTA_PROJECT_SOURCE | ANJUTA_PROJECT_PROJECT,
1362 NULL);
1364 /* fill an hash table with all the items of the list just taken.
1365 * We won't g_strdup () the elements because they'll be freed later
1367 prj_elements_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
1368 NULL, g_free);
1370 node = prj_elements_list;
1371 while (node != NULL)
1373 GFile *gfile;
1374 gchar *filename;
1376 gfile = node->data;
1378 if ((filename = g_file_get_path (gfile)) == NULL ||
1379 g_strcmp0 (filename, "") == 0)
1381 if (gfile)
1382 g_object_unref (gfile);
1384 node = g_list_next (node);
1385 continue;
1388 /* test its existence */
1389 if (g_file_query_exists (gfile, NULL) == FALSE)
1391 if (gfile)
1392 g_object_unref (gfile);
1394 node = g_list_next (node);
1395 continue;
1398 /* Use g_hash_table_replace instead of g_hash_table_insert because the key
1399 * and the value use the same block of memory, both must be changed at
1400 * the same time. */
1401 g_hash_table_replace (prj_elements_hash,
1402 (gpointer) symbol_db_util_get_file_db_path
1403 (sdb_plugin->sdbe_project,
1404 filename),
1405 filename);
1406 g_object_unref (gfile);
1408 node = g_list_next (node);
1412 /* some files may have added/removed editing Makefile.am while
1413 * Anjuta was offline. Check this case too.
1414 * FIXME: Get rid of data model here.
1416 GdaDataModel *model =
1417 symbol_db_engine_get_files_for_project (sdb_plugin->sdbe_project);
1418 GdaDataModelIter *it =
1419 gda_data_model_create_iter (model);
1421 if (it && gda_data_model_iter_move_to_row (it, 0))
1423 GPtrArray *remove_array;
1424 remove_array = g_ptr_array_new_with_free_func (g_free);
1425 do {
1426 const GValue *val = gda_data_model_iter_get_value_at (it, 0);
1427 const gchar * file = g_value_get_string (val);
1429 if (file && g_hash_table_remove (prj_elements_hash, file) == FALSE)
1430 g_ptr_array_add (remove_array, g_strdup (file));
1432 } while (gda_data_model_iter_move_next (it));
1434 symbol_db_engine_remove_files (sdb_plugin->sdbe_project,
1435 sdb_plugin->project_opened,
1436 remove_array);
1437 g_ptr_array_unref (remove_array);
1440 /* great, at this point we should have this situation:
1441 * remove array = files to remove, remaining items in the hash_table = files
1442 * to add.
1444 to_add_files = g_ptr_array_new ();
1445 if (g_hash_table_size (prj_elements_hash) > 0)
1447 gint i;
1448 GList *keys = g_hash_table_get_keys (prj_elements_hash);
1450 /* get all the nodes from the hash table and add them to the wannabe-added
1451 * array
1453 for (i = 0; i < g_hash_table_size (prj_elements_hash); i++)
1455 /*DEBUG_PRINT ("ARRAY ADD %s", (gchar*)g_list_nth_data (keys, i));*/
1456 g_ptr_array_add (to_add_files,
1457 g_hash_table_lookup (prj_elements_hash,
1458 g_list_nth_data (keys, i)));
1462 /* good. Let's go on with add of new files. */
1463 if (to_add_files->len > 0)
1465 /* block the signals spreading from engine to local-view tab */
1466 sdb_plugin->is_offline_scanning = TRUE;
1467 real_added = do_add_new_files (sdb_plugin, to_add_files,
1468 TASK_OFFLINE_CHANGES);
1470 DEBUG_PRINT ("going to do add %d files with TASK_OFFLINE_CHANGES",
1471 real_added);
1473 if (real_added <= 0)
1475 sdb_plugin->is_offline_scanning = FALSE;
1477 else {
1478 /* connect to receive signals on single file scan complete. We'll
1479 * update a status bar notifying the user about the status
1481 sdb_plugin->files_count_project += real_added;
1483 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_project), "single-file-scan-end",
1484 G_CALLBACK (on_check_offline_single_file_scan_end), ANJUTA_PLUGIN (sdb_plugin));
1488 /*if (it != NULL) g_object_unref (it);*/
1489 g_object_unref (it);
1490 g_object_unref (model);
1491 g_ptr_array_unref (to_add_files);
1492 g_hash_table_destroy (prj_elements_hash);
1494 return real_added > 0 ? TRUE : FALSE;
1497 static void
1498 on_session_save (AnjutaShell *shell, AnjutaSessionPhase phase,
1499 AnjutaSession *session,
1500 SymbolDBPlugin *sdb_plugin)
1502 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
1503 return;
1505 DEBUG_PRINT ("%s", "SymbolDB: session_save");
1508 static void
1509 on_session_load (AnjutaShell *shell, AnjutaSessionPhase phase,
1510 AnjutaSession *session,
1511 SymbolDBPlugin *sdb_plugin)
1513 if (phase == ANJUTA_SESSION_PHASE_START)
1515 DEBUG_PRINT ("SymbolDB: session_loading started. Getting info from %s",
1516 anjuta_session_get_session_directory (session));
1517 sdb_plugin->session_loading = TRUE;
1519 /* get preferences about the parallel scan */
1520 gboolean parallel_scan = g_settings_get_boolean (sdb_plugin->settings,
1521 PARALLEL_SCAN);
1523 if (parallel_scan == TRUE &&
1524 symbol_db_engine_is_connected (sdb_plugin->sdbe_globals) == TRUE)
1526 /* we simulate a project-import-end signal received */
1527 do_import_system_sources (sdb_plugin);
1530 else if (phase == ANJUTA_SESSION_PHASE_END)
1532 IAnjutaDocumentManager* docman;
1533 sdb_plugin->session_loading = FALSE;
1534 DEBUG_PRINT ("SymbolDB: session_loading finished");
1536 /* Show the symbols for the current editor */
1537 docman = anjuta_shell_get_interface (shell, IAnjutaDocumentManager, NULL);
1538 if (docman)
1540 IAnjutaDocument* cur_doc =
1541 ianjuta_document_manager_get_current_document (docman, NULL);
1542 if (cur_doc)
1544 GValue value = {0, };
1545 g_value_init (&value, G_TYPE_OBJECT);
1546 g_value_set_object (&value, cur_doc);
1547 value_added_current_editor (ANJUTA_PLUGIN (sdb_plugin),
1548 "document_manager_current_document",
1549 &value, NULL);
1550 g_value_unset(&value);
1554 if (sdb_plugin->project_opened == NULL)
1556 gtk_widget_hide (sdb_plugin->progress_bar_project);
1557 gtk_widget_hide (sdb_plugin->progress_bar_system);
1562 static void
1563 on_project_loaded (IAnjutaProjectManager *pm, GError *error,
1564 SymbolDBPlugin *sdb_plugin)
1566 g_return_if_fail (sdb_plugin->project_root_uri != NULL);
1567 g_return_if_fail (sdb_plugin->project_root_dir != NULL);
1569 /* Malformed project abort */
1570 if (error != NULL) return;
1573 * we need an initial import
1575 if (sdb_plugin->needs_sources_scan == TRUE)
1577 DEBUG_PRINT ("Importing sources.");
1578 do_import_project_sources (sdb_plugin, pm, sdb_plugin->project_root_dir);
1580 else
1583 * no import needed. But we may have aborted the scan of sources in
1584 * a previous session..
1586 GPtrArray *sources_array = NULL;
1588 DEBUG_PRINT ("Checking for files with zero symbols.");
1589 sources_array =
1590 symbol_db_util_get_files_with_zero_symbols (sdb_plugin->sdbe_project);
1592 if (sources_array != NULL && sources_array->len > 0)
1594 DEBUG_PRINT ("Importing files after abort.");
1595 do_import_project_sources_after_abort (sdb_plugin, sources_array);
1597 g_ptr_array_unref (sources_array);
1600 DEBUG_PRINT ("Checking for offline changes.");
1601 /* check for offline changes */
1602 if (do_check_offline_files_changed (sdb_plugin) == FALSE)
1604 DEBUG_PRINT ("no changes. Skipping.");
1607 DEBUG_PRINT ("Updating project symbols.");
1608 /* update any files of the project which isn't up-to-date */
1609 if (do_update_project_symbols (sdb_plugin, sdb_plugin->project_opened) == FALSE)
1611 DEBUG_PRINT ("no changes. Skipping.");
1616 /* add a new project */
1617 static void
1618 on_project_root_added (AnjutaPlugin *plugin, const gchar *name,
1619 const GValue *value, gpointer user_data)
1621 IAnjutaProjectManager *pm;
1622 SymbolDBPlugin *sdb_plugin;
1623 const gchar *root_uri;
1624 gchar *root_dir;
1625 GFile *gfile;
1626 IAnjutaProject *project;
1627 AnjutaProjectNode *root;
1628 const gchar *root_name;
1630 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
1633 * The Global System symbols thing
1636 /* is the global db connected? */
1637 if (symbol_db_engine_is_connected (sdb_plugin->sdbe_globals) == FALSE)
1639 gchar *anjuta_cache_path;
1640 /* open the connection to global db */
1641 anjuta_cache_path = anjuta_util_get_user_cache_file_path (".", NULL);
1642 if (symbol_db_engine_open_db (sdb_plugin->sdbe_globals,
1643 anjuta_cache_path,
1644 PROJECT_GLOBALS) == DB_OPEN_STATUS_FATAL)
1646 g_error ("Opening global project under %s", anjuta_cache_path);
1648 g_free (anjuta_cache_path);
1650 /* unref and recreate the sdbs object */
1651 if (sdb_plugin->sdbs != NULL)
1652 g_object_unref (sdb_plugin->sdbs);
1654 sdb_plugin->sdbs = symbol_db_system_new (sdb_plugin,
1655 sdb_plugin->sdbe_globals);
1658 /* Hide the progress bar. Default system tags thing: we'll import after abort even
1659 * if the preferences says not to automatically scan the packages.
1661 gtk_widget_hide (sdb_plugin->progress_bar_system);
1663 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
1664 IAnjutaProjectManager, NULL);
1668 * The Project thing
1671 g_free (sdb_plugin->project_root_uri);
1672 sdb_plugin->project_root_uri = NULL;
1673 if ((root_uri = g_value_get_string (value)) == NULL)
1675 DEBUG_PRINT ("Warning, root_uri for project is NULL");
1676 return;
1680 gfile = g_file_new_for_uri (root_uri);
1682 root_dir = g_file_get_path (gfile);
1683 DEBUG_PRINT ("Symbol-DB: added project root_dir %s, name %s", root_dir,
1684 name);
1686 g_object_unref (gfile);
1688 project = ianjuta_project_manager_get_current_project (pm, NULL);
1689 root = ianjuta_project_get_root (project, NULL);
1690 root_name = anjuta_project_node_get_name (root);
1692 sdb_plugin->project_opened = g_strdup (root_name);
1694 if (root_dir)
1696 gboolean project_exist = FALSE;
1697 guint id;
1699 /* we'll use the same values for db_directory and project_directory */
1700 DEBUG_PRINT ("Opening db %s and project_dir %s", root_dir, root_dir);
1701 gint open_status = symbol_db_engine_open_db (sdb_plugin->sdbe_project, root_dir,
1702 root_dir);
1704 /* is it a fresh-new project? is it an imported project with
1705 * no 'new' symbol-db database but the 'old' one symbol-browser?
1707 sdb_plugin->needs_sources_scan = FALSE;
1708 switch (open_status)
1710 case DB_OPEN_STATUS_FATAL:
1711 g_warning ("*** Error in opening db ***");
1712 return;
1714 case DB_OPEN_STATUS_NORMAL:
1715 project_exist = TRUE;
1716 break;
1718 case DB_OPEN_STATUS_CREATE:
1719 case DB_OPEN_STATUS_UPGRADE:
1720 sdb_plugin->needs_sources_scan = TRUE;
1721 project_exist = FALSE;
1722 break;
1724 default:
1725 break;
1728 /* if project did not exist add a new project */
1729 if (project_exist == FALSE)
1731 DEBUG_PRINT ("Creating new project.");
1732 symbol_db_engine_add_new_project (sdb_plugin->sdbe_project,
1733 NULL, /* still no workspace logic */
1734 sdb_plugin->project_opened,
1735 "1.0");
1738 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_project),
1739 _("Populating symbol database…"));
1740 id = g_idle_add ((GSourceFunc) gtk_progress_bar_pulse,
1741 sdb_plugin->progress_bar_project);
1742 gtk_widget_show (sdb_plugin->progress_bar_project);
1743 g_source_remove (id);
1744 gtk_widget_hide (sdb_plugin->progress_bar_project);
1746 /* root dir */
1747 sdb_plugin->project_root_dir = root_dir;
1749 /* this is uri */
1750 sdb_plugin->project_root_uri = g_strdup (root_uri);
1753 static void
1754 on_project_root_removed (AnjutaPlugin *plugin, const gchar *name,
1755 gpointer user_data)
1757 IAnjutaProjectManager *pm;
1758 SymbolDBPlugin *sdb_plugin;
1760 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
1761 DEBUG_PRINT ("%s", "project_root_removed ()");
1762 /* Disconnect events from project manager */
1764 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
1765 IAnjutaProjectManager, NULL);
1766 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
1767 on_project_element_added,
1768 sdb_plugin);
1769 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
1770 on_project_element_removed,
1771 sdb_plugin);
1773 /* don't forget to close the project */
1774 symbol_db_engine_close_db (sdb_plugin->sdbe_project);
1776 /* and the globals one */
1777 symbol_db_engine_close_db (sdb_plugin->sdbe_globals);
1779 /* stop any opened scanning process */
1780 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_system), "");
1781 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_project), "");
1782 gtk_widget_hide (sdb_plugin->progress_bar_system);
1783 gtk_widget_hide (sdb_plugin->progress_bar_project);
1785 sdb_plugin->files_count_system_done = 0;
1786 sdb_plugin->files_count_system = 0;
1788 sdb_plugin->files_count_project_done = 0;
1789 sdb_plugin->files_count_project = 0;
1792 g_free (sdb_plugin->project_root_uri);
1793 g_free (sdb_plugin->project_root_dir);
1794 g_free (sdb_plugin->project_opened);
1795 sdb_plugin->project_root_uri = NULL;
1796 sdb_plugin->project_root_dir = NULL;
1797 sdb_plugin->project_opened = NULL;
1800 static void
1801 on_scan_end_manager (SymbolDBEngine *dbe, gint process_id,
1802 gpointer data)
1804 SymbolDBPlugin *sdb_plugin;
1805 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (data);
1806 gint task_registered;
1808 task_registered = GPOINTER_TO_INT (g_tree_lookup (sdb_plugin->proc_id_tree,
1809 GINT_TO_POINTER (process_id)));
1810 /* hey, we haven't find anything */
1811 if (task_registered <= 0)
1813 DEBUG_PRINT ("No task found, proc id was %d", process_id);
1814 return;
1817 switch (task_registered)
1819 case TASK_IMPORT_PROJECT:
1820 case TASK_IMPORT_PROJECT_AFTER_ABORT:
1822 DEBUG_PRINT ("received TASK_IMPORT_PROJECT (AFTER_ABORT)");
1824 /* re-enable signals receiving on local-view */
1825 sdb_plugin->is_project_importing = FALSE;
1827 /* disconnect this coz it's not important after the process of importing */
1828 g_signal_handlers_disconnect_by_func (dbe, on_project_single_file_scan_end,
1829 sdb_plugin);
1831 /* get preferences about the parallel scan */
1832 gboolean parallel_scan = g_settings_get_boolean (sdb_plugin->settings,
1833 PARALLEL_SCAN);
1836 /* check the system population has a parallel fashion or not. */
1837 if (parallel_scan == FALSE)
1838 do_import_system_sources (sdb_plugin);
1840 break;
1842 case TASK_BUFFER_UPDATE:
1843 DEBUG_PRINT ("received TASK_BUFFER_UPDATE");
1844 on_editor_buffer_symbol_update_scan_end (dbe, process_id, sdb_plugin);
1845 break;
1847 case TASK_ELEMENT_ADDED:
1848 DEBUG_PRINT ("received TASK_ELEMENT_ADDED");
1849 sdb_plugin->is_adding_element = FALSE;
1850 break;
1852 case TASK_OFFLINE_CHANGES:
1853 DEBUG_PRINT ("received TASK_OFFLINE_CHANGES");
1855 /* disconnect this coz it's not important after the process of importing */
1856 g_signal_handlers_disconnect_by_func (dbe, on_check_offline_single_file_scan_end,
1857 sdb_plugin);
1859 sdb_plugin->is_offline_scanning = FALSE;
1860 break;
1862 case TASK_PROJECT_UPDATE:
1863 DEBUG_PRINT ("received TASK_PROJECT_UPDATE");
1864 sdb_plugin->is_project_updating = FALSE;
1865 break;
1867 case TASK_FILE_UPDATE:
1868 DEBUG_PRINT ("received TASK_FILE_UPDATE");
1869 break;
1871 default:
1872 DEBUG_PRINT ("Don't know what to to with task_registered %d",
1873 task_registered);
1876 /* ok, we're done. Remove the proc_id from the GTree coz we won't use it anymore */
1877 if (g_tree_remove (sdb_plugin->proc_id_tree, GINT_TO_POINTER (process_id)) == FALSE)
1878 g_warning ("Cannot remove proc_id from GTree");
1880 DEBUG_PRINT ("is_offline_scanning %d, is_project_importing %d, is_project_updating %d, "
1881 "is_adding_element %d", sdb_plugin->is_offline_scanning,
1882 sdb_plugin->is_project_importing, sdb_plugin->is_project_updating,
1883 sdb_plugin->is_adding_element);
1885 /* is the project still opened? */
1886 if (sdb_plugin->project_opened == NULL)
1888 /* just return, the project may have been closed while we were waiting for the
1889 * scanning to finish
1891 return;
1895 * perform some checks on some booleans. If they're all successfully passed
1896 * then activate the display of local view
1898 if (sdb_plugin->is_offline_scanning == FALSE &&
1899 sdb_plugin->is_project_importing == FALSE &&
1900 sdb_plugin->is_project_updating == FALSE &&
1901 sdb_plugin->is_adding_element == FALSE)
1903 sdb_plugin->files_count_project_done = 0;
1904 sdb_plugin->files_count_project = 0;
1905 clear_project_progress_bar (dbe, sdb_plugin);
1909 static void
1910 on_isymbol_manager_prj_scan_end (SymbolDBEngine *dbe,
1911 gint process_id,
1912 IAnjutaSymbolManager *sm)
1914 g_signal_emit_by_name (sm, "prj-scan-end", process_id);
1917 static void
1918 on_isymbol_manager_sys_scan_begin (SymbolDBEngine *dbe, gint process_id,
1919 SymbolDBPlugin *sdb_plugin)
1921 sdb_plugin->current_pkg_scanned = g_async_queue_pop (sdb_plugin->global_scan_aqueue);
1923 if (sdb_plugin->current_pkg_scanned == NULL)
1924 return;
1926 DEBUG_PRINT ("==%d==>\n"
1927 "begin %s", process_id, sdb_plugin->current_pkg_scanned->package_name);
1928 gtk_widget_show (sdb_plugin->progress_bar_system);
1931 static void
1932 on_isymbol_manager_sys_single_scan_end (SymbolDBEngine *dbe, SymbolDBPlugin *sdb_plugin)
1934 PackageScanData *pkg_scan;
1936 /* ignore signals when scan-end has already been received */
1937 if (sdb_plugin->current_pkg_scanned == NULL)
1939 return;
1942 pkg_scan = sdb_plugin->current_pkg_scanned;
1943 pkg_scan->files_done++;
1945 gtk_widget_show (sdb_plugin->progress_bar_system);
1946 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (sdb_plugin->progress_bar_system),
1947 (gdouble)pkg_scan->files_done /
1948 (gdouble)pkg_scan->files_length);
1951 static void
1952 on_isymbol_manager_sys_scan_end (SymbolDBEngine *dbe,
1953 gint process_id,
1954 SymbolDBPlugin *sdb_plugin)
1956 IAnjutaSymbolManager *sm;
1957 PackageScanData *pkg_scan;
1959 g_return_if_fail (sdb_plugin->current_pkg_scanned != NULL);
1961 DEBUG_PRINT ("<==%d==\nscan end %s. Queue now is %d",
1962 process_id,
1963 sdb_plugin->current_pkg_scanned->package_name,
1964 g_async_queue_length (sdb_plugin->global_scan_aqueue));
1966 sm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
1967 IAnjutaSymbolManager, NULL);
1969 g_signal_emit_by_name (sm, "sys-scan-end", process_id);
1971 pkg_scan = sdb_plugin->current_pkg_scanned;
1972 g_free (pkg_scan->package_name);
1973 g_free (pkg_scan->package_version);
1974 g_free (pkg_scan);
1976 sdb_plugin->current_pkg_scanned = NULL;
1978 gtk_widget_hide (sdb_plugin->progress_bar_system);
1981 static gboolean
1982 symbol_db_activate (AnjutaPlugin *plugin)
1984 IAnjutaProjectManager *pm;
1985 SymbolDBPlugin *sdb_plugin;
1986 gchar *anjuta_cache_path;
1987 gchar *ctags_path;
1988 GtkWidget *view, *label;
1990 DEBUG_PRINT ("SymbolDBPlugin: Activating SymbolDBPlugin plugin …");
1992 /* Initialize gda library. */
1993 gda_init ();
1995 register_stock_icons (plugin);
1997 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
1998 sdb_plugin->ui = anjuta_shell_get_ui (plugin->shell, NULL);
1999 sdb_plugin->project_opened = NULL;
2001 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
2002 IAnjutaProjectManager, NULL);
2004 ctags_path = NULL;
2006 /* leaving here this code. Maybe in future ctags-devs will include our patches
2007 * upstream and this can be useful again.
2009 if (ctags_path == NULL)
2011 DEBUG_PRINT ("ctags is not in preferences. Trying a default one %s",
2012 CTAGS_PATH);
2013 ctags_path = g_strdup (CTAGS_PATH);
2016 sdb_plugin->buf_update_timeout_id = 0;
2017 sdb_plugin->need_symbols_update = FALSE;
2018 /* creates and start a new timer. */
2019 sdb_plugin->update_timer = g_timer_new ();
2021 /* these two arrays will maintain the same number of objects,
2022 * so that if you search, say on the first, an occurrence of a file,
2023 * you'll be able to get in O(1) the _index in the second array, where the
2024 * scan process ids are stored. This is true in the other way too.
2026 sdb_plugin->buffer_update_files = g_ptr_array_new_with_free_func (g_free);
2027 sdb_plugin->buffer_update_ids = g_ptr_array_new ();
2028 sdb_plugin->buffer_update_semaphore = FALSE;
2030 sdb_plugin->is_offline_scanning = FALSE;
2031 sdb_plugin->is_project_importing = FALSE;
2032 sdb_plugin->is_project_updating = FALSE;
2033 sdb_plugin->is_adding_element = FALSE;
2035 DEBUG_PRINT ("SymbolDBPlugin: Initializing engines with %s", ctags_path);
2036 /* create SymbolDBEngine(s) */
2037 sdb_plugin->sdbe_project = symbol_db_engine_new (ctags_path);
2038 if (sdb_plugin->sdbe_project == NULL)
2040 g_critical ("sdbe_project == NULL");
2041 return FALSE;
2044 /* the globals one too */
2045 sdb_plugin->sdbe_globals = symbol_db_engine_new (ctags_path);
2046 if (sdb_plugin->sdbe_globals == NULL)
2048 g_critical ("sdbe_globals == NULL");
2049 return FALSE;
2052 g_free (ctags_path);
2054 /* open it */
2055 anjuta_cache_path = anjuta_util_get_user_cache_file_path (".", NULL);
2056 if (symbol_db_engine_open_db (sdb_plugin->sdbe_globals,
2057 anjuta_cache_path,
2058 PROJECT_GLOBALS) == DB_OPEN_STATUS_FATAL)
2060 g_error ("Opening global project under %s", anjuta_cache_path);
2063 g_free (anjuta_cache_path);
2065 sdb_plugin->global_scan_aqueue = g_async_queue_new ();
2066 /* create the object that'll manage the globals population */
2067 sdb_plugin->sdbs = symbol_db_system_new (sdb_plugin, sdb_plugin->sdbe_globals);
2068 #if 0
2069 g_signal_connect (G_OBJECT (sdb_plugin->sdbs), "scan-package-start",
2070 G_CALLBACK (on_system_scan_package_start), plugin);
2072 g_signal_connect (G_OBJECT (sdb_plugin->sdbs), "scan-package-end",
2073 G_CALLBACK (on_system_scan_package_end), plugin);
2075 g_signal_connect (G_OBJECT (sdb_plugin->sdbs), "single-file-scan-end",
2076 G_CALLBACK (on_system_single_file_scan_end), plugin);
2077 #endif
2078 /* beign necessary to listen to many scan-end signals, we'll build up a method
2079 * to manage them with just one signal connection
2081 sdb_plugin->proc_id_tree = g_tree_new_full ((GCompareDataFunc)&symbol_db_gtree_compare_func,
2082 NULL,
2083 NULL,
2084 NULL);
2086 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_project), "scan-end",
2087 G_CALLBACK (on_scan_end_manager), sdb_plugin);
2089 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_project), "scan-end",
2090 G_CALLBACK (on_isymbol_manager_prj_scan_end), sdb_plugin);
2092 /* connect signals for interface to receive them */
2093 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_globals), "single-file-scan-end",
2094 G_CALLBACK (on_isymbol_manager_sys_single_scan_end), sdb_plugin);
2096 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_globals), "scan-end",
2097 G_CALLBACK (on_isymbol_manager_sys_scan_end), sdb_plugin);
2099 g_signal_connect (G_OBJECT (sdb_plugin->sdbe_globals), "scan-begin",
2100 G_CALLBACK (on_isymbol_manager_sys_scan_begin), sdb_plugin);
2104 /* connect signals for project loading and element adding */
2105 g_signal_connect (G_OBJECT (pm), "element-added",
2106 G_CALLBACK (on_project_element_added), sdb_plugin);
2107 g_signal_connect (G_OBJECT (pm), "element-removed",
2108 G_CALLBACK (on_project_element_removed), sdb_plugin);
2109 g_signal_connect (G_OBJECT (pm), "project-loaded",
2110 G_CALLBACK (on_project_loaded), sdb_plugin);
2112 /* Create widgets */
2113 sdb_plugin->dbv_main = gtk_vbox_new(FALSE, 5);
2114 sdb_plugin->dbv_notebook = gtk_notebook_new();
2115 gtk_notebook_set_show_border (GTK_NOTEBOOK (sdb_plugin->dbv_notebook), FALSE);
2116 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (sdb_plugin->dbv_notebook), FALSE);
2117 sdb_plugin->dbv_hbox = gtk_hbox_new (FALSE, 1);
2119 label = gtk_label_new (_("Symbols"));
2120 gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f);
2121 gtk_box_pack_start (GTK_BOX(sdb_plugin->dbv_hbox),
2122 gtk_image_new_from_stock ("symbol-db-plugin-icon",
2123 GTK_ICON_SIZE_MENU),
2124 FALSE, FALSE, 0);
2125 gtk_box_pack_start (GTK_BOX(sdb_plugin->dbv_hbox), label,
2126 FALSE, FALSE, 0);
2128 sdb_plugin->tabber = anjuta_tabber_new (GTK_NOTEBOOK (sdb_plugin->dbv_notebook));
2129 label = gtk_label_new (_("File"));
2130 gtk_label_set_ellipsize (GTK_LABEL (label),
2131 PANGO_ELLIPSIZE_END);
2132 anjuta_tabber_add_tab (ANJUTA_TABBER (sdb_plugin->tabber),
2133 label);
2134 label = gtk_label_new (_("Project"));
2135 gtk_label_set_ellipsize (GTK_LABEL (label),
2136 PANGO_ELLIPSIZE_END);
2137 anjuta_tabber_add_tab (ANJUTA_TABBER (sdb_plugin->tabber),
2138 label);
2139 label = gtk_label_new (_("Search"));
2140 gtk_label_set_ellipsize (GTK_LABEL (label),
2141 PANGO_ELLIPSIZE_END);
2142 anjuta_tabber_add_tab (ANJUTA_TABBER (sdb_plugin->tabber),
2143 label);
2144 gtk_box_pack_end (GTK_BOX(sdb_plugin->dbv_hbox), sdb_plugin->tabber,
2145 TRUE, TRUE, 5);
2147 gtk_widget_show_all (sdb_plugin->dbv_hbox);
2149 sdb_plugin->progress_bar_project = gtk_progress_bar_new();
2150 gtk_progress_bar_set_ellipsize (GTK_PROGRESS_BAR(sdb_plugin->progress_bar_project),
2151 PANGO_ELLIPSIZE_MIDDLE);
2152 g_object_ref (sdb_plugin->progress_bar_project);
2154 sdb_plugin->progress_bar_system = gtk_progress_bar_new();
2155 gtk_progress_bar_set_ellipsize (GTK_PROGRESS_BAR(sdb_plugin->progress_bar_system),
2156 PANGO_ELLIPSIZE_MIDDLE);
2157 g_object_ref (sdb_plugin->progress_bar_system);
2159 gtk_box_pack_start (GTK_BOX (sdb_plugin->dbv_main), sdb_plugin->dbv_notebook,
2160 TRUE, TRUE, 0);
2161 gtk_box_pack_start (GTK_BOX (sdb_plugin->dbv_main), sdb_plugin->progress_bar_project,
2162 FALSE, FALSE, 0);
2163 gtk_box_pack_start (GTK_BOX (sdb_plugin->dbv_main), sdb_plugin->progress_bar_system,
2164 FALSE, FALSE, 0);
2165 gtk_widget_show_all (sdb_plugin->dbv_main);
2167 /* Local symbols */
2168 view = symbol_db_view_new (SYMBOL_DB_VIEW_FILE, sdb_plugin->sdbe_project,
2169 sdb_plugin);
2170 gtk_notebook_append_page (GTK_NOTEBOOK (sdb_plugin->dbv_notebook),
2171 view, gtk_label_new (_("Local")));
2172 sdb_plugin->file_model =
2173 gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_bin_get_child (GTK_BIN(view))));
2175 g_object_add_weak_pointer (G_OBJECT (sdb_plugin->file_model),
2176 (gpointer)&sdb_plugin->file_model);
2178 /* Global symbols */
2179 view = symbol_db_view_new (SYMBOL_DB_VIEW_PROJECT,
2180 sdb_plugin->sdbe_project,
2181 sdb_plugin);
2182 gtk_notebook_append_page (GTK_NOTEBOOK (sdb_plugin->dbv_notebook),
2183 view, gtk_label_new (_("Global" )));
2185 /* Search symbols */
2186 view = symbol_db_view_new (SYMBOL_DB_VIEW_SEARCH,
2187 sdb_plugin->sdbe_project,
2188 sdb_plugin);
2189 sdb_plugin->search_entry = symbol_db_view_get_search_entry (view);
2190 gtk_notebook_append_page (GTK_NOTEBOOK (sdb_plugin->dbv_notebook),
2191 view, gtk_label_new (_("Search" )));
2193 gtk_widget_show_all (sdb_plugin->dbv_notebook);
2195 /* setting focus to the tree_view*/
2196 gtk_notebook_set_current_page (GTK_NOTEBOOK (sdb_plugin->dbv_notebook), 0);
2198 sdb_plugin->editor_watch_id =
2199 anjuta_plugin_add_watch (plugin, IANJUTA_DOCUMENT_MANAGER_CURRENT_DOCUMENT,
2200 value_added_current_editor,
2201 value_removed_current_editor, NULL);
2202 /* Added widgets */
2203 anjuta_shell_add_widget_custom (plugin->shell, sdb_plugin->dbv_main,
2204 "AnjutaSymbolDB", _("Symbols"),
2205 "symbol-db-plugin-icon",
2206 sdb_plugin->dbv_hbox,
2207 ANJUTA_SHELL_PLACEMENT_LEFT, NULL);
2209 /* Add action group */
2210 sdb_plugin->popup_action_group =
2211 anjuta_ui_add_action_group_entries (sdb_plugin->ui,
2212 "ActionGroupPopupSymbolDB",
2213 _("SymbolDb popup actions"),
2214 actions,
2215 G_N_ELEMENTS (actions),
2216 GETTEXT_PACKAGE, FALSE, plugin);
2218 sdb_plugin->menu_action_group =
2219 anjuta_ui_add_action_group_entries (sdb_plugin->ui,
2220 "ActionGroupEditSearchSymbolDB",
2221 _("SymbolDb menu actions"),
2222 actions_search,
2223 G_N_ELEMENTS (actions_search),
2224 GETTEXT_PACKAGE, FALSE, plugin);
2226 /* Add UI */
2227 sdb_plugin->merge_id =
2228 anjuta_ui_merge (sdb_plugin->ui, UI_FILE);
2230 /* set up project directory watch */
2231 sdb_plugin->root_watch_id = anjuta_plugin_add_watch (plugin,
2232 IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI,
2233 on_project_root_added,
2234 on_project_root_removed, NULL);
2236 /* Determine session state */
2237 g_signal_connect (plugin->shell, "load-session",
2238 G_CALLBACK (on_session_load), plugin);
2240 g_signal_connect (plugin->shell, "save-session",
2241 G_CALLBACK (on_session_save), plugin);
2243 /* be sure to hide the progress bars in case no project has been opened. */
2244 gtk_widget_hide (sdb_plugin->progress_bar_project);
2245 gtk_widget_hide (sdb_plugin->progress_bar_system);
2247 static IAnjutaSymbolField search_fields[] =
2249 IANJUTA_SYMBOL_FIELD_KIND,
2250 IANJUTA_SYMBOL_FIELD_FILE_PATH,
2251 IANJUTA_SYMBOL_FIELD_FILE_POS
2253 sdb_plugin->search_query =
2254 ianjuta_symbol_manager_create_query (IANJUTA_SYMBOL_MANAGER (sdb_plugin),
2255 IANJUTA_SYMBOL_QUERY_SEARCH,
2256 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
2257 NULL);
2258 ianjuta_symbol_query_set_fields (sdb_plugin->search_query,
2259 G_N_ELEMENTS (search_fields),
2260 search_fields, NULL);
2261 return TRUE;
2264 static gboolean
2265 symbol_db_deactivate (AnjutaPlugin *plugin)
2267 SymbolDBPlugin *sdb_plugin;
2268 IAnjutaProjectManager *pm;
2270 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (plugin);
2272 pm = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell,
2273 IAnjutaProjectManager, NULL);
2277 DEBUG_PRINT ("%s", "SymbolDBPlugin: Dectivating SymbolDBPlugin plugin …");
2279 /* Unmerge UI */
2280 gtk_ui_manager_remove_ui (GTK_UI_MANAGER (sdb_plugin->ui),
2281 sdb_plugin->merge_id);
2282 gtk_ui_manager_remove_action_group (GTK_UI_MANAGER (sdb_plugin->ui),
2283 sdb_plugin->popup_action_group);
2284 gtk_ui_manager_remove_action_group (GTK_UI_MANAGER (sdb_plugin->ui),
2285 sdb_plugin->menu_action_group);
2286 g_signal_handlers_disconnect_by_func (G_OBJECT (plugin->shell),
2287 on_session_load,
2288 plugin);
2290 g_signal_handlers_disconnect_by_func (G_OBJECT (plugin->shell),
2291 on_session_save,
2292 plugin);
2294 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbs),
2295 on_system_scan_package_start,
2296 plugin);
2298 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbs),
2299 on_system_scan_package_end,
2300 plugin);
2302 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbs),
2303 on_system_single_file_scan_end,
2304 plugin);
2306 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbs),
2307 on_scan_end_manager,
2308 plugin);
2310 /* disconnect the interface ones */
2311 /* connect signals for interface to receive them */
2312 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbe_globals),
2313 G_CALLBACK (on_isymbol_manager_sys_scan_end), plugin);
2315 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin->sdbe_project),
2316 G_CALLBACK (on_isymbol_manager_prj_scan_end), plugin);
2318 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
2319 G_CALLBACK (on_project_element_added), plugin);
2321 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
2322 G_CALLBACK (on_project_element_removed), plugin);
2324 g_signal_handlers_disconnect_by_func (G_OBJECT (pm),
2325 G_CALLBACK (on_project_loaded), plugin);
2327 if (sdb_plugin->update_timer)
2329 g_timer_destroy (sdb_plugin->update_timer);
2330 sdb_plugin->update_timer = NULL;
2333 /* destroy search query */
2334 if (sdb_plugin->search_query)
2336 g_object_unref (sdb_plugin->search_query);
2338 sdb_plugin->search_query = NULL;
2340 /* destroy objects */
2341 if (sdb_plugin->sdbe_project)
2343 DEBUG_PRINT ("Destroying project engine object. ");
2344 g_object_unref (sdb_plugin->sdbe_project);
2346 sdb_plugin->sdbe_project = NULL;
2348 PackageScanData *pkg_scan_data;
2349 while ((pkg_scan_data = g_async_queue_try_pop (sdb_plugin->global_scan_aqueue)) != NULL)
2351 g_free (pkg_scan_data->package_name);
2352 g_free (pkg_scan_data->package_version);
2353 g_free (pkg_scan_data);
2356 g_async_queue_unref (sdb_plugin->global_scan_aqueue);
2357 sdb_plugin->global_scan_aqueue = NULL;
2359 /* this must be done *before* destroying sdbe_globals */
2360 g_object_unref (sdb_plugin->sdbs);
2361 sdb_plugin->sdbs = NULL;
2363 g_free (sdb_plugin->current_scanned_package);
2364 sdb_plugin->current_scanned_package = NULL;
2366 DEBUG_PRINT ("Destroying global engine object. ");
2367 g_object_unref (sdb_plugin->sdbe_globals);
2368 sdb_plugin->sdbe_globals = NULL;
2370 g_free (sdb_plugin->project_opened);
2371 sdb_plugin->project_opened = NULL;
2373 if (sdb_plugin->buffer_update_files)
2375 g_ptr_array_unref (sdb_plugin->buffer_update_files);
2376 sdb_plugin->buffer_update_files = NULL;
2379 if (sdb_plugin->buffer_update_ids)
2381 g_ptr_array_unref (sdb_plugin->buffer_update_ids);
2382 sdb_plugin->buffer_update_ids = NULL;
2385 /* Ensure all editor cached info are released */
2386 if (sdb_plugin->editor_connected)
2388 g_hash_table_foreach (sdb_plugin->editor_connected,
2389 on_editor_foreach_disconnect, plugin);
2390 g_hash_table_destroy (sdb_plugin->editor_connected);
2391 sdb_plugin->editor_connected = NULL;
2394 // FIXME
2395 g_tree_destroy (sdb_plugin->proc_id_tree);
2397 /* Remove watches */
2398 anjuta_plugin_remove_watch (plugin, sdb_plugin->root_watch_id, FALSE);
2399 anjuta_plugin_remove_watch (plugin, sdb_plugin->editor_watch_id, TRUE);
2401 /* Remove UI */
2402 anjuta_ui_unmerge (sdb_plugin->ui, sdb_plugin->merge_id);
2404 /* Remove widgets: Widgets will be destroyed when dbv_main is removed */
2405 anjuta_shell_remove_widget (plugin->shell, sdb_plugin->dbv_main, NULL);
2407 sdb_plugin->root_watch_id = 0;
2408 sdb_plugin->editor_watch_id = 0;
2409 sdb_plugin->merge_id = 0;
2410 sdb_plugin->dbv_notebook = NULL;
2411 sdb_plugin->progress_bar_project = NULL;
2412 sdb_plugin->progress_bar_system = NULL;
2413 return TRUE;
2416 static void
2417 symbol_db_finalize (GObject *obj)
2419 DEBUG_PRINT ("Symbol-DB finalize");
2420 /* Finalization codes here */
2421 G_OBJECT_CLASS (parent_class)->finalize (obj);
2424 static void
2425 symbol_db_dispose (GObject *obj)
2427 SymbolDBPlugin *plugin = (SymbolDBPlugin*)obj;
2428 DEBUG_PRINT ("Symbol-DB dispose");
2429 /* Disposition codes */
2430 g_object_unref (plugin->settings);
2433 G_OBJECT_CLASS (parent_class)->dispose (obj);
2436 static void
2437 symbol_db_instance_init (GObject *obj)
2439 SymbolDBPlugin *plugin = (SymbolDBPlugin*)obj;
2441 plugin->files_count_project_done = 0;
2442 plugin->files_count_project = 0;
2444 plugin->files_count_system_done = 0;
2445 plugin->files_count_system = 0;
2446 plugin->current_scanned_package = NULL;
2447 plugin->settings = g_settings_new (PREF_SCHEMA);
2450 static void
2451 symbol_db_class_init (GObjectClass *klass)
2453 AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
2455 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2456 parent_class = g_type_class_peek_parent (klass);
2458 plugin_class->activate = symbol_db_activate;
2459 plugin_class->deactivate = symbol_db_deactivate;
2460 klass->finalize = symbol_db_finalize;
2461 klass->dispose = symbol_db_dispose;
2463 signals[PROJECT_IMPORT_END]
2464 = g_signal_new ("project-import-end",
2465 G_OBJECT_CLASS_TYPE (object_class),
2466 G_SIGNAL_RUN_FIRST,
2467 G_STRUCT_OFFSET (SymbolDBPluginClass, project_import_end),
2468 NULL, NULL,
2469 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2471 signals[GLOBALS_IMPORT_END]
2472 = g_signal_new ("globals-import-end",
2473 G_OBJECT_CLASS_TYPE (object_class),
2474 G_SIGNAL_RUN_FIRST,
2475 G_STRUCT_OFFSET (SymbolDBPluginClass, globals_import_end),
2476 NULL, NULL,
2477 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2480 static void
2481 on_prefs_buffer_update_toggled (GtkToggleButton* button,
2482 gpointer user_data)
2484 SymbolDBPlugin *sdb_plugin;
2485 gboolean sensitive;
2487 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (user_data);
2489 sensitive = gtk_toggle_button_get_active (button);
2491 DEBUG_PRINT ("on_prefs_buffer_update_toggled () %d", sensitive);
2493 if (sensitive == FALSE)
2495 if (sdb_plugin->buf_update_timeout_id)
2496 g_source_remove (sdb_plugin->buf_update_timeout_id);
2497 sdb_plugin->buf_update_timeout_id = 0;
2499 else
2501 if (sdb_plugin->buf_update_timeout_id == 0)
2502 sdb_plugin->buf_update_timeout_id =
2503 g_timeout_add_seconds (TIMEOUT_INTERVAL_SYMBOLS_UPDATE,
2504 on_editor_buffer_symbols_update_timeout,
2505 sdb_plugin);
2509 static void
2510 ipreferences_merge(IAnjutaPreferences* ipref, AnjutaPreferences* prefs, GError** e)
2512 DEBUG_PRINT ("%s", "SymbolDB: ipreferences_merge");
2513 SymbolDBPlugin *sdb_plugin;
2514 GtkWidget *buf_up_widget;
2515 GError* error = NULL;
2517 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (ipref);
2519 if (sdb_plugin->prefs_bxml == NULL)
2521 /* Create the preferences page */
2522 sdb_plugin->prefs_bxml = gtk_builder_new ();
2523 if (!gtk_builder_add_from_file (sdb_plugin->prefs_bxml, BUILDER_FILE, &error))
2525 g_warning ("Couldn't load builder file: %s", error->message);
2526 g_error_free(error);
2530 anjuta_preferences_add_from_builder (prefs,
2531 sdb_plugin->prefs_bxml,
2532 sdb_plugin->settings,
2533 BUILDER_ROOT,
2534 _("Symbol Database"),
2535 ICON_FILE);
2537 buf_up_widget = GTK_WIDGET (gtk_builder_get_object (sdb_plugin->prefs_bxml,
2538 PREFS_BUFFER_UPDATE));
2540 g_signal_connect (buf_up_widget, "toggled",
2541 G_CALLBACK (on_prefs_buffer_update_toggled),
2542 sdb_plugin);
2545 static void
2546 ipreferences_unmerge(IAnjutaPreferences* ipref, AnjutaPreferences* prefs, GError** e)
2548 SymbolDBPlugin *sdb_plugin;
2550 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (ipref);
2552 anjuta_preferences_remove_page(prefs, _("Symbol Database"));
2553 g_object_unref (sdb_plugin->prefs_bxml);
2554 sdb_plugin->prefs_bxml = NULL;
2557 static void
2558 ipreferences_iface_init(IAnjutaPreferencesIface* iface)
2560 DEBUG_PRINT ("%s", "SymbolDB: ipreferences_iface_init");
2561 iface->merge = ipreferences_merge;
2562 iface->unmerge = ipreferences_unmerge;
2565 /* IAnjutaSymbolManager implementation */
2566 static IAnjutaSymbolQuery*
2567 isymbol_manager_create_query (IAnjutaSymbolManager *isymbol_manager,
2568 IAnjutaSymbolQueryName query_name,
2569 IAnjutaSymbolQueryDb db,
2570 GError **err)
2572 SymbolDBPlugin *sdb_plugin;
2573 SymbolDBQuery *query;
2575 g_return_val_if_fail (isymbol_manager != NULL, NULL);
2577 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (isymbol_manager);
2579 query = symbol_db_query_new (sdb_plugin->sdbe_globals,
2580 sdb_plugin->sdbe_project,
2581 query_name,
2583 db == IANJUTA_SYMBOL_QUERY_DB_PROJECT ?
2584 NULL : /* FIXME */ NULL);
2585 return IANJUTA_SYMBOL_QUERY (query);
2588 static gboolean
2589 isymbol_manager_add_package (IAnjutaSymbolManager *isymbol_manager,
2590 const gchar* pkg_name,
2591 const gchar* pkg_version,
2592 GList* files,
2593 GError **err)
2595 SymbolDBPlugin *sdb_plugin;
2596 IAnjutaLanguage *lang_manager;
2597 GPtrArray *files_array;
2598 PackageScanData *pkg_scan_data;
2601 g_return_val_if_fail (isymbol_manager != NULL, FALSE);
2603 /* DEBUG */
2604 GList *node;
2605 node = files;
2606 while (node != NULL)
2608 node = node->next;
2611 /* FIXME: pkg_version comes with \n at the end. This should be avoided */
2612 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (isymbol_manager);
2613 lang_manager = anjuta_shell_get_interface (ANJUTA_PLUGIN (sdb_plugin)->shell, IAnjutaLanguage,
2614 NULL);
2616 if (symbol_db_engine_add_new_project (sdb_plugin->sdbe_globals, NULL, pkg_name,
2617 pkg_version) == FALSE)
2619 return FALSE;
2622 files_array = anjuta_util_convert_string_list_to_array (files);
2624 pkg_scan_data = g_new0 (PackageScanData, 1);
2626 g_async_queue_push (sdb_plugin->global_scan_aqueue, pkg_scan_data);
2627 pkg_scan_data->files_length = g_list_length (files);
2628 pkg_scan_data->package_name = g_strdup (pkg_name);
2629 pkg_scan_data->package_version = g_strdup (pkg_version);
2631 pkg_scan_data->proc_id = 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 /* FIXME: do this thread safe */
2640 static gboolean
2641 isymbol_manager_activate_package (IAnjutaSymbolManager *isymbol_manager,
2642 const gchar *pkg_name,
2643 const gchar *pkg_version,
2644 GError **err)
2646 SymbolDBPlugin *sdb_plugin;
2648 g_return_val_if_fail (isymbol_manager != NULL, FALSE);
2650 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (isymbol_manager);
2652 if (symbol_db_engine_project_exists (sdb_plugin->sdbe_globals, pkg_name,
2653 pkg_version) == TRUE)
2655 /* FIXME: Activate package in database */
2656 DEBUG_PRINT ("STUB");
2657 return TRUE;
2660 /* user should add a package before activating it. */
2661 return FALSE;
2664 static void
2665 isymbol_manager_deactivate_package (IAnjutaSymbolManager *isymbol_manager,
2666 const gchar *pkg_name,
2667 const gchar *pkg_version,
2668 GError **err)
2670 SymbolDBPlugin *sdb_plugin;
2672 g_return_if_fail (isymbol_manager != NULL);
2674 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (isymbol_manager);
2676 if (symbol_db_engine_project_exists (sdb_plugin->sdbe_globals, pkg_name,
2677 pkg_version) == TRUE)
2679 DEBUG_PRINT ("STUB");
2680 /* FIXME: deactivate package in database */
2684 static void
2685 isymbol_manager_deactivate_all (IAnjutaSymbolManager *isymbol_manager,
2686 GError **err)
2688 #if 0
2689 SymbolDBPlugin *sdb_plugin;
2691 g_return_if_fail (isymbol_manager != NULL);
2693 sdb_plugin = ANJUTA_PLUGIN_SYMBOL_DB (isymbol_manager);
2694 #endif
2695 /* FIXME: deactivate all packages in database */
2696 DEBUG_PRINT ("STUB");
2699 static void
2700 isymbol_manager_iface_init (IAnjutaSymbolManagerIface *iface)
2702 iface->create_query = isymbol_manager_create_query;
2703 iface->activate_package = isymbol_manager_activate_package;
2704 iface->deactivate_package = isymbol_manager_deactivate_package;
2705 iface->deactivate_all = isymbol_manager_deactivate_all;
2706 iface->add_package = isymbol_manager_add_package;
2709 ANJUTA_PLUGIN_BEGIN (SymbolDBPlugin, symbol_db);
2710 ANJUTA_PLUGIN_ADD_INTERFACE (isymbol_manager, IANJUTA_TYPE_SYMBOL_MANAGER);
2711 ANJUTA_PLUGIN_ADD_INTERFACE(ipreferences, IANJUTA_TYPE_PREFERENCES);
2712 ANJUTA_PLUGIN_END;
2714 ANJUTA_SIMPLE_PLUGIN (SymbolDBPlugin, symbol_db);