workcraft/workcraft

View on GitHub
workcraft/SonPlugin/src/org/workcraft/plugins/son/elements/VisualBlock.java

Summary

Maintainability
A
3 hrs
Test Coverage
package org.workcraft.plugins.son.elements;

import org.workcraft.dom.visual.*;
import org.workcraft.gui.tools.Decoration;
import org.workcraft.observation.TransformChangedEvent;
import org.workcraft.observation.TransformChangingEvent;
import org.workcraft.plugins.builtin.settings.VisualCommonSettings;
import org.workcraft.plugins.son.SONSettings;
import org.workcraft.plugins.son.connections.VisualSONConnection;
import org.workcraft.plugins.son.util.Interval;
import org.workcraft.utils.ColorUtils;
import org.workcraft.utils.Hierarchy;

import java.awt.*;
import java.awt.font.GlyphVector;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Collection;

public class VisualBlock extends VisualPage implements VisualTransitionNode {
    private final Block mathBlock;
    private static final float strokeWidth = 0.06f;

    private static final Font font = new Font("Sans-serif", Font.PLAIN, 1).deriveFont(0.45f);
    protected Font timeFont = new Font("Sans-serif", Font.PLAIN, 1).deriveFont(0.35f);

    private static final Positioning durationLabelPositioning = Positioning.BOTTOM;
    private RenderedText durationRenderedText = new RenderedText("", font, durationLabelPositioning, new Point2D.Double(0.0, 0.0));

    public VisualBlock(Block refNode) {
        super(refNode);
        this.mathBlock = refNode;
    }

    @Override
    public void draw(DrawRequest r) {
        // This is to update the rendered text for names (and labels) of group children,
        // which is necessary to calculate the bounding box before children have been drawn
        for (VisualComponent component: Hierarchy.getChildrenOfType(this, VisualComponent.class)) {
            component.cacheRenderedText(r);
        }
        cacheRenderedText(r);

        Rectangle2D bb = getInternalBoundingBoxInLocalSpace();
        if ((bb != null) && (getParent() != null)) {
            Graphics2D g = r.getGraphics();
            Decoration d = r.getDecoration();

            if (getIsCollapsed() && !isCurrentLevelInside()) {
                g.setColor(ColorUtils.colorise(getFillColor(), d.getBackground()));
                g.fill(bb);
                g.setColor(ColorUtils.colorise(getForegroundColor(), d.getColorisation()));
                g.setStroke(new BasicStroke(strokeWidth));
                g.draw(bb);

                double s = 2.3 * VisualCommonSettings.getNodeSize() / 3.0;
                Shape shape = new Rectangle2D.Double(-s / 2, -s / 2, s, s);
                g.setStroke(new BasicStroke(strokeWidth / 2));
                g.setColor(ColorUtils.colorise(getForegroundColor(), d.getColorisation()));
                g.draw(shape);

                drawFault(r);
            } else {
                g.setColor(ColorUtils.colorise(Color.WHITE, d.getBackground()));
                g.fill(bb);
                float[] pattern = {0.2f, 0.2f};
                g.setStroke(new BasicStroke(0.02f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 1.0f, pattern, 0.0f));
                g.setColor(ColorUtils.colorise(getForegroundColor(), d.getColorisation()));
                g.draw(bb);
            }

            drawNameInLocalSpace(r);
            drawLabelInLocalSpace(r);
            drawDurationInLocalSpace(r);
        }
    }

    @Override
    public void drawFault(DrawRequest r) {
        if (SONSettings.isErrorTracing()) {
            Graphics2D g = r.getGraphics();
            GlyphVector glyphVector = null;
            Rectangle2D labelBB = null;

            Font labelFont = new Font(Font.SANS_SERIF, Font.PLAIN, 1).deriveFont(0.5f);
            if (isFaulty()) {
                glyphVector = labelFont.createGlyphVector(g.getFontRenderContext(), "1");
            } else {
                glyphVector = labelFont.createGlyphVector(g.getFontRenderContext(), "0");
            }
            labelBB = glyphVector.getVisualBounds();
            Point2D bitPosition = new Point2D.Double(labelBB.getCenterX(), labelBB.getCenterY());
            g.drawGlyphVector(glyphVector, -(float) bitPosition.getX(), -(float) bitPosition.getY());
        }
    }

    private void cahceDurationRenderedText() {
        String duration = "D: " + getDuration();
        Point2D offset = getOffset(durationLabelPositioning);
        if (durationLabelPositioning.ySign < 0) {
            offset.setLocation(offset.getX(), offset.getY() - 0.6);
        } else {
            offset.setLocation(offset.getX(), offset.getY() + 0.6);
        }

        if (durationRenderedText.isDifferent(duration, timeFont, durationLabelPositioning, offset)) {
            durationRenderedText = new RenderedText(duration, timeFont, durationLabelPositioning, offset);
        }
    }

    protected void drawDurationInLocalSpace(DrawRequest r) {
        if (SONSettings.getTimeVisibility() && getReferencedComponent().getDuration().isSpecified()) {
            cahceDurationRenderedText();
            Graphics2D g = r.getGraphics();
            Decoration d = r.getDecoration();
            g.setColor(ColorUtils.colorise(getDurationColor(), d.getColorisation()));
            durationRenderedText.draw(g);
        }
    }

    @Override
    public void cacheRenderedText(DrawRequest r) {
        super.cacheRenderedText(r);
        cahceDurationRenderedText();
    }

    @Override
    public Rectangle2D getBoundingBoxInLocalSpace() {
        Rectangle2D bb = super.getBoundingBoxInLocalSpace();

        if (SONSettings.getTimeVisibility() && getReferencedComponent().getDuration().isSpecified()) {
            bb = BoundingBoxHelper.union(bb, durationRenderedText.getBoundingBox());
        }
        return bb;
    }

    @Override
    public void setIsCollapsed(boolean value) {
        sendNotification(new TransformChangingEvent(this));
        getReferencedComponent().setIsCollapsed(value);
        sendNotification(new TransformChangedEvent(this));
    }

    @Override
    public boolean getIsCollapsed() {
        return  this.getReferencedComponent().getIsCollapsed();
    }

    public String getStartTime() {
        return getReferencedComponent().getStartTime().toString();
    }

    public void setStartTime(String time) {
        Interval input = new Interval(Interval.getMin(time), Interval.getMax(time));
        getReferencedComponent().setStartTime(input);
    }

    public String getEndTime() {
        return getReferencedComponent().getEndTime().toString();
    }

    public void setEndTime(String time) {
        Interval input = new Interval(Interval.getMin(time), Interval.getMax(time));
        getReferencedComponent().setEndTime(input);
    }

    public String getDuration() {
        return getReferencedComponent().getDuration().toString();
    }

    public void setDuration(String time) {
        Interval input = new Interval(Interval.getMin(time), Interval.getMax(time));
        getReferencedComponent().setDuration(input);
    }

    public Color getDurationColor() {
        return getReferencedComponent().getDurationColor();
    }

    public void setDurationColor(Color value) {
        getReferencedComponent().setDurationColor(value);
    }

    @Override
    public boolean isFaulty() {
        return getReferencedComponent().isFaulty();
    }

    @Override
    public void setLabel(String label) {
        super.setLabel(label);
        this.getReferencedComponent().setLabel(label);
    }

    @Override
    public String getLabel() {
        super.getLabel();
        return this.getReferencedComponent().getLabel();
    }

    @Override
    public void setForegroundColor(Color color) {
        this.getReferencedComponent().setForegroundColor(color);
    }

    @Override
    public Color getForegroundColor() {
        return this.getReferencedComponent().getForegroundColor();
    }

    @Override
    public void setFillColor(Color color) {
        this.getReferencedComponent().setFillColor(color);
    }

    @Override
    public Color getFillColor() {
        return this.getReferencedComponent().getFillColor();
    }

    @Override
    public Block getReferencedComponent() {
        return mathBlock;
    }

    public Collection<VisualSONConnection> getVisualSONConnections() {
        return Hierarchy.getDescendantsOfType(this, VisualSONConnection.class);
    }

    public Collection<VisualEvent> getVisualEvents() {
        return Hierarchy.getDescendantsOfType(this, VisualEvent.class);
    }

    @Override
    public Block getMathTransitionNode() {
        return getReferencedComponent();
    }

}