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