Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
tvnodes.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include <assert.h>
12#include "tvnodes.h"
13#include "viewport.h"
14#include "topviewfuncs.h"
15#include <cgraph/tokenize.h>
16#include <stdbool.h>
17#include <string.h>
18#include <util/alloc.h>
19#include <util/strview.h>
20
21typedef struct {
22 GType type;
23 char *name;
25} gridCol;
26typedef struct {
27 int count;
29 GtkTreeStore *store;
30 char *flds;
31 char *buf;
32} grid_t;
33
34static char* ID = "ID";
35static char* Name = "Name";
36static char* Visible = "Visible";
37
38/* induceEdges:
39 * Add all edges of g which have both ends in sg to sg
40 */
41static void induceEdges (Agraph_t * g, Agraph_t * sg)
42{
43 Agnode_t *n;
44 Agedge_t *e;
45
46 for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) {
47 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
48 if (agsubnode(sg, aghead(e), 0)) {
49 agsubedge(sg, e, 1);
50 }
51 }
52 }
53}
54
55/*
56 call this function to create a subgraph from filtered nodes and maybe edges
57*/
58static int create_save_subgraph_from_filter(char *filename, int withEdges)
59{
60 Agraph_t *subg = agsubg(view->g[view->activeGraph], "temp", 1);
61 FILE *outputfile;
62 Agnode_t *v;
63 Agraph_t *g;
64 int ret;
65
66 g = view->g[view->activeGraph];
67 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
68 if (ND_selected(v))
69 agsubnode(subg, v, 1);
70 }
71 if (withEdges)
73
74 if ((outputfile = fopen(filename, "w"))) {
75 ret = agwrite(subg, outputfile);
76 fclose(outputfile);
77 } else {
78 fprintf (stderr, "Could not open %s for writing\n", filename);
79 ret = 1;
80 }
82 return ret;
83}
84
85
86static void set_visibility(Agraph_t * g, int visibility)
87{
88 Agnode_t *v;
89 char *bf;
90 Agsym_t *visible_attr = GN_visible(g);
91 Agsym_t *selected_attr = GN_selected(g);
92
93 if (!selected_attr)
94 return;
95 if (!visible_attr)
96 visible_attr = GN_visible(g) = agattr(g, AGNODE, "visible", "1");
97 if (visibility)
98 bf = "1";
99 else
100 bf = "0";
101 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
102 if (!ND_selected(v)) continue;
103 agxset(v, visible_attr, bf);
104 }
105}
106
107int tv_show_all(void)
108{
111 return 1;
112}
113
114int tv_hide_all(void)
115{
118
119 return 1;
120}
121
122int tv_save_as(int withEdges)
123{
124 GtkWidget *dialog;
125 dialog = gtk_file_chooser_dialog_new("Save File",
126 NULL,
127 GTK_FILE_CHOOSER_ACTION_SAVE,
128 GTK_STOCK_CANCEL,
129 GTK_RESPONSE_CANCEL,
130 GTK_STOCK_SAVE,
131 GTK_RESPONSE_ACCEPT, NULL);
132 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER
133 (dialog), TRUE);
134 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
135 char *filename;
136 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
137
138 create_save_subgraph_from_filter(filename, withEdges);
139 g_free(filename);
140 gtk_widget_destroy(dialog);
141
142 return 1;
143 }
144 gtk_widget_destroy(dialog);
145 return 0;
146}
147
148static void create_text_column(char *Title, GtkTreeView * tree, int asso,
149 bool editable)
150{
151 PangoColor c;
152 GtkTreeViewColumn *column;
153 GtkCellRendererText *renderer;
154
155
156 renderer = (GtkCellRendererText *) gtk_cell_renderer_text_new();
157 ((GtkCellRenderer *) renderer)->mode = GTK_CELL_RENDERER_MODE_EDITABLE;
158 renderer->editable = editable;
159 c.blue = 0;
160 c.green = 1;
161 c.red = 0;
162 renderer->foreground = c;
163
164 column =
165 gtk_tree_view_column_new_with_attributes(Title,
166 (GtkCellRenderer *)
167 renderer, "text", asso,
168 NULL);
169
170 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
171 gtk_tree_view_column_set_resizable(column, 1);
172
173}
174
175static void create_toggle_column(char *Title, GtkTreeView * tree, int asso,
176 bool editable)
177{
178 GtkTreeViewColumn *column;
179 GtkCellRendererToggle *renderer;
180 renderer = (GtkCellRendererToggle *) gtk_cell_renderer_toggle_new();
181 renderer->activatable = editable;
182
183 column =
184 gtk_tree_view_column_new_with_attributes(Title,
185 (GtkCellRenderer *)
186 renderer, "active", asso,
187 NULL);
188 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
189 gtk_tree_view_column_set_resizable(column, 1);
190
191}
192
194 Agnode_t *v;
195 int id = 0;
196 GtkTreeIter iter;
197 GValue value = {0};
198 char* bf;
199
200 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
201 if (!ND_selected(v))
202 continue;
203 gtk_tree_store_append(grid->store, &iter, NULL);
204
205 for (id = 0; id < grid->count; id++) {
206 gridCol *cp = &grid->columns[id];
207 if (strcmp(cp->name, ID) == 0) continue;
208
209 if (strcmp(cp->name, Name) == 0)
210 bf = agnameof(v);
211 else
212 bf = agget(v, cp->name);
213 if (!bf && strcmp(cp->name, Visible) != 0)
214 continue;
215
216 g_value_init(&value, cp->type);
217 switch (grid->columns[id].type) {
218 case G_TYPE_BOOLEAN:
219 if (bf) {
220 if ((strcmp(bf, "1") == 0) || (strcmp(bf, "true") == 0)
221 || (strcmp(bf, "True") == 0))
222 g_value_set_boolean(&value, 1);
223 else
224 g_value_set_boolean(&value, 0);
225 } else {
226 if (strcmp(cp->name, Visible) == 0)
227 g_value_set_boolean(&value, 1);
228 }
229 break;
230 default:
231 g_value_set_static_string(&value, bf);
232
233 }
234 gtk_tree_store_set_value(grid->store, &iter, id, &value);
235 g_value_unset(&value);
236 }
237 }
238}
239
240static GtkTreeStore *update_tree_store(GtkTreeStore * store, int ncolumns,
241 GType * types)
242{
243 if ((ncolumns == 0) || (types == NULL))
244 return NULL;
245 if (store) {
246 gtk_tree_store_clear(store);
247 g_object_unref(store);
248 }
249
250 store = gtk_tree_store_newv(ncolumns, types);
251 return store;
252}
253
254
255static void create_column(gridCol * c, GtkTreeView * tree, int id)
256{
257 assert(c != NULL);
258 switch (c->type) {
259 case G_TYPE_STRING:
260 case G_TYPE_INT:
262 break;
263 case G_TYPE_BOOLEAN:
265 break;
266 default:
268 }
269}
270
271static GtkTreeView *update_tree(GtkTreeView *tree, grid_t *g) {
272
273 GtkTreeStore *store = NULL;
274 GtkTreeViewColumn *column;
275 GType *types;
276 int id = 0;
277
278 if (tree) {
279 while ((column = gtk_tree_view_get_column(tree, 0))) /*clear all columns */
280 gtk_tree_view_remove_column(tree, column);
281 store = (GtkTreeStore *) gtk_tree_view_get_model(tree);
282 } else {
283 tree = (GtkTreeView *) gtk_tree_view_new();
284 gtk_widget_show((GtkWidget *) tree);
285
286 gtk_container_add((GtkContainer *)
287 glade_xml_get_widget(xml, "scrolledwindow9"),
288 (GtkWidget *) tree);
289
290 }
291 if (g->count > 0) {
292 types = gv_calloc((size_t)g->count, sizeof(GType));
293 for (id = 0; id < g->count; id++)
294 types[id] = g->columns[id].type;
295 store = update_tree_store(g->store, g->count, types);
296 free (types);
297 gtk_tree_view_set_model(tree, (GtkTreeModel *) store);
298 /*insert columns */
299 for (id = 0; id < g->count; id++)
300 create_column(&g->columns[id], tree, id);
301 }
302 g->store = store;
303 return tree;
304}
305
306static void add_column(grid_t *g, strview_t name, bool editable, GType g_type) {
307 if (strview_str_eq(name, ""))
308 return;
309 assert(g->count >= 0);
310 g->columns = gv_recalloc(g->columns, (size_t)g->count, (size_t)g->count + 1,
311 sizeof(gridCol));
312 g->columns[g->count].editable = editable;
313 g->columns[g->count].name = strview_str(name);
314 g->columns[g->count].type = g_type;
315 g->count++;
316}
317
318static void clearGrid(grid_t * g) {
319 int id;
320 for (id = 0; id < g->count; id++) {
321 free(g->columns[id].name);
322 }
323 free(g->columns);
324 free(g->buf);
325 g->count = 0;
326 g->columns = 0;
327 g->flds = 0;
328}
329
330static grid_t *initGrid(void) {
331 grid_t *gr = gv_alloc(sizeof(grid_t));
332 gr->columns = NULL;
333 gr->count = 0;
334 gr->buf = 0;
335 return gr;
336}
337
338static grid_t *update_columns(grid_t *g, char *str) {
339 if (g) {
340 if (g->flds != str)
341 clearGrid(g);
342 else
343 return g;
344 } else
345 g = initGrid();
346 add_column(g, strview(Name, '\0'), false, G_TYPE_STRING);
347 if (!str)
348 return g;
349
350 g->flds = str;
351 for (tok_t t = tok(str, ","); !tok_end(&t); tok_next(&t)) {
352 strview_t a = tok_get(&t);
353 add_column(g, a, true, G_TYPE_STRING);
354 }
355 return g;
356}
357
359{
360 /*
361 G_TYPE_STRING:
362 G_TYPE_INT:
363 G_TYPE_BOOLEAN:
364 */
365 static GtkTreeView *tree;
366 static grid_t *gr;
367 char *buf = agget(g, "datacolumns");
368
369 gr = update_columns(gr, buf);
370 tree = update_tree(tree, gr);
371 populate_data(g, gr);
372}
Memory allocation wrappers that exit on failure.
static void * gv_recalloc(void *ptr, size_t old_nmemb, size_t new_nmemb, size_t size)
Definition alloc.h:73
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static void * gv_alloc(size_t size)
Definition alloc.h:47
void free(void *)
node NULL
Definition grammar.y:163
Agsym_t * agattr(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up attributes of a graph
Definition attr.c:338
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:478
char * agget(void *obj, char *name)
Definition attr.c:439
Agedge_t * agsubedge(Agraph_t *g, Agedge_t *e, int createflag)
Definition edge.c:355
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:24
#define aghead(e)
Definition cgraph.h:881
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:39
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Definition write.c:730
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
Definition node.c:259
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:158
@ AGNODE
Definition cgraph.h:207
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:58
int agdelsubg(Agraph_t *g, Agraph_t *sub)
Definition subg.c:99
GladeXML * xml
Definition gui.c:22
static uint64_t id
Definition gv2gml.c:42
@ tree
Definition gvgen.c:33
@ grid
Definition gvgen.c:32
textitem scanner parser str
Definition htmlparse.y:224
static int store(segment_t *seg, int first, pointf *pts)
Definition partition.c:115
ViewInfo * view
Definition viewport.c:37
#define GN_selected(g)
Definition smyrnadefs.h:199
#define ND_selected(n)
Definition smyrnadefs.h:162
#define GN_visible(g)
Definition smyrnadefs.h:198
graph or subgraph
Definition cgraph.h:425
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:637
topview * Topview
Definition smyrnadefs.h:313
Agraph_t ** g
Definition smyrnadefs.h:296
int activeGraph
Definition smyrnadefs.h:300
char * name
Definition tvnodes.c:23
bool editable
Definition tvnodes.c:24
GType type
Definition tvnodes.c:22
char * buf
Definition tvnodes.c:31
gridCol * columns
Definition tvnodes.c:28
int count
Definition tvnodes.c:27
GtkTreeStore * store
Definition tvnodes.c:29
char * flds
Definition tvnodes.c:30
a non-owning string reference
Definition strview.h:20
state for an in-progress string tokenization
Definition tokenize.h:36
Non-owning string references.
static bool strview_str_eq(strview_t a, const char *b)
compare a string reference to a string for equality
Definition strview.h:98
static char * strview_str(strview_t source)
make a heap-allocated string from this string view
Definition strview.h:41
static strview_t strview(const char *referent, char terminator)
create a string reference
Definition strview.h:26
String tokenization.
static strview_t tok_get(const tok_t *t)
get the current token
Definition tokenize.h:76
static tok_t tok(const char *input, const char *separators)
begin tokenization of a new string
Definition tokenize.h:43
static bool tok_end(const tok_t *t)
is this tokenizer exhausted?
Definition tokenize.h:68
static void tok_next(tok_t *t)
advance to the next token in the string being scanned
Definition tokenize.h:85
void updateSmGraph(Agraph_t *g, topview *t)
int tv_show_all(void)
Definition tvnodes.c:107
static int create_save_subgraph_from_filter(char *filename, int withEdges)
Definition tvnodes.c:58
static void create_column(gridCol *c, GtkTreeView *tree, int id)
Definition tvnodes.c:255
static char * Visible
Definition tvnodes.c:36
static grid_t * update_columns(grid_t *g, char *str)
Definition tvnodes.c:338
static void create_text_column(char *Title, GtkTreeView *tree, int asso, bool editable)
Definition tvnodes.c:148
int tv_save_as(int withEdges)
Definition tvnodes.c:122
static grid_t * initGrid(void)
Definition tvnodes.c:330
static void clearGrid(grid_t *g)
Definition tvnodes.c:318
static void add_column(grid_t *g, strview_t name, bool editable, GType g_type)
Definition tvnodes.c:306
static char * Name
Definition tvnodes.c:35
static char * ID
Definition tvnodes.c:34
static GtkTreeStore * update_tree_store(GtkTreeStore *store, int ncolumns, GType *types)
Definition tvnodes.c:240
static GtkTreeView * update_tree(GtkTreeView *tree, grid_t *g)
Definition tvnodes.c:271
void setup_tree(Agraph_t *g)
Definition tvnodes.c:358
int tv_hide_all(void)
Definition tvnodes.c:114
static void create_toggle_column(char *Title, GtkTreeView *tree, int asso, bool editable)
Definition tvnodes.c:175
static void populate_data(Agraph_t *g, grid_t *grid)
Definition tvnodes.c:193
static void induceEdges(Agraph_t *g, Agraph_t *sg)
Definition tvnodes.c:41
static void set_visibility(Agraph_t *g, int visibility)
Definition tvnodes.c:86
VIS_API void visibility(vconfig_t *)
Definition visibility.c:211