workcraft/workcraft

View on GitHub
workcraft/CircuitPlugin/src/org/workcraft/plugins/circuit/commands/ToggleBubbleTransformationCommand.java

Summary

Maintainability
A
30 mins
Test Coverage
package org.workcraft.plugins.circuit.commands;

import org.workcraft.commands.AbstractTransformationCommand;
import org.workcraft.commands.NodeTransformer;
import org.workcraft.dom.Node;
import org.workcraft.dom.visual.VisualModel;
import org.workcraft.dom.visual.VisualNode;
import org.workcraft.formula.BooleanFormula;
import org.workcraft.formula.FormulaUtils;
import org.workcraft.formula.workers.CleverBooleanWorker;
import org.workcraft.plugins.circuit.*;
import org.workcraft.utils.Hierarchy;
import org.workcraft.utils.LogUtils;
import org.workcraft.utils.WorkspaceUtils;
import org.workcraft.workspace.ModelEntry;
import org.workcraft.workspace.WorkspaceEntry;

import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;

public class ToggleBubbleTransformationCommand extends AbstractTransformationCommand implements NodeTransformer {

    @Override
    public String getDisplayName() {
        return "Toggle inversion of selected contacts and outputs of selected components";
    }

    @Override
    public String getPopupName() {
        return "Toggle inversion";
    }

    @Override
    public boolean isApplicableTo(WorkspaceEntry we) {
        return WorkspaceUtils.isApplicable(we, VisualCircuit.class);
    }

    @Override
    public boolean isApplicableTo(VisualNode node) {
        return (node instanceof VisualFunctionComponent)
                || ((node instanceof VisualFunctionContact)
                && (node.getParent() instanceof VisualFunctionComponent));
    }

    @Override
    public boolean isEnabled(ModelEntry me, VisualNode node) {
        if (node instanceof VisualFunctionComponent) {
            FunctionComponent component = ((VisualFunctionComponent) node).getReferencedComponent();
            if (checkSetResetFunctions(component.getFunctionOutputs())) {
                return true;
            }
        }
        if (node instanceof VisualFunctionContact) {
            FunctionContact contact = ((VisualFunctionContact) node).getReferencedComponent();
            if (checkSetResetFunctions(getDependantContacts(contact))) {
                return true;
            }
        }
        return false;
    }

    private boolean checkSetResetFunctions(Collection<FunctionContact> contacts) {
        for (FunctionContact contact : contacts) {
            if ((contact.getSetFunction() != null) || (contact.getResetFunction() != null)) {
                return true;
            }
        }
        return false;
    }

    private HashSet<FunctionContact> getDependantContacts(FunctionContact contact) {
        HashSet<FunctionContact> result = new HashSet<>();
        Node parent = contact.getParent();
        if (parent instanceof FunctionComponent) {
            if (contact.isOutput()) {
                result.add(contact);
            } else {
                FunctionComponent component = (FunctionComponent) parent;
                for (Contact outputContact: component.getOutputs()) {
                    if (outputContact instanceof FunctionContact) {
                        result.add((FunctionContact) outputContact);
                    }
                }
            }
        }
        return result;
    }

    @Override
    public Position getPosition() {
        return Position.TOP;
    }

    @Override
    public Collection<VisualNode> collectNodes(VisualModel model) {
        Collection<VisualNode> contacts = new HashSet<>();
        if (model instanceof VisualCircuit) {
            VisualCircuit circuit = (VisualCircuit) model;
            contacts.addAll(Hierarchy.getDescendantsOfType(circuit.getRoot(), VisualFunctionContact.class));
            Collection<VisualNode> selection = new LinkedList<>(circuit.getSelection());
            for (Node node: new LinkedList<>(selection)) {
                if (node instanceof VisualFunctionComponent) {
                    VisualFunctionComponent component = (VisualFunctionComponent) node;
                    selection.addAll(component.getVisualOutputs());
                }
            }
            contacts.retainAll(selection);
        }
        return contacts;
    }

    @Override
    public void transformNode(VisualModel model, VisualNode node) {
        if ((model instanceof VisualCircuit) && (node instanceof VisualFunctionContact)) {
            FunctionContact contact = ((VisualFunctionContact) node).getReferencedComponent();
            if (contact.isOutput()) {
                BooleanFormula setFunction = contact.getSetFunction();
                BooleanFormula resetFunction = contact.getResetFunction();
                if ((setFunction != null) && (resetFunction == null)) {
                    contact.setSetFunction(FormulaUtils.invert(setFunction));
                } else {
                    contact.setSetFunction(resetFunction);
                    contact.setResetFunction(setFunction);
                }
            } else {
                for (FunctionContact dependantContact: getDependantContacts(contact)) {
                    BooleanFormula setFunction = dependantContact.getSetFunction();
                    BooleanFormula notContact = FormulaUtils.invert(contact);
                    if (setFunction != null) {
                        BooleanFormula f = FormulaUtils.replace(setFunction, contact, notContact, CleverBooleanWorker.getInstance());
                        dependantContact.setSetFunction(f);
                    }
                    BooleanFormula resetFunction = dependantContact.getResetFunction();
                    if (resetFunction != null) {
                        BooleanFormula f = FormulaUtils.replace(resetFunction, contact, notContact, CleverBooleanWorker.getInstance());
                        dependantContact.setResetFunction(f);
                    }
                }
            }
            Node parent = node.getParent();
            if (parent instanceof VisualFunctionComponent) {
                VisualFunctionComponent component = (VisualFunctionComponent) parent;
                String label = component.getLabel();
                if (!label.isEmpty()) {
                    String ref = model.getMathReference(node);
                    LogUtils.logWarning("Label '" + label + "' is removed from component '" + ref + "'.");
                    component.clearMapping();
                }
                component.invalidateRenderingResult();
                model.addToSelection(component);
            }
        }
    }

}