/** * Copyright (C) 2008-2010 Daniel Senff * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package de.danielsenff.imageflow.models.connection; import visualap.Node; import de.danielsenff.imageflow.models.Lockable; import de.danielsenff.imageflow.models.unit.UnitElement; /** * Connection between two {@link Pin}s, {@link Input} and {@link Output}. * @author Daniel Senff * */ public class Connection implements Lockable { /** * the id of this connection */ public int id; /** * Target and origin Pin. */ protected Pin from, to; /** * Connection-Status * */ public enum Status {OK, MISSING_TO_UNIT, MISSING_FROM_UNIT, MISSING_BOTH } protected boolean locked = false; /** * @param fromUnit * @param fromOutputNumber index starting with 1 * @param toUnit * @param toInputNumber index starting with 1 */ public Connection(final UnitElement fromUnit, final int fromOutputNumber, final UnitElement toUnit, final int toInputNumber) { this(fromUnit.getOutput(fromOutputNumber-1), toUnit.getInput(toInputNumber-1)); } /** * Creates a Connection between the two defined pins. * The order for Input and Output is irrelevant. * @param pin1 * @param pin2 */ public Connection(final Pin pin1, final Pin pin2) { if(pin1 instanceof Input && pin2 instanceof Output) { this.from = pin2; this.to = pin1; } else { this.from = pin1; this.to = pin2; } UnitElement fromUnit = (UnitElement) getOutput().getParent(); UnitElement toUnit = (UnitElement) getInput().getParent(); id = getID(fromUnit.getNodeID(), getOutput().getIndex(), toUnit.getNodeID(), getInput().getIndex()); } /** * connect the inputs and outputs of the units * @param unitElements */ public void connect() { ((Output)this.from).addConnection(this); ((Input)this.to).setConnection(this); } /** * creates a unique id for each connection * @param fromUnitNumber * @param fromOutputNumber * @param toUnitNumber * @param toInputNumber * @return */ public static int getID(final int fromUnitNumber, final int fromOutputNumber, final int toUnitNumber, final int toInputNumber) { final int id = (fromUnitNumber<<20) | (fromOutputNumber<<16) | (toUnitNumber<<4) | toInputNumber; return id; } /** * Returns the status of the connection, whether all ends are connected. * Good for finding corrupt connections to non-existent units. * @return */ public Status checkConnection() { if(getFromUnit() != null && getToUnit() != null) { return Status.OK; } else if (getFromUnit() == null || getToUnit() != null) { return Status.MISSING_FROM_UNIT; } else if (getFromUnit() != null || getToUnit() == null) { return Status.MISSING_TO_UNIT; } return Status.MISSING_BOTH; } /** * Returns the {@link UnitElement} from which this connection comes. * @return */ public Node getFromUnit() { return this.from.getParent(); } /** * Returns the {@link UnitElement} to which this connections leads. * @return */ public Node getToUnit() { return this.to.getParent(); } /** * Get the {@link Input}-Pin. * @return */ public Input getInput() { return (Input)this.to; } /** * Get the {@link Output}-pin * @return */ public Output getOutput() { return (Output)this.from; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return super.toString() + " fromUnit: "+ getFromUnit() +" toUnit:" + getToUnit(); } /** * Checks a unit, if it's inputs have already been registered in the algorithm. * @param unit * @return */ public boolean hasInputMarked() { boolean hasMarked = true; UnitElement toUnit = (UnitElement) getToUnit(); UnitElement fromUnit = (UnitElement) getFromUnit(); if(toUnit.getInputsCount() > 0) { // check each input, if it's parent has been registered int mark = fromUnit.getOutput(0).getMark(); // if mark is not set if(mark == 0) { // this connected ouput hasn't been registered and // is missing a mark, // so the whole unit isn't ready set. hasMarked = false; } // else mark is already set, so this output is fine } return hasMarked; } /** * Checks if this connection is attached to the {@link Pin} * @param pin * @return */ public boolean isConnected(Pin pin) { return (this.from.equals(pin)) || this.to.equals(pin); } /** * Gets whether this Connection is connected with this {@link UnitElement}. * @param unit * @return */ public boolean isConnectedToUnit(final Node unit) { return (getFromUnit().equals(unit)) || (getToUnit().equals(unit)); } /** * Is true, when the ImageBitDepth given by the {@link Output} is * supported by this Input. * @return */ public boolean isCompatible() { Input input = ((Input)this.to); Output output = ((Output)this.from); return input.isCompatible(output); } /** * Checks if this Connection is connected to a from- and a to-pin. * Technically, if the connection isn't true, this connection object is kinda zombie * @return */ public boolean isConnected() { Output from = (Output)this.from; Input to = (Input)this.to; return (from.isConnectedWith(to) && to.isConnectedWith(from)); } /** * Returns true if the connection is locked and cann not be removed. * @return the locked */ public boolean isLocked() { return locked; } /** * If set true, the connection can not be removed and is write protected. * @param locked the locked to set */ public void setLocked(boolean locked) { this.locked = locked; this.to.setLocked(locked); this.from.setLocked(locked); } public boolean causesLoop() { if(((Input)this.to).isConnectedInOutputBranch(getFromUnit())) return true; if(((Output)this.from).existsInInputSubgraph(getToUnit())) return true; return false; } }