1 /*
2  *		wtree.c
3  *
4  *      Copyright 2010 Alexander Petukhov <devel(at)apetukhov.ru>
5  *
6  *      This program is free software; you can redistribute it and/or modify
7  *      it under the terms of the GNU General Public License as published by
8  *      the Free Software Foundation; either version 2 of the License, or
9  *      (at your option) any later version.
10  *
11  *      This program is distributed in the hope that it will be useful,
12  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *      GNU General Public License for more details.
15  *
16  *      You should have received a copy of the GNU General Public License
17  *      along with this program; if not, write to the Free Software
18  *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *      MA 02110-1301, USA.
20  */
21 
22 /*
23  *		Watch tree view.
24  */
25 
26 
27 #include <gtk/gtk.h>
28 
29 #include "wtree.h"
30 #include "watch_model.h"
31 #include "vtree.h"
32 #include "dconfig.h"
33 #include "breakpoint.h"
34 #include "debug_module.h"
35 
36 /* drag types */
37 enum
38 {
39   TARGET_STRING,
40 };
41 static GtkTargetEntry targetentries[] =
42 {
43   { (gchar*)"STRING",        0, TARGET_STRING }
44 };
45 
46 /* reference to an empty row */
47 static GtkTreeRowReference *empty_row = NULL;
48 
49 /* tree view widget */
50 static GtkWidget *tree = NULL;
51 static GtkTreeModel *model = NULL;
52 static GtkTreeStore *store = NULL;
53 
54 /*
55  * add empty row
56  */
add_empty_row(void)57 static void add_empty_row(void)
58 {
59 	GtkTreeIter empty;
60 	GtkTreePath *path;
61 
62 	if (empty_row)
63 		gtk_tree_row_reference_free(empty_row);
64 
65 	gtk_tree_store_prepend (store, &empty, NULL);
66 	gtk_tree_store_set (store, &empty,
67 		W_NAME, "",
68 		W_VALUE, "",
69 		W_TYPE, "",
70 		W_LAST_VISIBLE, "",
71 		W_INTERNAL, "",
72 		W_EXPRESSION, "",
73 		W_STUB, 0,
74 		W_CHANGED, 0,
75 		W_VT, VT_NONE,
76 		-1);
77 
78 	/* save reference */
79 	path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &empty);
80 	empty_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), path);
81 	gtk_tree_path_free(path);
82 }
83 
84 /*
85  * name column renderer
86  */
on_render_name(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell,GtkTreeModel * tree_model,GtkTreeIter * iter,gpointer data)87 static void on_render_name(GtkTreeViewColumn *tree_column,
88 	 GtkCellRenderer *cell,
89 	 GtkTreeModel *tree_model,
90 	 GtkTreeIter *iter,
91 	 gpointer data)
92 {
93 	/* sets editable to true only for root items */
94 	GtkTreePath *path = gtk_tree_model_get_path(tree_model, iter);
95 	g_object_set (cell, "editable", gtk_tree_path_get_depth(path) <= 1, NULL);
96 	gtk_tree_path_free(path);
97 }
98 
99 /*
100  * get iterator to an empty row
101  */
wtree_empty_row(GtkTreeIter * iter)102 void wtree_empty_row(GtkTreeIter *iter)
103 {
104 	GtkTreePath *path = gtk_tree_row_reference_get_path(empty_row);
105 
106 	gtk_tree_model_get_iter(gtk_tree_view_get_model(GTK_TREE_VIEW(tree)),
107 		iter,
108 		path);
109 	gtk_tree_path_free(path);
110 }
111 
112 /*
113  * get an empty row path
114  */
wtree_empty_path(void)115 GtkTreePath* wtree_empty_path(void)
116 {
117 	return gtk_tree_row_reference_get_path(empty_row);
118 }
119 
120 /*
121  * iterating function to collect all watches
122  */
watches_foreach_collect(GtkTreeModel * _model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)123 static gboolean watches_foreach_collect(GtkTreeModel *_model,
124 	GtkTreePath *path,
125     GtkTreeIter *iter,
126     gpointer data)
127 {
128 	if (gtk_tree_path_compare(path, wtree_empty_path()) &&  1 == gtk_tree_path_get_depth(path))
129 	{
130 		gchar *watch;
131 		GList **watches = (GList**)data;
132 
133 		gtk_tree_model_get (
134 			_model,
135 			iter,
136 			W_NAME, &watch,
137 			-1);
138 
139 		*watches = g_list_append(*watches, watch);
140 	}
141 
142     return FALSE;
143 }
144 
145 /*
146  * init watches tree view
147  */
wtree_init(watch_expanded_callback expanded,new_watch_dragged dragged,watch_key_pressed keypressed,watch_expression_changed changed,watch_button_pressed buttonpressed)148 GtkWidget* wtree_init(watch_expanded_callback expanded,
149 	new_watch_dragged dragged,
150 	watch_key_pressed keypressed,
151 	watch_expression_changed changed,
152 	watch_button_pressed buttonpressed)
153 {
154 	GtkTreeSelection *selection;
155 
156 	tree = vtree_create(on_render_name, changed);
157 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree));
158 	store = GTK_TREE_STORE(model);
159 
160 	gtk_tree_view_enable_model_drag_dest(
161 		GTK_TREE_VIEW(tree),
162 		targetentries,
163 		1,
164 		GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
165 
166 	g_signal_connect(G_OBJECT(tree), "row-expanded", G_CALLBACK (expanded), NULL);
167 	g_signal_connect(G_OBJECT(tree), "drag_data_received", G_CALLBACK(dragged), NULL);
168 	g_signal_connect(G_OBJECT(tree), "key-press-event", G_CALLBACK (keypressed), NULL);
169     g_signal_connect(G_OBJECT(tree), "button-press-event", G_CALLBACK (buttonpressed) , NULL);
170 
171 	/* add empty row */
172 	add_empty_row();
173 
174 	/* set multiple selection */
175 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
176 	gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
177 
178 	return tree;
179 }
180 
181 /*
182  * get watches list
183  */
wtree_get_watches(void)184 GList *wtree_get_watches(void)
185 {
186 	GList *watches = NULL;
187 	gtk_tree_model_foreach(gtk_tree_view_get_model(GTK_TREE_VIEW(tree)), watches_foreach_collect, &watches);
188 
189 	return watches;
190 }
191 
192 /*
193  * remove all watches from the tree view
194  */
wtree_remove_all(void)195 void wtree_remove_all(void)
196 {
197 	gtk_tree_store_clear(store);
198 	add_empty_row();
199 }
200 
201 /*
202  * add new watche to the tree view
203  */
wtree_add_watch(gchar * watch)204 void wtree_add_watch(gchar *watch)
205 {
206 	GtkTreeIter newvar, empty;
207 
208 	wtree_empty_row(&empty);
209 	gtk_tree_store_insert_before(store, &newvar, NULL, &empty);
210 
211 	variable_set_name_only(store, &newvar, watch);
212 }
213