workcraft/workcraft

View on GitHub
workcraft/WorkcraftCore/src/org/workcraft/dom/visual/TransformEventPropagator.java

Summary

Maintainability
A
3 hrs
Test Coverage
package org.workcraft.dom.visual;

import java.util.HashMap;
import java.util.LinkedList;

import org.workcraft.dom.Node;
import org.workcraft.observation.HierarchyEvent;
import org.workcraft.observation.HierarchySupervisor;
import org.workcraft.observation.NodesAddedEvent;
import org.workcraft.observation.NodesDeletedEvent;
import org.workcraft.observation.NodesReparentedEvent;
import org.workcraft.observation.ObservableState;
import org.workcraft.observation.StateEvent;
import org.workcraft.observation.StateObserver;
import org.workcraft.observation.TransformEvent;
import org.workcraft.observation.TransformObserver;

public class TransformEventPropagator extends HierarchySupervisor implements StateObserver, TransformDispatcher {

    private final HashMap<Node, LinkedList<TransformObserver>> nodeToObservers = new HashMap<>();
    private final HashMap<TransformObserver, LinkedList<Node>> observerToNodes = new HashMap<>();

    private void addObserver(Node node, TransformObserver to) {
        LinkedList<TransformObserver> list = nodeToObservers.get(node);
        if (list == null) {
            list = new LinkedList<>();
            nodeToObservers.put(node, list);
        }
        list.add(to);
    }

    private void removeObserver(Node node, TransformObserver to) {
        LinkedList<TransformObserver> list = nodeToObservers.get(node);
        list.remove(to);
        if (list.isEmpty()) {
            nodeToObservers.remove(node);
        }
    }

    private void addObservedNode(TransformObserver to, Node node) {
        LinkedList<Node> list = observerToNodes.get(to);
        if (list == null) {
            list = new LinkedList<>();
            observerToNodes.put(to, list);
        }
        list.add(node);
    }

    private void removeObservedNode(TransformObserver to, Node node) {
        LinkedList<Node> list = observerToNodes.get(to);
        list.remove(node);

        if (list.isEmpty()) {
            observerToNodes.remove(to);
        }
    }

    @Override
    public void handleEvent(HierarchyEvent e) {
        if (e instanceof NodesAddedEvent || e instanceof NodesReparentedEvent) {
            for (Node n : e.getAffectedNodes()) {
                nodeAdded(n);
            }
        } else if (e instanceof NodesDeletedEvent) {
            for (Node n : e.getAffectedNodes()) {
                nodeRemoved(n);
            }
        }
    }

    private void nodeRemoved(Node node) {
        if (node instanceof ObservableState) {
            ((ObservableState) node).removeObserver(this);

            // remove node from all observer lists
            LinkedList<TransformObserver> observers = nodeToObservers.get(node);
            if (observers != null) {
                for (TransformObserver to : observers) {
                    removeObservedNode(to, node);
                }
            }

            nodeToObservers.remove(node);
        }

        if (node instanceof TransformObserver) {
            TransformObserver to = (TransformObserver) node;
            LinkedList<Node> nodes = observerToNodes.get(to);
            if (nodes != null) {
                for (Node n : nodes) {
                    removeObserver(n, to);
                }
            }
        }

        for (Node n : node.getChildren()) {
            nodeRemoved(n);
        }
    }

    private void nodeAdded(Node node) {
        if (node instanceof ObservableState) {
            ((ObservableState) node).addObserver(this);
        }

        if (node instanceof TransformObserver) {
            TransformObserver to = (TransformObserver) node;
            to.subscribe(this);
        }

        for (Node n : node.getChildren()) {
            nodeAdded(n);
        }
    }

    private void propagate(Node node, TransformEvent e) {
        LinkedList<TransformObserver> list = nodeToObservers.get(node);
        if (list != null) {
            for (TransformObserver to : list) {
                to.notify(e);
            }
        }

        for (Node n : node.getChildren()) {
            propagate(n, e);
        }
    }

    @Override
    public void notify(StateEvent e) {
        if (e instanceof TransformEvent) {
            propagate(((TransformEvent) e).getSender(), (TransformEvent) e);
        }
    }

    @Override
    public void subscribe(TransformObserver observer, Node observed) {
        addObserver(observed, observer);
        addObservedNode(observer, observed);
    }

    @Override
    public void unsubscribe(TransformObserver observer, Node observed) {
        removeObserver(observed, observer);
        removeObservedNode(observer, observed);
    }

}