Check that a given filename is valid before setting it on a GtkFileChooserButton
[anjuta-git-plugin.git] / plugins / symbol-db / symbol-db-view.c
blobf65ab239b18b677c2a05bf533dea1b35409ab7a4
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| SYMINFO_KIND| SYMINFO_ACCESS
982 g_ptr_array_free (filter_array, TRUE);
984 if (iterator != NULL)
986 NodeIdleExpand *node_expand;
987 gint idle_id;
989 node_expand = g_new0 (NodeIdleExpand, 1);
991 node_expand->dbv = dbv;
992 node_expand->iterator = iterator;
993 node_expand->dbe = dbe;
994 node_expand->expanded_path =
995 gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
996 expanded_iter);
997 node_expand->expanded_symbol_id = expanded_symbol_id;
999 /* be sure that the expanding process doesn't freeze the gui */
1000 idle_id = g_idle_add_full (G_PRIORITY_LOW,
1001 (GSourceFunc) sdb_view_row_expanded_idle,
1002 (gpointer) node_expand,
1003 (GDestroyNotify) sdb_view_row_expanded_idle_destroy);
1005 /* insert the idle_id into a g_tree */
1006 g_tree_insert (priv->expanding_gfunc_ids, (gpointer)expanded_symbol_id,
1007 (gpointer)idle_id);
1012 static void
1013 sdb_view_global_row_expanded (SymbolDBView *dbv, SymbolDBEngine *dbe,
1014 GtkTreeIter *expanded_iter, gint expanded_symbol_id)
1016 GtkTreeStore *store;
1017 SymbolDBViewPriv *priv;
1018 SymbolDBEngineIterator *iterator;
1019 GPtrArray *filter_array;
1020 gpointer node;
1021 g_return_if_fail (dbv != NULL);
1023 priv = dbv->priv;
1025 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1027 filter_array = g_ptr_array_new ();
1028 g_ptr_array_add (filter_array, "class");
1029 g_ptr_array_add (filter_array, "struct");
1031 DEBUG_PRINT ("sdb_view_global_row_expanded ()");
1033 /* check if there's another expanding idle_func running */
1034 node = g_tree_lookup (priv->expanding_gfunc_ids, (gpointer)expanded_symbol_id);
1035 if (node != NULL)
1037 return;
1040 /* check for the presence of namespaces.
1041 * If that's the case then populate the root with a 'Global' node.
1043 iterator = symbol_db_engine_get_global_members_filtered (dbe, filter_array, TRUE,
1044 TRUE,
1047 SYMINFO_SIMPLE |
1048 SYMINFO_ACCESS |
1049 SYMINFO_KIND);
1050 g_ptr_array_free (filter_array, TRUE);
1052 if (iterator != NULL)
1054 NodeIdleExpand *node_expand;
1055 gint idle_id;
1057 node_expand = g_new0 (NodeIdleExpand, 1);
1059 node_expand->dbv = dbv;
1060 node_expand->iterator = iterator;
1061 node_expand->dbe = dbe;
1062 node_expand->expanded_path = gtk_tree_model_get_path (
1063 gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
1064 expanded_iter);
1065 node_expand->expanded_symbol_id = expanded_symbol_id;
1067 idle_id = g_idle_add_full (G_PRIORITY_LOW,
1068 (GSourceFunc) sdb_view_row_expanded_idle,
1069 (gpointer) node_expand,
1070 (GDestroyNotify) sdb_view_row_expanded_idle_destroy);
1072 /* insert the idle_id into a g_tree for (eventually) a later retrieval */
1073 DEBUG_PRINT ("Inserting into g_tree expanded_symbol_id %d and idle_id %d",
1074 expanded_symbol_id, idle_id);
1075 g_tree_insert (priv->expanding_gfunc_ids, (gpointer)expanded_symbol_id,
1076 (gpointer)idle_id);
1080 static void
1081 sdb_view_vars_row_expanded (SymbolDBView *dbv, SymbolDBEngine *dbe,
1082 GtkTreeIter *expanded_iter, gint expanded_symbol_id)
1084 SymbolDBViewPriv *priv;
1085 SymbolDBEngineIterator *iterator;
1086 GtkTreeStore *store;
1087 GPtrArray *filter_array;
1088 gint positive_symbol_expanded;
1089 gpointer node;
1091 g_return_if_fail (dbv != NULL);
1092 priv = dbv->priv;
1094 positive_symbol_expanded = -expanded_symbol_id;
1095 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1097 DEBUG_PRINT ("sdb_view_vars_row_expanded ()");
1099 /* check if there's another expanding idle_func running */
1100 node = g_tree_lookup (priv->expanding_gfunc_ids, (gpointer)expanded_symbol_id);
1101 if (node != NULL)
1103 return;
1106 filter_array = g_ptr_array_new ();
1107 g_ptr_array_add (filter_array, "class");
1108 g_ptr_array_add (filter_array, "struct");
1110 if (positive_symbol_expanded == ROOT_GLOBAL)
1112 iterator = symbol_db_engine_get_global_members_filtered (dbe, filter_array,
1113 FALSE,
1114 TRUE,
1117 SYMINFO_SIMPLE |
1118 SYMINFO_ACCESS |
1119 SYMINFO_KIND);
1121 else
1123 iterator = symbol_db_engine_get_scope_members_by_symbol_id_filtered (dbe,
1124 positive_symbol_expanded,
1125 filter_array,
1126 FALSE,
1129 SYMINFO_SIMPLE|
1130 SYMINFO_KIND|
1131 SYMINFO_ACCESS
1135 g_ptr_array_free (filter_array, TRUE);
1137 if (iterator != NULL)
1139 NodeIdleExpand *node_expand;
1140 gint idle_id;
1142 node_expand = g_new0 (NodeIdleExpand, 1);
1144 node_expand->dbv = dbv;
1145 node_expand->iterator = iterator;
1146 node_expand->dbe = dbe;
1147 node_expand->expanded_path = gtk_tree_model_get_path (
1148 gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
1149 expanded_iter);
1150 node_expand->expanded_symbol_id = expanded_symbol_id;
1152 idle_id = g_idle_add_full (G_PRIORITY_LOW,
1153 (GSourceFunc) sdb_view_row_expanded_idle,
1154 (gpointer) node_expand,
1155 (GDestroyNotify) sdb_view_row_expanded_idle_destroy);
1157 /* insert the idle_id into a g_tree */
1158 g_tree_insert (priv->expanding_gfunc_ids, (gpointer)expanded_symbol_id,
1159 (gpointer)idle_id);
1164 * Usually on a row expanded event we should perform the following steps:
1165 * 1. retrieve a list of scoped children.
1166 * 2. check if the nth children has already been displayed or not.
1167 * 3. if it isn't then append a child *and* check if that child has children itself.
1168 * using a dummy node we can achieve a performant population while setting an expand
1169 * mark on the child firstly appended.
1171 void
1172 symbol_db_view_row_expanded (SymbolDBView *dbv, SymbolDBEngine *dbe,
1173 GtkTreeIter *expanded_iter)
1175 GtkTreeStore *store;
1176 gint expanded_symbol_id;
1177 SymbolDBViewPriv *priv;
1178 SymbolDBEngineIterator *iterator;
1179 GtkTreePath *path;
1181 g_return_if_fail (dbv != NULL);
1182 priv = dbv->priv;
1184 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1186 gtk_tree_model_get (GTK_TREE_MODEL (store), expanded_iter,
1187 COLUMN_SYMBOL_ID, &expanded_symbol_id, -1);
1189 /* remove the dummy item, if present */
1190 if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (store), expanded_iter))
1192 GtkTreeIter child;
1193 gint dummy_symbol;
1194 gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, expanded_iter);
1196 gtk_tree_model_get (GTK_TREE_MODEL (store), &child,
1197 COLUMN_SYMBOL_ID, &dummy_symbol, -1);
1199 if (dummy_symbol == DUMMY_SYMBOL_ID)
1200 gtk_tree_store_remove (store, &child);
1203 /* Ok. Is the expanded node a 'namespace' one? A 'global' one? Or a
1204 * 'vars/etc' one? parse here the cases and if we're not there
1205 * go on with a classic expanding node algo.
1208 /* Case Global */
1209 if (expanded_symbol_id == ROOT_GLOBAL)
1211 sdb_view_global_row_expanded (dbv, dbe, expanded_iter, expanded_symbol_id);
1212 return;
1215 /* Case vars/etc */
1216 /* To identify a vars/etc node we'll check if the expanded_symbol_id is negative.
1217 * If yes, we can have the parent namespace by making the id positive.
1219 if (expanded_symbol_id < 0)
1221 sdb_view_vars_row_expanded (dbv, dbe, expanded_iter, expanded_symbol_id);
1222 return;
1226 /* Case namespace */
1227 iterator = symbol_db_engine_get_symbol_info_by_id (dbe, expanded_symbol_id,
1228 SYMINFO_KIND);
1229 if (iterator != NULL)
1231 SymbolDBEngineIteratorNode *iter_node;
1232 const gchar* symbol_kind;
1234 iter_node = SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator);
1235 symbol_kind = symbol_db_engine_iterator_node_get_symbol_extra_string (
1236 iter_node, SYMINFO_KIND);
1237 if (strcmp (symbol_kind, "namespace") == 0)
1239 sdb_view_namespace_row_expanded (dbv, dbe, expanded_iter,
1240 expanded_symbol_id);
1241 g_object_unref (iterator);
1242 return;
1244 g_object_unref (iterator);
1247 /* Case Normal: go on with usual expanding */
1248 DEBUG_PRINT ("symbol_db_view_row_expanded (): expanded %d", expanded_symbol_id);
1250 /* Step 1 */
1251 iterator = symbol_db_engine_get_scope_members_by_symbol_id (dbe,
1252 expanded_symbol_id,
1255 SYMINFO_SIMPLE|
1256 SYMINFO_KIND|
1257 SYMINFO_ACCESS);
1259 if (iterator != NULL)
1261 do {
1262 gint curr_symbol_id;
1263 SymbolDBEngineIteratorNode *iter_node;
1264 const GdkPixbuf *pixbuf;
1265 const gchar* symbol_name;
1266 GtkTreeIter child_iter;
1267 GtkTreePath *path;
1268 GtkTreeRowReference *child_row_ref;
1269 gpointer node;
1271 iter_node = SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator);
1273 curr_symbol_id = symbol_db_engine_iterator_node_get_symbol_id (iter_node);
1275 /* Step 2:
1276 * check if the curr_symbol_id is already displayed. In that case
1277 * skip to the next symbol
1279 node = g_tree_lookup (priv->nodes_displayed, (gpointer)curr_symbol_id);
1281 if (node != NULL)
1283 continue;
1286 /* Step 3 */
1287 /* ok we must display this symbol */
1288 pixbuf = symbol_db_view_get_pixbuf (
1289 symbol_db_engine_iterator_node_get_symbol_extra_string (
1290 iter_node, SYMINFO_KIND),
1291 symbol_db_engine_iterator_node_get_symbol_extra_string (
1292 iter_node, SYMINFO_ACCESS));
1294 symbol_name = symbol_db_engine_iterator_node_get_symbol_name (iter_node);
1296 gtk_tree_store_append (store, &child_iter, expanded_iter);
1298 gtk_tree_store_set (store, &child_iter,
1299 COLUMN_PIXBUF, pixbuf,
1300 COLUMN_NAME, symbol_name,
1301 COLUMN_SYMBOL_ID, curr_symbol_id,
1302 -1);
1304 path = gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
1305 &child_iter);
1306 child_row_ref = gtk_tree_row_reference_new (
1307 gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)), path);
1308 gtk_tree_path_free (path);
1310 /* insert the just append row_ref into the GTree for a quick retrieval
1311 * later
1313 g_tree_insert (priv->nodes_displayed, (gpointer)curr_symbol_id,
1314 child_row_ref);
1316 /* good. Let's check now for a child (B) of the just appended child (A).
1317 * Adding B (a dummy one for now) to A will make A expandable
1319 sdb_view_do_add_hidden_dummy_child (dbv, dbe, &child_iter, curr_symbol_id,
1320 FALSE);
1322 } while (symbol_db_engine_iterator_move_next (iterator) == TRUE);
1324 g_object_unref (iterator);
1327 /* force expand it */
1328 path = gtk_tree_model_get_path (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)),
1329 expanded_iter);
1330 gtk_tree_view_expand_row (GTK_TREE_VIEW (dbv), path, FALSE);
1331 gtk_tree_path_free (path);
1334 void
1335 symbol_db_view_row_collapsed (SymbolDBView *dbv, SymbolDBEngine *dbe,
1336 GtkTreeIter *collapsed_iter)
1338 GtkTreeStore *store;
1339 gint collapsed_symbol_id;
1340 SymbolDBViewPriv *priv;
1341 gpointer node;
1343 g_return_if_fail (dbv != NULL);
1344 priv = dbv->priv;
1346 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1348 gtk_tree_model_get (GTK_TREE_MODEL (store), collapsed_iter,
1349 COLUMN_SYMBOL_ID, &collapsed_symbol_id, -1);
1351 /* do a quick check to see if the collapsed_symbol_id is listed into the
1352 * currently expanding symbols. If that's the case remove the gsource func.
1354 node = g_tree_lookup (priv->expanding_gfunc_ids, (gpointer)collapsed_symbol_id);
1356 if (node == NULL)
1358 /* no expanding gfunc found. */
1359 return;
1361 else {
1362 g_source_remove ((gint)node);
1363 g_tree_remove (priv->expanding_gfunc_ids, (gpointer)collapsed_symbol_id);
1367 static GtkTreeStore *
1368 sdb_view_create_new_store ()
1370 GtkTreeStore *store;
1371 store = gtk_tree_store_new (COLUMN_MAX, GDK_TYPE_PIXBUF,
1372 G_TYPE_STRING, G_TYPE_INT);
1373 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
1374 COLUMN_NAME,
1375 GTK_SORT_ASCENDING);
1376 return store;
1379 static void
1380 sdb_view_init (SymbolDBView *object)
1382 SymbolDBView *dbv;
1383 GtkTreeStore *store;
1384 GtkTreeViewColumn *column;
1385 GtkCellRenderer *renderer;
1386 GtkTreeSelection *selection;
1387 SymbolDBViewPriv *priv;
1389 dbv = SYMBOL_DB_VIEW (object);
1390 dbv->priv = g_new0 (SymbolDBViewPriv, 1);
1392 priv = dbv->priv;
1394 /* initialize some priv data */
1395 priv->insert_handler = 0;
1396 priv->remove_handler = 0;
1397 priv->nodes_displayed = NULL;
1398 priv->waiting_for = NULL;
1400 priv->row_ref_global = NULL;
1401 priv->scan_end_handler = 0;
1402 priv->remove_handler = 0;
1403 priv->scan_end_handler = 0;
1405 /* create a GTree where to store the row_expanding ids of the gfuncs.
1406 * we would be able then to g_source_remove them on row_collapsed
1408 priv->expanding_gfunc_ids = g_tree_new_full ((GCompareDataFunc)&gtree_compare_func,
1409 NULL, NULL, NULL);
1411 /* Tree and his model */
1412 store = NULL;
1414 gtk_tree_view_set_model (GTK_TREE_VIEW (dbv), GTK_TREE_MODEL (store));
1415 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dbv), FALSE);
1417 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dbv));
1418 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1420 /* search through the tree interactively */
1421 gtk_tree_view_set_search_column (GTK_TREE_VIEW (dbv), COLUMN_NAME);
1422 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (dbv), TRUE);
1424 /* Columns */
1425 column = gtk_tree_view_column_new ();
1426 gtk_tree_view_column_set_sizing (column,
1427 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1428 gtk_tree_view_column_set_title (column, _("Symbol"));
1430 renderer = gtk_cell_renderer_pixbuf_new ();
1431 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1432 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
1433 COLUMN_PIXBUF);
1435 renderer = gtk_cell_renderer_text_new ();
1436 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1437 gtk_tree_view_column_add_attribute (column, renderer, "text",
1438 COLUMN_NAME);
1440 gtk_tree_view_append_column (GTK_TREE_VIEW (dbv), column);
1441 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (dbv), column);
1445 static void
1446 sdb_view_finalize (GObject *object)
1448 SymbolDBView *view = SYMBOL_DB_VIEW (object);
1449 SymbolDBViewPriv *priv = view->priv;
1451 DEBUG_PRINT ("finalizing symbol_db_view ()");
1453 symbol_db_view_clear_cache (view);
1455 if (priv->expanding_gfunc_ids)
1456 g_tree_destroy (priv->expanding_gfunc_ids);
1458 g_free (priv);
1460 /* dbe must be freed outside. */
1461 G_OBJECT_CLASS (parent_class)->finalize (object);
1464 static void
1465 sdb_view_class_init (SymbolDBViewClass *klass)
1467 SymbolDBViewClass *sdbc;
1468 GObjectClass* object_class = G_OBJECT_CLASS (klass);
1469 parent_class = g_type_class_peek_parent (klass);
1471 sdbc = SYMBOL_DB_VIEW_CLASS (klass);
1472 object_class->finalize = sdb_view_finalize;
1475 GType
1476 symbol_db_view_get_type (void)
1478 static GType obj_type = 0;
1480 if (!obj_type)
1482 static const GTypeInfo obj_info = {
1483 sizeof (SymbolDBViewClass),
1484 (GBaseInitFunc) NULL,
1485 (GBaseFinalizeFunc) NULL,
1486 (GClassInitFunc) sdb_view_class_init,
1487 (GClassFinalizeFunc) NULL,
1488 NULL, /* class_data */
1489 sizeof (SymbolDBViewClass),
1490 0, /* n_preallocs */
1491 (GInstanceInitFunc) sdb_view_init,
1492 NULL /* value_table */
1494 obj_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
1495 "SymbolDBView",
1496 &obj_info, 0);
1498 return obj_type;
1502 #define CREATE_SYM_ICON(N, F) \
1503 pix_file = anjuta_res_get_pixmap_file (F); \
1504 g_hash_table_insert (pixbufs_hash, \
1505 N, \
1506 gdk_pixbuf_new_from_file (pix_file, NULL)); \
1507 g_free (pix_file);
1509 static void
1510 sdb_view_load_symbol_pixbufs ()
1512 gchar *pix_file;
1514 if (pixbufs_hash != NULL)
1516 /* we already have loaded it */
1517 return;
1520 pixbufs_hash = g_hash_table_new (g_str_hash, g_str_equal);
1522 CREATE_SYM_ICON ("class", "Icons.16x16.Class");
1523 CREATE_SYM_ICON ("enum", "Icons.16x16.Enum");
1524 CREATE_SYM_ICON ("enumerator", "Icons.16x16.Enum");
1525 CREATE_SYM_ICON ("function", "Icons.16x16.Method");
1526 CREATE_SYM_ICON ("interface", "Icons.16x16.Interface");
1527 CREATE_SYM_ICON ("macro", "Icons.16x16.Field");
1528 CREATE_SYM_ICON ("namespace", "Icons.16x16.NameSpace");
1529 CREATE_SYM_ICON ("none", "Icons.16x16.Literal");
1530 CREATE_SYM_ICON ("struct", "Icons.16x16.ProtectedStruct");
1531 CREATE_SYM_ICON ("typedef", "Icons.16x16.Reference");
1532 CREATE_SYM_ICON ("union", "Icons.16x16.PrivateStruct");
1533 CREATE_SYM_ICON ("variable", "Icons.16x16.Literal");
1534 CREATE_SYM_ICON ("prototype", "Icons.16x16.Interface");
1536 CREATE_SYM_ICON ("privateclass", "Icons.16x16.PrivateClass");
1537 CREATE_SYM_ICON ("privateenum", "Icons.16x16.PrivateEnum");
1538 CREATE_SYM_ICON ("privatefield", "Icons.16x16.PrivateField");
1539 CREATE_SYM_ICON ("privatefunction", "Icons.16x16.PrivateMethod");
1540 CREATE_SYM_ICON ("privateinterface", "Icons.16x16.PrivateInterface");
1541 CREATE_SYM_ICON ("privatemember", "Icons.16x16.PrivateProperty");
1542 CREATE_SYM_ICON ("privatemethod", "Icons.16x16.PrivateMethod");
1543 CREATE_SYM_ICON ("privateproperty", "Icons.16x16.PrivateProperty");
1544 CREATE_SYM_ICON ("privatestruct", "Icons.16x16.PrivateStruct");
1545 CREATE_SYM_ICON ("privateprototype", "Icons.16x16.PrivateInterface");
1547 CREATE_SYM_ICON ("protectedclass", "Icons.16x16.ProtectedClass");
1548 CREATE_SYM_ICON ("protectedenum", "Icons.16x16.ProtectedEnum");
1549 CREATE_SYM_ICON ("protectedfield", "Icons.16x16.ProtectedField");
1550 CREATE_SYM_ICON ("protectedmember", "Icons.16x16.ProtectedProperty");
1551 CREATE_SYM_ICON ("protectedmethod", "Icons.16x16.ProtectedMethod");
1552 CREATE_SYM_ICON ("protectedproperty", "Icons.16x16.ProtectedProperty");
1553 CREATE_SYM_ICON ("publicprototype", "Icons.16x16.ProtectedInterface");
1555 CREATE_SYM_ICON ("publicclass", "Icons.16x16.Class");
1556 CREATE_SYM_ICON ("publicenum", "Icons.16x16.Enum");
1557 CREATE_SYM_ICON ("publicfunction", "Icons.16x16.Method");
1558 CREATE_SYM_ICON ("publicmember", "Icons.16x16.Method");
1559 CREATE_SYM_ICON ("publicproperty", "Icons.16x16.Property");
1560 CREATE_SYM_ICON ("publicstruct", "Icons.16x16.Struct");
1561 CREATE_SYM_ICON ("publicprototype", "Icons.16x16.Interface");
1563 /* special icon */
1564 CREATE_SYM_ICON ("othersvars", "Icons.16x16.Event");
1565 CREATE_SYM_ICON ("globalglobal", "Icons.16x16.Event");
1569 * @return The pixbufs. It will initialize pixbufs first if they weren't before
1570 * @param node_access can be NULL.
1572 const GdkPixbuf*
1573 symbol_db_view_get_pixbuf (const gchar *node_type, const gchar *node_access)
1575 gchar *search_node;
1576 GdkPixbuf *pix;
1577 if (!pixbufs_hash)
1579 sdb_view_load_symbol_pixbufs ();
1582 g_return_val_if_fail (node_type != NULL, NULL);
1584 /* is there a better/quicker method to retrieve pixbufs? */
1585 if (node_access != NULL)
1587 search_node = g_strdup_printf ("%s%s", node_access, node_type);
1589 else
1591 /* we will not free search_node gchar, so casting here is ok. */
1592 search_node = (gchar*)node_type;
1594 pix = GDK_PIXBUF (g_hash_table_lookup (pixbufs_hash, search_node));
1596 if (node_access)
1598 g_free (search_node);
1601 if (pix == NULL)
1603 DEBUG_PRINT ("symbol_db_view_get_pixbuf (): no pixbuf for %s %s",
1604 node_type, node_access);
1607 return pix;
1611 GtkWidget*
1612 symbol_db_view_new (void)
1614 return GTK_WIDGET (g_object_new (SYMBOL_TYPE_DB_VIEW, NULL));
1617 gboolean
1618 symbol_db_view_get_file_and_line (SymbolDBView *dbv, SymbolDBEngine *dbe,
1619 GtkTreeIter * iter, gint *OUT_line, gchar **OUT_file)
1621 GtkTreeStore *store;
1623 g_return_val_if_fail (dbv != NULL, FALSE);
1624 g_return_val_if_fail (dbe != NULL, FALSE);
1625 g_return_val_if_fail (iter != NULL, FALSE);
1627 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1629 if (store)
1631 gint symbol_id;
1632 const gchar* relative_file;
1633 SymbolDBEngineIteratorNode *node;
1635 gtk_tree_model_get (GTK_TREE_MODEL
1636 (store), iter,
1637 COLUMN_SYMBOL_ID, &symbol_id, -1);
1639 /* getting line at click time with a query is faster than updating every
1640 * entry in the gtktreeview. We can be sure that the db is in a consistent
1641 * state and has all the last infos
1643 node = SYMBOL_DB_ENGINE_ITERATOR_NODE (
1644 symbol_db_engine_get_symbol_info_by_id (dbe, symbol_id,
1645 SYMINFO_SIMPLE |
1646 SYMINFO_FILE_PATH));
1647 if (node != NULL)
1649 *OUT_line = symbol_db_engine_iterator_node_get_symbol_file_pos (node);
1650 relative_file =
1651 symbol_db_engine_iterator_node_get_symbol_extra_string (node,
1652 SYMINFO_FILE_PATH);
1653 *OUT_file = symbol_db_engine_get_full_local_path (dbe, relative_file);
1654 return TRUE;
1658 return FALSE;
1661 static void
1662 sdb_view_build_and_display_base_tree (SymbolDBView *dbv, SymbolDBEngine *dbe)
1664 GtkTreeStore *store;
1665 SymbolDBViewPriv *priv;
1666 SymbolDBEngineIterator *iterator;
1667 gboolean we_have_namespaces;
1668 GPtrArray *filter_array;
1669 GtkTreeRowReference *global_tree_row_ref;
1670 GtkTreeIter global_child_iter;
1671 const GdkPixbuf *global_pixbuf;
1673 g_return_if_fail (dbv != NULL);
1675 priv = dbv->priv;
1677 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dbv)));
1679 we_have_namespaces = FALSE;
1681 filter_array = g_ptr_array_new ();
1682 g_ptr_array_add (filter_array, "namespace");
1684 /* check for the presence of namespaces.
1685 * If that's the case then populate the root with a 'Global' node.
1687 iterator = symbol_db_engine_get_global_members_filtered (dbe, filter_array, TRUE,
1688 TRUE,
1691 SYMINFO_SIMPLE |
1692 SYMINFO_ACCESS |
1693 SYMINFO_KIND);
1694 g_ptr_array_free (filter_array, TRUE);
1696 if (iterator != NULL)
1698 we_have_namespaces = TRUE;
1700 do {
1701 gint curr_symbol_id;
1702 SymbolDBEngineIteratorNode *iter_node;
1703 const GdkPixbuf *pixbuf;
1704 const gchar* symbol_name;
1705 GtkTreeRowReference *curr_tree_row_ref;
1706 GtkTreeIter child_iter;
1708 iter_node = SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator);
1710 curr_symbol_id = symbol_db_engine_iterator_node_get_symbol_id (iter_node);
1712 pixbuf = symbol_db_view_get_pixbuf (
1713 symbol_db_engine_iterator_node_get_symbol_extra_string (
1714 iter_node, SYMINFO_KIND),
1715 symbol_db_engine_iterator_node_get_symbol_extra_string (
1716 iter_node, SYMINFO_ACCESS));
1718 symbol_name = symbol_db_engine_iterator_node_get_symbol_name (iter_node);
1720 curr_tree_row_ref = do_add_root_symbol_to_view (dbv, pixbuf,
1721 symbol_name, curr_symbol_id);
1722 if (curr_tree_row_ref == NULL)
1724 continue;
1727 /* we'll fake the gpointer to store an int */
1728 g_tree_insert (priv->nodes_displayed, (gpointer)curr_symbol_id,
1729 curr_tree_row_ref);
1731 if (sdb_view_get_iter_from_row_ref (dbv, curr_tree_row_ref,
1732 &child_iter) == FALSE)
1734 g_warning ("sdb_view_build_and_display_base_tree (): something "
1735 "went wrong");
1736 continue;
1738 /* add a dummy child */
1739 sdb_view_do_add_hidden_dummy_child (dbv, dbe,
1740 &child_iter, curr_symbol_id, FALSE);
1742 } while (symbol_db_engine_iterator_move_next (iterator) == TRUE);
1744 g_object_unref (iterator);
1748 * Good. Add a 'Global' node to the store.
1750 global_pixbuf = symbol_db_view_get_pixbuf ("global", "global");
1752 global_tree_row_ref = do_add_root_symbol_to_view (dbv, global_pixbuf,
1753 "Global", ROOT_GLOBAL);
1755 if (global_tree_row_ref == NULL)
1757 return;
1759 g_tree_insert (priv->nodes_displayed, (gpointer)ROOT_GLOBAL,
1760 global_tree_row_ref);
1762 if (sdb_view_get_iter_from_row_ref (dbv, global_tree_row_ref,
1763 &global_child_iter) == FALSE)
1765 g_warning ("sdb_view_build_and_display_base_tree (): cannot retrieve iter for "
1766 "row_ref");
1767 return;
1770 /* add a dummy child */
1771 sdb_view_do_add_hidden_dummy_child (dbv, dbe,
1772 &global_child_iter, ROOT_GLOBAL, TRUE);
1775 void
1776 symbol_db_view_recv_signals_from_engine (SymbolDBView *dbv, SymbolDBEngine *dbe,
1777 gboolean enable_status)
1779 SymbolDBViewPriv *priv;
1781 g_return_if_fail (dbv != NULL);
1782 priv = dbv->priv;
1784 if (enable_status == TRUE)
1786 gtk_widget_set_sensitive (GTK_WIDGET (dbv), TRUE);
1787 /* connect some signals */
1788 if (priv->insert_handler <= 0)
1790 priv->insert_handler = g_signal_connect (G_OBJECT (dbe), "symbol-inserted",
1791 G_CALLBACK (on_symbol_inserted), dbv);
1794 if (priv->remove_handler <= 0)
1796 priv->remove_handler = g_signal_connect (G_OBJECT (dbe), "symbol-removed",
1797 G_CALLBACK (on_symbol_removed), dbv);
1800 if (priv->scan_end_handler <= 0)
1802 priv->scan_end_handler = g_signal_connect (G_OBJECT (dbe), "scan-end",
1803 G_CALLBACK (on_scan_end), dbv);
1806 else /* disconnect them, if they were ever connected before */
1808 gtk_widget_set_sensitive (GTK_WIDGET (dbv), FALSE);
1810 if (priv->insert_handler >= 0)
1812 g_signal_handler_disconnect (G_OBJECT (dbe), priv->insert_handler);
1813 priv->insert_handler = 0;
1816 if (priv->remove_handler >= 0)
1818 g_signal_handler_disconnect (G_OBJECT (dbe), priv->remove_handler);
1819 priv->remove_handler = 0;
1822 if (priv->scan_end_handler >= 0)
1824 g_signal_handler_disconnect (G_OBJECT (dbe), priv->scan_end_handler);
1825 priv->scan_end_handler = 0;
1830 void
1831 symbol_db_view_open (SymbolDBView *dbv, SymbolDBEngine *dbe)
1833 SymbolDBViewPriv *priv;
1834 GtkTreeStore *store;
1836 g_return_if_fail (dbv != NULL);
1838 priv = dbv->priv;
1840 DEBUG_PRINT ("symbol_db_view_open ()");
1841 symbol_db_view_clear_cache (dbv);
1843 store = sdb_view_create_new_store ();
1844 gtk_tree_view_set_model (GTK_TREE_VIEW (dbv), GTK_TREE_MODEL (store));
1846 priv->nodes_displayed = g_tree_new_full ((GCompareDataFunc)&gtree_compare_func,
1847 NULL,
1848 NULL,
1849 (GDestroyNotify)&gtk_tree_row_reference_free);
1851 priv->waiting_for = g_tree_new_full ((GCompareDataFunc)&gtree_compare_func,
1852 NULL,
1853 NULL,
1854 NULL);
1856 sdb_view_build_and_display_base_tree (dbv, dbe);