Integrate adding files with the file manager
[anjuta-git-plugin.git] / plugins / symbol-db / symbol-db-view-locals.c
blob056e6abb2ee37bb7eee0cf671cbb68b8a33af4d4
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta
4 * Copyright (C) Massimo Cora' 2007 <maxcvs@email.it>
5 *
6 * anjuta is free software.
7 *
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
11 * any later version.
13 * 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.
25 #include <glib.h>
26 #include <gtk/gtk.h>
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"
37 enum {
38 COLUMN_PIXBUF,
39 COLUMN_NAME,
40 COLUMN_SYMBOL_ID,
41 COLUMN_MAX
44 static GtkTreeViewClass *parent_class = NULL;
47 typedef struct _WaitingForSymbol {
48 gint child_symbol_id;
49 gchar *child_symbol_name;
50 const GdkPixbuf *pixbuf;
52 } WaitingForSymbol;
54 typedef struct _TraverseData {
55 SymbolDBViewLocals *dbvl;
56 SymbolDBEngine *dbe;
58 } TraverseData;
60 typedef struct _FileSymbolsStatus {
61 GtkTreeStore *store;
62 GTree *nodes_displayed;
63 GTree *waiting_for;
64 GQueue *symbols_inserted_ids;
66 } FileSymbolsStatus;
68 struct _SymbolDBViewLocalsPriv {
69 gchar *current_db_file;
70 gchar *current_local_file_path;
71 gint insert_handler;
72 gint remove_handler;
73 gint scan_end_handler;
74 gint insertion_idle_handler;
76 GTree *nodes_displayed;
77 GTree *waiting_for;
78 GQueue *symbols_inserted_ids;
80 gboolean recv_signals;
81 GHashTable *files_view_status;
85 static void
86 trigger_on_symbol_inserted (SymbolDBViewLocals *dbvl, gint symbol_id);
89 static gint
90 gtree_compare_func (gconstpointer a, gconstpointer b, gpointer user_data)
92 return (gint)a - (gint)b;
95 static void
96 waiting_for_symbol_destroy (WaitingForSymbol *wfs)
98 g_return_if_fail (wfs != NULL);
99 g_free (wfs->child_symbol_name);
100 g_free (wfs);
103 static gboolean
104 traverse_free_waiting_for (gpointer key, gpointer value, gpointer data)
106 if (value == NULL || key == NULL)
107 return FALSE;
109 g_slist_foreach ((GSList*)value, (GFunc)waiting_for_symbol_destroy, NULL);
110 g_slist_free ((GSList*)value);
111 return FALSE;
114 static void
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);
129 g_free (fss);
132 static GtkTreeStore *
133 sdb_view_locals_create_new_store ()
135 GtkTreeStore *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),
139 COLUMN_NAME,
140 GTK_SORT_ASCENDING);
141 return store;
144 static gboolean
145 traverse_files_view_status (gpointer key, gpointer value, gpointer user_data)
147 return TRUE;
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)
158 GtkTreePath *path;
159 if (row_ref == NULL)
161 /* no node displayed found */
162 return FALSE;
165 path = gtk_tree_row_reference_get_path (row_ref);
166 if (path == NULL)
168 DEBUG_PRINT ("sdb_view_locals_get_iter_from_row_ref (): path is null, something "
169 "went wrong ?!");
170 return FALSE;
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);
177 return FALSE;
179 gtk_tree_path_free (path);
181 return TRUE;
184 void
185 symbol_db_view_locals_clear_cache (SymbolDBViewLocals *dbvl)
187 SymbolDBViewLocalsPriv *priv;
188 GtkTreeStore *store;
189 gpointer hash_node = NULL;
191 g_return_if_fail (dbvl != NULL);
193 priv = dbvl->priv;
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)));
223 if (store != NULL)
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;
246 static void
247 sdb_view_locals_init (SymbolDBViewLocals *dbvl)
249 DEBUG_PRINT ("sdb_view_locals_init ()");
250 GtkTreeViewColumn *column;
251 GtkCellRenderer *renderer;
252 GtkTreeSelection *selection;
253 GtkTreeStore *store;
254 SymbolDBViewLocalsPriv *priv;
256 g_return_if_fail (dbvl != NULL);
258 dbvl->priv = g_new0 (SymbolDBViewLocalsPriv, 1);
259 priv = dbvl->priv;
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 */
276 store = 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);
288 /* Columns */
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",
297 COLUMN_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",
302 COLUMN_NAME);
304 gtk_tree_view_append_column (GTK_TREE_VIEW (dbvl), column);
305 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (dbvl), column);
307 /* gtk 2.12
308 * gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (dbvl), FALSE); */
311 static void
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);
320 priv = locals->priv;
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);
326 g_free (priv);
328 G_OBJECT_CLASS (parent_class)->finalize (object);
331 static void
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;
340 GType
341 symbol_db_view_locals_get_type (void)
343 static GType our_type = 0;
345 if(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 */
356 0, /* n_preallocs */
357 (GInstanceInitFunc) sdb_view_locals_init, /* instance_init */
358 NULL /* value_table */
361 our_type = g_type_register_static (GTK_TYPE_TREE_VIEW, "SymbolDBViewLocals",
362 &our_info, 0);
365 return our_type;
368 GtkWidget *
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;
379 GtkTreeStore *store;
380 GtkTreeIter child_iter;
381 GtkTreePath *path;
382 GtkTreeRowReference *row_ref;
384 g_return_val_if_fail (dbvl != NULL, NULL);
386 priv = dbvl->priv;
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,
395 -1);
397 path = gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl)),
398 &child_iter);
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);
403 return row_ref;
406 static GtkTreeRowReference *
407 do_add_child_symbol_to_view (SymbolDBViewLocals *dbvl, gint parent_symbol_id,
408 const GdkPixbuf *pixbuf, const gchar* symbol_name,
409 gint symbol_id)
411 SymbolDBViewLocalsPriv *priv;
412 GtkTreePath *path;
413 GtkTreeStore *store;
414 GtkTreeIter iter, child_iter;
415 GtkTreeRowReference *row_ref;
417 g_return_val_if_fail (dbvl != NULL, NULL);
419 priv = dbvl->priv;
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.");
429 return NULL;
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,
439 -1);
441 /* grab the row ref and return it */
442 path = gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl)),
443 &child_iter);
444 row_ref = gtk_tree_row_reference_new (gtk_tree_view_get_model (GTK_TREE_VIEW (dbvl)),
445 path);
446 gtk_tree_path_free (path);
447 return row_ref;
450 static gboolean
451 traverse_on_scan_end (gpointer key, gpointer value, gpointer data)
453 TraverseData *tdata;
454 SymbolDBEngine *dbe;
455 SymbolDBViewLocals *dbvl;
456 SymbolDBViewLocalsPriv *priv;
457 SymbolDBEngineIterator *iterator;
458 gint parent_id;
460 g_return_val_if_fail (data != NULL, FALSE);
462 tdata = (TraverseData *)data;
464 dbe = tdata->dbe;
465 dbvl = tdata->dbvl;
467 g_return_val_if_fail (dbe != NULL, FALSE);
468 g_return_val_if_fail (dbvl != NULL, FALSE);
470 priv = dbvl->priv;
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,
477 SYMINFO_SIMPLE |
478 SYMINFO_ACCESS |
479 SYMINFO_KIND);
480 if (iterator != NULL)
482 SymbolDBEngineIteratorNode *iter_node;
483 const GdkPixbuf *pixbuf;
484 const gchar* symbol_name;
485 GtkTreeRowReference *row_ref = NULL;
486 gint grandparent_id;
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,
501 parent_id,
502 priv->current_db_file);
503 DEBUG_PRINT ("traverse_on_scan_end (): grandparent_id %d", grandparent_id);
505 if (grandparent_id > 0)
507 row_ref =
508 g_tree_lookup (priv->nodes_displayed, (gpointer)grandparent_id);
509 if (row_ref != NULL)
511 /* hey we have a namespace or something which is the parent of
512 * our parent.
514 DEBUG_PRINT ("traverse_on_scan_end (): adding parent_id %d "
515 "to grandparent %d", parent_id,
516 grandparent_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,
521 row_ref);
523 /* DEBUG_PRINT ("traverse_on_scan_end (): row_ref %d", row_ref);*/
526 /* we're in the case that no grandparent has been found */
527 if (row_ref == NULL)
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,
533 row_ref);
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 */
543 return FALSE;
547 static void
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);
558 priv = dbvl->priv;
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,
567 child_tree_row_ref);
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);
574 static void
575 trigger_on_symbol_inserted (SymbolDBViewLocals *dbvl, gint symbol_id)
577 SymbolDBViewLocalsPriv *priv;
578 GSList *slist;
579 WaitingForSymbol *wfs;
581 g_return_if_fail (dbvl != NULL);
583 priv = dbvl->priv;
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);
590 if (slist == NULL)
592 /* nothing waiting for us */
593 /* DEBUG_PRINT ("trigger_on_symbol_inserted (): no children waiting for us...");*/
594 return;
596 else {
597 gint i;
598 gint length = g_slist_length (slist);
600 /* DEBUG_PRINT ("trigger_on_symbol_inserted (): consuming slist for parent %d",
601 symbol_id);*/
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);
621 static void
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;
627 gpointer node;
629 g_return_if_fail (dbvl != NULL);
630 priv = dbvl->priv;
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",
644 parent_symbol_id);*/
645 node = g_tree_lookup (priv->waiting_for, (gpointer)parent_symbol_id);
646 if (node == NULL)
648 /* no lists already set. Create one. */
649 GSList *slist;
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,
659 slist);
661 else
663 /* found a list */
664 GSList *slist;
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,
673 slist);
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.
681 static void
682 do_recurse_subtree_and_invalidate (SymbolDBViewLocals *dbvl,
683 GtkTreeIter *parent_subtree_iter,
684 gint parent_id_to_wait_for)
686 gint curr_symbol_id;
687 const GdkPixbuf *curr_pixbuf;
688 GtkTreeStore *store;
689 gchar *curr_symbol_name;
691 SymbolDBViewLocalsPriv *priv;
693 g_return_if_fail (dbvl != NULL);
695 priv = dbvl->priv;
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 */
702 -1);
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))
710 GtkTreeIter child;
711 gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child,
712 parent_subtree_iter);
714 /* recurse */
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
731 * for trigger).
733 static void
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);
741 priv = dbvl->priv;
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]",
748 symbol_id);*/
750 /* get the current iter row reference in the just added root gtktreeview
751 * node
753 curr_tree_row_ref = do_add_root_symbol_to_view (dbvl, pixbuf, symbol_name,
754 symbol_id);
756 /* we'll fake the gpointer to store an int */
757 g_tree_insert (priv->nodes_displayed, (gpointer)symbol_id,
758 curr_tree_row_ref);
760 /* let's trigger the insertion of the symbol_id, there may be some children
761 * waiting for it.
763 trigger_on_symbol_inserted (dbvl, symbol_id);
765 else
767 gpointer node;
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);
773 if (node != NULL)
775 /* hey we found it */
776 GtkTreeRowReference *child_row_ref;
777 /* DEBUG_PRINT ("prepare_for_adding(): found node already displayed %d",
778 parent_symbol_id);*/
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,
785 child_row_ref);
786 trigger_on_symbol_inserted (dbvl, symbol_id);
788 else
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,
796 pixbuf);
801 static void
802 consume_symbols_inserted_queue_idle_destroy (gpointer data)
804 TraverseData *tdata;
805 SymbolDBViewLocals *dbvl;
806 SymbolDBEngine *dbe;
807 SymbolDBViewLocalsPriv *priv;
808 gint waiting_for_size;
810 tdata = (TraverseData *)data;
812 dbvl = tdata->dbvl;
813 dbe = tdata->dbe;
814 g_return_if_fail (dbvl != NULL);
815 priv = dbvl->priv;
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)
831 return;
833 /* we have something left. Search the parent_symbol_id [identified by the
834 * waiting_for id]
836 DEBUG_PRINT ("destroying tdata");
837 g_tree_foreach (priv->waiting_for, traverse_on_scan_end, tdata);
840 g_free (tdata);
843 static gboolean
844 consume_symbols_inserted_queue_idle (gpointer data)
846 TraverseData *tdata;
847 SymbolDBViewLocals *dbvl;
848 SymbolDBEngine *dbe;
849 SymbolDBViewLocalsPriv *priv;
850 SymbolDBEngineIterator *iterator;
851 GtkTreeStore *store;
852 gint consumed_symbol_id;
853 gint queue_length;
855 /* it's not obligatory referred to a class inheritance */
856 gint parent_symbol_id;
858 tdata = (TraverseData *)data;
860 dbvl = tdata->dbvl;
861 dbe = tdata->dbe;
862 g_return_val_if_fail (dbvl != NULL, FALSE);
863 priv = dbvl->priv;
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);
875 else {
876 return FALSE;
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
891 * symbol.
894 parent_symbol_id = symbol_db_engine_get_parent_scope_id_by_symbol_id (dbe,
895 consumed_symbol_id,
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,
900 consumed_symbol_id,
901 NULL);
903 /* get the original symbol infos */
904 iterator = symbol_db_engine_get_symbol_info_by_id (dbe, consumed_symbol_id,
905 SYMINFO_SIMPLE |
906 SYMINFO_ACCESS |
907 SYMINFO_KIND);
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,
932 SYMINFO_SIMPLE);
933 if (iterator_for_children == NULL)
935 /* we don't have children */
936 /*DEBUG_PRINT ("on_symbol_inserted (): %d has no children.", symbol_id);*/
938 else
940 /* hey there are some children here.. kill 'em all and put them on
941 * a waiting_for list
945 gint curr_child_id;
946 GtkTreeIter child_iter;
947 GtkTreeRowReference *row_ref;
948 SymbolDBEngineIteratorNode *iter_node;
950 iter_node = SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator_for_children);
952 curr_child_id =
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);
958 if (row_ref == NULL)
959 continue;
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");
965 continue;
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)
971 == TRUE);
973 g_object_unref (iterator_for_children);
976 prepare_for_adding (dbvl, parent_symbol_id, symbol_name, consumed_symbol_id,
977 pixbuf);
979 g_object_unref (iterator);
982 gtk_tree_view_expand_all (GTK_TREE_VIEW (dbvl));
984 return TRUE;
987 static void
988 on_scan_end (SymbolDBEngine *dbe, gpointer data)
990 SymbolDBViewLocals *dbvl;
991 SymbolDBViewLocalsPriv *priv;
992 TraverseData *tdata;
994 dbvl = SYMBOL_DB_VIEW_LOCALS (data);
995 g_return_if_fail (dbvl != NULL);
996 priv = dbvl->priv;
998 tdata = g_new (TraverseData, 1);
999 tdata->dbvl = dbvl;
1000 tdata->dbe = dbe;
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,
1012 (gpointer) tdata,
1013 (GDestroyNotify) consume_symbols_inserted_queue_idle_destroy);
1018 static void
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);
1031 priv = dbvl->priv;
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 */
1038 -1);
1040 /*DEBUG_PRINT ("do_recurse_subtree_and_remove (): curr_symbol_id %d",
1041 curr_symbol_id);*/
1043 while (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (store), parent_subtree_iter))
1045 GtkTreeIter child;
1046 gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, parent_subtree_iter);
1048 /* recurse */
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);
1060 static void
1061 on_symbol_removed (SymbolDBEngine *dbe, gint symbol_id, gpointer data)
1063 GtkTreeStore *store;
1064 SymbolDBViewLocals *dbvl;
1065 SymbolDBViewLocalsPriv *priv;
1066 GtkTreeIter iter;
1067 GtkTreeRowReference *row_ref;
1069 dbvl = SYMBOL_DB_VIEW_LOCALS (data);
1071 g_return_if_fail (dbvl != NULL);
1072 priv = dbvl->priv;
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)
1081 return;
1084 do_recurse_subtree_and_remove (dbvl, &iter);
1087 static void
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);
1096 priv = dbvl->priv;
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);
1102 gint
1103 symbol_db_view_locals_get_line (SymbolDBViewLocals *dbvl,
1104 SymbolDBEngine *dbe,
1105 GtkTreeIter * iter)
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)));
1115 if (store)
1117 gint symbol_id;
1118 gint line;
1119 SymbolDBEngineIteratorNode *node;
1121 gtk_tree_model_get (GTK_TREE_MODEL
1122 (store), iter,
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,
1130 SYMINFO_SIMPLE));
1131 if (node != NULL)
1133 line = symbol_db_engine_iterator_node_get_symbol_file_pos (node);
1134 return line;
1137 return -1;
1140 void
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);
1147 priv = dbvl->priv;
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;
1198 void
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);
1212 priv = dbvl->priv;
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);
1220 return;
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.
1227 fsstatus = NULL;
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);
1258 fss->store = store;
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 ");
1264 /* insert it */
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");
1285 return;
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);
1323 tdata->dbvl = dbvl;
1324 tdata->dbe = dbe;
1326 priv->insertion_idle_handler = g_idle_add_full (G_PRIORITY_LOW,
1327 (GSourceFunc) consume_symbols_inserted_queue_idle,
1328 (gpointer) tdata,
1329 (GDestroyNotify) consume_symbols_inserted_queue_idle_destroy);
1332 else
1334 priv->nodes_displayed = g_tree_new_full ((GCompareDataFunc)&gtree_compare_func,
1335 NULL,
1336 NULL,
1337 (GDestroyNotify)&gtk_tree_row_reference_free);
1339 priv->waiting_for = g_tree_new_full ((GCompareDataFunc)&gtree_compare_func,
1340 NULL,
1341 NULL,
1342 NULL);
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 |
1353 SYMINFO_ACCESS |
1354 SYMINFO_KIND);
1356 if (iterator != NULL)
1358 do {
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));