]> granicus.if.org Git - graphviz/commitdiff
Fix bug 1480; simplify code in emit.c constructing internal object ids;
authorerg <devnull@localhost>
Wed, 26 Jan 2011 23:57:53 +0000 (23:57 +0000)
committererg <devnull@localhost>
Wed, 26 Jan 2011 23:57:53 +0000 (23:57 +0000)
add the id field to TD and TABLE elements; use graph id attribute as
prefix for xml ids, if supplied.

lib/common/emit.c
lib/common/htmllex.c
lib/common/htmltable.c
lib/common/htmltable.h
lib/common/input.c
lib/common/render.h
lib/common/types.h

index 9e350870f4bdc63f62cd372ae13486e6acbfb9a6..e3239974795908637d093b91927650bdc7ced6bc 100644 (file)
@@ -44,6 +44,7 @@ void* init_xdot (Agraph_t* g)
     xdot* xd = NULL;
 
     if ((p = agget(g, "_draw_")) && p[0]) {
+#define DEBUG 1
 #ifdef DEBUG
        if (Verbose) {
            start_timer();
@@ -169,25 +170,75 @@ initMapData (GVJ_t* job, char* lbl, char* url, char* tooltip, char* target, char
     return assigned;
 }
 
+/* genObjId:
+ * Use id of root graph if any, plus kind and internal id of object
+ */
+char*
+getObjId (GVJ_t* job, void* obj, agxbuf* xb)
+{
+    char* id;
+    graph_t* root = job->gvc->g;
+    char* gid = GD_drawing(root)->id;
+    long idnum;
+    char* pfx;
+    char buf[30]; /* large enough for decimal 64-bit int */
+
+    id = agget(obj, "id");
+    if (id && *id)
+       return id;
+
+    switch (agobjkind(obj)) {
+#ifndef WITH_CGRAPH
+    case AGGRAPH:
+       idnum = ((graph_t*)obj)->meta_node->id;
+#else
+    case AGRAPH:
+       idnum = AGID((graph_t*)obj);
+#endif
+       pfx = "graph";
+       break;
+    case AGNODE:
+        idnum = AGID((node_t*)obj);
+       pfx = "node";
+       break;
+    case AGEDGE:
+        idnum = AGID((edge_t*)obj);
+       pfx = "edge";
+       break;
+    }
+
+    if (gid) {
+       agxbput (xb, gid);
+       agxbputc (xb, '_');
+    }
+    agxbput (xb, pfx);
+    sprintf (buf, "%ld", idnum);
+    agxbput (xb, buf);
+
+    return agxbuse(xb);
+}
+
 static void
-initObjMapData (GVJ_t* job, textlabel_t *lab, char *otyp, long int idnum, void* gobj)
+initObjMapData (GVJ_t* job, textlabel_t *lab, void* gobj)
 {
     char* lbl;
     char* url = agget(gobj, "href");
     char* tooltip = agget(gobj, "tooltip");
     char* target = agget(gobj, "target");
-    char* id = agget(gobj, "id");
-    char buf[50];
+    char* id;
+    unsigned char buf[SMALLBUF];
+    agxbuf xb;
+
+    agxbinit(&xb, SMALLBUF, buf);
 
     if (lab) lbl = lab->text;
     else lbl = NULL;
     if (!url || !*url)  /* try URL as an alias for href */
        url = agget(gobj, "URL");
-    if (!id || !*id) { /* no external id, so use the internal one */
-       sprintf(buf, "%s%ld", otyp, idnum);
-       id = buf;
-    }
+    id = getObjId (job, gobj, &xb);
     initMapData (job, lbl, url, tooltip, target, id, gobj);
+
+    agxbfree(&xb);
 }
 
 static void map_point(GVJ_t *job, pointf pf)
@@ -1217,7 +1268,7 @@ static void emit_begin_node(GVJ_t * job, node_t * n)
        else
             obj->z = 0.0;
     }
-    initObjMapData (job, ND_label(n), "node", AGID(n), n);
+    initObjMapData (job, ND_label(n), n);
     if ((flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS))
            && (obj->url || obj->explicit_tooltip)) {
 
@@ -1950,7 +2001,7 @@ static void emit_begin_edge(GVJ_t * job, edge_t * e, char** styles)
 {
     obj_state_t *obj;
     int flags = job->flags;
-    char *s, buf[50];
+    char *s;
     textlabel_t *lab = NULL, *tlab = NULL, *hlab = NULL;
     pointf *pbs = NULL;
     int        i, nump, *pbs_n = NULL, pbs_poly_n = 0;
@@ -2001,16 +2052,14 @@ static void emit_begin_edge(GVJ_t * job, edge_t * e, char** styles)
     }
 
     if (flags & GVRENDER_DOES_MAPS) {
-        s = agget(e, "id");
-        if (!s || !*s) { /* no external id, so use the internal one */
-#ifndef WITH_CGRAPH
-           sprintf(buf,"edge%d", AGID(e));
-#else
-           sprintf(buf,"edge%ld", AGID(e));
-#endif
-           s = buf;
-        }
+       agxbuf xb;
+       unsigned char xbuf[SMALLBUF];
+
+       agxbinit(&xb, SMALLBUF, xbuf);
+       s = getObjId (job, e, &xb);
        obj->id = strdup_and_subst_obj(s, (void*)e);
+       agxbfree(&xb);
+
         if (((s = agget(e, "href")) && s[0]) || ((s = agget(e, "URL")) && s[0]))
             dflt_url = strdup_and_subst_obj(s, (void*)e);
        if (((s = agget(e, "edgehref")) && s[0]) || ((s = agget(e, "edgeURL")) && s[0]))
@@ -2840,11 +2889,7 @@ static void emit_begin_graph(GVJ_t * job, graph_t * g)
     obj->u.g = g;
     obj->emit_state = EMIT_GDRAW;
 
-#ifndef WITH_CGRAPH
-    initObjMapData (job, GD_label(g), "graph", g->meta_node->id, g);
-#else
-    initObjMapData (job, GD_label(g), "graph", AGID(g), g);
-#endif
+    initObjMapData (job, GD_label(g), g);
 
     gvrender_begin_graph(job, g);
 }
@@ -3054,11 +3099,7 @@ static void emit_begin_cluster(GVJ_t * job, Agraph_t * sg)
     obj->u.sg = sg;
     obj->emit_state = EMIT_CDRAW;
 
-#ifndef WITH_CGRAPH
-    initObjMapData (job, GD_label(sg), "graph", sg->meta_node->id, sg);
-#else
-    initObjMapData (job, GD_label(sg), "graph", AGID(sg), sg);
-#endif
+    initObjMapData (job, GD_label(sg), sg);
     
     gvrender_begin_cluster(job, sg);
 }
index 838943c3dfa6eadee269df506ce51e980092c73c..99eac0392089217543f9e31d69f9e03fb80facfe 100644 (file)
@@ -141,6 +141,12 @@ static int targetfn(htmldata_t * p, char *v)
     return 0;
 }
 
+static int idfn(htmldata_t * p, char *v)
+{
+    p->id = strdup(v);
+    return 0;
+}
+
 /* doInt:
  * Scan v for integral value. Check that
  * the value is >= min and <= max. Return value in ul.
@@ -396,6 +402,7 @@ static attr_item tbl_items[] = {
     {"fixedsize", (attrFn) fixedsizefn},
     {"height", (attrFn) heightfn},
     {"href", (attrFn) hreffn},
+    {"id", (attrFn) idfn},
     {"port", (attrFn) portfn},
     {"target", (attrFn) targetfn},
     {"title", (attrFn) titlefn},
@@ -416,6 +423,7 @@ static attr_item cell_items[] = {
     {"fixedsize", (attrFn) fixedsizefn},
     {"height", (attrFn) heightfn},
     {"href", (attrFn) hreffn},
+    {"id", (attrFn) idfn},
     {"port", (attrFn) portfn},
     {"rowspan", (attrFn) rowspanfn},
     {"target", (attrFn) targetfn},
index de55bdb5117986ab1192d51b0f88d33eafed3bed..edb1ffd70958374f6bdae2cbcf3539f154d7a80a 100644 (file)
@@ -47,12 +47,15 @@ typedef struct {
     void *obj;
     graph_t *g;
     char* imgscale;
+    char* objid;
+    boolean objid_set;
 } htmlenv_t;
 
 typedef struct {
     char *url; 
     char *tooltip;
     char *target;
+    char *id;
     boolean explicit_tooltip;
     point LL;
     point UR;
@@ -258,24 +261,46 @@ static void doFill(GVJ_t * job, char *color, boxf BF)
  * Initialize fields in job->obj pertaining to anchors.
  * In particular, this also sets the output rectangle.
  * If there is something to do, close current anchor if
- * necesary, start the anchor and returns 1.
+ * necessary, start the anchor and returns 1.
  * Otherwise, it returns 0.
  *
  * FIX: Should we provide a tooltip if none is set, as is done
  * for nodes, edges, etc. ?
  */
 static int
-initAnchor (GVJ_t* job, htmldata_t* data, boxf b, htmlmap_data_t* save,
+initAnchor (GVJ_t* job, htmlenv_t* env, htmldata_t* data, boxf b, htmlmap_data_t* save,
     int closePrev)
 {
     obj_state_t *obj = job->obj;
     int changed;
+    char* id;
+    static int anchorId;
+    int internalId = 0;
+    agxbuf xb;
+    char intbuf[30];  /* hold 64-bit decimal integer */
+    unsigned char buf[SMALLBUF];
 
     save->url = obj->url; 
     save->tooltip = obj->tooltip;
     save->target = obj->target;
+    save->id = obj->id;
     save->explicit_tooltip = obj->explicit_tooltip;
-    changed = initMapData (job, NULL, data->href, data->title, data->target, "\\N", obj->u.g);
+    id = data->id;
+    if (!id || !*id) { /* no external id, so use the internal one */
+       agxbinit(&xb, SMALLBUF, buf);
+       if (!env->objid) {
+           env->objid = strdup (getObjId (job, obj->u.n, &xb));
+           env->objid_set = 1;
+       }
+       agxbput (&xb, env->objid);
+       sprintf (intbuf, "_%d", anchorId++);
+       agxbput (&xb, intbuf);
+       id = agxbuse (&xb);
+       internalId = 1;
+    }
+    changed = initMapData (job, NULL, data->href, data->title, data->target, id, obj->u.g);
+    if (internalId)
+       agxbfree (&xb);
 
     if (changed) {
        if (closePrev && (save->url || save->explicit_tooltip))
@@ -313,6 +338,7 @@ endAnchor (GVJ_t* job, htmlmap_data_t* save, int openPrev)
     RESET(url);
     RESET(tooltip);
     RESET(target);
+    RESET(id);
     obj->explicit_tooltip = save->explicit_tooltip;
     if (openPrev && (obj->url || obj->explicit_tooltip))
        gvrender_begin_anchor(job,
@@ -342,7 +368,7 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env)
     pts.UR.y += pos.y;
 
     if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST))
-       anchor = initAnchor(job, &tbl->data, pts, &saved, 1);
+       anchor = initAnchor(job, env, &tbl->data, pts, &saved, 1);
     else
        anchor = 0;
 
@@ -361,7 +387,7 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env)
        endAnchor (job, &saved, 1);
 
     if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) {
-       if (initAnchor(job, &tbl->data, pts, &saved, 0))
+       if (initAnchor(job, env, &tbl->data, pts, &saved, 0))
            endAnchor (job, &saved, 0);
     }
 
@@ -414,7 +440,7 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env)
     pts.UR.y += pos.y;
 
     if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST))
-       inAnchor = initAnchor(job, &cp->data, pts, &saved, 1);
+       inAnchor = initAnchor(job, env, &cp->data, pts, &saved, 1);
     else
        inAnchor = 0;
 
@@ -436,7 +462,7 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env)
        endAnchor (job, &saved, 1);
 
     if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) {
-       if (initAnchor(job, &cp->data, pts, &saved, 0))
+       if (initAnchor(job, env, &cp->data, pts, &saved, 0))
            endAnchor (job, &saved, 0);
     }
 }
@@ -485,6 +511,7 @@ freeObj (GVJ_t * job)
     obj->url = NULL;
     obj->tooltip = NULL;
     obj->target = NULL;
+    obj->id = NULL;
     pop_obj_state(job);
 }
 
@@ -502,6 +529,8 @@ emit_html_label(GVJ_t * job, htmllabel_t * lp, textlabel_t * tp)
     env.finfo.size = tp->fontsize;
     env.finfo.size = tp->fontsize;
     env.imgscale = agget (job->obj->u.n, "imagescale");
+    env.objid = job->obj->id;
+    env.objid_set = 0;
     if ((env.imgscale == NULL) || (env.imgscale[0] == '\0'))
        env.imgscale = "false";
     if (lp->kind == HTML_TBL) {
@@ -518,6 +547,8 @@ emit_html_label(GVJ_t * job, htmllabel_t * lp, textlabel_t * tp)
     } else {
        emit_html_txt(job, lp->u.txt, &env);
     }
+    if (env.objid_set)
+       free (env.objid);
     freeObj (job);
 }
 
@@ -538,6 +569,7 @@ void free_html_data(htmldata_t * dp)
     free(dp->href);
     free(dp->port);
     free(dp->target);
+    free(dp->id);
     free(dp->title);
     free(dp->bgcolor);
     free(dp->pencolor);
index 84f4c4d68b4b2aba324499ae3b664945b9641cc3..5ae805cbaee615ca8e34c250bfb5218fb0ff3576 100644 (file)
@@ -66,6 +66,7 @@ extern "C" {
        char *port;
        char *target;
        char *title;
+       char *id;
        char *bgcolor;
        char *pencolor;
        signed char space;
index 0b0d891ebe1771bd767fe63258760b56bdee86b3..bf2ce61ddc52373dee1139ce83c409a3e033bfca 100644 (file)
@@ -834,12 +834,19 @@ void graph_init(graph_t * g, boolean use_rankdir)
 
     /* background */
     GD_drawing(g)->xdots = init_xdot (g);
+
+    /* initialize id, if any */
+
+    if ((p = agget(g, "id")) && *p)
+       GD_drawing(g)->id = strdup_and_subst_obj(p, g);
 }
 
 void graph_cleanup(graph_t *g)
 {
     if (GD_drawing(g)->xdots)
        freeXDot ((xdot*)GD_drawing(g)->xdots);
+    if (GD_drawing(g)->id)
+       free (GD_drawing(g)->id);
     free(GD_drawing(g));
     GD_drawing(g) = NULL;
     free_label(GD_label(g));
index 8d4e1ac54e08c6c9d28d0bf36072ed24a597da6d..5b58adec0ea1153e4baf2891d28ef095fa1c177b 100644 (file)
@@ -101,6 +101,7 @@ extern "C" {
     extern void dotneato_write(GVC_t * gvc, graph_t *g);
     extern void dotneato_write_one(GVC_t * gvc, graph_t *g);
     extern void emit_clusters(GVJ_t * job, Agraph_t * g, int flags);
+    extern char* getObjId (GVJ_t* job, void* obj, agxbuf* xb);
     /* extern void emit_begin_edge(GVJ_t * job, edge_t * e, char**); */
     /* extern void emit_end_edge(GVJ_t * job); */
     extern void emit_graph(GVJ_t * job, graph_t * g);
index 90e5c74614cc98d0ffa70ad52a280fb88e52e2f9..f2e790e3f4bc638e8c45906f08e40cca82dc1be5 100644 (file)
@@ -232,6 +232,7 @@ extern "C" {
        boolean centered;
        ratio_t ratio_kind;
        void* xdots;
+       char* id;
     } layout_t;
 
 /* for "record" shapes */