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