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