Graphviz 13.1.0~dev.20250626.0830
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 <stdbool.h>
16#include <string.h>
17#include <util/alloc.h>
18#include <util/strview.h>
19#include <util/tokenize.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 Agsym_t *visible_attr = GN_visible(g);
90 Agsym_t *selected_attr = GN_selected(g);
91
92 if (!selected_attr)
93 return;
94 if (!visible_attr)
95 visible_attr = GN_visible(g) = agattr_text(g, AGNODE, "visible", "1");
96 const char *const bf = visibility ? "1" : "0";
97 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
98 if (!ND_selected(v)) continue;
99 agxset(v, visible_attr, bf);
100 }
101}
102
107
112
113int tv_save_as(int withEdges)
114{
115 GtkWidget *dialog;
116 dialog = gtk_file_chooser_dialog_new("Save File",
117 NULL,
118 GTK_FILE_CHOOSER_ACTION_SAVE,
119 GTK_STOCK_CANCEL,
120 GTK_RESPONSE_CANCEL,
121 GTK_STOCK_SAVE,
122 GTK_RESPONSE_ACCEPT, NULL);
123 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER
124 (dialog), TRUE);
125 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
126 char *filename;
127 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
128
129 create_save_subgraph_from_filter(filename, withEdges);
130 g_free(filename);
131 gtk_widget_destroy(dialog);
132
133 return 1;
134 }
135 gtk_widget_destroy(dialog);
136 return 0;
137}
138
139static void create_text_column(char *Title, GtkTreeView * tree, int asso,
140 bool editable)
141{
142 PangoColor c;
143 GtkTreeViewColumn *column;
144 GtkCellRendererText *renderer;
145
146
147 renderer = (GtkCellRendererText *) gtk_cell_renderer_text_new();
148 ((GtkCellRenderer *) renderer)->mode = GTK_CELL_RENDERER_MODE_EDITABLE;
149 renderer->editable = editable;
150 c.blue = 0;
151 c.green = 1;
152 c.red = 0;
153 renderer->foreground = c;
154
155 column =
156 gtk_tree_view_column_new_with_attributes(Title,
157 (GtkCellRenderer *)
158 renderer, "text", asso,
159 NULL);
160
161 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
162 gtk_tree_view_column_set_resizable(column, 1);
163
164}
165
166static void create_toggle_column(char *Title, GtkTreeView * tree, int asso,
167 bool editable)
168{
169 GtkTreeViewColumn *column;
170 GtkCellRendererToggle *renderer;
171 renderer = (GtkCellRendererToggle *) gtk_cell_renderer_toggle_new();
172 renderer->activatable = editable;
173
174 column =
175 gtk_tree_view_column_new_with_attributes(Title,
176 (GtkCellRenderer *)
177 renderer, "active", asso,
178 NULL);
179 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
180 gtk_tree_view_column_set_resizable(column, 1);
181
182}
183
185 Agnode_t *v;
186 int id = 0;
187 GtkTreeIter iter;
188 GValue value = {0};
189 char* bf;
190
191 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
192 if (!ND_selected(v))
193 continue;
194 gtk_tree_store_append(grid->store, &iter, NULL);
195
196 for (id = 0; id < grid->count; id++) {
197 gridCol *cp = &grid->columns[id];
198 if (strcmp(cp->name, ID) == 0) continue;
199
200 if (strcmp(cp->name, Name) == 0)
201 bf = agnameof(v);
202 else
203 bf = agget(v, cp->name);
204 if (!bf && strcmp(cp->name, Visible) != 0)
205 continue;
206
207 g_value_init(&value, cp->type);
208 switch (grid->columns[id].type) {
209 case G_TYPE_BOOLEAN:
210 if (bf) {
211 if ((strcmp(bf, "1") == 0) || (strcmp(bf, "true") == 0)
212 || (strcmp(bf, "True") == 0))
213 g_value_set_boolean(&value, 1);
214 else
215 g_value_set_boolean(&value, 0);
216 } else {
217 if (strcmp(cp->name, Visible) == 0)
218 g_value_set_boolean(&value, 1);
219 }
220 break;
221 default:
222 g_value_set_static_string(&value, bf);
223
224 }
225 gtk_tree_store_set_value(grid->store, &iter, id, &value);
226 g_value_unset(&value);
227 }
228 }
229}
230
231static GtkTreeStore *update_tree_store(GtkTreeStore * store, int ncolumns,
232 GType * types)
233{
234 if ((ncolumns == 0) || (types == NULL))
235 return NULL;
236 if (store) {
237 gtk_tree_store_clear(store);
238 g_object_unref(store);
239 }
240
241 store = gtk_tree_store_newv(ncolumns, types);
242 return store;
243}
244
245
246static void create_column(gridCol * c, GtkTreeView * tree, int id)
247{
248 assert(c != NULL);
249 switch (c->type) {
250 case G_TYPE_STRING:
251 case G_TYPE_INT:
253 break;
254 case G_TYPE_BOOLEAN:
256 break;
257 default:
259 }
260}
261
262static GtkTreeView *update_tree(GtkTreeView *tree, grid_t *g) {
263
264 GtkTreeStore *store = NULL;
265 GtkTreeViewColumn *column;
266 GType *types;
267 int id = 0;
268
269 if (tree) {
270 while ((column = gtk_tree_view_get_column(tree, 0))) /*clear all columns */
271 gtk_tree_view_remove_column(tree, column);
272 store = (GtkTreeStore *) gtk_tree_view_get_model(tree);
273 } else {
274 tree = (GtkTreeView *) gtk_tree_view_new();
275 gtk_widget_show((GtkWidget *) tree);
276
277 gtk_container_add((GtkContainer *)
278 glade_xml_get_widget(xml, "scrolledwindow9"),
279 (GtkWidget *) tree);
280
281 }
282 if (g->count > 0) {
283 types = gv_calloc((size_t)g->count, sizeof(GType));
284 for (id = 0; id < g->count; id++)
285 types[id] = g->columns[id].type;
286 store = update_tree_store(g->store, g->count, types);
287 free (types);
288 gtk_tree_view_set_model(tree, (GtkTreeModel *) store);
289 /*insert columns */
290 for (id = 0; id < g->count; id++)
291 create_column(&g->columns[id], tree, id);
292 }
293 g->store = store;
294 return tree;
295}
296
297static void add_column(grid_t *g, strview_t name, bool editable, GType g_type) {
298 if (strview_str_eq(name, ""))
299 return;
300 assert(g->count >= 0);
301 g->columns = gv_recalloc(g->columns, (size_t)g->count, (size_t)g->count + 1,
302 sizeof(gridCol));
303 g->columns[g->count].editable = editable;
304 g->columns[g->count].name = strview_str(name);
305 g->columns[g->count].type = g_type;
306 g->count++;
307}
308
309static void clearGrid(grid_t * g) {
310 int id;
311 for (id = 0; id < g->count; id++) {
312 free(g->columns[id].name);
313 }
314 free(g->columns);
315 free(g->buf);
316 g->count = 0;
317 g->columns = 0;
318 g->flds = 0;
319}
320
321static grid_t *initGrid(void) {
322 grid_t *gr = gv_alloc(sizeof(grid_t));
323 gr->columns = NULL;
324 gr->count = 0;
325 gr->buf = 0;
326 return gr;
327}
328
329static grid_t *update_columns(grid_t *g, char *str) {
330 if (g) {
331 if (g->flds != str)
332 clearGrid(g);
333 else
334 return g;
335 } else
336 g = initGrid();
337 add_column(g, strview(Name, '\0'), false, G_TYPE_STRING);
338 if (!str)
339 return g;
340
341 g->flds = str;
342 for (tok_t t = tok(str, ","); !tok_end(&t); tok_next(&t)) {
343 strview_t a = tok_get(&t);
344 add_column(g, a, true, G_TYPE_STRING);
345 }
346 return g;
347}
348
350{
351 /*
352 G_TYPE_STRING:
353 G_TYPE_INT:
354 G_TYPE_BOOLEAN:
355 */
356 static GtkTreeView *tree;
357 static grid_t *gr;
358 char *buf = agget(g, "datacolumns");
359
360 gr = update_columns(gr, buf);
361 tree = update_tree(tree, gr);
362 populate_data(g, gr);
363}
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:181
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
Definition attr.c:348
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:536
char * agget(void *obj, char *name)
Definition attr.c:462
Agedge_t * agsubedge(Agraph_t *g, Agedge_t *e, int createflag)
Definition edge.c:348
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:26
#define aghead(e)
Definition cgraph.h:989
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:41
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Definition write.c:696
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:48
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:41
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
Definition node.c:252
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:143
@ AGNODE
Definition cgraph.h:207
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:53
int agdelsubg(Agraph_t *g, Agraph_t *sub)
Definition subg.c:94
GladeXML * xml
Definition gui.c:22
static uint64_t id
Definition gv2gml.c:40
@ tree
Definition gvgen.c:34
@ grid
Definition gvgen.c:33
textitem scanner parser str
Definition htmlparse.y:224
static int store(segment_t *seg, int first, pointf *pts)
Definition partition.c:120
ViewInfo * view
Definition viewport.c:37
#define GN_selected(g)
Definition smyrnadefs.h:195
#define ND_selected(n)
Definition smyrnadefs.h:158
#define GN_visible(g)
Definition smyrnadefs.h:194
graph or subgraph
Definition cgraph.h:424
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:651
topview * Topview
Definition smyrnadefs.h:309
Agraph_t ** g
Definition smyrnadefs.h:292
int activeGraph
Definition smyrnadefs.h:296
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)
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:246
static char * Visible
Definition tvnodes.c:36
static grid_t * update_columns(grid_t *g, char *str)
Definition tvnodes.c:329
static void create_text_column(char *Title, GtkTreeView *tree, int asso, bool editable)
Definition tvnodes.c:139
int tv_save_as(int withEdges)
Definition tvnodes.c:113
static grid_t * initGrid(void)
Definition tvnodes.c:321
static void clearGrid(grid_t *g)
Definition tvnodes.c:309
static void add_column(grid_t *g, strview_t name, bool editable, GType g_type)
Definition tvnodes.c:297
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:231
static GtkTreeView * update_tree(GtkTreeView *tree, grid_t *g)
Definition tvnodes.c:262
void setup_tree(Agraph_t *g)
Definition tvnodes.c:349
void tv_show_all(void)
Definition tvnodes.c:103
static void create_toggle_column(char *Title, GtkTreeView *tree, int asso, bool editable)
Definition tvnodes.c:166
void tv_hide_all(void)
Definition tvnodes.c:108
static void populate_data(Agraph_t *g, grid_t *grid)
Definition tvnodes.c:184
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