ded.model.Relation.java Source code

Java tutorial

Introduction

Here is the source code for ded.model.Relation.java

Source

// Relation.java
// See toplevel license.txt for copyright and license terms.

package ded.model;

import java.awt.Point;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import util.FlattenInputStream;
import util.Util;
import util.XParse;
import util.awt.AWTJSONUtil;

/** Arrow, sometimes between Entities (boxes). */
public class Relation {
    // ------------------- constants --------------------------
    /** Default routing algorithm.  Used to save space in serialized form. */
    public static final RoutingAlgorithm defaultRoutingAlgorithm = RoutingAlgorithm.RA_MANHATTAN_HORIZ;

    // ------------------ instance data -----------------------
    /** Endpoints, including their arrow style. */
    public RelationEndpoint start, end;

    /** Intermediate control points, if any. */
    public ArrayList<Point> controlPts = new ArrayList<Point>();

    /** Routing algorithm for displaying relation onscreen. */
    public RoutingAlgorithm routingAlg = defaultRoutingAlgorithm;

    /** Text label for the relation. */
    public String label = "";

    /** Optional line width.  If null, use default, which depends
      * on whether this is an inheritance edge. */
    public Integer lineWidth = null;

    // -------------------- methods ----------------------
    public Relation(RelationEndpoint start, RelationEndpoint end) {
        this.start = start;
        this.end = end;
    }

    /** Deep copy constructor, except for supplied endpoints. */
    public Relation(Relation obj, RelationEndpoint start, RelationEndpoint end) {
        this.start = start;
        this.end = end;

        for (Point pt : obj.controlPts) {
            this.controlPts.add(new Point(pt));
        }

        this.routingAlg = obj.routingAlg;
        this.label = obj.label;
        this.lineWidth = obj.lineWidth;
    }

    /** True if either endpoint is referentially equal to 'e'. */
    public boolean involvesEntity(Entity e) {
        return this.start.isSpecificEntity(e) || this.end.isSpecificEntity(e);
    }

    /** True if either endpoint is referentially equal to 'inh'. */
    public boolean involvesInheritance(Inheritance inh) {
        return this.start.isSpecificInheritance(inh) || this.end.isSpecificInheritance(inh);
    }

    public void globalSelfCheck(Diagram d) {
        this.start.globalSelfCheck(d);
        this.end.globalSelfCheck(d);
    }

    // -------------------- data object boilerplate --------------------
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (this.getClass() == obj.getClass()) {
            Relation r = (Relation) obj;
            return this.start.equals(r.start) && this.end.equals(r.end) && this.controlPts.equals(r.controlPts)
                    && this.routingAlg.equals(r.routingAlg) && this.label.equals(r.label)
                    && Util.nullableEquals(this.lineWidth, r.lineWidth);
        }
        return false;
    }

    @Override
    public int hashCode() {
        int h = 1;
        h = h * 31 + this.start.hashCode();
        h = h * 31 + this.end.hashCode();
        h = h * 31 + Util.collectionHashCode(this.controlPts);
        h = h * 31 + this.routingAlg.hashCode();
        h = h * 31 + this.label.hashCode();
        h = h * 31 + Util.nullableHashCode(this.lineWidth);
        return h;
    }

    // -------------------- serialization ------------------------
    public JSONObject toJSON(HashMap<Entity, Integer> entityToInteger,
            HashMap<Inheritance, Integer> inheritanceToInteger) {
        JSONObject o = new JSONObject();
        try {
            o.put("start", this.start.toJSON(entityToInteger, inheritanceToInteger, ArrowStyle.AS_NONE));
            o.put("end", this.end.toJSON(entityToInteger, inheritanceToInteger, ArrowStyle.AS_FILLED_TRIANGLE));

            if (!this.controlPts.isEmpty()) {
                JSONArray pts = new JSONArray();
                for (Point p : this.controlPts) {
                    pts.put(AWTJSONUtil.pointToJSON(p));
                }
                o.put("controlPts", pts);
            }

            if (this.routingAlg != defaultRoutingAlgorithm) {
                o.put("routingAlg", this.routingAlg.name());
            }

            if (!this.label.isEmpty()) {
                o.put("label", this.label);
            }

            if (this.lineWidth != null) {
                o.put("lineWidth", this.lineWidth.intValue());
            }
        } catch (JSONException e) {
            assert (false);
        }
        return o;
    }

    public Relation(JSONObject o, ArrayList<Entity> integerToEntity, ArrayList<Inheritance> integerToInheritance,
            int version) throws JSONException {
        this.start = new RelationEndpoint(o.getJSONObject("start"), integerToEntity, integerToInheritance,
                ArrowStyle.AS_NONE, version);
        this.end = new RelationEndpoint(o.getJSONObject("end"), integerToEntity, integerToInheritance,
                ArrowStyle.AS_FILLED_TRIANGLE, version);

        JSONArray pts = o.optJSONArray("controlPts");
        if (pts != null) {
            for (int i = 0; i < pts.length(); i++) {
                this.controlPts.add(AWTJSONUtil.pointFromJSON(pts.getJSONObject(i)));
            }
        }

        if (o.has("routingAlg")) {
            this.routingAlg = RoutingAlgorithm.valueOf(RoutingAlgorithm.class, o.getString("routingAlg"));
        }

        this.label = o.optString("label", "");

        if (version < 9) {
            // The end arrowhead style was associated with the relation itself.
            this.setLegacyOwning(o.optBoolean("owning", false));
        }

        if (o.has("lineWidth")) {
            this.lineWidth = Integer.valueOf(o.getInt("lineWidth"));
        }
    }

    /** Set 'end.arrowStyle' based on the value of the legacy 'owning' value. */
    private void setLegacyOwning(boolean owning) {
        this.end.arrowStyle = (owning ? ArrowStyle.AS_DOUBLE_ANGLE : ArrowStyle.AS_FILLED_TRIANGLE);
    }

    // ------------------ legacy serialization -----------------
    /** Read a Relation from an ER FlattenInputStream. */
    public Relation(FlattenInputStream flat) throws XParse, IOException {
        this.start = new RelationEndpoint(flat);
        this.end = new RelationEndpoint(flat);
        this.label = flat.readString();
        this.setLegacyOwning(false);

        if (flat.version < 3) {
            return;
        }

        // routingAlg
        int r = flat.readInt();
        switch (r) {
        case 0:
            this.routingAlg = RoutingAlgorithm.RA_DIRECT;
            break;
        case 1:
            this.routingAlg = RoutingAlgorithm.RA_MANHATTAN_HORIZ;
            break;
        case 2:
            this.routingAlg = RoutingAlgorithm.RA_MANHATTAN_VERT;
            break;
        default:
            throw new XParse("invalid routingAlg code: " + r);
        }

        if (flat.version < 4) {
            return;
        }

        // controlPts
        {
            int numControlPts = flat.readInt();
            for (int i = 0; i < numControlPts; i++) {
                this.controlPts.add(flat.readPoint());
            }
        }

        if (flat.version < 8) {
            return;
        }

        this.setLegacyOwning(flat.readBoolean());
    }
}

// EOF