Fix a Gtk warning when checking path input in the log viewer.
[anjuta-git-plugin.git] / plugins / symbol-db / symbol-db-view.c
blob59c77173b6fcc752ee55c80dc62a3b69b1deaf49
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 <gdl/gdl-icons.h>
27 #include <libanjuta/resources.h>
28 #include <libanjuta/anjuta-utils.h>
29 #include <libanjuta/anjuta-debug.h>
30 #include "symbol-db-view.h"
31 #include "symbol-db-engine.h"
32 #include "symbol-db-engine-iterator.h"
33 #include "symbol-db-engine-iterator-node.h"
35 #define DUMMY_SYMBOL_ID G_MININT32+1
37 enum {
38 COLUMN_PIXBUF,
39 COLUMN_NAME,
40 COLUMN_SYMBOL_ID,
41 COLUMN_MAX
44 /* positive ids are used in real database */
45 enum {
46 ROOT_GLOBAL = G_MAXINT32
49 struct _SymbolDBViewPriv
51 gint insert_handler;
52 gint remove_handler;
53 gint scan_end_handler;
55 GtkTreeRowReference *row_ref_global;
56 GTree *nodes_displayed;
57 GTree *waiting_for;
58 GTree *expanding_gfunc_ids;
61 typedef struct _WaitingForSymbol {
62 gint child_symbol_id;
63 gchar *child_symbol_name;
64 const GdkPixbuf *pixbuf;
66 } WaitingForSymbol;
68 typedef struct _NodeIdleExpand {
69 SymbolDBView *dbv;
70 SymbolDBEngineIterator *iterator;
71 SymbolDBEngine *dbe;
72 GtkTreePath *expanded_path;
73 gint expanded_symbol_id;
75 } NodeIdleExpand;
78 static GtkTreeViewClass *parent_class = NULL;
79 static GHashTable *pixbufs_hash = NULL;
80 static void
81 trigger_on_symbol_inserted (SymbolDBView *dbv, gint symbol_id);
84 static gint
85 gtree_compare_func (gconstpointer a, gconstpointer b, gpointer user_data)
87 return (gint)a - (gint)b;
90 static void
91 waiting_for_symbol_destroy (WaitingForSymbol *wfs)
93 g_return_if_fail (wfs != NULL);
94 g_free (wfs->child_symbol_name);
95 g_free (wfs);
98 static inline gboolean
99 sdb_view_get_iter_from_row_ref (SymbolDBView *dbv, GtkTreeRowReference *row_ref,
100 GtkTreeIter *OUT_iter)
102 GtkTreePath *path;
103 if (row_ref == NULL)
105 /* no node displayed found */
106 return FALSE;
109 path = gtk_tree_row_reference_get_path (row_ref);
110 if (path == NULL)
112 DEBUG_PRINT ("sdb_view_get_iter_from_row_ref (): path is null, something "
113 "went wrong ?!");
114 return FALSE;
117 if (gtk_tree_model_get_iter (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
118 OUT_iter, path) == FALSE)
120 gtk_tree_path_free (path);
121 return FALSE;
123 gtk_tree_path_free (path);
125 return TRUE;
129 static gboolean
130 traverse_free_waiting_for (gpointer key, gpointer value, gpointer data)
132 if (value == NULL)
133 return FALSE;
135 g_slist_foreach ((GSList*)value, (GFunc)waiting_for_symbol_destroy, NULL);
136 g_slist_free ((GSList*)value);
137 return FALSE;
140 void
141 symbol_db_view_clear_cache (SymbolDBView *dbv)
143 SymbolDBViewPriv *priv;
144 GtkTreeStore *store;
146 g_return_if_fail (dbv != NULL);
148 priv = dbv->priv;
150 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
151 if (store != NULL)
152 g_object_unref (store);
154 /* this will free alto the priv->row_ref* instances */
155 if (priv->nodes_displayed)
157 g_tree_destroy (priv->nodes_displayed);
158 priv->nodes_displayed = NULL;
161 /* free the waiting_for structs before destroying the tree itself */
162 if (priv->waiting_for)
164 g_tree_foreach (priv->waiting_for, traverse_free_waiting_for, NULL);
165 g_tree_destroy (priv->waiting_for);
166 priv->waiting_for = NULL;
169 gtk_tree_view_set_model (GTK_TREE_VIEW (dbv), NULL);
172 static void
173 on_scan_end (SymbolDBEngine *dbe, gpointer data)
175 SymbolDBView *dbv;
176 SymbolDBViewPriv *priv;
178 dbv = SYMBOL_DB_VIEW (data);
179 g_return_if_fail (dbv != NULL);
180 priv = dbv->priv;
182 /* void the waiting_for symbols */
183 /* free the waiting_for structs before destroying the tree itself */
184 if (priv->waiting_for)
186 g_tree_foreach (priv->waiting_for, traverse_free_waiting_for, data);
187 g_tree_destroy (priv->waiting_for);
189 /* recreate it because there's a free_all_items function. And the
190 * one proposed by the doc is too complex.. create a list of the items
191 * and reparse them with g_tree_remove...
193 priv->waiting_for = g_tree_new_full ((GCompareDataFunc)&gtree_compare_func,
194 NULL,
195 NULL,
196 NULL);
201 static inline GtkTreeRowReference *
202 do_add_root_symbol_to_view (SymbolDBView *dbv, const GdkPixbuf *pixbuf,
203 const gchar* symbol_name, gint symbol_id)
205 SymbolDBViewPriv *priv;
206 GtkTreeStore *store;
207 GtkTreeIter child_iter;
208 GtkTreePath *path;
209 GtkTreeRowReference *row_ref;
211 g_return_val_if_fail (dbv != NULL, NULL);
213 priv = dbv->priv;
215 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
217 gtk_tree_store_append (store, &child_iter, NULL);
219 gtk_tree_store_set (store, &child_iter,
220 COLUMN_PIXBUF, pixbuf,
221 COLUMN_NAME, symbol_name,
222 COLUMN_SYMBOL_ID, symbol_id,
223 -1);
225 path = gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
226 &child_iter);
227 row_ref = gtk_tree_row_reference_new (
228 gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)), path);
229 gtk_tree_path_free (path);
231 return row_ref;
234 /* before calling this function be sure that parent_symbol_id is already into
235 * nodes_displayed GTree, or this will complain about it and will bail out
236 * with a warning.
238 static inline GtkTreeRowReference *
239 do_add_child_symbol_to_view (SymbolDBView *dbv, gint parent_symbol_id,
240 const GdkPixbuf *pixbuf, const gchar* symbol_name,
241 gint symbol_id)
243 SymbolDBViewPriv *priv;
244 GtkTreePath *path;
245 GtkTreeStore *store;
246 GtkTreeIter iter, child_iter;
247 GtkTreeRowReference *row_ref;
249 priv = dbv->priv;
251 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
253 /* look up the row ref in the hashtable, then get its associated gtktreeiter */
254 row_ref = g_tree_lookup (priv->nodes_displayed, (gpointer)parent_symbol_id);
256 if (sdb_view_get_iter_from_row_ref (dbv, row_ref, &iter) == FALSE)
258 g_warning ("do_add_symbol_to_view (): something went wrong.");
259 return NULL;
262 /* append a new child &child_iter, with a parent of &iter */
263 gtk_tree_store_append (store, &child_iter, &iter);
265 gtk_tree_store_set (store, &child_iter,
266 COLUMN_PIXBUF, pixbuf,
267 COLUMN_NAME, symbol_name,
268 COLUMN_SYMBOL_ID, symbol_id,
269 -1);
271 /* grab the row ref and return it */
272 path = gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
273 &child_iter);
274 row_ref = gtk_tree_row_reference_new (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
275 path);
276 gtk_tree_path_free (path);
277 return row_ref;
281 static void
282 add_waiting_for_symbol_to_view (SymbolDBView *dbv, WaitingForSymbol *wfs,
283 gint parent_symbol_id)
285 SymbolDBViewPriv *priv;
286 gint symbol_id_added;
287 GtkTreeRowReference *child_tree_row_ref;
289 g_return_if_fail (dbv != NULL);
290 g_return_if_fail (wfs != NULL);
292 priv = dbv->priv;
294 child_tree_row_ref = do_add_child_symbol_to_view (dbv, parent_symbol_id,
295 wfs->pixbuf, wfs->child_symbol_name, wfs->child_symbol_id);
297 symbol_id_added = wfs->child_symbol_id;
299 /* add a new entry on gtree 'nodes_displayed' */
300 g_tree_insert (priv->nodes_displayed, (gpointer)wfs->child_symbol_id,
301 child_tree_row_ref);
303 /* and now trigger the inserted symbol... (recursive function). */
304 if (wfs->child_symbol_id != parent_symbol_id)
305 trigger_on_symbol_inserted (dbv, wfs->child_symbol_id);
309 static void
310 trigger_on_symbol_inserted (SymbolDBView *dbv, gint symbol_id)
312 SymbolDBViewPriv *priv;
313 GSList *slist;
314 WaitingForSymbol *wfs;
316 g_return_if_fail (dbv != NULL);
318 priv = dbv->priv;
320 /* DEBUG_PRINT ("trigger_on_symbol_inserted (): triggering %d", symbol_id);*/
322 /* try to find a waiting for symbol */
323 slist = g_tree_lookup (priv->waiting_for, (gpointer)symbol_id);
325 if (slist == NULL)
327 /* nothing waiting for us */
328 /*DEBUG_PRINT ("trigger_on_symbol_inserted (): no children waiting for us...");*/
329 return;
331 else {
332 gint i;
333 gint length = g_slist_length (slist);
335 /* DEBUG_PRINT ("trigger_on_symbol_inserted (): consuming slist for parent %d",
336 symbol_id);*/
338 for (i=0; i < length-1; i++)
340 wfs = g_slist_nth_data (slist, 0);
342 slist = g_slist_remove (slist, wfs);
344 add_waiting_for_symbol_to_view (dbv, wfs, symbol_id);
346 /* destroy the data structure */
347 waiting_for_symbol_destroy (wfs);
350 /* remove the waiting for key/value */
351 g_tree_remove (priv->waiting_for, (gpointer)symbol_id);
352 g_slist_free (slist);
357 static void
358 add_new_waiting_for (SymbolDBView *dbv, gint parent_symbol_id,
359 const gchar* symbol_name,
360 gint symbol_id, const GdkPixbuf *pixbuf)
362 SymbolDBViewPriv *priv;
363 gpointer node;
365 g_return_if_fail (dbv != NULL);
366 priv = dbv->priv;
368 /* check if we already have some children waiting for a
369 * specific father to be inserted, then add this symbol_id to the list
370 * (or create a new one)
372 WaitingForSymbol *wfs;
374 wfs = g_new0 (WaitingForSymbol, 1);
375 wfs->child_symbol_id = symbol_id;
376 wfs->child_symbol_name = g_strdup (symbol_name);
377 wfs->pixbuf = pixbuf;
379 node = g_tree_lookup (priv->waiting_for, (gpointer)parent_symbol_id);
380 if (node == NULL)
382 /* no lists already set. Create one. */
383 GSList *slist;
384 slist = g_slist_alloc ();
386 slist = g_slist_prepend (slist, wfs);
388 /* add it to the binary tree. */
389 g_tree_insert (priv->waiting_for, (gpointer)parent_symbol_id,
390 slist);
392 else
394 /* found a list */
395 GSList *slist;
396 slist = (GSList*)node;
398 slist = g_slist_prepend (slist, wfs);
400 g_tree_replace (priv->waiting_for, (gpointer)parent_symbol_id,
401 slist);
406 /* Put every GtkTreeView node of the subtree headed by 'parent_subtree_iter'
407 * into a waiting_for GTree.
408 * It's a recursive function.
410 static void
411 do_recurse_subtree_and_invalidate (SymbolDBView *dbv,
412 GtkTreeIter *parent_subtree_iter,
413 gint parent_id_to_wait_for)
415 gint curr_symbol_id;
416 const GdkPixbuf *curr_pixbuf;
417 GtkTreeStore *store;
418 gchar *curr_symbol_name;
420 SymbolDBViewPriv *priv;
422 g_return_if_fail (dbv != NULL);
424 priv = dbv->priv;
425 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
427 gtk_tree_model_get (GTK_TREE_MODEL (store), parent_subtree_iter,
428 COLUMN_SYMBOL_ID, &curr_symbol_id,
429 COLUMN_PIXBUF, &curr_pixbuf,
430 COLUMN_NAME, &curr_symbol_name, /* no strdup required */
431 -1);
433 /*DEBUG_PRINT ("do_recurse_subtree_and_invalidate (): curr_symbol_id %d,"
434 "parent_id_to_wait_for %d", curr_symbol_id, parent_id_to_wait_for);*/
436 while (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (store),
437 parent_subtree_iter))
439 GtkTreeIter child;
440 gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child,
441 parent_subtree_iter);
443 /* recurse */
444 do_recurse_subtree_and_invalidate (dbv, &child, curr_symbol_id);
447 /* add to waiting for */
448 add_new_waiting_for (dbv, parent_id_to_wait_for, curr_symbol_name,
449 curr_symbol_id, curr_pixbuf);
451 gtk_tree_store_remove (store, parent_subtree_iter);
452 g_tree_remove (priv->nodes_displayed, (gpointer) curr_symbol_id);
454 /* don't forget to free this gchar */
455 g_free (curr_symbol_name);
458 /* Add promptly a symbol to the gtktreeview or add it for a later add (waiting
459 * for trigger).
461 static void
462 prepare_for_adding (SymbolDBView *dbv, gint parent_symbol_id,
463 const gchar* symbol_name, gint symbol_id,
464 const GdkPixbuf *pixbuf, const gchar* kind)
466 SymbolDBViewPriv *priv;
468 g_return_if_fail (dbv != NULL);
469 g_return_if_fail (kind != NULL);
470 priv = dbv->priv;
472 /* add to root if parent_symbol_id is <= 0 */
473 if (parent_symbol_id <= 0)
475 GtkTreeRowReference *curr_tree_row_ref = NULL;
477 /* ok, let's check the kind of the symbol. Based on that we'll retrieve
478 * the row_ref. It's quicker to check onlyl the first char than the whole
479 * string.
481 switch (kind[0])
483 case 'n': /* namespace */
484 curr_tree_row_ref = do_add_root_symbol_to_view (dbv,
485 pixbuf,
486 symbol_name,
487 symbol_id);
488 break;
490 case 'c': /* class */
491 case 's': /* struct */
492 curr_tree_row_ref = do_add_child_symbol_to_view (dbv,
493 ROOT_GLOBAL, pixbuf, symbol_name,
494 symbol_id);
495 break;
497 case 'u': /* union */
498 case 'f': /* function */
499 case 'v': /* variable */
500 case 't': /* typedef */
501 case 'e': /* enumerator */
502 default:
504 gpointer node;
505 /* Vars/Other may not be displayed already. Check it. */
506 node = g_tree_lookup (priv->nodes_displayed, (gpointer)-ROOT_GLOBAL);
508 if (node != NULL)
510 /* hey we found it */
511 /* note the negative: we'll store these under the vars/Other node */
512 curr_tree_row_ref = do_add_child_symbol_to_view (dbv,
513 -ROOT_GLOBAL, pixbuf, symbol_name,
514 symbol_id);
516 else
518 /* add it to the waiting_for trigger list */
519 add_new_waiting_for (dbv, parent_symbol_id, symbol_name, symbol_id,
520 pixbuf);
522 break;
526 if (curr_tree_row_ref == NULL)
528 return;
531 /* we'll fake the gpointer to store an int */
532 g_tree_insert (priv->nodes_displayed, (gpointer)symbol_id,
533 curr_tree_row_ref);
535 /* let's trigger the insertion of the symbol_id, there may be some children
536 * waiting for it.
538 trigger_on_symbol_inserted (dbv, symbol_id);
540 else
542 gpointer node;
544 switch (kind[0])
546 case 'u': /* union */
547 case 'f': /* function */
548 case 'v': /* variable */
549 case 't': /* typedef */
550 case 'e': /* enumerator */
551 /* switch to negative! i.e. schedule to put it under the
552 * Vars/Others node
554 parent_symbol_id = -parent_symbol_id;
555 break;
556 default: /* let it as it is */
557 break;
561 /* do we already have that parent_symbol displayed in gtktreeview?
562 * If that's the case add it as children.
564 node = g_tree_lookup (priv->nodes_displayed, (gpointer)parent_symbol_id);
566 if (node != NULL)
568 /* hey we found it */
569 GtkTreeRowReference *child_row_ref;
570 child_row_ref = do_add_child_symbol_to_view (dbv, parent_symbol_id,
571 pixbuf, symbol_name, symbol_id);
573 /* add the children_path to the GTree. */
574 g_tree_insert (priv->nodes_displayed, (gpointer)symbol_id,
575 child_row_ref);
576 trigger_on_symbol_inserted (dbv, symbol_id);
578 else
580 /* add it to the waiting_for trigger list */
581 add_new_waiting_for (dbv, parent_symbol_id, symbol_name, symbol_id,
582 pixbuf);
587 static void
588 on_symbol_inserted (SymbolDBEngine *dbe,
589 gint symbol_id, gpointer data)
591 SymbolDBEngineIterator *iterator;
592 GtkTreeStore *store;
594 /* it's not obligatory referred to a class inheritance */
595 gint parent_symbol_id;
596 SymbolDBView *dbv;
597 SymbolDBViewPriv *priv;
599 dbv = SYMBOL_DB_VIEW (data);
601 g_return_if_fail (dbv != NULL);
603 priv = dbv->priv;
605 /*DEBUG_PRINT ("on_symbol_inserted -global- %d", symbol_id);*/
606 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
608 parent_symbol_id = symbol_db_engine_get_parent_scope_id_by_symbol_id (dbe,
609 symbol_id,
610 NULL);
612 /*DEBUG_PRINT ("on_symbol_inserted parent_symbol_id detected %d", parent_symbol_id);*/
614 /* get the original symbol infos */
615 iterator = symbol_db_engine_get_symbol_info_by_id (dbe, symbol_id,
616 SYMINFO_SIMPLE |
617 SYMINFO_ACCESS |
618 SYMINFO_KIND);
620 if (iterator != NULL)
622 SymbolDBEngineIteratorNode *iter_node;
623 const GdkPixbuf *pixbuf;
624 const gchar* symbol_name;
625 const gchar* symbol_kind;
626 const gchar* symbol_access;
627 SymbolDBEngineIterator *iterator_for_children;
629 iter_node = SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator);
631 /* check if what we want to add is on a global_scope and not only a local
632 * file scope e.g. static functions
634 if (symbol_db_engine_iterator_node_get_symbol_is_file_scope (iter_node) == TRUE)
636 /* DEBUG_PRINT ("on_symbol_inserted() -global- symbol %d is not global scope",
637 symbol_id);*/
638 g_object_unref (iterator);
639 return;
642 symbol_kind = symbol_db_engine_iterator_node_get_symbol_extra_string (
643 iter_node, SYMINFO_KIND);
645 symbol_access = symbol_db_engine_iterator_node_get_symbol_extra_string (
646 iter_node, SYMINFO_ACCESS);
648 pixbuf = symbol_db_view_get_pixbuf (symbol_kind, symbol_access);
649 symbol_name = symbol_db_engine_iterator_node_get_symbol_name (iter_node);
651 /* check if one of the children [if they exist] of symbol_id are already
652 * displayed. In that case we'll invalidate all of them.
653 * i.e. we're in an updating insertion.
655 iterator_for_children =
656 symbol_db_engine_get_scope_members_by_symbol_id (dbe, symbol_id, -1,
658 SYMINFO_SIMPLE);
660 if (iterator_for_children == NULL)
662 /* we don't have children */
664 else
666 /* hey there are some children here.. kill 'em all and put them on
667 * a waiting_for list
671 gint curr_child_id;
672 GtkTreeIter child_iter;
673 GtkTreeRowReference *row_ref;
674 SymbolDBEngineIteratorNode *iter_node;
676 iter_node = SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator_for_children);
678 curr_child_id =
679 symbol_db_engine_iterator_node_get_symbol_id (iter_node);
681 row_ref = g_tree_lookup (priv->nodes_displayed,
682 (gpointer)curr_child_id);
683 if (row_ref == NULL)
684 continue;
686 if (sdb_view_get_iter_from_row_ref (dbv, row_ref, &child_iter) == FALSE)
688 /* no node displayed found */
689 g_warning ("on_symbol_inserted (): row_ref something went wrong ?!");
690 continue;
693 /* put on waiting_for the subtree */
694 do_recurse_subtree_and_invalidate (dbv, &child_iter, symbol_id);
695 } while (symbol_db_engine_iterator_move_next (iterator_for_children)
696 == TRUE);
698 g_object_unref (iterator_for_children);
701 prepare_for_adding (dbv, parent_symbol_id, symbol_name, symbol_id, pixbuf,
702 symbol_kind);
703 g_object_unref (iterator);
707 static void
708 do_recurse_subtree_and_remove (SymbolDBView *dbv,
709 GtkTreeIter *parent_subtree_iter)
711 gint curr_symbol_id;
712 const GdkPixbuf *curr_pixbuf;
713 GtkTreeStore *store;
714 gchar *curr_symbol_name;
716 SymbolDBViewPriv *priv;
718 g_return_if_fail (dbv != NULL);
720 priv = dbv->priv;
721 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
723 gtk_tree_model_get (GTK_TREE_MODEL (store), parent_subtree_iter,
724 COLUMN_SYMBOL_ID, &curr_symbol_id,
725 COLUMN_PIXBUF, &curr_pixbuf,
726 COLUMN_NAME, &curr_symbol_name, /* no strdup required */
727 -1);
729 while (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (store), parent_subtree_iter))
731 GtkTreeIter child;
732 gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, parent_subtree_iter);
734 /* recurse */
735 do_recurse_subtree_and_remove (dbv, &child);
738 gtk_tree_store_remove (store, parent_subtree_iter);
739 g_tree_remove (priv->nodes_displayed, (gpointer) curr_symbol_id);
741 /* don't forget to free this gchar */
742 g_free (curr_symbol_name);
746 static void
747 on_symbol_removed (SymbolDBEngine *dbe, gint symbol_id, gpointer data)
749 GtkTreeStore *store;
750 SymbolDBView *dbv;
751 SymbolDBViewPriv *priv;
752 GtkTreeIter iter;
753 GtkTreeRowReference *row_ref;
755 dbv = SYMBOL_DB_VIEW (data);
757 g_return_if_fail (dbv != NULL);
758 priv = dbv->priv;
760 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
762 DEBUG_PRINT ("on_symbol_removed (): -global- %d", symbol_id);
764 row_ref = g_tree_lookup (priv->nodes_displayed, (gpointer)symbol_id);
765 if (sdb_view_get_iter_from_row_ref (dbv, row_ref, &iter) == FALSE)
767 return;
770 do_recurse_subtree_and_remove (dbv, &iter);
774 * Add at most ONE dummy child to the parent_iter. This is done to let the parent_iter
775 * node be expandable.
776 * @param force If true a dummy symbol will be added even if it has no children on db.
778 static void
779 sdb_view_do_add_hidden_dummy_child (SymbolDBView *dbv, SymbolDBEngine *dbe,
780 GtkTreeIter *parent_iter, gint parent_symbol_id,
781 gboolean force)
783 SymbolDBEngineIterator *child_iterator;
784 GtkTreeStore *store;
785 SymbolDBViewPriv *priv;
787 g_return_if_fail (dbv != NULL);
788 priv = dbv->priv;
790 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
791 child_iterator = symbol_db_engine_get_scope_members_by_symbol_id (dbe,
792 parent_symbol_id,
794 -1,
795 SYMINFO_SIMPLE | SYMINFO_ACCESS | SYMINFO_KIND);
797 if (child_iterator != NULL || force == TRUE)
799 /* hey we have something here... */
800 GtkTreeIter child_iter;
802 gtk_tree_store_append (store, &child_iter, parent_iter);
803 gtk_tree_store_set (store, &child_iter,
804 COLUMN_PIXBUF, NULL,
805 COLUMN_NAME, _("Loading..."),
806 COLUMN_SYMBOL_ID, DUMMY_SYMBOL_ID,
807 -1);
809 if (child_iterator)
810 g_object_unref (child_iterator);
814 static void
815 sdb_view_row_expanded_idle_destroy (gpointer data)
817 NodeIdleExpand *node_expand;
818 SymbolDBView *dbv;
819 SymbolDBEngine *dbe;
821 g_return_if_fail (data != NULL);
822 node_expand = data;
823 DEBUG_PRINT ("sdb_view_global_row_expanded_idle_destroy ()");
824 dbv = node_expand->dbv;
825 dbe = node_expand->dbe;
827 /* remove from the GTree the ids of the func expanding */
828 g_tree_remove (dbv->priv->expanding_gfunc_ids,
829 (gpointer)node_expand->expanded_symbol_id);
831 if (node_expand->expanded_path != NULL) {
832 gtk_tree_path_free (node_expand->expanded_path);
833 node_expand->expanded_path = NULL;
835 g_object_unref (node_expand->iterator);
836 node_expand->iterator = NULL;
837 g_free (node_expand);
840 static gboolean
841 sdb_view_row_expanded_idle (gpointer data)
843 NodeIdleExpand *node_expand;
844 SymbolDBView *dbv;
845 SymbolDBEngine *dbe;
846 SymbolDBEngineIterator *iterator;
847 const GdkPixbuf *pixbuf;
848 const gchar* symbol_name;
849 const gchar* symbol_kind;
850 const gchar* symbol_access;
851 GtkTreeIter iter;
852 gint curr_symbol_id;
853 SymbolDBEngineIteratorNode *iter_node;
854 gpointer node;
855 GtkTreeRowReference *curr_tree_row_ref;
856 SymbolDBViewPriv *priv;
858 node_expand = data;
860 dbv = node_expand->dbv;
861 iterator = node_expand->iterator;
862 dbe = node_expand->dbe;
863 priv = dbv->priv;
865 if (iterator == NULL)
866 return FALSE;
868 iter_node = SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator);
869 curr_symbol_id = symbol_db_engine_iterator_node_get_symbol_id (iter_node);
870 node = g_tree_lookup (priv->nodes_displayed, (gpointer)curr_symbol_id);
872 if (node != NULL)
874 /* already displayed */
875 return symbol_db_engine_iterator_move_next (iterator);
878 symbol_name = symbol_db_engine_iterator_node_get_symbol_name (iter_node);
879 symbol_kind = symbol_db_engine_iterator_node_get_symbol_extra_string (iter_node,
880 SYMINFO_KIND);
881 symbol_access = symbol_db_engine_iterator_node_get_symbol_extra_string (iter_node,
882 SYMINFO_ACCESS);
883 pixbuf = symbol_db_view_get_pixbuf (symbol_kind, symbol_access);
885 curr_tree_row_ref = do_add_child_symbol_to_view (dbv,
886 node_expand->expanded_symbol_id, pixbuf,
887 symbol_name, curr_symbol_id);
888 if (curr_tree_row_ref == NULL)
890 return symbol_db_engine_iterator_move_next (iterator);
893 /* we'll fake the gpointer to store an int */
894 g_tree_insert (priv->nodes_displayed, (gpointer)curr_symbol_id,
895 curr_tree_row_ref);
897 sdb_view_get_iter_from_row_ref (dbv, curr_tree_row_ref, &iter);
899 /* check for children about this node... */
900 sdb_view_do_add_hidden_dummy_child (dbv, dbe, &iter, curr_symbol_id,
901 FALSE);
903 if (node_expand->expanded_path != NULL)
905 gtk_tree_view_expand_row (GTK_TREE_VIEW (dbv),
906 node_expand->expanded_path,
907 FALSE);
908 gtk_tree_path_free (node_expand->expanded_path);
909 node_expand->expanded_path = NULL;
912 if (symbol_db_engine_iterator_move_next (iterator) == TRUE)
914 return TRUE;
916 else {
917 if (g_tree_lookup (priv->nodes_displayed,
918 (gpointer)-node_expand->expanded_symbol_id) == NULL)
920 GtkTreeRowReference *others_row_ref;
921 GtkTreeIter others_dummy_node;
922 others_row_ref = do_add_child_symbol_to_view (dbv,
923 node_expand->expanded_symbol_id,
924 symbol_db_view_get_pixbuf ("vars", "others"),
925 "Vars/Others",
926 -node_expand->expanded_symbol_id);
928 /* insert a negative node ... */
929 g_tree_insert (priv->nodes_displayed,
930 (gpointer)-node_expand->expanded_symbol_id,
931 others_row_ref);
933 /* ... and a dummy child */
934 sdb_view_get_iter_from_row_ref (dbv, others_row_ref, &others_dummy_node);
936 sdb_view_do_add_hidden_dummy_child (dbv, dbe, &others_dummy_node, 0,
937 TRUE);
940 return FALSE;
944 static void
945 sdb_view_namespace_row_expanded (SymbolDBView *dbv, SymbolDBEngine *dbe,
946 GtkTreeIter *expanded_iter, gint expanded_symbol_id)
948 SymbolDBViewPriv *priv;
949 SymbolDBEngineIterator *iterator;
950 GtkTreeStore *store;
951 GPtrArray *filter_array;
952 gpointer node;
954 g_return_if_fail (dbv != NULL);
955 priv = dbv->priv;
957 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
959 DEBUG_PRINT ("sdb_view_namespace_row_expanded ");
961 /* check if there's another expanding idle_func running */
962 node = g_tree_lookup (priv->expanding_gfunc_ids, (gpointer)expanded_symbol_id);
963 if (node != NULL)
965 return;
968 filter_array = g_ptr_array_new ();
969 g_ptr_array_add (filter_array, "class");
970 g_ptr_array_add (filter_array, "struct");
972 /* get results from database */
973 iterator = symbol_db_engine_get_scope_members_by_symbol_id_filtered (dbe,
974 expanded_symbol_id,
975 filter_array,
976 TRUE,
979 SYMINFO_SIMPLE|
980 SYMINFO_KIND|
981 SYMINFO_ACCESS
984 g_ptr_array_free (filter_array, TRUE);
986 if (iterator != NULL)
988 NodeIdleExpand *node_expand;
989 gint idle_id;
991 node_expand = g_new0 (NodeIdleExpand, 1);
993 node_expand->dbv = dbv;
994 node_expand->iterator = iterator;
995 node_expand->dbe = dbe;
996 node_expand->expanded_path =
997 gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
998 expanded_iter);
999 node_expand->expanded_symbol_id = expanded_symbol_id;
1001 /* be sure that the expanding process doesn't freeze the gui */
1002 idle_id = g_idle_add_full (G_PRIORITY_LOW,
1003 (GSourceFunc) sdb_view_row_expanded_idle,
1004 (gpointer) node_expand,
1005 (GDestroyNotify) sdb_view_row_expanded_idle_destroy);
1007 /* insert the idle_id into a g_tree */
1008 g_tree_insert (priv->expanding_gfunc_ids, (gpointer)expanded_symbol_id,
1009 (gpointer)idle_id);
1014 static void
1015 sdb_view_global_row_expanded (SymbolDBView *dbv, SymbolDBEngine *dbe,
1016 GtkTreeIter *expanded_iter, gint expanded_symbol_id)
1018 GtkTreeStore *store;
1019 SymbolDBViewPriv *priv;
1020 SymbolDBEngineIterator *iterator;
1021 GPtrArray *filter_array;
1022 gpointer node;
1023 g_return_if_fail (dbv != NULL);
1025 priv = dbv->priv;
1027 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1029 DEBUG_PRINT ("sdb_view_global_row_expanded ()");
1031 /* check if there's another expanding idle_func running */
1032 node = g_tree_lookup (priv->expanding_gfunc_ids, (gpointer)expanded_symbol_id);
1033 if (node != NULL)
1035 return;
1038 filter_array = g_ptr_array_new ();
1039 g_ptr_array_add (filter_array, "class");
1040 g_ptr_array_add (filter_array, "struct");
1042 /* check for the presence of namespaces.
1043 * If that's the case then populate the root with a 'Global' node.
1045 iterator = symbol_db_engine_get_global_members_filtered (dbe, filter_array,
1046 TRUE,
1047 TRUE,
1050 SYMINFO_SIMPLE |
1051 SYMINFO_ACCESS |
1052 SYMINFO_KIND);
1053 g_ptr_array_free (filter_array, TRUE);
1055 if (iterator != NULL)
1057 NodeIdleExpand *node_expand;
1058 gint idle_id;
1060 node_expand = g_new0 (NodeIdleExpand, 1);
1062 node_expand->dbv = dbv;
1063 node_expand->iterator = iterator;
1064 node_expand->dbe = dbe;
1065 node_expand->expanded_path = gtk_tree_model_get_path (
1066 gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
1067 expanded_iter);
1068 node_expand->expanded_symbol_id = expanded_symbol_id;
1070 idle_id = g_idle_add_full (G_PRIORITY_LOW,
1071 (GSourceFunc) sdb_view_row_expanded_idle,
1072 (gpointer) node_expand,
1073 (GDestroyNotify) sdb_view_row_expanded_idle_destroy);
1075 /* insert the idle_id into a g_tree for (eventually) a later retrieval */
1076 DEBUG_PRINT ("Inserting into g_tree expanded_symbol_id %d and idle_id %d",
1077 expanded_symbol_id, idle_id);
1078 g_tree_insert (priv->expanding_gfunc_ids, (gpointer)expanded_symbol_id,
1079 (gpointer)idle_id);
1083 static void
1084 sdb_view_vars_row_expanded (SymbolDBView *dbv, SymbolDBEngine *dbe,
1085 GtkTreeIter *expanded_iter, gint expanded_symbol_id)
1087 SymbolDBViewPriv *priv;
1088 SymbolDBEngineIterator *iterator;
1089 GtkTreeStore *store;
1090 GPtrArray *filter_array;
1091 gint positive_symbol_expanded;
1092 gpointer node;
1094 g_return_if_fail (dbv != NULL);
1095 priv = dbv->priv;
1097 positive_symbol_expanded = -expanded_symbol_id;
1098 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1100 DEBUG_PRINT ("sdb_view_vars_row_expanded ()");
1102 /* check if there's another expanding idle_func running */
1103 node = g_tree_lookup (priv->expanding_gfunc_ids, (gpointer)expanded_symbol_id);
1104 if (node != NULL)
1106 return;
1109 filter_array = g_ptr_array_new ();
1110 g_ptr_array_add (filter_array, "class");
1111 g_ptr_array_add (filter_array, "struct");
1113 if (positive_symbol_expanded == ROOT_GLOBAL)
1115 iterator = symbol_db_engine_get_global_members_filtered (dbe, filter_array,
1116 FALSE,
1117 TRUE,
1120 SYMINFO_SIMPLE |
1121 SYMINFO_ACCESS |
1122 SYMINFO_KIND);
1124 else
1126 iterator = symbol_db_engine_get_scope_members_by_symbol_id_filtered (dbe,
1127 positive_symbol_expanded,
1128 filter_array,
1129 FALSE,
1132 SYMINFO_SIMPLE|
1133 SYMINFO_KIND|
1134 SYMINFO_ACCESS
1138 g_ptr_array_free (filter_array, TRUE);
1140 if (iterator != NULL)
1142 NodeIdleExpand *node_expand;
1143 gint idle_id;
1145 node_expand = g_new0 (NodeIdleExpand, 1);
1147 node_expand->dbv = dbv;
1148 node_expand->iterator = iterator;
1149 node_expand->dbe = dbe;
1150 node_expand->expanded_path = gtk_tree_model_get_path (
1151 gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
1152 expanded_iter);
1153 node_expand->expanded_symbol_id = expanded_symbol_id;
1155 idle_id = g_idle_add_full (G_PRIORITY_LOW,
1156 (GSourceFunc) sdb_view_row_expanded_idle,
1157 (gpointer) node_expand,
1158 (GDestroyNotify) sdb_view_row_expanded_idle_destroy);
1160 /* insert the idle_id into a g_tree */
1161 g_tree_insert (priv->expanding_gfunc_ids, (gpointer)expanded_symbol_id,
1162 (gpointer)idle_id);
1167 * Usually on a row expanded event we should perform the following steps:
1168 * 1. retrieve a list of scoped children.
1169 * 2. check if the nth children has already been displayed or not.
1170 * 3. if it isn't then append a child *and* check if that child has children itself.
1171 * using a dummy node we can achieve a performant population while setting an expand
1172 * mark on the child firstly appended.
1174 void
1175 symbol_db_view_row_expanded (SymbolDBView *dbv, SymbolDBEngine *dbe,
1176 GtkTreeIter *expanded_iter)
1178 GtkTreeStore *store;
1179 gint expanded_symbol_id;
1180 SymbolDBViewPriv *priv;
1181 SymbolDBEngineIterator *iterator;
1182 GtkTreePath *path;
1184 g_return_if_fail (dbv != NULL);
1185 priv = dbv->priv;
1187 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1189 gtk_tree_model_get (GTK_TREE_MODEL (store), expanded_iter,
1190 COLUMN_SYMBOL_ID, &expanded_symbol_id, -1);
1192 /* remove the dummy item, if present */
1193 if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (store), expanded_iter))
1195 GtkTreeIter child;
1196 gint dummy_symbol;
1197 gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, expanded_iter);
1199 gtk_tree_model_get (GTK_TREE_MODEL (store), &child,
1200 COLUMN_SYMBOL_ID, &dummy_symbol, -1);
1202 if (dummy_symbol == DUMMY_SYMBOL_ID)
1203 gtk_tree_store_remove (store, &child);
1206 /* Ok. Is the expanded node a 'namespace' one? A 'global' one? Or a
1207 * 'vars/etc' one? parse here the cases and if we're not there
1208 * go on with a classic expanding node algo.
1211 /* Case Global */
1212 if (expanded_symbol_id == ROOT_GLOBAL)
1214 sdb_view_global_row_expanded (dbv, dbe, expanded_iter, expanded_symbol_id);
1215 return;
1218 /* Case vars/etc */
1219 /* To identify a vars/etc node we'll check if the expanded_symbol_id is negative.
1220 * If yes, we can have the parent namespace by making the id positive.
1222 if (expanded_symbol_id < 0)
1224 sdb_view_vars_row_expanded (dbv, dbe, expanded_iter, expanded_symbol_id);
1225 return;
1229 /* Case namespace */
1230 iterator = symbol_db_engine_get_symbol_info_by_id (dbe, expanded_symbol_id,
1231 SYMINFO_KIND);
1232 if (iterator != NULL)
1234 SymbolDBEngineIteratorNode *iter_node;
1235 const gchar* symbol_kind;
1237 iter_node = SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator);
1238 symbol_kind = symbol_db_engine_iterator_node_get_symbol_extra_string (
1239 iter_node, SYMINFO_KIND);
1240 if (strcmp (symbol_kind, "namespace") == 0)
1242 sdb_view_namespace_row_expanded (dbv, dbe, expanded_iter,
1243 expanded_symbol_id);
1244 g_object_unref (iterator);
1245 return;
1247 g_object_unref (iterator);
1250 /* Case Normal: go on with usual expanding */
1251 DEBUG_PRINT ("symbol_db_view_row_expanded (): expanded %d", expanded_symbol_id);
1253 /* Step 1 */
1254 iterator = symbol_db_engine_get_scope_members_by_symbol_id (dbe,
1255 expanded_symbol_id,
1258 SYMINFO_SIMPLE|
1259 SYMINFO_KIND|
1260 SYMINFO_ACCESS);
1262 if (iterator != NULL)
1264 do {
1265 gint curr_symbol_id;
1266 SymbolDBEngineIteratorNode *iter_node;
1267 const GdkPixbuf *pixbuf;
1268 const gchar* symbol_name;
1269 GtkTreeIter child_iter;
1270 GtkTreePath *path;
1271 GtkTreeRowReference *child_row_ref;
1272 gpointer node;
1274 iter_node = SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator);
1276 curr_symbol_id = symbol_db_engine_iterator_node_get_symbol_id (iter_node);
1278 /* Step 2:
1279 * check if the curr_symbol_id is already displayed. In that case
1280 * skip to the next symbol
1282 node = g_tree_lookup (priv->nodes_displayed, (gpointer)curr_symbol_id);
1284 if (node != NULL)
1286 continue;
1289 /* Step 3 */
1290 /* ok we must display this symbol */
1291 pixbuf = symbol_db_view_get_pixbuf (
1292 symbol_db_engine_iterator_node_get_symbol_extra_string (
1293 iter_node, SYMINFO_KIND),
1294 symbol_db_engine_iterator_node_get_symbol_extra_string (
1295 iter_node, SYMINFO_ACCESS));
1297 symbol_name = symbol_db_engine_iterator_node_get_symbol_name (iter_node);
1299 gtk_tree_store_append (store, &child_iter, expanded_iter);
1301 gtk_tree_store_set (store, &child_iter,
1302 COLUMN_PIXBUF, pixbuf,
1303 COLUMN_NAME, symbol_name,
1304 COLUMN_SYMBOL_ID, curr_symbol_id,
1305 -1);
1307 path = gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
1308 &child_iter);
1309 child_row_ref = gtk_tree_row_reference_new (
1310 gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)), path);
1311 gtk_tree_path_free (path);
1313 /* insert the just append row_ref into the GTree for a quick retrieval
1314 * later
1316 g_tree_insert (priv->nodes_displayed, (gpointer)curr_symbol_id,
1317 child_row_ref);
1319 /* good. Let's check now for a child (B) of the just appended child (A).
1320 * Adding B (a dummy one for now) to A will make A expandable
1322 sdb_view_do_add_hidden_dummy_child (dbv, dbe, &child_iter, curr_symbol_id,
1323 FALSE);
1325 } while (symbol_db_engine_iterator_move_next (iterator) == TRUE);
1327 g_object_unref (iterator);
1330 /* force expand it */
1331 path = gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
1332 expanded_iter);
1333 gtk_tree_view_expand_row (GTK_TREE_VIEW (dbv), path, FALSE);
1334 gtk_tree_path_free (path);
1337 void
1338 symbol_db_view_row_collapsed (SymbolDBView *dbv, SymbolDBEngine *dbe,
1339 GtkTreeIter *collapsed_iter)
1341 GtkTreeStore *store;
1342 gint collapsed_symbol_id;
1343 SymbolDBViewPriv *priv;
1344 gpointer node;
1346 g_return_if_fail (dbv != NULL);
1347 priv = dbv->priv;
1349 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1351 gtk_tree_model_get (GTK_TREE_MODEL (store), collapsed_iter,
1352 COLUMN_SYMBOL_ID, &collapsed_symbol_id, -1);
1354 /* do a quick check to see if the collapsed_symbol_id is listed into the
1355 * currently expanding symbols. If that's the case remove the gsource func.
1357 node = g_tree_lookup (priv->expanding_gfunc_ids, (gpointer)collapsed_symbol_id);
1359 if (node == NULL)
1361 /* no expanding gfunc found. */
1362 return;
1364 else {
1365 g_source_remove ((gint)node);
1366 g_tree_remove (priv->expanding_gfunc_ids, (gpointer)collapsed_symbol_id);
1370 static GtkTreeStore *
1371 sdb_view_create_new_store ()
1373 GtkTreeStore *store;
1374 store = gtk_tree_store_new (COLUMN_MAX, GDK_TYPE_PIXBUF,
1375 G_TYPE_STRING, G_TYPE_INT);
1376 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
1377 COLUMN_NAME,
1378 GTK_SORT_ASCENDING);
1379 return store;
1382 static void
1383 sdb_view_init (SymbolDBView *object)
1385 SymbolDBView *dbv;
1386 GtkTreeStore *store;
1387 GtkTreeViewColumn *column;
1388 GtkCellRenderer *renderer;
1389 GtkTreeSelection *selection;
1390 SymbolDBViewPriv *priv;
1392 dbv = SYMBOL_DB_VIEW (object);
1393 dbv->priv = g_new0 (SymbolDBViewPriv, 1);
1395 priv = dbv->priv;
1397 /* initialize some priv data */
1398 priv->insert_handler = 0;
1399 priv->remove_handler = 0;
1400 priv->nodes_displayed = NULL;
1401 priv->waiting_for = NULL;
1403 priv->row_ref_global = NULL;
1404 priv->scan_end_handler = 0;
1405 priv->remove_handler = 0;
1406 priv->scan_end_handler = 0;
1408 /* create a GTree where to store the row_expanding ids of the gfuncs.
1409 * we would be able then to g_source_remove them on row_collapsed
1411 priv->expanding_gfunc_ids = g_tree_new_full ((GCompareDataFunc)&gtree_compare_func,
1412 NULL, NULL, NULL);
1414 /* Tree and his model */
1415 store = NULL;
1417 gtk_tree_view_set_model (GTK_TREE_VIEW (dbv), GTK_TREE_MODEL (store));
1418 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dbv), FALSE);
1420 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dbv));
1421 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1423 /* search through the tree interactively */
1424 gtk_tree_view_set_search_column (GTK_TREE_VIEW (dbv), COLUMN_NAME);
1425 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (dbv), TRUE);
1427 /* Columns */
1428 column = gtk_tree_view_column_new ();
1429 gtk_tree_view_column_set_sizing (column,
1430 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1431 gtk_tree_view_column_set_title (column, _("Symbol"));
1433 renderer = gtk_cell_renderer_pixbuf_new ();
1434 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1435 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
1436 COLUMN_PIXBUF);
1438 renderer = gtk_cell_renderer_text_new ();
1439 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1440 gtk_tree_view_column_add_attribute (column, renderer, "text",
1441 COLUMN_NAME);
1443 gtk_tree_view_append_column (GTK_TREE_VIEW (dbv), column);
1444 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (dbv), column);
1448 static void
1449 sdb_view_finalize (GObject *object)
1451 SymbolDBView *view = SYMBOL_DB_VIEW (object);
1452 SymbolDBViewPriv *priv = view->priv;
1454 DEBUG_PRINT ("finalizing symbol_db_view ()");
1456 symbol_db_view_clear_cache (view);
1458 if (priv->expanding_gfunc_ids)
1459 g_tree_destroy (priv->expanding_gfunc_ids);
1461 g_free (priv);
1463 /* dbe must be freed outside. */
1464 G_OBJECT_CLASS (parent_class)->finalize (object);
1467 static void
1468 sdb_view_class_init (SymbolDBViewClass *klass)
1470 SymbolDBViewClass *sdbc;
1471 GObjectClass* object_class = G_OBJECT_CLASS (klass);
1472 parent_class = g_type_class_peek_parent (klass);
1474 sdbc = SYMBOL_DB_VIEW_CLASS (klass);
1475 object_class->finalize = sdb_view_finalize;
1478 GType
1479 symbol_db_view_get_type (void)
1481 static GType obj_type = 0;
1483 if (!obj_type)
1485 static const GTypeInfo obj_info = {
1486 sizeof (SymbolDBViewClass),
1487 (GBaseInitFunc) NULL,
1488 (GBaseFinalizeFunc) NULL,
1489 (GClassInitFunc) sdb_view_class_init,
1490 (GClassFinalizeFunc) NULL,
1491 NULL, /* class_data */
1492 sizeof (SymbolDBViewClass),
1493 0, /* n_preallocs */
1494 (GInstanceInitFunc) sdb_view_init,
1495 NULL /* value_table */
1497 obj_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
1498 "SymbolDBView",
1499 &obj_info, 0);
1501 return obj_type;
1505 #define CREATE_SYM_ICON(N, F) \
1506 pix_file = anjuta_res_get_pixmap_file (F); \
1507 g_hash_table_insert (pixbufs_hash, \
1508 N, \
1509 gdk_pixbuf_new_from_file (pix_file, NULL)); \
1510 g_free (pix_file);
1512 static void
1513 sdb_view_load_symbol_pixbufs ()
1515 gchar *pix_file;
1517 if (pixbufs_hash != NULL)
1519 /* we already have loaded it */
1520 return;
1523 pixbufs_hash = g_hash_table_new (g_str_hash, g_str_equal);
1525 CREATE_SYM_ICON ("class", "Icons.16x16.Class");
1526 CREATE_SYM_ICON ("enum", "Icons.16x16.Enum");
1527 CREATE_SYM_ICON ("enumerator", "Icons.16x16.Enum");
1528 CREATE_SYM_ICON ("function", "Icons.16x16.Method");
1529 CREATE_SYM_ICON ("interface", "Icons.16x16.Interface");
1530 CREATE_SYM_ICON ("macro", "Icons.16x16.Field");
1531 CREATE_SYM_ICON ("namespace", "Icons.16x16.NameSpace");
1532 CREATE_SYM_ICON ("none", "Icons.16x16.Literal");
1533 CREATE_SYM_ICON ("struct", "Icons.16x16.ProtectedStruct");
1534 CREATE_SYM_ICON ("typedef", "Icons.16x16.Reference");
1535 CREATE_SYM_ICON ("union", "Icons.16x16.PrivateStruct");
1536 CREATE_SYM_ICON ("variable", "Icons.16x16.Literal");
1537 CREATE_SYM_ICON ("prototype", "Icons.16x16.Interface");
1539 CREATE_SYM_ICON ("privateclass", "Icons.16x16.PrivateClass");
1540 CREATE_SYM_ICON ("privateenum", "Icons.16x16.PrivateEnum");
1541 CREATE_SYM_ICON ("privatefield", "Icons.16x16.PrivateField");
1542 CREATE_SYM_ICON ("privatefunction", "Icons.16x16.PrivateMethod");
1543 CREATE_SYM_ICON ("privateinterface", "Icons.16x16.PrivateInterface");
1544 CREATE_SYM_ICON ("privatemember", "Icons.16x16.PrivateProperty");
1545 CREATE_SYM_ICON ("privatemethod", "Icons.16x16.PrivateMethod");
1546 CREATE_SYM_ICON ("privateproperty", "Icons.16x16.PrivateProperty");
1547 CREATE_SYM_ICON ("privatestruct", "Icons.16x16.PrivateStruct");
1548 CREATE_SYM_ICON ("privateprototype", "Icons.16x16.PrivateInterface");
1550 CREATE_SYM_ICON ("protectedclass", "Icons.16x16.ProtectedClass");
1551 CREATE_SYM_ICON ("protectedenum", "Icons.16x16.ProtectedEnum");
1552 CREATE_SYM_ICON ("protectedfield", "Icons.16x16.ProtectedField");
1553 CREATE_SYM_ICON ("protectedmember", "Icons.16x16.ProtectedProperty");
1554 CREATE_SYM_ICON ("protectedmethod", "Icons.16x16.ProtectedMethod");
1555 CREATE_SYM_ICON ("protectedproperty", "Icons.16x16.ProtectedProperty");
1556 CREATE_SYM_ICON ("publicprototype", "Icons.16x16.ProtectedInterface");
1558 CREATE_SYM_ICON ("publicclass", "Icons.16x16.Class");
1559 CREATE_SYM_ICON ("publicenum", "Icons.16x16.Enum");
1560 CREATE_SYM_ICON ("publicfunction", "Icons.16x16.Method");
1561 CREATE_SYM_ICON ("publicmember", "Icons.16x16.Method");
1562 CREATE_SYM_ICON ("publicproperty", "Icons.16x16.Property");
1563 CREATE_SYM_ICON ("publicstruct", "Icons.16x16.Struct");
1564 CREATE_SYM_ICON ("publicprototype", "Icons.16x16.Interface");
1566 /* special icon */
1567 CREATE_SYM_ICON ("othersvars", "Icons.16x16.Event");
1568 CREATE_SYM_ICON ("globalglobal", "Icons.16x16.Event");
1572 * @return The pixbufs. It will initialize pixbufs first if they weren't before
1573 * @param node_access can be NULL.
1575 const GdkPixbuf*
1576 symbol_db_view_get_pixbuf (const gchar *node_type, const gchar *node_access)
1578 gchar *search_node;
1579 GdkPixbuf *pix;
1580 if (!pixbufs_hash)
1582 sdb_view_load_symbol_pixbufs ();
1585 g_return_val_if_fail (node_type != NULL, NULL);
1587 /* is there a better/quicker method to retrieve pixbufs? */
1588 if (node_access != NULL)
1590 search_node = g_strdup_printf ("%s%s", node_access, node_type);
1592 else
1594 /* we will not free search_node gchar, so casting here is ok. */
1595 search_node = (gchar*)node_type;
1597 pix = GDK_PIXBUF (g_hash_table_lookup (pixbufs_hash, search_node));
1599 if (node_access)
1601 g_free (search_node);
1604 if (pix == NULL)
1606 DEBUG_PRINT ("symbol_db_view_get_pixbuf (): no pixbuf for %s %s",
1607 node_type, node_access);
1610 return pix;
1614 GtkWidget*
1615 symbol_db_view_new (void)
1617 return GTK_WIDGET (g_object_new (SYMBOL_TYPE_DB_VIEW, NULL));
1620 gboolean
1621 symbol_db_view_get_file_and_line (SymbolDBView *dbv, SymbolDBEngine *dbe,
1622 GtkTreeIter * iter, gint *OUT_line, gchar **OUT_file)
1624 GtkTreeStore *store;
1626 g_return_val_if_fail (dbv != NULL, FALSE);
1627 g_return_val_if_fail (dbe != NULL, FALSE);
1628 g_return_val_if_fail (iter != NULL, FALSE);
1630 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1632 if (store)
1634 gint symbol_id;
1635 const gchar* relative_file;
1636 SymbolDBEngineIteratorNode *node;
1638 gtk_tree_model_get (GTK_TREE_MODEL
1639 (store), iter,
1640 COLUMN_SYMBOL_ID, &symbol_id, -1);
1642 /* getting line at click time with a query is faster than updating every
1643 * entry in the gtktreeview. We can be sure that the db is in a consistent
1644 * state and has all the last infos
1646 node = SYMBOL_DB_ENGINE_ITERATOR_NODE (
1647 symbol_db_engine_get_symbol_info_by_id (dbe, symbol_id,
1648 SYMINFO_SIMPLE |
1649 SYMINFO_FILE_PATH));
1650 if (node != NULL)
1652 *OUT_line = symbol_db_engine_iterator_node_get_symbol_file_pos (node);
1653 relative_file =
1654 symbol_db_engine_iterator_node_get_symbol_extra_string (node,
1655 SYMINFO_FILE_PATH);
1656 *OUT_file = symbol_db_engine_get_full_local_path (dbe, relative_file);
1657 return TRUE;
1661 return FALSE;
1664 static void
1665 sdb_view_build_and_display_base_tree (SymbolDBView *dbv, SymbolDBEngine *dbe)
1667 GtkTreeStore *store;
1668 SymbolDBViewPriv *priv;
1669 SymbolDBEngineIterator *iterator;
1670 gboolean we_have_namespaces;
1671 GPtrArray *filter_array;
1672 GtkTreeRowReference *global_tree_row_ref;
1673 GtkTreeIter global_child_iter;
1674 const GdkPixbuf *global_pixbuf;
1676 g_return_if_fail (dbv != NULL);
1678 priv = dbv->priv;
1680 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1682 we_have_namespaces = FALSE;
1684 filter_array = g_ptr_array_new ();
1685 g_ptr_array_add (filter_array, "namespace");
1687 /* check for the presence of namespaces.
1688 * If that's the case then populate the root with a 'Global' node.
1690 iterator = symbol_db_engine_get_global_members_filtered (dbe, filter_array, TRUE,
1691 TRUE,
1694 SYMINFO_SIMPLE |
1695 SYMINFO_ACCESS |
1696 SYMINFO_KIND);
1697 g_ptr_array_free (filter_array, TRUE);
1699 if (iterator != NULL)
1701 we_have_namespaces = TRUE;
1703 do {
1704 gint curr_symbol_id;
1705 SymbolDBEngineIteratorNode *iter_node;
1706 const GdkPixbuf *pixbuf;
1707 const gchar* symbol_name;
1708 GtkTreeRowReference *curr_tree_row_ref;
1709 GtkTreeIter child_iter;
1711 iter_node = SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator);
1713 curr_symbol_id = symbol_db_engine_iterator_node_get_symbol_id (iter_node);
1715 pixbuf = symbol_db_view_get_pixbuf (
1716 symbol_db_engine_iterator_node_get_symbol_extra_string (
1717 iter_node, SYMINFO_KIND),
1718 symbol_db_engine_iterator_node_get_symbol_extra_string (
1719 iter_node, SYMINFO_ACCESS));
1721 symbol_name = symbol_db_engine_iterator_node_get_symbol_name (iter_node);
1723 curr_tree_row_ref = do_add_root_symbol_to_view (dbv, pixbuf,
1724 symbol_name, curr_symbol_id);
1725 if (curr_tree_row_ref == NULL)
1727 continue;
1730 /* we'll fake the gpointer to store an int */
1731 g_tree_insert (priv->nodes_displayed, (gpointer)curr_symbol_id,
1732 curr_tree_row_ref);
1734 if (sdb_view_get_iter_from_row_ref (dbv, curr_tree_row_ref,
1735 &child_iter) == FALSE)
1737 g_warning ("sdb_view_build_and_display_base_tree (): something "
1738 "went wrong");
1739 continue;
1741 /* add a dummy child */
1742 sdb_view_do_add_hidden_dummy_child (dbv, dbe,
1743 &child_iter, curr_symbol_id, FALSE);
1745 } while (symbol_db_engine_iterator_move_next (iterator) == TRUE);
1747 g_object_unref (iterator);
1751 * Good. Add a 'Global' node to the store.
1753 global_pixbuf = symbol_db_view_get_pixbuf ("global", "global");
1755 global_tree_row_ref = do_add_root_symbol_to_view (dbv, global_pixbuf,
1756 "Global", ROOT_GLOBAL);
1758 if (global_tree_row_ref == NULL)
1760 return;
1762 g_tree_insert (priv->nodes_displayed, (gpointer)ROOT_GLOBAL,
1763 global_tree_row_ref);
1765 if (sdb_view_get_iter_from_row_ref (dbv, global_tree_row_ref,
1766 &global_child_iter) == FALSE)
1768 g_warning ("sdb_view_build_and_display_base_tree (): cannot retrieve iter for "
1769 "row_ref");
1770 return;
1773 /* add a dummy child */
1774 sdb_view_do_add_hidden_dummy_child (dbv, dbe,
1775 &global_child_iter, ROOT_GLOBAL, TRUE);
1778 void
1779 symbol_db_view_recv_signals_from_engine (SymbolDBView *dbv, SymbolDBEngine *dbe,
1780 gboolean enable_status)
1782 SymbolDBViewPriv *priv;
1784 g_return_if_fail (dbv != NULL);
1785 priv = dbv->priv;
1787 if (enable_status == TRUE)
1789 gtk_widget_set_sensitive (GTK_WIDGET (dbv), TRUE);
1790 /* connect some signals */
1791 if (priv->insert_handler <= 0)
1793 priv->insert_handler = g_signal_connect (G_OBJECT (dbe), "symbol-inserted",
1794 G_CALLBACK (on_symbol_inserted), dbv);
1797 if (priv->remove_handler <= 0)
1799 priv->remove_handler = g_signal_connect (G_OBJECT (dbe), "symbol-removed",
1800 G_CALLBACK (on_symbol_removed), dbv);
1803 if (priv->scan_end_handler <= 0)
1805 priv->scan_end_handler = g_signal_connect (G_OBJECT (dbe), "scan-end",
1806 G_CALLBACK (on_scan_end), dbv);
1809 else /* disconnect them, if they were ever connected before */
1811 gtk_widget_set_sensitive (GTK_WIDGET (dbv), FALSE);
1813 if (priv->insert_handler >= 0)
1815 g_signal_handler_disconnect (G_OBJECT (dbe), priv->insert_handler);
1816 priv->insert_handler = 0;
1819 if (priv->remove_handler >= 0)
1821 g_signal_handler_disconnect (G_OBJECT (dbe), priv->remove_handler);
1822 priv->remove_handler = 0;
1825 if (priv->scan_end_handler >= 0)
1827 g_signal_handler_disconnect (G_OBJECT (dbe), priv->scan_end_handler);
1828 priv->scan_end_handler = 0;
1833 void
1834 symbol_db_view_open (SymbolDBView *dbv, SymbolDBEngine *dbe)
1836 SymbolDBViewPriv *priv;
1837 GtkTreeStore *store;
1839 g_return_if_fail (dbv != NULL);
1841 priv = dbv->priv;
1843 DEBUG_PRINT ("symbol_db_view_open ()");
1844 symbol_db_view_clear_cache (dbv);
1846 store = sdb_view_create_new_store ();
1847 gtk_tree_view_set_model (GTK_TREE_VIEW (dbv), GTK_TREE_MODEL (store));
1849 priv->nodes_displayed = g_tree_new_full ((GCompareDataFunc)&gtree_compare_func,
1850 NULL,
1851 NULL,
1852 (GDestroyNotify)&gtk_tree_row_reference_free);
1854 priv->waiting_for = g_tree_new_full ((GCompareDataFunc)&gtree_compare_func,
1855 NULL,
1856 NULL,
1857 NULL);
1859 sdb_view_build_and_display_base_tree (dbv, dbe);