workcraft/workcraft

View on GitHub
workcraft/DtdPlugin/src/org/workcraft/plugins/dtd/VisualSignal.java

Summary

Maintainability
A
1 hr
Test Coverage
package org.workcraft.plugins.dtd;

import org.workcraft.annotations.DisplayName;
import org.workcraft.annotations.Hotkey;
import org.workcraft.annotations.SVGIcon;
import org.workcraft.dom.Container;
import org.workcraft.dom.DefaultGroupImpl;
import org.workcraft.dom.Node;
import org.workcraft.dom.visual.*;
import org.workcraft.gui.properties.PropertyDeclaration;
import org.workcraft.observation.HierarchyObserver;
import org.workcraft.observation.ObservableHierarchy;
import org.workcraft.plugins.builtin.settings.VisualCommonSettings;
import org.workcraft.plugins.dtd.utils.DtdUtils;
import org.workcraft.serialisation.NoAutoSerialisation;
import org.workcraft.utils.ColorUtils;
import org.workcraft.utils.Hierarchy;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Collection;
import java.util.HashSet;

@Hotkey(KeyEvent.VK_X)
@DisplayName("Signal")
@SVGIcon("images/dtd-node-signal.svg")
public class VisualSignal extends VisualComponent implements Container, CustomTouchable, ObservableHierarchy {

    protected DefaultGroupImpl groupImpl = new DefaultGroupImpl(this);

    public VisualSignal(Signal signal) {
        super(signal);
        configureProperties();
    }

    private void configureProperties() {
        removePropertyDeclarationByName(PROPERTY_FILL_COLOR);
        removePropertyDeclarationByName(PROPERTY_NAME_POSITIONING);
        removePropertyDeclarationByName(PROPERTY_NAME_COLOR);
        removePropertyDeclarationByName(PROPERTY_LABEL);
        removePropertyDeclarationByName(PROPERTY_LABEL_POSITIONING);
        removePropertyDeclarationByName(PROPERTY_LABEL_COLOR);

        addPropertyDeclaration(new PropertyDeclaration<>(Signal.Type.class, Signal.PROPERTY_TYPE,
                this::setType, this::getType).setCombinable().setTemplatable());

        addPropertyDeclaration(new PropertyDeclaration<>(Signal.State.class, Signal.PROPERTY_INITIAL_STATE,
                this::setInitialState, this::getInitialState).setCombinable().setTemplatable());
    }

    @Override
    public Signal getReferencedComponent() {
        return (Signal) super.getReferencedComponent();
    }

    @Override
    public boolean checkForegroundColor(Color value) {
        if (!super.checkForegroundColor(value)) {
            return false;
        }

        VisualEntryEvent entry = getVisualSignalEntry();
        if ((entry != null) && !entry.checkForegroundColor(value)) {
            return false;
        }

        VisualExitEvent exit = getVisualSignalExit();
        if ((exit != null) && !exit.checkForegroundColor(value)) {
            return false;
        }

        for (VisualTransitionEvent transition : getVisualTransitions()) {
            if ((transition != null) && !transition.checkForegroundColor(value)) {
                return false;
            }
        }
        return true;
    }

    @NoAutoSerialisation
    public Signal.Type getType() {
        return getReferencedComponent().getType();
    }

    @NoAutoSerialisation
    public void setType(Signal.Type value) {
        getReferencedComponent().setType(value);
    }

    @NoAutoSerialisation
    public Signal.State getInitialState() {
        return getReferencedComponent().getInitialState();
    }

    @NoAutoSerialisation
    public void setInitialState(Signal.State value) {
        getReferencedComponent().setInitialState(value);
    }

    @Override
    public void draw(DrawRequest r) {
        Graphics2D g = r.getGraphics();
        Color colorisation = r.getDecoration().getColorisation();
        g.setColor(ColorUtils.colorise(getForegroundColor(), colorisation));
        drawNameInLocalSpace(r);
    }

    @Override
    public Rectangle2D getInternalBoundingBoxInLocalSpace() {
        double size = VisualCommonSettings.getNodeSize();
        return new Rectangle2D.Double(-0.25 * size, -0.25 * size, 0.5 * size, 0.5 * size);
    }

    @Override
    public Rectangle2D getBoundingBoxInLocalSpace() {
        Rectangle2D bb = super.getBoundingBoxInLocalSpace();
        Collection<Touchable> touchableChildren = Hierarchy.getChildrenOfType(this, Touchable.class);
        Rectangle2D childrenBB = BoundingBoxHelper.mergeBoundingBoxes(touchableChildren);
        return BoundingBoxHelper.union(bb, childrenBB);
    }

    @Override
    public boolean hitTestInLocalSpace(Point2D pointInLocalSpace) {
        return getBoundingBoxInLocalSpace().contains(pointInLocalSpace);
    }

    @Override
    public Positioning getNamePositioning() {
        return Positioning.LEFT;
    }

    @Override
    public Positioning getLabelPositioning() {
        return Positioning.CENTER;
    }

    @Override
    public Alignment getLabelAlignment() {
        return Alignment.CENTER;
    }

    @Override
    public boolean getLabelVisibility() {
        return true;
    }

    @Override
    public boolean getNameVisibility() {
        return true;
    }

    @Override
    public Color getNameColor() {
        return DtdUtils.getTypeColor(getType());
    }

    @Override
    public void add(Node node) {
        groupImpl.add(node);
    }

    @Override
    public Collection<Node> getChildren() {
        return groupImpl.getChildren();
    }

    @Override
    public Node getParent() {
        return groupImpl.getParent();
    }

    @Override
    public void setParent(Node parent) {
        groupImpl.setParent(parent);
    }

    @Override
    public void remove(Node node) {
        groupImpl.remove(node);
    }

    @Override
    public void add(Collection<? extends Node> nodes) {
        groupImpl.add(nodes);
    }

    @Override
    public void remove(Collection<? extends Node> nodes) {
        for (Node n : nodes) {
            remove(n);
        }
    }

    @Override
    public void reparent(Collection<? extends Node> nodes, Container newParent) {
        groupImpl.reparent(nodes, newParent);
    }

    @Override
    public void reparent(Collection<? extends Node> nodes) {
        groupImpl.reparent(nodes);
    }

    @Override
    public Node hitCustom(Point2D point) {
        Point2D pointInLocalSpace = getParentToLocalTransform().transform(point, null);
        for (Node node : getChildren()) {
            if (node instanceof VisualEvent) {
                VisualEvent event = (VisualEvent) node;
                double threshold = Math.min(0.1, event.getShape().getBounds2D().getWidth());
                if (event.hitTest(pointInLocalSpace)
                        || event.hitTest(new Point2D.Double(pointInLocalSpace.getX() - threshold, pointInLocalSpace.getY()))
                        || event.hitTest(new Point2D.Double(pointInLocalSpace.getX() + threshold, pointInLocalSpace.getY()))) {
                    return event;
                }
            }
        }
        return hitTest(point) ? this : null;
    }

    @Override
    public void addObserver(HierarchyObserver obs) {
        groupImpl.addObserver(obs);
    }

    @Override
    public void removeObserver(HierarchyObserver obs) {
        groupImpl.removeObserver(obs);
    }

    @Override
    public void removeAllObservers() {
        groupImpl.removeAllObservers();
    }

    public Collection<VisualTransitionEvent> getVisualTransitions() {
        HashSet<VisualTransitionEvent> result = new HashSet<>();
        for (Node node: getChildren()) {
            if (node instanceof VisualTransitionEvent) {
                result.add((VisualTransitionEvent) node);
            }
        }
        return result;
    }

    public VisualEntryEvent getVisualSignalEntry() {
        for (Node node: getChildren()) {
            if (node instanceof VisualEntryEvent) {
                return (VisualEntryEvent) node;
            }
        }
        return null;
    }

    public VisualExitEvent getVisualSignalExit() {
        for (Node node: getChildren()) {
            if (node instanceof VisualExitEvent) {
                return (VisualExitEvent) node;
            }
        }
        return null;
    }

}