workcraft/workcraft

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

Summary

Maintainability
A
2 hrs
Test Coverage
package org.workcraft.plugins.dtd.observers;

import org.workcraft.dom.Container;
import org.workcraft.dom.Node;
import org.workcraft.dom.visual.VisualComponent;
import org.workcraft.observation.*;
import org.workcraft.plugins.dtd.*;
import org.workcraft.plugins.dtd.utils.DtdUtils;

import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

public final class DtdStateSupervisor extends StateSupervisor {

    private final VisualDtd dtd;

    public DtdStateSupervisor(VisualDtd dtd) {
        this.dtd = dtd;
    }

    @Override
    public void handleHierarchyEvent(HierarchyEvent e) {
        Object sender = e.getSender();
        if ((e instanceof NodesAddedEvent) && (sender instanceof VisualSignal)) {
            for (Node node : e.getAffectedNodes()) {
                if (node instanceof VisualEntryEvent) {
                    handleSignalEntryCreation((VisualEntryEvent) node);
                } else if (node instanceof VisualExitEvent) {
                    handleSignalExitCreation((VisualSignal) sender, (VisualExitEvent) node);
                }
            }
        }
    }

    @Override
    public void handleEvent(StateEvent e) {
        Object sender = e.getSender();
        if (e instanceof TransformChangedEvent) {
            if (sender instanceof VisualSignal) {
                handleSignalTransformation((VisualSignal) sender);
            } else if (sender instanceof VisualTransitionEvent) {
                handleSignalTransitionTransformation((VisualTransitionEvent) sender);
            } else if (sender instanceof VisualEntryEvent) {
                handleSignalEntryTransformation((VisualEntryEvent) sender);
            } else if (sender instanceof VisualExitEvent) {
                handleSignalExitTransformation((VisualExitEvent) sender);
            }
        } else if (e instanceof PropertyChangedEvent) {
            PropertyChangedEvent pce = (PropertyChangedEvent) e;
            String propertyName = pce.getPropertyName();
            if ((sender instanceof Signal) && (propertyName.equals(Signal.PROPERTY_INITIAL_STATE))) {
                VisualSignal signal = dtd.getVisualComponent((Signal) sender, VisualSignal.class);
                handleSignalInitialStateChange(signal);
            } else if ((sender instanceof TransitionEvent) && (propertyName.equals(TransitionEvent.PROPERTY_DIRECTION))) {
                VisualTransitionEvent transtition = dtd.getVisualComponent((TransitionEvent) sender, VisualTransitionEvent.class);
                handleTransitionDirectionChange(transtition);
            } else if ((sender instanceof VisualSignal) && (propertyName.equals(VisualSignal.PROPERTY_COLOR))) {
                handleSignalColorChange((VisualSignal) sender);
            }
        }
    }

    private void handleSignalEntryCreation(VisualEntryEvent entry) {
        entry.setPosition(new Point2D.Double(0.0, 0.0));
    }

    private void handleSignalExitCreation(VisualSignal signal, VisualExitEvent exit) {
        // Offset exit event to align with the furthest one
        Container container = (Container) signal.getParent();
        double x = DtdSettings.getTransitionSeparation();
        for (VisualExitEvent otherExit : dtd.getVisualSignalExits(container)) {
            if (otherExit.getX() > x) {
                x = otherExit.getX();
            }
        }
        if (exit.getX() != x) {
            exit.setX(x);
        }
    }

    private void handleSignalTransformation(VisualSignal signal) {
        if (signal.getX() != 0.0) {
            signal.setX(0.0);
        }
    }

    private void handleSignalTransitionTransformation(VisualTransitionEvent transition) {
        VisualSignal signal = transition.getVisualSignal();
        if (signal != null) {
            VisualEntryEvent entry = signal.getVisualSignalEntry();
            VisualExitEvent exit = signal.getVisualSignalExit();
            if ((entry != null) && (exit != null)) {
                Rectangle2D bbEntry = entry.getBoundingBox();
                double xMin = bbEntry.getMinX();
                for (Node predNode: dtd.getPreset(transition)) {
                    VisualComponent predComponent = (VisualComponent) predNode;
                    xMin = Math.max(xMin, predComponent.getBoundingBox().getMaxX());
                }
                Rectangle2D bbExit = exit.getBoundingBox();
                double xMax = bbExit.getMaxX();
                for (Node succNode: dtd.getPostset(transition)) {
                    VisualComponent succComponent = (VisualComponent) succNode;
                    xMax = Math.min(xMax, succComponent.getBoundingBox().getMinX());
                }
                limitSignalEventPosition(transition, xMin, xMax);
            }
        }
    }

    private void handleSignalEntryTransformation(VisualEntryEvent entry) {
        if (entry.getX() != 0.0) {
            entry.setX(0.0);
        }
        if (entry.getY() != 0.0) {
            entry.setY(0.0);
        }
    }

    private void handleSignalExitTransformation(VisualExitEvent exit) {
        VisualSignal signal = exit.getVisualSignal();
        if (signal != null) {
            VisualEntryEvent entry = signal.getVisualSignalEntry();
            if (entry != null) {
                Rectangle2D bbEntry = entry.getBoundingBox();
                double xMin = bbEntry.getMinX();
                for (VisualTransitionEvent transition: signal.getVisualTransitions()) {
                    xMin = Math.max(xMin, transition.getBoundingBox().getMaxX());
                }
                double xMax = xMin + 1000.0;
                limitSignalEventPosition(exit, xMin, xMax);
                // Align other exit events to this one
                Container container = (Container) signal.getParent();
                for (VisualExitEvent otherExit : dtd.getVisualSignalExits(container)) {
                    if (exit.getX() != otherExit.getX()) {
                        otherExit.setX(exit.getX());
                    }
                }
            }
        }
    }

    private void limitSignalEventPosition(VisualEvent event, double xMin, double xMax) {
        Rectangle2D bb = event.getBoundingBox();
        double x = event.getX();
        if (bb.getMinX() < xMin) {
            x = xMin + event.getX() - bb.getMinX();
        } else if (bb.getMaxX() > xMax) {
            x = xMax - bb.getMaxX() + event.getX();
        }
        Point2D pos = new Point2D.Double(x, 0.0);
        if (pos.distance(event.getPosition()) > 0.001) {
            event.setPosition(pos);
        }
    }

    private void handleSignalInitialStateChange(VisualSignal signal) {
        VisualEntryEvent entry = signal.getVisualSignalEntry();
        VisualEvent nextEvent = DtdUtils.getNextVisualEvent(dtd, entry);
        if (nextEvent instanceof VisualTransitionEvent) {
            VisualTransitionEvent nextTransition = (VisualTransitionEvent) nextEvent;
            Signal.State state = signal.getInitialState();
            if (DtdUtils.getPreviousDirection(state) == nextTransition.getDirection()) {
                DtdUtils.dissolveTransitionEvent(dtd, nextTransition);
            } else if (state == Signal.State.STABLE) {
                DtdUtils.dissolveSuffixTransitionEvents(dtd, entry);
            } else {
                DtdUtils.decorateVisualLevelConnection(dtd, entry, nextEvent);
            }
        } else {
            DtdUtils.decorateVisualLevelConnection(dtd, entry, nextEvent);
        }
    }

    private void handleTransitionDirectionChange(VisualTransitionEvent transition) {
        boolean nextDone = false;
        if (transition.getDirection() == TransitionEvent.Direction.STABILISE) {
            DtdUtils.dissolvePrefixTransitionEvents(dtd, transition, TransitionEvent.Direction.DESTABILISE);
            DtdUtils.dissolveSuffixTransitionEvents(dtd, transition);
            nextDone = true;
        }
        VisualEvent nextEvent = DtdUtils.getNextVisualEvent(dtd, transition);
        if (nextEvent instanceof VisualTransitionEvent) {
            VisualTransitionEvent nextTransition = (VisualTransitionEvent) nextEvent;
            if (transition.getDirection() == nextTransition.getDirection()) {
                DtdUtils.dissolveTransitionEvent(dtd, nextTransition);
                nextDone = true;
            }
        }
        if (!nextDone) {
            DtdUtils.decorateVisualLevelConnection(dtd, transition, nextEvent);
        }

        boolean prevDone = false;
        VisualEvent prevEvent = DtdUtils.getPrevVisualEvent(dtd, transition);
        if (prevEvent instanceof VisualTransitionEvent) {
            VisualTransitionEvent prevTransition = (VisualTransitionEvent) prevEvent;
            if (prevTransition.getDirection() == transition.getDirection()) {
                DtdUtils.dissolveTransitionEvent(dtd, transition);
                prevDone = true;
            }
        }
        if (prevEvent instanceof VisualEntryEvent) {
            VisualSignal signal = transition.getVisualSignal();
            Signal.State state = signal.getInitialState();
            if (DtdUtils.getPreviousDirection(state) == transition.getDirection()) {
                DtdUtils.dissolveTransitionEvent(dtd, transition);
                prevDone = true;
            }
        }
        if (!prevDone) {
            DtdUtils.decorateVisualLevelConnection(dtd, prevEvent,  transition);
        }
    }

    private void handleSignalColorChange(VisualSignal signal) {
        Color color = signal.getForegroundColor();
        setEventAndNextLevelColor(signal.getVisualSignalEntry(), color);
        for (VisualTransitionEvent transition : signal.getVisualTransitions()) {
            setEventAndNextLevelColor(transition, color);
        }
        setEventAndNextLevelColor(signal.getVisualSignalExit(), color);
    }

    private void setEventAndNextLevelColor(VisualEvent event, Color color) {
        if (event != null) {
            event.setForegroundColor(color);
            VisualLevelConnection level = DtdUtils.getNextVisualLevel(dtd, event);
            if (level != null) {
                level.setColor(color);
            }
        }
    }

}