1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) Massimo Cora' 2007 <maxcvs@email.it>
6 * anjuta 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 * anjuta 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 anjuta. 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-utils.h>
28 #include <libanjuta/anjuta-debug.h>
30 #include "symbol-db-view-locals.h"
31 #include "symbol-db-engine.h"
32 #include "symbol-db-engine-iterator.h"
33 #include "symbol-db-engine-iterator-node.h"
34 #include "symbol-db-view.h"
44 static GtkTreeViewClass
*parent_class
= NULL
;
47 typedef struct _WaitingForSymbol
{
49 gchar
*child_symbol_name
;
50 const GdkPixbuf
*pixbuf
;
54 typedef struct _TraverseData
{
55 SymbolDBViewLocals
*dbvl
;
60 typedef struct _FileSymbolsStatus
{
62 GTree
*nodes_displayed
;
64 GQueue
*symbols_inserted_ids
;
68 struct _SymbolDBViewLocalsPriv
{
69 gchar
*current_db_file
;
70 gchar
*current_local_file_path
;
73 gint scan_end_handler
;
74 gint insertion_idle_handler
;
76 GTree
*nodes_displayed
;
78 GQueue
*symbols_inserted_ids
;
80 gboolean recv_signals
;
81 GHashTable
*files_view_status
;
86 trigger_on_symbol_inserted (SymbolDBViewLocals
*dbvl
, gint symbol_id
);
90 gtree_compare_func (gconstpointer a
, gconstpointer b
, gpointer user_data
)
92 return (gint
)a
- (gint
)b
;
96 waiting_for_symbol_destroy (WaitingForSymbol
*wfs
)
98 g_return_if_fail (wfs
!= NULL
);
99 g_free (wfs
->child_symbol_name
);
104 traverse_free_waiting_for (gpointer key
, gpointer value
, gpointer data
)
106 if (value
== NULL
|| key
== NULL
)
109 g_slist_foreach ((GSList
*)value
, (GFunc
)waiting_for_symbol_destroy
, NULL
);
110 g_slist_free ((GSList
*)value
);
115 file_view_status_destroy (FileSymbolsStatus
*fss
)
117 g_object_unref (fss
->store
);
119 if (fss
->nodes_displayed
)
120 g_tree_destroy (fss
->nodes_displayed
);
122 /* free the waiting_for structs before destroying the tree itself */
123 if (fss
->waiting_for
)
125 g_tree_foreach (fss
->waiting_for
, traverse_free_waiting_for
, NULL
);
126 g_tree_destroy (fss
->waiting_for
);
132 static GtkTreeStore
*
133 sdb_view_locals_create_new_store ()
136 store
= gtk_tree_store_new (COLUMN_MAX
, GDK_TYPE_PIXBUF
,
137 G_TYPE_STRING
, G_TYPE_INT
);
138 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store
),
145 traverse_files_view_status (gpointer key
, gpointer value
, gpointer user_data
)
150 /* the function will check for a NULL row_ref of its associated path. In that
151 * case will return FALSE
153 static inline gboolean
154 sdb_view_locals_get_iter_from_row_ref (SymbolDBViewLocals
*dbvl
,
155 GtkTreeRowReference
*row_ref
,
156 GtkTreeIter
*OUT_iter
)
161 /* no node displayed found */
165 path
= gtk_tree_row_reference_get_path (row_ref
);
168 DEBUG_PRINT ("sdb_view_locals_get_iter_from_row_ref (): path is null, something "
173 if (gtk_tree_model_get_iter (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)),
174 OUT_iter
, path
) == FALSE
)
176 gtk_tree_path_free (path
);
179 gtk_tree_path_free (path
);
185 symbol_db_view_locals_clear_cache (SymbolDBViewLocals
*dbvl
)
187 SymbolDBViewLocalsPriv
*priv
;
189 gpointer hash_node
= NULL
;
191 g_return_if_fail (dbvl
!= NULL
);
195 DEBUG_PRINT ("symbol_db_view_locals_clear_cache ()");
196 /* check whether we already have the view status saved on hash table or not.
197 * If we saved that then don't remove it, or there may be a memory leak
199 if (priv
->current_db_file
!= NULL
)
201 DEBUG_PRINT ("priv->current_db_file %s ", priv
->current_db_file
);
202 hash_node
= g_hash_table_lookup (priv
->files_view_status
,
203 priv
->current_db_file
);
206 if (hash_node
== NULL
)
208 if (priv
->nodes_displayed
)
210 g_tree_destroy (priv
->nodes_displayed
);
211 priv
->nodes_displayed
= NULL
;
214 /* free the waiting_for structs before destroying the tree itself */
215 if (priv
->waiting_for
)
217 g_tree_foreach (priv
->waiting_for
, traverse_free_waiting_for
, NULL
);
218 g_tree_destroy (priv
->waiting_for
);
219 priv
->waiting_for
= NULL
;
222 store
= GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)));
224 g_object_unref (store
);
227 gtk_tree_view_set_model (GTK_TREE_VIEW (dbvl
), NULL
);
229 g_free (priv
->current_db_file
);
230 priv
->current_db_file
= NULL
;
232 g_free (priv
->current_local_file_path
);
233 priv
->current_local_file_path
= NULL
;
235 if (priv
->files_view_status
)
237 g_hash_table_foreach_remove (priv
->files_view_status
,
238 traverse_files_view_status
, NULL
);
241 priv
->waiting_for
= NULL
;
242 priv
->nodes_displayed
= NULL
;
247 sdb_view_locals_init (SymbolDBViewLocals
*dbvl
)
249 DEBUG_PRINT ("sdb_view_locals_init ()");
250 GtkTreeViewColumn
*column
;
251 GtkCellRenderer
*renderer
;
252 GtkTreeSelection
*selection
;
254 SymbolDBViewLocalsPriv
*priv
;
256 g_return_if_fail (dbvl
!= NULL
);
258 dbvl
->priv
= g_new0 (SymbolDBViewLocalsPriv
, 1);
261 priv
->current_db_file
= NULL
;
262 priv
->current_local_file_path
= NULL
;
263 priv
->nodes_displayed
= NULL
;
264 priv
->waiting_for
= NULL
;
265 priv
->symbols_inserted_ids
= NULL
;
266 priv
->insert_handler
= 0;
267 priv
->scan_end_handler
= 0;
268 priv
->remove_handler
= 0;
269 priv
->insertion_idle_handler
= 0;
270 priv
->files_view_status
= g_hash_table_new_full (g_str_hash
,
271 g_str_equal
, g_free
, (GDestroyNotify
)file_view_status_destroy
);
273 priv
->recv_signals
= FALSE
;
275 /* initially set it to NULL */
278 gtk_tree_view_set_model (GTK_TREE_VIEW (dbvl
), GTK_TREE_MODEL (store
));
279 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dbvl
), FALSE
);
281 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (dbvl
));
282 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_SINGLE
);
284 /* search through the tree interactively */
285 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (dbvl
), TRUE
);
286 gtk_tree_view_set_search_column (GTK_TREE_VIEW (dbvl
), COLUMN_NAME
);
289 column
= gtk_tree_view_column_new ();
290 gtk_tree_view_column_set_sizing (column
,
291 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
292 gtk_tree_view_column_set_title (column
, _("Symbol"));
294 renderer
= gtk_cell_renderer_pixbuf_new ();
295 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
296 gtk_tree_view_column_add_attribute (column
, renderer
, "pixbuf",
299 renderer
= gtk_cell_renderer_text_new ();
300 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
301 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
304 gtk_tree_view_append_column (GTK_TREE_VIEW (dbvl
), column
);
305 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (dbvl
), column
);
308 * gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (dbvl), FALSE); */
312 sdb_view_locals_finalize (GObject
*object
)
314 SymbolDBViewLocals
*locals
;
315 SymbolDBViewLocalsPriv
*priv
;
317 g_return_if_fail (object
!= NULL
);
319 locals
= SYMBOL_DB_VIEW_LOCALS (object
);
322 DEBUG_PRINT ("finalizing symbol_db_view_locals ()");
324 symbol_db_view_locals_clear_cache (locals
);
325 g_hash_table_destroy (priv
->files_view_status
);
328 G_OBJECT_CLASS (parent_class
)->finalize (object
);
332 sdb_view_locals_class_init (SymbolDBViewLocalsClass
*klass
)
334 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
335 parent_class
= g_type_class_peek_parent (klass
);
337 object_class
->finalize
= sdb_view_locals_finalize
;
341 symbol_db_view_locals_get_type (void)
343 static GType our_type
= 0;
347 static const GTypeInfo our_info
=
349 sizeof (SymbolDBViewLocalsClass
), /* class_size */
350 (GBaseInitFunc
) NULL
, /* base_init */
351 (GBaseFinalizeFunc
) NULL
, /* base_finalize */
352 (GClassInitFunc
) sdb_view_locals_class_init
, /* class_init */
353 (GClassFinalizeFunc
) NULL
, /* class_finalize */
354 NULL
/* class_data */,
355 sizeof (SymbolDBViewLocals
), /* instance_size */
357 (GInstanceInitFunc
) sdb_view_locals_init
, /* instance_init */
358 NULL
/* value_table */
361 our_type
= g_type_register_static (GTK_TYPE_TREE_VIEW
, "SymbolDBViewLocals",
369 symbol_db_view_locals_new (void)
371 return GTK_WIDGET (g_object_new (SYMBOL_TYPE_DB_VIEW_LOCALS
, NULL
));
374 static GtkTreeRowReference
*
375 do_add_root_symbol_to_view (SymbolDBViewLocals
*dbvl
, const GdkPixbuf
*pixbuf
,
376 const gchar
* symbol_name
, gint symbol_id
)
378 SymbolDBViewLocalsPriv
*priv
;
380 GtkTreeIter child_iter
;
382 GtkTreeRowReference
*row_ref
;
384 g_return_val_if_fail (dbvl
!= NULL
, NULL
);
388 store
= GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)));
390 gtk_tree_store_append (store
, &child_iter
, NULL
);
391 gtk_tree_store_set (store
, &child_iter
,
392 COLUMN_PIXBUF
, pixbuf
,
393 COLUMN_NAME
, symbol_name
,
394 COLUMN_SYMBOL_ID
, symbol_id
,
397 path
= gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)),
399 row_ref
= gtk_tree_row_reference_new (
400 gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)), path
);
401 gtk_tree_path_free (path
);
406 static GtkTreeRowReference
*
407 do_add_child_symbol_to_view (SymbolDBViewLocals
*dbvl
, gint parent_symbol_id
,
408 const GdkPixbuf
*pixbuf
, const gchar
* symbol_name
,
411 SymbolDBViewLocalsPriv
*priv
;
414 GtkTreeIter iter
, child_iter
;
415 GtkTreeRowReference
*row_ref
;
417 g_return_val_if_fail (dbvl
!= NULL
, NULL
);
421 store
= GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)));
423 /* look up the row ref in the hashtable, then get its associated gtktreeiter */
424 row_ref
= g_tree_lookup (priv
->nodes_displayed
, (gpointer
)parent_symbol_id
);
426 if (sdb_view_locals_get_iter_from_row_ref (dbvl
, row_ref
, &iter
) == FALSE
)
428 g_warning ("do_add_symbol_to_view (): something went wrong.");
432 /* append a new child &child_iter, with a parent of &iter */
433 gtk_tree_store_append (store
, &child_iter
, &iter
);
435 gtk_tree_store_set (store
, &child_iter
,
436 COLUMN_PIXBUF
, pixbuf
,
437 COLUMN_NAME
, symbol_name
,
438 COLUMN_SYMBOL_ID
, symbol_id
,
441 /* grab the row ref and return it */
442 path
= gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)),
444 row_ref
= gtk_tree_row_reference_new (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)),
446 gtk_tree_path_free (path
);
451 traverse_on_scan_end (gpointer key
, gpointer value
, gpointer data
)
455 SymbolDBViewLocals
*dbvl
;
456 SymbolDBViewLocalsPriv
*priv
;
457 SymbolDBEngineIterator
*iterator
;
460 g_return_val_if_fail (data
!= NULL
, FALSE
);
462 tdata
= (TraverseData
*)data
;
467 g_return_val_if_fail (dbe
!= NULL
, FALSE
);
468 g_return_val_if_fail (dbvl
!= NULL
, FALSE
);
472 parent_id
= (gint
) key
;
473 DEBUG_PRINT ("traverse_on_scan_end (): something has been left on "
474 "waiting_for_tree.. checking for %d", parent_id
);
476 iterator
= symbol_db_engine_get_symbol_info_by_id (dbe
, parent_id
,
480 if (iterator
!= NULL
)
482 SymbolDBEngineIteratorNode
*iter_node
;
483 const GdkPixbuf
*pixbuf
;
484 const gchar
* symbol_name
;
485 GtkTreeRowReference
*row_ref
= NULL
;
488 iter_node
= SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator
);
490 pixbuf
= symbol_db_view_get_pixbuf (
491 symbol_db_engine_iterator_node_get_symbol_extra_string (
492 iter_node
, SYMINFO_KIND
),
493 symbol_db_engine_iterator_node_get_symbol_extra_string (
494 iter_node
, SYMINFO_ACCESS
));
495 symbol_name
= symbol_db_engine_iterator_node_get_symbol_name (iter_node
);
497 /* ok, we can have the last case in which this parent_id is a class, that,
498 * suppose, is inside an already displayed namespace node.
500 grandparent_id
= symbol_db_engine_get_parent_scope_id_by_symbol_id (dbe
,
502 priv
->current_db_file
);
503 DEBUG_PRINT ("traverse_on_scan_end (): grandparent_id %d", grandparent_id
);
505 if (grandparent_id
> 0)
508 g_tree_lookup (priv
->nodes_displayed
, (gpointer
)grandparent_id
);
511 /* hey we have a namespace or something which is the parent of
514 DEBUG_PRINT ("traverse_on_scan_end (): adding parent_id %d "
515 "to grandparent %d", parent_id
,
517 row_ref
= do_add_child_symbol_to_view (dbvl
, grandparent_id
, pixbuf
,
518 symbol_name
, parent_id
);
520 g_tree_insert (priv
->nodes_displayed
, (gpointer
)parent_id
,
523 /* DEBUG_PRINT ("traverse_on_scan_end (): row_ref %d", row_ref);*/
526 /* we're in the case that no grandparent has been found */
530 row_ref
= do_add_root_symbol_to_view (dbvl
, pixbuf
,
531 symbol_name
, parent_id
);
532 g_tree_insert (priv
->nodes_displayed
, (gpointer
)parent_id
,
536 /* now the waiters should be added as children */
537 trigger_on_symbol_inserted (dbvl
, parent_id
);
539 g_object_unref (iterator
);
542 /* continue the traversing */
548 add_waiting_for_symbol_to_view (SymbolDBViewLocals
*dbvl
, WaitingForSymbol
*wfs
,
549 gint parent_symbol_id
)
551 SymbolDBViewLocalsPriv
*priv
;
552 gint symbol_id_added
;
553 GtkTreeRowReference
*child_tree_row_ref
;
555 g_return_if_fail (dbvl
!= NULL
);
556 g_return_if_fail (wfs
!= NULL
);
560 child_tree_row_ref
= do_add_child_symbol_to_view (dbvl
, parent_symbol_id
,
561 wfs
->pixbuf
, wfs
->child_symbol_name
, wfs
->child_symbol_id
);
563 symbol_id_added
= wfs
->child_symbol_id
;
565 /* add a new entry on gtree 'nodes_displayed' */
566 g_tree_insert (priv
->nodes_displayed
, (gpointer
)wfs
->child_symbol_id
,
569 /* and now trigger the inserted symbol... (recursive function). */
570 if (wfs
->child_symbol_id
!= parent_symbol_id
)
571 trigger_on_symbol_inserted (dbvl
, wfs
->child_symbol_id
);
575 trigger_on_symbol_inserted (SymbolDBViewLocals
*dbvl
, gint symbol_id
)
577 SymbolDBViewLocalsPriv
*priv
;
579 WaitingForSymbol
*wfs
;
581 g_return_if_fail (dbvl
!= NULL
);
585 /* DEBUG_PRINT ("trigger_on_symbol_inserted (): triggering %d", symbol_id);*/
587 /* try to find a waiting for symbol */
588 slist
= g_tree_lookup (priv
->waiting_for
, (gpointer
)symbol_id
);
592 /* nothing waiting for us */
593 /* DEBUG_PRINT ("trigger_on_symbol_inserted (): no children waiting for us...");*/
598 gint length
= g_slist_length (slist
);
600 /* DEBUG_PRINT ("trigger_on_symbol_inserted (): consuming slist for parent %d",
603 for (i
=0; i
< length
-1; i
++)
605 wfs
= g_slist_nth_data (slist
, 0);
607 slist
= g_slist_remove (slist
, wfs
);
609 add_waiting_for_symbol_to_view (dbvl
, wfs
, symbol_id
);
611 /* destroy the data structure */
612 waiting_for_symbol_destroy (wfs
);
615 /* remove the waiting for key/value */
616 g_tree_remove (priv
->waiting_for
, (gpointer
)symbol_id
);
617 g_slist_free (slist
);
622 add_new_waiting_for (SymbolDBViewLocals
*dbvl
, gint parent_symbol_id
,
623 const gchar
* symbol_name
,
624 gint symbol_id
, const GdkPixbuf
*pixbuf
)
626 SymbolDBViewLocalsPriv
*priv
;
629 g_return_if_fail (dbvl
!= NULL
);
632 /* check if we already have some children waiting for a
633 * specific father to be inserted, then add this symbol_id to the list
634 * (or create a new one)
636 WaitingForSymbol
*wfs
;
638 wfs
= g_new0 (WaitingForSymbol
, 1);
639 wfs
->child_symbol_id
= symbol_id
;
640 wfs
->child_symbol_name
= g_strdup (symbol_name
);
641 wfs
->pixbuf
= pixbuf
;
643 /* DEBUG_PRINT ("add_new_waiting_for (): looking up waiting_for %d",
645 node
= g_tree_lookup (priv
->waiting_for
, (gpointer
)parent_symbol_id
);
648 /* no lists already set. Create one. */
650 slist
= g_slist_alloc ();
652 slist
= g_slist_prepend (slist
, wfs
);
654 /*DEBUG_PRINT ("add_new_waiting_for (): NEW adding to "
655 "waiting_for [%d]", parent_symbol_id);*/
657 /* add it to the binary tree. */
658 g_tree_insert (priv
->waiting_for
, (gpointer
)parent_symbol_id
,
665 slist
= (GSList
*)node
;
667 /*DEBUG_PRINT ("prepare_for_adding (): NEW adding to "
668 "parent_waiting_for_list [%d] %s",
669 parent_symbol_id, symbol_name);*/
670 slist
= g_slist_prepend (slist
, wfs
);
672 g_tree_replace (priv
->waiting_for
, (gpointer
)parent_symbol_id
,
677 /* Put every GtkTreeView node of the subtree headed by 'parent_subtree_iter'
678 * into a waiting_for GTree.
679 * It's a recursive function.
682 do_recurse_subtree_and_invalidate (SymbolDBViewLocals
*dbvl
,
683 GtkTreeIter
*parent_subtree_iter
,
684 gint parent_id_to_wait_for
)
687 const GdkPixbuf
*curr_pixbuf
;
689 gchar
*curr_symbol_name
;
691 SymbolDBViewLocalsPriv
*priv
;
693 g_return_if_fail (dbvl
!= NULL
);
696 store
= GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)));
698 gtk_tree_model_get (GTK_TREE_MODEL (store
), parent_subtree_iter
,
699 COLUMN_SYMBOL_ID
, &curr_symbol_id
,
700 COLUMN_PIXBUF
, &curr_pixbuf
,
701 COLUMN_NAME
, &curr_symbol_name
, /* no strdup required */
704 /*DEBUG_PRINT ("do_recurse_subtree_and_invalidate (): curr_symbol_id %d,"
705 "parent_id_to_wait_for %d", curr_symbol_id, parent_id_to_wait_for);*/
707 while (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (store
),
708 parent_subtree_iter
))
711 gtk_tree_model_iter_children (GTK_TREE_MODEL (store
), &child
,
712 parent_subtree_iter
);
715 do_recurse_subtree_and_invalidate (dbvl
, &child
, curr_symbol_id
);
718 /* add to waiting for */
719 add_new_waiting_for (dbvl
, parent_id_to_wait_for
, curr_symbol_name
,
720 curr_symbol_id
, curr_pixbuf
);
722 gtk_tree_store_remove (store
, parent_subtree_iter
);
723 g_tree_remove (priv
->nodes_displayed
, (gpointer
) curr_symbol_id
);
725 /* don't forget to free this gchar */
726 g_free (curr_symbol_name
);
730 /* Add promptly a symbol to the gtktreeview or add it for a later add (waiting
734 prepare_for_adding (SymbolDBViewLocals
*dbvl
, gint parent_symbol_id
,
735 const gchar
* symbol_name
, gint symbol_id
,
736 const GdkPixbuf
*pixbuf
)
738 SymbolDBViewLocalsPriv
*priv
;
740 g_return_if_fail (dbvl
!= NULL
);
743 /* add to root if parent_symbol_id is <= 0 */
744 if (parent_symbol_id
<= 0)
746 GtkTreeRowReference
*curr_tree_row_ref
;
747 /* DEBUG_PRINT ("prepare_for_adding(): parent_symbol_id <= 0 root with id [%d]",
750 /* get the current iter row reference in the just added root gtktreeview
753 curr_tree_row_ref
= do_add_root_symbol_to_view (dbvl
, pixbuf
, symbol_name
,
756 /* we'll fake the gpointer to store an int */
757 g_tree_insert (priv
->nodes_displayed
, (gpointer
)symbol_id
,
760 /* let's trigger the insertion of the symbol_id, there may be some children
763 trigger_on_symbol_inserted (dbvl
, symbol_id
);
768 /* do we already have that parent_symbol displayed in gtktreeview?
769 * If that's the case add it as children.
771 node
= g_tree_lookup (priv
->nodes_displayed
, (gpointer
)parent_symbol_id
);
775 /* hey we found it */
776 GtkTreeRowReference
*child_row_ref
;
777 /* DEBUG_PRINT ("prepare_for_adding(): found node already displayed %d",
780 child_row_ref
= do_add_child_symbol_to_view (dbvl
, parent_symbol_id
,
781 pixbuf
, symbol_name
, symbol_id
);
783 /* add the children_path to the GTree. */
784 g_tree_insert (priv
->nodes_displayed
, (gpointer
)symbol_id
,
786 trigger_on_symbol_inserted (dbvl
, symbol_id
);
790 /* DEBUG_PRINT ("prepare_for_adding(): gonna pass parent: %d name: %s "
791 "id: %d to add_new_waiting_for", parent_symbol_id,
792 symbol_name, symbol_id);*/
794 /* add it to the waiting_for trigger list */
795 add_new_waiting_for (dbvl
, parent_symbol_id
, symbol_name
, symbol_id
,
802 consume_symbols_inserted_queue_idle_destroy (gpointer data
)
805 SymbolDBViewLocals
*dbvl
;
807 SymbolDBViewLocalsPriv
*priv
;
808 gint waiting_for_size
;
810 tdata
= (TraverseData
*)data
;
814 g_return_if_fail (dbvl
!= NULL
);
817 tdata
= (TraverseData
*)data
;
819 DEBUG_PRINT ("consume_symbols_inserted_queue_idle_destroy");
820 priv
->insertion_idle_handler
= 0;
822 if (g_queue_get_length (priv
->symbols_inserted_ids
) <= 0)
824 /* ok, symbol parsing has ended, are we sure that all the waiting_for
825 * objects have been checked?
826 * If it's not the case then try to add it to the on the root of the gtktreeview
827 * and to trigger the insertion.
829 if (priv
->waiting_for
== NULL
||
830 (waiting_for_size
= g_tree_nnodes (priv
->waiting_for
)) <= 0)
833 /* we have something left. Search the parent_symbol_id [identified by the
836 DEBUG_PRINT ("destroying tdata");
837 g_tree_foreach (priv
->waiting_for
, traverse_on_scan_end
, tdata
);
844 consume_symbols_inserted_queue_idle (gpointer data
)
847 SymbolDBViewLocals
*dbvl
;
849 SymbolDBViewLocalsPriv
*priv
;
850 SymbolDBEngineIterator
*iterator
;
852 gint consumed_symbol_id
;
855 /* it's not obligatory referred to a class inheritance */
856 gint parent_symbol_id
;
858 tdata
= (TraverseData
*)data
;
862 g_return_val_if_fail (dbvl
!= NULL
, FALSE
);
866 queue_length
= g_queue_get_length (priv
->symbols_inserted_ids
);
868 /* DEBUG_PRINT ("consume_symbols_inserted_queue_idle [remaining %d]", queue_length);*/
870 /* consume a symbol */
871 if (queue_length
> 0)
873 consumed_symbol_id
= (gint
) g_queue_pop_head (priv
->symbols_inserted_ids
);
879 store
= GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)));
881 /* again we use a little trick to insert symbols here. First of all forget chars
882 * and symbol names. They are too much cpu-intensive. We'll use symbol-ids instead.
884 * Suppose we have a symbol_id X to insert. Where should we put it into the
885 * gtktree? Well.. look at its parent! By knowing its parent we're able to
886 * know the right place where to store this child, being it on the root /
887 * or under some path. Please note this: the whole path isn't computed at once
888 * when the global gtk tree view is loaded, but it's incremental. So we can
889 * have a case where our symbol X has a parent Y, but that parent isn't already
890 * mapped into the gtktreestore: we'll just avoid to insert 'visually' the
894 parent_symbol_id
= symbol_db_engine_get_parent_scope_id_by_symbol_id (dbe
,
896 priv
->current_db_file
);
897 /* try in a global fashion */
898 if (parent_symbol_id
<= 0)
899 parent_symbol_id
= symbol_db_engine_get_parent_scope_id_by_symbol_id (dbe
,
903 /* get the original symbol infos */
904 iterator
= symbol_db_engine_get_symbol_info_by_id (dbe
, consumed_symbol_id
,
909 if (iterator
!= NULL
)
911 SymbolDBEngineIteratorNode
*iter_node
;
912 const GdkPixbuf
*pixbuf
;
913 const gchar
* symbol_name
;
915 iter_node
= SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator
);
917 pixbuf
= symbol_db_view_get_pixbuf (
918 symbol_db_engine_iterator_node_get_symbol_extra_string (
919 iter_node
, SYMINFO_KIND
),
920 symbol_db_engine_iterator_node_get_symbol_extra_string (
921 iter_node
, SYMINFO_ACCESS
));
922 symbol_name
= symbol_db_engine_iterator_node_get_symbol_name (iter_node
);
924 /* check if one of the children [if they exist] of symbol_id are already
925 * displayed. In that case we'll invalidate all of them.
926 * i.e. we're in an updating insertion.
928 SymbolDBEngineIterator
*iterator_for_children
;
929 iterator_for_children
=
930 symbol_db_engine_get_scope_members_by_symbol_id (dbe
, consumed_symbol_id
, -1,
933 if (iterator_for_children
== NULL
)
935 /* we don't have children */
936 /*DEBUG_PRINT ("on_symbol_inserted (): %d has no children.", symbol_id);*/
940 /* hey there are some children here.. kill 'em all and put them on
946 GtkTreeIter child_iter
;
947 GtkTreeRowReference
*row_ref
;
948 SymbolDBEngineIteratorNode
*iter_node
;
950 iter_node
= SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator_for_children
);
953 symbol_db_engine_iterator_node_get_symbol_id (iter_node
);
955 row_ref
= g_tree_lookup (priv
->nodes_displayed
,
956 (gpointer
)curr_child_id
);
961 if (sdb_view_locals_get_iter_from_row_ref (dbvl
,
962 row_ref
, &child_iter
) == FALSE
)
964 g_warning ("on_symbol_inserted (): something went wrong");
968 /* put on waiting_for the subtree */
969 do_recurse_subtree_and_invalidate (dbvl
, &child_iter
, consumed_symbol_id
);
970 } while (symbol_db_engine_iterator_move_next (iterator_for_children
)
973 g_object_unref (iterator_for_children
);
976 prepare_for_adding (dbvl
, parent_symbol_id
, symbol_name
, consumed_symbol_id
,
979 g_object_unref (iterator
);
982 gtk_tree_view_expand_all (GTK_TREE_VIEW (dbvl
));
988 on_scan_end (SymbolDBEngine
*dbe
, gpointer data
)
990 SymbolDBViewLocals
*dbvl
;
991 SymbolDBViewLocalsPriv
*priv
;
994 dbvl
= SYMBOL_DB_VIEW_LOCALS (data
);
995 g_return_if_fail (dbvl
!= NULL
);
998 tdata
= g_new (TraverseData
, 1);
1002 DEBUG_PRINT ("locals: on_scan_end");
1003 if (priv
->symbols_inserted_ids
!= NULL
)
1005 if (g_queue_get_length (priv
->symbols_inserted_ids
) > 0)
1007 /* reverswe the queue */
1008 g_queue_reverse (priv
->symbols_inserted_ids
);
1010 priv
->insertion_idle_handler
= g_idle_add_full (G_PRIORITY_LOW
,
1011 (GSourceFunc
) consume_symbols_inserted_queue_idle
,
1013 (GDestroyNotify
) consume_symbols_inserted_queue_idle_destroy
);
1019 do_recurse_subtree_and_remove (SymbolDBViewLocals
*dbvl
,
1020 GtkTreeIter
*parent_subtree_iter
)
1022 gint curr_symbol_id
;
1023 const GdkPixbuf
*curr_pixbuf
;
1024 GtkTreeStore
*store
;
1025 gchar
*curr_symbol_name
;
1027 SymbolDBViewLocalsPriv
*priv
;
1029 g_return_if_fail (dbvl
!= NULL
);
1032 store
= GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)));
1034 gtk_tree_model_get (GTK_TREE_MODEL (store
), parent_subtree_iter
,
1035 COLUMN_SYMBOL_ID
, &curr_symbol_id
,
1036 COLUMN_PIXBUF
, &curr_pixbuf
,
1037 COLUMN_NAME
, &curr_symbol_name
, /* no strdup required */
1040 /*DEBUG_PRINT ("do_recurse_subtree_and_remove (): curr_symbol_id %d",
1043 while (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (store
), parent_subtree_iter
))
1046 gtk_tree_model_iter_children (GTK_TREE_MODEL (store
), &child
, parent_subtree_iter
);
1049 do_recurse_subtree_and_remove (dbvl
, &child
);
1052 gtk_tree_store_remove (store
, parent_subtree_iter
);
1053 g_tree_remove (priv
->nodes_displayed
, (gpointer
) curr_symbol_id
);
1055 /* don't forget to free this gchar */
1056 g_free (curr_symbol_name
);
1061 on_symbol_removed (SymbolDBEngine
*dbe
, gint symbol_id
, gpointer data
)
1063 GtkTreeStore
*store
;
1064 SymbolDBViewLocals
*dbvl
;
1065 SymbolDBViewLocalsPriv
*priv
;
1067 GtkTreeRowReference
*row_ref
;
1069 dbvl
= SYMBOL_DB_VIEW_LOCALS (data
);
1071 g_return_if_fail (dbvl
!= NULL
);
1074 store
= GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)));
1076 DEBUG_PRINT ("on_symbol_removed (): -local- %d", symbol_id
);
1078 row_ref
= g_tree_lookup (priv
->nodes_displayed
, (gpointer
)symbol_id
);
1079 if (sdb_view_locals_get_iter_from_row_ref (dbvl
, row_ref
, &iter
) == FALSE
)
1084 do_recurse_subtree_and_remove (dbvl
, &iter
);
1088 on_symbol_inserted (SymbolDBEngine
*dbe
, gint symbol_id
, gpointer data
)
1090 SymbolDBViewLocals
*dbvl
;
1091 SymbolDBViewLocalsPriv
*priv
;
1093 dbvl
= SYMBOL_DB_VIEW_LOCALS (data
);
1095 g_return_if_fail (dbvl
!= NULL
);
1098 /* save the symbol_id to be added in the queue and just return */
1099 g_queue_push_head (priv
->symbols_inserted_ids
, (gpointer
)symbol_id
);
1103 symbol_db_view_locals_get_line (SymbolDBViewLocals
*dbvl
,
1104 SymbolDBEngine
*dbe
,
1107 GtkTreeStore
*store
;
1109 g_return_val_if_fail (dbvl
!= NULL
, -1);
1110 g_return_val_if_fail (dbe
!= NULL
, -1);
1111 g_return_val_if_fail (iter
!= NULL
, -1);
1113 store
= GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)));
1119 SymbolDBEngineIteratorNode
*node
;
1121 gtk_tree_model_get (GTK_TREE_MODEL
1123 COLUMN_SYMBOL_ID
, &symbol_id
, -1);
1125 /* getting line at click time with a query is faster than updating every
1126 * entry in the gtktreeview. We can be sure that the db is in a consistent
1127 * state and has all the last infos */
1128 node
= SYMBOL_DB_ENGINE_ITERATOR_NODE (
1129 symbol_db_engine_get_symbol_info_by_id (dbe
, symbol_id
,
1133 line
= symbol_db_engine_iterator_node_get_symbol_file_pos (node
);
1141 symbol_db_view_locals_recv_signals_from_engine (SymbolDBViewLocals
*dbvl
,
1142 SymbolDBEngine
*dbe
, gboolean enable_status
)
1144 SymbolDBViewLocalsPriv
*priv
;
1146 g_return_if_fail (dbvl
!= NULL
);
1149 if (enable_status
== TRUE
)
1151 gtk_widget_set_sensitive (GTK_WIDGET (dbvl
), TRUE
);
1153 priv
->recv_signals
= TRUE
;
1154 /* connect some signals */
1155 if (priv
->insert_handler
<= 0)
1157 priv
->insert_handler
= g_signal_connect (G_OBJECT (dbe
),
1158 "symbol-inserted", G_CALLBACK (on_symbol_inserted
), dbvl
);
1161 if (priv
->remove_handler
<= 0)
1163 priv
->remove_handler
= g_signal_connect (G_OBJECT (dbe
), "symbol-removed",
1164 G_CALLBACK (on_symbol_removed
), dbvl
);
1167 if (priv
->scan_end_handler
<= 0)
1169 priv
->scan_end_handler
= g_signal_connect (G_OBJECT (dbe
), "scan-end",
1170 G_CALLBACK (on_scan_end
), dbvl
);
1173 else /* disconnect them, if they were ever connected before */
1175 gtk_widget_set_sensitive (GTK_WIDGET (dbvl
), FALSE
);
1177 priv
->recv_signals
= FALSE
;
1178 if (priv
->insert_handler
>= 0)
1180 g_signal_handler_disconnect (G_OBJECT (dbe
), priv
->insert_handler
);
1181 priv
->insert_handler
= 0;
1184 if (priv
->remove_handler
>= 0)
1186 g_signal_handler_disconnect (G_OBJECT (dbe
), priv
->remove_handler
);
1187 priv
->remove_handler
= 0;
1190 if (priv
->scan_end_handler
>= 0)
1192 g_signal_handler_disconnect (G_OBJECT (dbe
), priv
->scan_end_handler
);
1193 priv
->scan_end_handler
= 0;
1199 symbol_db_view_locals_update_list (SymbolDBViewLocals
*dbvl
, SymbolDBEngine
*dbe
,
1200 const gchar
* filepath
)
1202 SymbolDBViewLocalsPriv
*priv
;
1204 SymbolDBEngineIterator
*iterator
;
1205 GtkTreeStore
*store
;
1206 FileSymbolsStatus
*fsstatus
;
1208 g_return_if_fail (dbvl
!= NULL
);
1209 g_return_if_fail (filepath
!= NULL
);
1210 g_return_if_fail (dbe
!= NULL
);
1214 /* we're not interested in giving user an updated gtktreestore if recv signals
1215 * is false. In that case we can have a project importing...
1217 if (priv
->recv_signals
== FALSE
)
1219 gtk_tree_view_set_model (GTK_TREE_VIEW (dbvl
), NULL
);
1223 /* ok, we can have a case where we're revisiting an old file with an already
1224 * populated GtkTreeStore. We're gonna set that gtktreestore along with the
1225 * GTree(s) for nodes_displayed and waiting_for.
1229 if (priv
->current_db_file
!= NULL
)
1231 FileSymbolsStatus
*hash_node
;
1232 /* save current symbols status - e.g. gtktreestore, symbols_displayed etc.,
1233 * if it hasn't already been done.
1235 hash_node
= g_hash_table_lookup (priv
->files_view_status
,
1236 priv
->current_db_file
);
1238 /* did we find something? yes? well, then we should save nothing... */
1239 if (hash_node
== NULL
)
1241 /* found nothing? ok, save the status */
1242 GtkTreeStore
* store
;
1244 /* remove the GSourceFunc, if it's running */
1245 if (priv
->insertion_idle_handler
> 0)
1247 g_source_remove (priv
->insertion_idle_handler
);
1248 priv
->insertion_idle_handler
= 0;
1251 store
= GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl
)));
1253 if (store
!= NULL
&& priv
->nodes_displayed
!= NULL
1254 && priv
->waiting_for
!= NULL
)
1256 FileSymbolsStatus
*fss
;
1257 fss
= g_new0 (FileSymbolsStatus
, 1);
1259 fss
->nodes_displayed
= priv
->nodes_displayed
;
1260 fss
->waiting_for
= priv
->waiting_for
;
1261 fss
->symbols_inserted_ids
= priv
->symbols_inserted_ids
;
1263 DEBUG_PRINT ("symbol_db_view_locals_update_list (): g_hash_table_insert ");
1265 g_hash_table_insert (priv
->files_view_status
,
1266 g_strdup (priv
->current_db_file
), fss
);
1272 /* adjust some vars */
1273 g_free (priv
->current_db_file
);
1274 priv
->current_db_file
= NULL
;
1276 g_free (priv
->current_local_file_path
);
1277 priv
->current_local_file_path
= NULL
;
1279 priv
->current_db_file
=
1280 symbol_db_engine_get_file_db_path (dbe
, filepath
);
1281 if (priv
->current_db_file
== NULL
)
1283 DEBUG_PRINT ("symbol_db_view_locals_update_list (): "
1284 "Warning: priv->current_db_file is NULL");
1287 priv
->current_local_file_path
= g_strdup (filepath
);
1289 /* try to see if we had something saved before in the hash table */
1290 fsstatus
= g_hash_table_lookup (priv
->files_view_status
,
1291 priv
->current_db_file
);
1293 if (fsstatus
!= NULL
)
1295 /* restore the previous saved status ... */
1297 /* set the nodes_displayed */
1298 priv
->nodes_displayed
= fsstatus
->nodes_displayed
;
1300 /* ... the waiting_for ... */
1301 priv
->waiting_for
= fsstatus
->waiting_for
;
1303 /* ... the pending symbols_id to be inserted ... */
1304 priv
->symbols_inserted_ids
= fsstatus
->symbols_inserted_ids
;
1306 /* and last but not the least the store */
1307 store
= fsstatus
->store
;
1309 /* with this set there's no need to re-retrieve the symbols from db,
1310 * speeding up the things.
1312 DEBUG_PRINT ("symbol_db_view_locals_update_list (): "
1313 "setting gtk_tree_view_set_model to the saved one");
1314 gtk_tree_view_set_model (GTK_TREE_VIEW (dbvl
), GTK_TREE_MODEL (store
));
1317 /* check if we left some ids on the queue. In case restart the idle_function */
1318 if (g_queue_get_length (priv
->symbols_inserted_ids
) > 0)
1320 TraverseData
*tdata
;
1322 tdata
= g_new0 (TraverseData
, 1);
1326 priv
->insertion_idle_handler
= g_idle_add_full (G_PRIORITY_LOW
,
1327 (GSourceFunc
) consume_symbols_inserted_queue_idle
,
1329 (GDestroyNotify
) consume_symbols_inserted_queue_idle_destroy
);
1334 priv
->nodes_displayed
= g_tree_new_full ((GCompareDataFunc
)>ree_compare_func
,
1337 (GDestroyNotify
)>k_tree_row_reference_free
);
1339 priv
->waiting_for
= g_tree_new_full ((GCompareDataFunc
)>ree_compare_func
,
1344 priv
->symbols_inserted_ids
= g_queue_new ();
1346 DEBUG_PRINT ("symbol_db_view_locals_update_list (): creating new store");
1347 store
= sdb_view_locals_create_new_store ();
1348 gtk_tree_view_set_model (GTK_TREE_VIEW (dbvl
), GTK_TREE_MODEL (store
));
1350 /* Removes all rows from tree_store */
1351 gtk_tree_store_clear (store
);
1352 iterator
= symbol_db_engine_get_file_symbols (dbe
, filepath
, SYMINFO_SIMPLE
|
1356 if (iterator
!= NULL
)
1359 gint curr_symbol_id
;
1360 SymbolDBEngineIteratorNode
*iter_node
;
1362 iter_node
= SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator
);
1364 curr_symbol_id
= symbol_db_engine_iterator_node_get_symbol_id (iter_node
);
1366 /* we can just call the symbol inserted function. It'll take care of
1367 * building the tree and populating it
1369 on_symbol_inserted (dbe
, curr_symbol_id
, (gpointer
)dbvl
);
1370 } while (symbol_db_engine_iterator_move_next (iterator
) == TRUE
);
1372 g_object_unref (iterator
);
1375 /* ok, there may be some symbols left on the waiting_for_list...
1376 * launch the callback function by hand, flushing the list it in case
1378 on_scan_end (dbe
, dbvl
);
1381 /* only gtk 2.12 ...
1382 * gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (dbvl)); */
1384 gtk_tree_view_expand_all (GTK_TREE_VIEW (dbvl
));