1 #include <gtk/gtk.h>
2 #include "ggobi.h"
3 #include "externs.h"
4 #include "GGobiAPI.h"
5
6 #include <stdio.h>
7
8 #include "plugin.h"
9 #include "graphact.h"
10
11 #include "GGStructSizes.c"
12
13 void close_graphact_window(GtkWidget *w, PluginInstance *inst);
14 GtkWidget *create_graphact_window(ggobid *gg, PluginInstance *inst);
15 void show_graphact_window (GtkAction *action, PluginInstance *inst);
16
17
18 gboolean
addToToolsMenu(ggobid * gg,GGobiPluginInfo * plugin,PluginInstance * inst)19 addToToolsMenu(ggobid *gg, GGobiPluginInfo *plugin, PluginInstance *inst)
20 {
21 static GtkActionEntry entry = {
22 "GraphAction", NULL, "Graph _Operations", NULL, "Perform misc operations on a graph",
23 G_CALLBACK (show_graphact_window)
24 };
25 GGOBI(addToolAction)(&entry, (gpointer)inst, gg);
26 return(true);
27 }
28
29
30 void
show_graphact_window(GtkAction * action,PluginInstance * inst)31 show_graphact_window (GtkAction *action, PluginInstance *inst)
32 {
33 graphactd *ga;
34
35 if (g_slist_length(inst->gg->d) < 1) {
36 g_printerr ("No datasets to show\n");
37 return;
38 }
39
40 if (inst->data == NULL) {
41 ga = (graphactd *) g_malloc (sizeof (graphactd));
42
43 graphact_init (ga);
44 inst->data = ga;
45
46 create_graphact_window (inst->gg, inst);
47 g_object_set_data(G_OBJECT (ga->window), "graphactd", ga);
48
49 } else {
50 ga = (graphactd *) inst->data;
51 gtk_widget_show_now ((GtkWidget*) ga->window);
52 }
53 }
54
55 graphactd *
graphactFromInst(PluginInstance * inst)56 graphactFromInst (PluginInstance *inst)
57 {
58 graphactd *ga = (graphactd *) inst->data;
59 return ga;
60 }
61
62 static void
graphact_datad_set_cb(GtkTreeSelection * tree_sel,PluginInstance * inst)63 graphact_datad_set_cb (GtkTreeSelection *tree_sel, PluginInstance *inst)
64 {
65 graphactd *ga = graphactFromInst (inst);
66 GGobiData *d;
67 const gchar *clname = gtk_widget_get_name(GTK_WIDGET(gtk_tree_selection_get_tree_view(tree_sel)));
68 gboolean changed = false;
69 GtkTreeModel *model;
70 GtkTreeIter iter;
71
72 if (!gtk_tree_selection_get_selected(tree_sel, &model, &iter))
73 return;
74 gtk_tree_model_get(model, &iter, 1, &d, -1);
75 if (strcmp (clname, "nodeset") == 0) {
76 changed = ga->d != d;
77 ga->d = d;
78 } else if (strcmp (clname, "edgeset") == 0) {
79 changed = ga->e != d;
80 ga->e = d;
81 }
82
83 #if 0
84 gtk_clist_get_text (GTK_CLIST (cl), row, 0, &dname);
85 for (l = gg->d; l; l = l->next) {
86 d = l->data;
87 if (strcmp (d->name, dname) == 0) {
88 if (strcmp (clname, "nodeset") == 0) {
89 changed = changed || (ga->d != d);
90 ga->d = d;
91 } else if (strcmp (clname, "edgeset") == 0) {
92 changed = changed || (ga->e != d);
93 ga->e = d;
94 }
95 break;
96 }
97 }
98 #endif
99
100 if (ga->d != NULL && ga->e != NULL) {
101 init_edge_vectors (changed, inst);
102 }
103 }
104
105 static void
graphact_tree_view_datad_added_cb(ggobid * gg,GGobiData * d,GtkWidget * tree_view)106 graphact_tree_view_datad_added_cb (ggobid *gg, GGobiData *d, GtkWidget *tree_view)
107 {
108 GtkWidget *swin = (GtkWidget *)
109 g_object_get_data(G_OBJECT (tree_view), "datad_swin");
110 const gchar *clname = gtk_widget_get_name (GTK_WIDGET(tree_view));
111 GtkTreeIter iter;
112 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view));
113
114 if ((strcmp (clname, "nodeset") == 0 && d->rowIds != NULL) ||
115 (strcmp (clname, "edgeset") == 0 && d->edge.n > 0))
116 {
117 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
118 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, d->name, 1, d, -1);
119 }
120
121 gtk_widget_show_all (swin);
122 }
123
124 static const gchar *const neighborhood_depth_lbl[] = {
125 " 1 ", " 2 "};
126 GtkWidget *
create_graphact_window(ggobid * gg,PluginInstance * inst)127 create_graphact_window(ggobid *gg, PluginInstance *inst)
128 {
129 GtkWidget *window, *main_vbox, *notebook, *label, *frame, *vbox, *btn, *opt;
130 GtkTooltips *tips = gtk_tooltips_new ();
131 /*-- for lists of datads --*/
132 gchar *tree_view_titles[2] = {"node sets", "edge sets"};
133 GGobiData *d;
134 GtkWidget *hbox, *swin, *tree_view;
135 GSList *l;
136 graphactd *ga = graphactFromInst (inst);
137 GtkTreeIter iter;
138 GtkListStore *model;
139
140 /*-- I will probably have to get hold of this window, after which
141 I can name all the other widgets --*/
142 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
143 ga->window = window;
144
145 gtk_window_set_title(GTK_WINDOW(window), "Graph operations");
146 g_signal_connect (G_OBJECT (window), "destroy",
147 G_CALLBACK (close_graphact_window), inst);
148
149 main_vbox = gtk_vbox_new (FALSE,1);
150 gtk_container_set_border_width (GTK_CONTAINER(main_vbox), 5);
151 gtk_container_add (GTK_CONTAINER(window), main_vbox);
152
153 notebook = gtk_notebook_new ();
154 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook),
155 GTK_POS_TOP);
156 gtk_box_pack_start (GTK_BOX (main_vbox), notebook, false, false, 2);
157
158 /*-- "Specify datasets" list widgets --*/
159 /*-- this is exactly the same code that appears in ggvis.c --*/
160
161 hbox = gtk_hbox_new (false, 10);
162 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
163
164 /*
165 * node sets
166 */
167 /* Create a scrolled window to pack the CList widget into */
168 swin = gtk_scrolled_window_new (NULL, NULL);
169 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
170 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
171
172 model = gtk_list_store_new(2, G_TYPE_STRING, GGOBI_TYPE_DATA);
173 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
174 populate_tree_view(tree_view, tree_view_titles, 1, true, GTK_SELECTION_SINGLE,
175 G_CALLBACK(graphact_datad_set_cb), inst);
176 gtk_widget_set_name (GTK_WIDGET(tree_view), "nodeset");
177 g_object_set_data(G_OBJECT (tree_view), "datad_swin", swin);
178 g_signal_connect (G_OBJECT (gg), "datad_added",
179 G_CALLBACK(graphact_tree_view_datad_added_cb), tree_view);
180 /*-- --*/
181
182 for (l = gg->d; l; l = l->next) {
183 d = (GGobiData *) l->data;
184 if (d->rowIds != NULL) { /*-- node sets --*/
185 gtk_list_store_append(model, &iter);
186 gtk_list_store_set(model, &iter, 0, d->name, 1, d, -1);
187 }
188 }
189 select_tree_view_row(tree_view, 0);
190
191 gtk_container_add (GTK_CONTAINER (swin), tree_view);
192 gtk_box_pack_start (GTK_BOX (hbox), swin, false, false, 2);
193
194 /*
195 * edge sets
196 */
197 /* Create a scrolled window to pack the CList widget into */
198 swin = gtk_scrolled_window_new (NULL, NULL);
199 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
200 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
201
202 model = gtk_list_store_new(2, G_TYPE_STRING, GGOBI_TYPE_DATA);
203 tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
204 populate_tree_view(tree_view, tree_view_titles+1, 1, true, GTK_SELECTION_SINGLE,
205 G_CALLBACK(graphact_datad_set_cb), inst);
206 gtk_widget_set_name (GTK_WIDGET(tree_view), "edgeset");
207 g_object_set_data(G_OBJECT (tree_view), "datad_swin", swin);
208 g_signal_connect (G_OBJECT (gg), "datad_added",
209 G_CALLBACK(graphact_tree_view_datad_added_cb), tree_view);
210 /*-- --*/
211
212 for (l = gg->d; l; l = l->next) {
213 d = (GGobiData *) l->data;
214 if (d->edge.n != 0) { /*-- edge sets --*/
215 gtk_list_store_append(model, &iter);
216 gtk_list_store_set(model, &iter, 0, d->name, 1, d, -1);
217 }
218 }
219 select_tree_view_row(tree_view, 0);
220 gtk_container_add (GTK_CONTAINER (swin), tree_view);
221 gtk_box_pack_start (GTK_BOX (hbox), swin, true, true, 2);
222
223 label = gtk_label_new_with_mnemonic ("Specify _datasets");
224 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), hbox, label);
225
226 /*-- --*/
227
228 /*-- Thin the graph in different ways --*/
229 frame = gtk_frame_new ("Thin the graph");
230 gtk_container_set_border_width (GTK_CONTAINER (frame), 1);
231
232 vbox = gtk_vbox_new (false, 1);
233 gtk_container_add (GTK_CONTAINER(frame), vbox);
234
235 hbox = gtk_hbox_new (true, 10);
236 gtk_box_pack_start (GTK_BOX (vbox), hbox, false, false, 2);
237 btn = gtk_button_new_with_mnemonic ("Shadow _leaves");
238 gtk_tooltips_set_tip (GTK_TOOLTIPS (tips), btn,
239 "Recursively shadow brush leaf nodes and edges", NULL);
240 g_signal_connect (G_OBJECT (btn), "clicked",
241 G_CALLBACK (ga_leaf_hide_cb), inst);
242 gtk_box_pack_start (GTK_BOX (hbox), btn, false, false, 2);
243
244 btn = gtk_button_new_with_mnemonic ("Shadow _orphans");
245 gtk_tooltips_set_tip (GTK_TOOLTIPS (tips), btn,
246 "Shadow brush nodes without any edges that are both included and not shadowed",
247 NULL);
248 g_signal_connect (G_OBJECT (btn), "clicked",
249 G_CALLBACK (ga_orphans_hide_cb), inst);
250 gtk_box_pack_start (GTK_BOX (hbox), btn, false, false, 2);
251
252
253 btn = gtk_button_new_with_mnemonic ("Show _all");
254 gtk_tooltips_set_tip (GTK_TOOLTIPS (tips), btn,
255 "Show all nodes and edges", NULL);
256 g_signal_connect (G_OBJECT (btn), "clicked",
257 G_CALLBACK (ga_nodes_show_cb), inst); /*-- show all nodes --*/
258 gtk_box_pack_start (GTK_BOX (vbox), btn, false, false, 2);
259
260 label = gtk_label_new_with_mnemonic ("_Thin");
261 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
262 /*-- --*/
263
264
265 /*-- --*/
266 frame = gtk_frame_new ("Find neighbors");
267 gtk_container_set_border_width (GTK_CONTAINER (frame), 1);
268
269 vbox = gtk_vbox_new (false, 1);
270 gtk_container_add (GTK_CONTAINER(frame), vbox);
271 /*
272 checkbox: Neighborhood finder on or off
273 button: restore all nodes and edges
274 option menu taking the values {1,2} for the radius of the path to be reported
275 possibilities:
276 button: sticky label everything showing
277 button: remove all sticky labels
278 color: draw the rest of the graph in a ghost color, just a
279 few shades lighter/darker than the background color. That
280 would necessitate the use of a custom colorscheme.
281 */
282
283 hbox = gtk_hbox_new (true, 10);
284 gtk_box_pack_start (GTK_BOX (vbox), hbox, false, false, 2);
285
286 btn = gtk_check_button_new_with_mnemonic ("Show _neighbors");
287 gtk_tooltips_set_tip (GTK_TOOLTIPS (tips), btn,
288 "To display only a node and its neighbors, turn this on, select 'Identify' in ggobi, and double-click to make a label 'sticky.'", NULL);
289 g_signal_connect (G_OBJECT (btn), "toggled",
290 G_CALLBACK (show_neighbors_toggle_cb), inst);
291 gtk_box_pack_start (GTK_BOX (hbox), btn, false, false, 2);
292
293 btn = gtk_button_new_with_mnemonic ("Show _all");
294 gtk_tooltips_set_tip (GTK_TOOLTIPS (tips), btn,
295 "Show all nodes and edges", NULL);
296 g_signal_connect (G_OBJECT (btn), "clicked",
297 G_CALLBACK (ga_nodes_show_cb), inst); /*-- show all nodes --*/
298 gtk_box_pack_start (GTK_BOX (hbox), btn, false, false, 2);
299
300
301 hbox = gtk_hbox_new (true, 10);
302 gtk_box_pack_start (GTK_BOX (vbox), hbox, false, false, 2);
303 label = gtk_label_new_with_mnemonic ("_Depth:");
304 gtk_misc_set_alignment (GTK_MISC (label), 0, 1);
305 gtk_box_pack_start (GTK_BOX (hbox), label, false, false, 0);
306 opt = gtk_combo_box_new_text();
307 gtk_label_set_mnemonic_widget(GTK_LABEL(label), opt);
308 gtk_tooltips_set_tip (GTK_TOOLTIPS (tips), opt,
309 "Select the size of the selected node's neighborhood to show; ie, the number of steps from the node.", NULL);
310 gtk_box_pack_start (GTK_BOX (hbox), opt, false, false, 0);
311 populate_combo_box (opt, (gchar**) neighborhood_depth_lbl, G_N_ELEMENTS(neighborhood_depth_lbl),
312 G_CALLBACK(neighborhood_depth_cb), inst);
313
314 label = gtk_label_new_with_mnemonic ("_Neighbors");
315 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
316 /*-- --*/
317
318
319 /*-- Tidy the graph in different ways --*/
320 frame = gtk_frame_new ("Tidy the graph");
321 gtk_container_set_border_width (GTK_CONTAINER (frame), 1);
322
323 vbox = gtk_vbox_new (false, 1);
324 gtk_container_add (GTK_CONTAINER(frame), vbox);
325
326 hbox = gtk_hbox_new (true, 10);
327 gtk_box_pack_start (GTK_BOX (vbox), hbox, false, false, 2);
328 btn = gtk_button_new_with_mnemonic ("_Shadow orphaned edges");
329 gtk_tooltips_set_tip (GTK_TOOLTIPS (tips), btn,
330 "Shadow brush edges connected to shadowed nodes", NULL);
331 g_signal_connect (G_OBJECT (btn), "clicked",
332 G_CALLBACK (ga_edge_tidy_cb), inst);
333 gtk_box_pack_start (GTK_BOX (hbox), btn, false, false, 2);
334
335 label = gtk_label_new_with_mnemonic ("_Tidy");
336 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
337 /*-- --*/
338
339
340 gtk_widget_show_all (window);
341
342 return(window);
343 }
344
345
close_graphact_window(GtkWidget * w,PluginInstance * inst)346 void close_graphact_window(GtkWidget *w, PluginInstance *inst)
347 {
348 inst->data = NULL;
349 }
350
closeWindow(ggobid * gg,GGobiPluginInfo * plugin,PluginInstance * inst)351 void closeWindow(ggobid *gg, GGobiPluginInfo *plugin, PluginInstance *inst)
352 {
353 if (inst->data) {
354 graphactd *ga = graphactFromInst (inst);
355 /* I don't remember what this line is for -- dfs
356 g_signal_handlers_disconnect_by_func(G_OBJECT(inst->data),
357 G_CALLBACK (close_graphact_window), inst);
358 */
359 gtk_widget_destroy (ga->window);
360 }
361 }
362
363 gint
visible_set(glong * visible,GGobiData * d)364 visible_set (glong *visible, GGobiData *d)
365 {
366 gint i, m;
367 gint nvisible = 0;
368
369 for (m=0; m<d->nrows_in_plot; m++) {
370 i = d->rows_in_plot.els[m];
371 if (!d->hidden.els[i]) {
372 visible[nvisible++] = i;
373 }
374 }
375
376 return nvisible;
377 }
378