1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) Massimo Cora' 2007-2008 <maxcvs@email.it>
6 * plugin.c is free software.
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)
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.
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>
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
;
88 TASK_IMPORT_PROJECT
= 1,
89 TASK_IMPORT_PROJECT_AFTER_ABORT
,
97 static unsigned int signals
[LAST_SIGNAL
] = { 0 };
100 register_stock_icons (AnjutaPlugin
*plugin
)
102 static gboolean registered
= FALSE
;
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
);
117 goto_file_line (AnjutaPlugin
*plugin
, const gchar
*filename
, gint lineno
)
119 IAnjutaDocumentManager
*docman
;
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
,
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
140 find_file_line (IAnjutaIterable
*iterator
, gboolean impl
, const gchar
*current_document
,
148 const gchar
*symbol_kind
;
150 IAnjutaSymbol
*iter_node
= IANJUTA_SYMBOL (iterator
);
152 if (iter_node
== NULL
)
154 /* not found or some error occurred */
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
)
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
,
179 /* we store the first match incase there is no match against the current document */
180 else if (_line
== -1)
183 _line
= ianjuta_symbol_get_int (iter_node
,
184 IANJUTA_SYMBOL_FIELD_FILE_POS
,
192 } while (ianjuta_iterable_next (iterator
, NULL
) == TRUE
);
201 goto_file_tag (SymbolDBPlugin
*sdb_plugin
, const gchar
*word
,
202 gboolean prefer_implementation
)
204 IAnjutaIterable
*iterator
;
208 gboolean found
= FALSE
;
209 SymbolDBEngine
*engine
;
211 for (i
= 0; i
< 2; i
++)
215 engine
= sdb_plugin
->sdbe_project
;
219 engine
= sdb_plugin
->sdbe_globals
;
223 if (symbol_db_engine_is_connected (engine
))
225 iterator
= ianjuta_symbol_query_search (sdb_plugin
->search_query
,
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
))
238 if ((file
= ianjuta_file_get_file (IANJUTA_FILE (sdb_plugin
->current_editor
),
241 current_document
= g_file_get_path (file
);
242 g_object_unref (file
);
246 path
= find_file_line (iterator
, prefer_implementation
, current_document
, &line
);
250 ianjuta_iterable_first (iterator
, NULL
);
251 path
= find_file_line (iterator
, !prefer_implementation
, current_document
,
257 goto_file_line (ANJUTA_PLUGIN (sdb_plugin
), path
, line
);
262 g_free (current_document
);
266 g_object_unref (iterator
);
268 /* have we found it in the project db? */
275 on_goto_file_tag_impl_activate (GtkAction
*action
, SymbolDBPlugin
*sdb_plugin
)
280 if (sdb_plugin
->current_editor
)
282 ed
= IANJUTA_EDITOR (sdb_plugin
->current_editor
);
283 word
= ianjuta_editor_get_current_word (ed
, NULL
);
286 goto_file_tag (sdb_plugin
, word
, TRUE
);
293 on_goto_file_tag_decl_activate (GtkAction
*action
, SymbolDBPlugin
*sdb_plugin
)
298 if (sdb_plugin
->current_editor
)
300 ed
= IANJUTA_EDITOR (sdb_plugin
->current_editor
);
301 word
= ianjuta_editor_get_current_word (ed
, NULL
);
304 goto_file_tag (sdb_plugin
, word
, FALSE
);
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"),
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"),
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
)
351 editor_buffer_symbols_update (IAnjutaEditor
*editor
, SymbolDBPlugin
*sdb_plugin
)
353 gchar
*current_buffer
= NULL
;
354 gsize buffer_size
= 0;
357 GPtrArray
*real_files_list
;
358 GPtrArray
*text_buffers
;
359 GPtrArray
*buffer_sizes
;
363 /* we won't proceed with the updating of the symbols if we didn't type in
365 if (sdb_plugin
->need_symbols_update
== FALSE
)
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
);
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
),
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
);
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
));
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
,
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
);
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
439 sdb_plugin
->need_symbols_update
= FALSE
;
441 return proc_id
> 0 ? TRUE
: FALSE
;
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
)
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
)
462 seconds_elapsed
= g_timer_elapsed (sdb_plugin
->update_timer
, NULL
);
464 if (seconds_elapsed
< TIMEOUT_SECONDS_AFTER_LAST_TIP
)
467 return editor_buffer_symbols_update (IANJUTA_EDITOR (sdb_plugin
->current_editor
),
472 on_editor_buffer_symbol_update_scan_end (SymbolDBEngine
*dbe
, gint process_id
,
475 SymbolDBPlugin
*sdb_plugin
;
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
))
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
)
501 gboolean tags_update
;
502 if (!IANJUTA_IS_EDITOR (sdb_plugin
->current_editor
))
505 file
= ianjuta_file_get_file (IANJUTA_FILE (sdb_plugin
->current_editor
),
511 local_path
= g_file_get_path (file
);
513 if (local_path
== NULL
)
515 g_critical ("local_path == NULL");
519 /* add a default timeout to the updating of buffer symbols */
520 tags_update
= g_settings_get_boolean (sdb_plugin
->settings
, BUFFER_UPDATE
);
524 sdb_plugin
->buf_update_timeout_id
=
525 g_timeout_add_seconds (TIMEOUT_INTERVAL_SYMBOLS_UPDATE
,
526 on_editor_buffer_symbols_update_timeout
,
531 sdb_plugin
->buffer_update_semaphore
= FALSE
;
536 on_editor_destroy (SymbolDBPlugin
*sdb_plugin
, IAnjutaEditor
*editor
)
539 DEBUG_PRINT ("%s", "on_editor_destroy ()");
540 if (!sdb_plugin
->editor_connected
)
542 DEBUG_PRINT ("%s", "on_editor_destroy (): returning….");
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
);
558 on_editor_update_ui (IAnjutaEditor
*editor
, SymbolDBPlugin
*sdb_plugin
)
560 g_timer_reset (sdb_plugin
->update_timer
);
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
);
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 */
579 sdb_plugin
->need_symbols_update
= TRUE
;
583 on_editor_saved (IAnjutaEditor
*editor
, GFile
* file
,
584 SymbolDBPlugin
*sdb_plugin
)
586 const gchar
*old_uri
;
587 gchar
*local_filename
;
589 GPtrArray
*files_array
;
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. */
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
)
617 old_uri
= g_hash_table_lookup (sdb_plugin
->editor_connected
, editor
);
619 if (old_uri
&& strlen (old_uri
) <= 0)
622 /* files_array will be freed once updating has taken place */
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
);
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
);
648 value_added_current_editor (AnjutaPlugin
*plugin
, const char *name
,
649 const GValue
*value
, gpointer data
)
652 gboolean tags_update
;
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
)
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
,
673 sdb_plugin
->current_editor
= editor
;
675 if (!IANJUTA_IS_EDITOR (editor
))
678 file
= ianjuta_file_get_file (IANJUTA_FILE (editor
), NULL
);
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");
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
;
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
);
711 sdb_plugin
->buf_update_timeout_id
=
712 g_timeout_add_seconds (TIMEOUT_INTERVAL_SYMBOLS_UPDATE
,
713 on_editor_buffer_symbols_update_timeout
,
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
),
725 g_hash_table_insert (sdb_plugin
->editor_connected
, editor
,
730 g_hash_table_insert (sdb_plugin
->editor_connected
, editor
,
734 g_signal_connect (G_OBJECT (editor
), "saved",
735 G_CALLBACK (on_editor_saved
),
737 g_signal_connect (G_OBJECT (editor
), "char-added",
738 G_CALLBACK (on_char_added
),
740 g_signal_connect (G_OBJECT (editor
), "code-added",
741 G_CALLBACK (on_code_added
),
743 g_signal_connect (G_OBJECT(editor
), "update_ui",
744 G_CALLBACK (on_editor_update_ui
),
750 sdb_plugin
->need_symbols_update
= FALSE
;
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
),
759 g_signal_handlers_disconnect_by_func (G_OBJECT(key
),
760 G_CALLBACK (on_editor_update_ui
),
762 g_signal_handlers_disconnect_by_func (G_OBJECT(key
),
763 G_CALLBACK (on_char_added
),
765 g_signal_handlers_disconnect_by_func (G_OBJECT(key
),
766 G_CALLBACK (on_code_added
),
768 g_object_weak_unref (G_OBJECT(key
),
769 (GWeakNotify
) (on_editor_destroy
),
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.
797 do_add_new_files (SymbolDBPlugin
*sdb_plugin
, const GPtrArray
*sources_array
,
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
;
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
,
823 g_critical ("LanguageManager not found");
827 for (i
=0; i
< sources_array
->len
; i
++)
829 const gchar
*file_mime
;
831 const gchar
*local_filename
;
833 GFileInfo
*gfile_info
;
834 IAnjutaLanguageId lang_id
;
836 if ( (local_filename
= g_ptr_array_index (sources_array
, i
)) == NULL
)
839 if ((gfile
= g_file_new_for_path (local_filename
)) == NULL
)
842 gfile_info
= g_file_query_info (gfile
,
843 "standard::content-type",
844 G_FILE_QUERY_INFO_NONE
,
847 if (gfile_info
== NULL
)
849 g_object_unref (gfile
);
853 /* check if it's already present in the list. This avoids
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
);
865 /* you're a dup! we don't want you */
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
,
877 g_object_unref (gfile
);
878 g_object_unref (gfile_info
);
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
);
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
,
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
);
927 on_project_element_added (IAnjutaProjectManager
*pm
, GFile
*gfile
,
928 SymbolDBPlugin
*sdb_plugin
)
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
);
948 sdb_plugin
->is_adding_element
= FALSE
;
951 g_ptr_array_unref (files_array
);
955 on_project_element_removed (IAnjutaProjectManager
*pm
, GFile
*gfile
,
956 SymbolDBPlugin
*sdb_plugin
)
960 if (!sdb_plugin
->project_root_uri
)
963 filename
= g_file_get_path (gfile
);
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
,
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
);
998 on_system_scan_package_end (SymbolDBEngine
*dbe
, const gchar
*package
,
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;
1014 on_system_single_file_scan_end (SymbolDBEngine
*dbe
, gpointer data
)
1016 AnjutaPlugin
*plugin
;
1017 SymbolDBPlugin
*sdb_plugin
;
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
);
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
),
1045 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin
->progress_bar_system
), message
);
1051 on_project_single_file_scan_end (SymbolDBEngine
*dbe
, gpointer data
)
1053 AnjutaPlugin
*plugin
;
1054 SymbolDBPlugin
*sdb_plugin
;
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…"));
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
;
1075 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (sdb_plugin
->progress_bar_project
),
1077 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (sdb_plugin
->progress_bar_project
), message
);
1078 gtk_widget_show (sdb_plugin
->progress_bar_project
);
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
);
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 */
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
;
1112 plugin
= ANJUTA_PLUGIN (sdb_plugin
);
1114 lang_manager
= anjuta_shell_get_interface (plugin
->shell
, IAnjutaLanguage
,
1117 /* create array of languages */
1118 languages_array
= g_ptr_array_new ();
1119 to_scan_array
= g_ptr_array_new ();
1123 g_critical ("LanguageManager not found");
1127 for (i
=0; i
< sources_array
->len
; i
++)
1129 const gchar
*file_mime
;
1131 const gchar
*local_filename
;
1133 GFileInfo
*gfile_info
;
1134 IAnjutaLanguageId lang_id
;
1136 local_filename
= g_ptr_array_index (sources_array
, i
);
1138 if (local_filename
== NULL
)
1141 gfile
= g_file_new_for_path (local_filename
);
1145 gfile_info
= g_file_query_info (gfile
,
1147 G_FILE_QUERY_INFO_NONE
,
1150 if (gfile_info
== NULL
)
1152 g_object_unref (gfile
);
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
,
1164 g_object_unref (gfile
);
1165 g_object_unref (gfile_info
);
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
);
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
,
1189 /* no need to free the GPtrArray, Huston. They'll be auto-destroyed in that
1194 /* we assume that sources_array has already unique elements */
1195 /* note the *project* word in the function */
1197 do_import_project_sources_after_abort (SymbolDBPlugin
*sdb_plugin
,
1198 const GPtrArray
*sources_array
)
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
;
1218 sdb_plugin
->files_count_project
+= real_added
;
1223 do_import_project_sources (SymbolDBPlugin
*sdb_plugin
, IAnjutaProjectManager
*pm
,
1224 const gchar
*root_dir
)
1226 GList
* prj_elements_list
;
1227 GPtrArray
* sources_array
;
1231 prj_elements_list
= ianjuta_project_manager_get_elements (pm
,
1232 ANJUTA_PROJECT_SOURCE
| ANJUTA_PROJECT_PROJECT
,
1235 if (prj_elements_list
== NULL
)
1237 g_warning ("No sources found within this project");
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
)
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.
1296 do_import_system_sources (SymbolDBPlugin
*sdb_plugin
)
1298 /* the resume thing */
1299 GPtrArray
*sys_src_array
= NULL
;
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.
1315 do_update_project_symbols (SymbolDBPlugin
*sdb_plugin
, const gchar
*root_dir
)
1318 /* Update the symbols */
1319 proc_id
= symbol_db_engine_update_project_symbols (sdb_plugin
->sdbe_project
,
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
));
1335 * @return TRUE is a scan process is started, FALSE elsewhere.
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
;
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
,
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
,
1360 for (i
= 0; i
< g_list_length (prj_elements_list
); i
++)
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)
1371 g_object_unref (gfile
);
1375 /* test its existence */
1376 if (g_file_query_exists (gfile
, NULL
) == FALSE
)
1379 g_object_unref (gfile
);
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
1386 g_hash_table_replace (prj_elements_hash
,
1387 (gpointer
) symbol_db_util_get_file_db_path
1388 (sdb_plugin
->sdbe_project
,
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
);
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
,
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
1427 to_add_files
= g_ptr_array_new ();
1428 if (g_hash_table_size (prj_elements_hash
) > 0)
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
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",
1456 if (real_added
<= 0)
1458 sdb_plugin
->is_offline_scanning
= FALSE
;
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
1485 save_session_packages (SymbolDBPlugin
*sdb_plugin
)
1487 GHashTableIter iter
;
1488 gpointer key
, versions
;
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
))
1501 result
= g_string_new (key
);
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
);
1520 on_session_save (AnjutaShell
*shell
, AnjutaSessionPhase phase
,
1521 AnjutaSession
*session
,
1522 SymbolDBPlugin
*sdb_plugin
)
1525 if (phase
!= ANJUTA_SESSION_PHASE_NORMAL
)
1528 DEBUG_PRINT ("%s", "SymbolDB: session_save");
1530 pkgs
= save_session_packages (sdb_plugin
);
1532 anjuta_session_set_string_list (session
,
1539 load_session_packages (SymbolDBPlugin
*sdb_plugin
, GList
*hash_glist
)
1544 while (node
!= NULL
)
1546 if (node
->data
!= NULL
)
1552 split
= g_strsplit (node
->data
, ":", 0);
1554 len
= g_strv_length (split
);
1558 node
= g_list_next (node
);
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
);
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
,
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
,
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
);
1621 IAnjutaDocument
* cur_doc
=
1622 ianjuta_document_manager_get_current_document (docman
, NULL
);
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",
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
);
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
);
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.");
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 */
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
;
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
,
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
);
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");
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
,
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
);
1772 gboolean project_exist
= FALSE
;
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
,
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 ***");
1790 case DB_OPEN_STATUS_NORMAL
:
1791 project_exist
= TRUE
;
1794 case DB_OPEN_STATUS_CREATE
:
1795 case DB_OPEN_STATUS_UPGRADE
:
1796 sdb_plugin
->needs_sources_scan
= TRUE
;
1797 project_exist
= FALSE
;
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
,
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
);
1823 sdb_plugin
->project_root_dir
= root_dir
;
1826 sdb_plugin
->project_root_uri
= g_strdup (root_uri
);
1830 on_project_root_removed (AnjutaPlugin
*plugin
, const gchar
*name
,
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
,
1845 g_signal_handlers_disconnect_by_func (G_OBJECT (pm
),
1846 on_project_element_removed
,
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
;
1877 on_scan_end_manager (SymbolDBEngine
*dbe
, gint process_id
,
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
);
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
,
1907 /* get preferences about the parallel scan */
1908 gboolean parallel_scan
= g_settings_get_boolean (sdb_plugin
->settings
,
1912 /* check the system population has a parallel fashion or not. */
1913 if (parallel_scan
== FALSE
)
1914 do_import_system_sources (sdb_plugin
);
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
);
1923 case TASK_ELEMENT_ADDED
:
1924 DEBUG_PRINT ("received TASK_ELEMENT_ADDED");
1925 sdb_plugin
->is_adding_element
= FALSE
;
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
,
1935 sdb_plugin
->is_offline_scanning
= FALSE
;
1938 case TASK_PROJECT_UPDATE
:
1939 DEBUG_PRINT ("received TASK_PROJECT_UPDATE");
1940 sdb_plugin
->is_project_updating
= FALSE
;
1943 case TASK_FILE_UPDATE
:
1944 DEBUG_PRINT ("received TASK_FILE_UPDATE");
1948 DEBUG_PRINT ("Don't know what to to with task_registered %d",
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
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
);
1986 on_isymbol_manager_prj_scan_end (SymbolDBEngine
*dbe
,
1988 IAnjutaSymbolManager
*sm
)
1990 g_signal_emit_by_name (sm
, "prj-scan-end", process_id
);
1994 on_isymbol_manager_sys_scan_end (SymbolDBEngine
*dbe
,
1996 IAnjutaSymbolManager
*sm
)
1998 g_signal_emit_by_name (sm
, "sys-scan-end", process_id
);
2002 symbol_db_activate (AnjutaPlugin
*plugin
)
2004 IAnjutaProjectManager
*pm
;
2005 SymbolDBPlugin
*sdb_plugin
;
2006 gchar
*anjuta_cache_path
;
2008 GtkWidget
*view
, *label
;
2010 DEBUG_PRINT ("SymbolDBPlugin: Activating SymbolDBPlugin plugin …");
2012 /* Initialize gda library. */
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
);
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",
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");
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");
2078 g_free (ctags_path
);
2081 anjuta_cache_path
= anjuta_util_get_user_cache_file_path (".", NULL
);
2082 if (symbol_db_engine_open_db (sdb_plugin
->sdbe_globals
,
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
,
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
),
2142 gtk_box_pack_start (GTK_BOX(sdb_plugin
->dbv_hbox
), label
,
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
),
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
),
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
),
2161 gtk_box_pack_end (GTK_BOX(sdb_plugin
->dbv_hbox
), sdb_plugin
->tabber
,
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
,
2178 gtk_box_pack_start (GTK_BOX (sdb_plugin
->dbv_main
), sdb_plugin
->progress_bar_project
,
2180 gtk_box_pack_start (GTK_BOX (sdb_plugin
->dbv_main
), sdb_plugin
->progress_bar_system
,
2182 gtk_widget_show_all (sdb_plugin
->dbv_main
);
2185 view
= symbol_db_view_new (SYMBOL_DB_VIEW_FILE
, sdb_plugin
->sdbe_project
,
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
,
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
,
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
);
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"),
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"),
2240 G_N_ELEMENTS (actions_search
),
2241 GETTEXT_PACKAGE
, FALSE
, plugin
);
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
,
2275 ianjuta_symbol_query_set_fields (sdb_plugin
->search_query
,
2276 G_N_ELEMENTS (search_fields
),
2277 search_fields
, NULL
);
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 …");
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
),
2307 g_signal_handlers_disconnect_by_func (G_OBJECT (plugin
->shell
),
2311 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin
->sdbs
),
2312 on_system_scan_package_start
,
2315 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin
->sdbs
),
2316 on_system_scan_package_end
,
2319 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin
->sdbs
),
2320 on_system_single_file_scan_end
,
2323 g_signal_handlers_disconnect_by_func (G_OBJECT (sdb_plugin
->sdbs
),
2324 on_scan_end_manager
,
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
;
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
);
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
;
2429 symbol_db_finalize (GObject
*obj
)
2431 DEBUG_PRINT ("Symbol-DB finalize");
2432 /* Finalization codes here */
2433 G_OBJECT_CLASS (parent_class
)->finalize (obj
);
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
);
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
);
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
),
2479 G_STRUCT_OFFSET (SymbolDBPluginClass
, project_import_end
),
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
),
2487 G_STRUCT_OFFSET (SymbolDBPluginClass
, globals_import_end
),
2489 g_cclosure_marshal_VOID__VOID
, G_TYPE_NONE
, 0);
2493 on_prefs_buffer_update_toggled (GtkToggleButton
* button
,
2496 SymbolDBPlugin
*sdb_plugin
;
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;
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
,
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
,
2546 _("Symbol Database"),
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
),
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
;
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
,
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
);
2597 isymbol_manager_add_package (IAnjutaSymbolManager
*isymbol_manager
,
2598 const gchar
* pkg_name
,
2599 const gchar
* pkg_version
,
2603 SymbolDBPlugin
*sdb_plugin
;
2604 IAnjutaLanguage
*lang_manager
;
2605 GPtrArray
*files_array
;
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
,
2614 if (symbol_db_engine_add_new_project (sdb_plugin
->sdbe_globals
, NULL
, pkg_name
,
2615 pkg_version
) == FALSE
)
2620 files_array
= g_ptr_array_sized_new (g_list_length (files
));
2621 g_ptr_array_set_free_func (files_array
, g_free
);
2624 while (node
!= NULL
)
2626 g_ptr_array_add (files_array
, g_strdup (node
->data
));
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
);
2640 isymbol_manager_activate_package (IAnjutaSymbolManager
*isymbol_manager
,
2641 const gchar
*pkg_name
,
2642 const gchar
*pkg_version
,
2645 SymbolDBPlugin
*sdb_plugin
;
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
)
2657 /* if the package is already activated return true */
2659 while (node
!= NULL
)
2661 if (g_strcmp0 (node
->data
, pkg_version
) == 0)
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
),
2687 /* nothing found on db. This is hopeless */
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
),
2704 /* user should add a package before activating it. */
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
);
2719 ANJUTA_SIMPLE_PLUGIN (SymbolDBPlugin
, symbol_db
);