All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pathvisio.libgpml.model.DataNode Maven / Gradle / Ivy

Go to download

libGPML is a library for reading, writing, manipulation, and conversion of files and data streams in the GPML (Graphical Pathway Markup Language) format.

The newest version!
/*******************************************************************************
 * PathVisio, a tool for data visualization and analysis using biological pathways
 * Copyright 2006-2022 BiGCaT Bioinformatics, WikiPathways
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.  You may obtain a copy
 * of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations under
 * the License.
 ******************************************************************************/
package org.pathvisio.libgpml.model;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;

import javax.swing.JOptionPane;

import org.bridgedb.Xref;
import org.pathvisio.libgpml.model.type.DataNodeType;
import org.pathvisio.libgpml.model.type.ObjectType;
import org.pathvisio.libgpml.model.type.StateType;
import org.pathvisio.libgpml.prop.StaticProperty;
import org.pathvisio.libgpml.util.Utils;

/**
 * This class stores information for a DataNode pathway element.
 *
 * @author finterly
 */
public class DataNode extends ShapedElement implements Xrefable {

	private String textLabel;
	private DataNodeType type = DataNodeType.UNDEFINED;
	private List states;
	private Xref xref; // optional
	private Group aliasRef; // optional, the pathway element to which this data node refers to as an alias.

	// ================================================================================
	// Constructors for DataNode or "Alias" DataNode
	// ================================================================================

	/**
	 * Instantiates a DataNode given all possible parameters. A DataNode of type
	 * Alias can have an aliasRef which refers to a {@link Group} and/or have a
	 * textLabel which points to a group somewhere.
	 *
	 * @param textLabel the text or link of this datanode.
	 * @param type      the type of datanode, e.g. complex.
	 * @param xref      the data node Xref.
	 * @param aliasRef  the group this data node alias refers to.
	 */
	public DataNode(String textLabel, DataNodeType type, Xref xref, Group aliasRef) {
		super();
		this.textLabel = textLabel;
		setType(type);
		this.states = new ArrayList();
		this.xref = xref;
		setAliasRef(aliasRef);
	}

	/**
	 * Instantiates a DataNode given all required parameters.
	 * 
	 * @param textLabel the datanode text label.
	 * @param type      the datanode type.
	 */
	public DataNode(String textLabel, DataNodeType type) {
		this(textLabel, type, null, null);
	}

	// ================================================================================
	// Accessors
	// ================================================================================
	/**
	 * Returns the object type of this pathway element.
	 *
	 * @return the object type.
	 */
	@Override
	public ObjectType getObjectType() {
		return ObjectType.DATANODE;
	}

	/**
	 * Returns the text of this datanode.
	 *
	 * @return textLabel the text of this datanode.
	 *
	 */
	@Override
	public String getTextLabel() {
		return textLabel;
	}

	/**
	 * Sets the text of this shaped pathway element.
	 *
	 * @param v the text to set.
	 */
	@Override
	public void setTextLabel(String v) {
		String value = (v == null) ? "" : v;
		if (!Utils.stringEquals(textLabel, value)) {
			textLabel = value;
			fireObjectModifiedEvent(PathwayObjectEvent.createSinglePropertyEvent(this, StaticProperty.TEXTLABEL));
		}
	}

	/**
	 * Returns the type of this datanode.
	 *
	 * @return type the type of this datanode, e.g. complex.
	 */
	public DataNodeType getType() {
		return type;
	}

	/**
	 * Sets the type of this datanode, e.g. complex.
	 *
	 * NB: Cannot change type if this is an alias data node.
	 *
	 * @param v the type to set for this datanode.
	 */
	public void setType(DataNodeType v) {
		if (type != v && v != null) {
			if (type == DataNodeType.ALIAS && aliasRef != null) {
				unsetAliasRef(); // unset alias ref
			}
			// set new data node type
			type = v;
			fireObjectModifiedEvent(PathwayObjectEvent.createSinglePropertyEvent(this, StaticProperty.DATANODETYPE));
		}
	}

	/**
	 * Returns the Xref for this datanode.
	 *
	 * @return xref the xref of this datanode.
	 */
	@Override
	public Xref getXref() {
		return xref;
	}

	/**
	 * Sets the Xref for this datanode.
	 *
	 * @param v the xref to set for this datanode.
	 */
	@Override
	public void setXref(Xref v) {
		xref = v;
		fireObjectModifiedEvent(PathwayObjectEvent.createSinglePropertyEvent(this, StaticProperty.XREF));
	}

	// ================================================================================
	// State Methods
	// ================================================================================
	/*
	 * Returns the list of states of this data node.
	 *
	 * @return states the list of states.
	 */
	public List getStates() {
		return states;
	}

	/**
	 * Checks whether states has the given state.
	 *
	 * @param state the state to look for.
	 * @return true if has state, false otherwise.
	 */
	public boolean hasState(State state) {
		return states.contains(state);
	}

	/**
	 * Adds given state to states list. Sets datanode for the given state.
	 *
	 * @param state the state to be added.
	 */
	public void addState(State state) {
		if (state == null) {
			throw new IllegalArgumentException("Cannot add invalid state to data node " + getElementId());
		}
		if (state.getDataNode() != this) {
			throw new IllegalArgumentException("Cannot add state to data node other than its parent data node");
		}
		if (!hasState(state)) {
			// add state to same pathway model as data node if applicable
			if (pathwayModel != null) {
				pathwayModel.addPathwayObject(state);
			}
			states.add(state);
			// No state property, use BORDERSTYLE as dummy property to force redraw
			fireObjectModifiedEvent(PathwayObjectEvent.createSinglePropertyEvent(this, StaticProperty.BORDERSTYLE));
		} else {
			System.out.println("State " + state.getElementId() + " already belongs to data node " + getElementId());
		}
	}

	/**
	 * Instantiates a state with the given properties. Adds new state to states list
	 * and pathway model.
	 *
	 * @param textLabel the text label of the state.
	 * @param type      the type of the state, e.g. protein modification.
	 * @param relX      the relative x coordinates.
	 * @param relY      the relative y coordinates.
	 * @return state the instantiated state.
	 */
	public State addState(String textLabel, StateType type, double relX, double relY) {
		State state = new State(textLabel, type, relX, relY);
		addState(state);
		return state;
	}

	/**
	 * Instantiates a state with the given properties including elementId. Adds new
	 * state to states list and pathway model.
	 *
	 * @param elementId the elementId to set for the instantiated state.
	 * @param textLabel the text label of the state.
	 * @param type      the type of the state, e.g. protein modification.
	 * @param relX      the relative x coordinates.
	 * @param relY      the relative y coordinates.
	 * @return state the instantiated state.
	 */
	public State addState(String elementId, String textLabel, StateType type, double relX, double relY) {
		State state = new State(textLabel, type, relX, relY);
		state.setElementId(elementId);
		addState(state);
		return state;
	}

	/**
	 * Removes given state from states list. State ceases to exist and is
	 * terminated.
	 *
	 * @param state the state to be removed.
	 */
	public void removeState(State state) {
		if (pathwayModel != null)
			pathwayModel.removePathwayObject(state);
		states.remove(state);
		// No state property, use BORDERSTYLE as dummy property to force redraw
		fireObjectModifiedEvent(PathwayObjectEvent.createSinglePropertyEvent(this, StaticProperty.BORDERSTYLE));
	}

	/**
	 * Removes all states from states list.
	 */
	private void removeStates() {
		for (int i = states.size() - 1; i >= 0; i--) {
			if (pathwayModel != null)
				pathwayModel.removePathwayObject(states.get(i));
		}
		states.clear();
	}

	// ================================================================================
	// AliasRef Methods
	// ================================================================================
	/**
	 * Returns the pathway element to which the data node refers to as an alias. In
	 * GPML, this is aliasRef which refers to the elementId of a pathway element
	 * (normally gpml:Group).
	 *
	 * @return aliasRef the pathway element to which the data node refers.
	 */
	public Group getAliasRef() {
		return aliasRef;
	}

	/**
	 * Sets the group aliasRef to which this data node refers to as an alias. In
	 * GPML, this is aliasRef which refers to the elementId of gpml:Group.
	 *
	 * 

* NB: *

    *
  1. This method calls {@link #unsetAliasRef} to remove any existing links. *
  2. This method calls {@link PathwayModel#linkAlias} to add information to * pathway model. *
  3. DataNode type must be "Alias". *
* * @param v the group to which this data node refers. */ public void setAliasRef(Group v) { if (v != null) { if (type != DataNodeType.ALIAS) { throw new IllegalArgumentException("DataNode type must be Alias before setting aliasRef"); } unsetAliasRef(); v.getPathwayModel().linkAlias(v, this); aliasRef = v; fireObjectModifiedEvent(PathwayObjectEvent.createSinglePropertyEvent(this, StaticProperty.ALIASREF)); } } /** * Unsets the aliasRef, if any, from this data node. Also removes references in * pathway model. *

*

    *
  1. This method calls {@link #unsetAliasRef} to remove any existing links. *
  2. This method calls {@link PathwayModel#unlinkAlias} to remove information * in the pathway model. *
  3. This method is also called when this data node alias is * {@link #terminate}. *
*/ public void unsetAliasRef() { if (getAliasRef() != null) { pathwayModel.unlinkAlias(aliasRef, this); aliasRef = null; fireObjectModifiedEvent(PathwayObjectEvent.createSinglePropertyEvent(this, StaticProperty.ALIASREF)); } } // ================================================================================ // Copy Methods // ================================================================================ /** * Copies values from the given source pathway element. * *

* NB: *

    *
  1. AliasRef value is not copied. References to other PathwayObjects are * stored in {@link CopyElement} by {@link #copy}. *
* * @param src the source pathway element. */ public void copyValuesFrom(DataNode src) { super.copyValuesFrom(src); textLabel = src.textLabel; type = src.type; states = new ArrayList(); for (State s : src.states) { State result = addState(null, null, 0, 0); result.copyValuesFrom(s); } xref = src.xref; fireObjectModifiedEvent(PathwayObjectEvent.createAllPropertiesEvent(this)); } /** * Copies this pathway element. * * @return the copyElement for the new pathway element and this source pathway * element. */ @Override public CopyElement copy() { DataNode result = new DataNode(textLabel, type); result.copyValuesFrom(this); return new CopyElement(result, this); } /** * Copies references from the given source data node, including state * references. *

* NB: *

    *
  1. For each state, copies references from the corresponding source state. *
  2. To be called after new data node is added to a pathway model. *
  3. The source data node may be the immediate copy element source of the new * data node, or an older source data node. *
* * @param srcDataNode the source element to copy references from. */ @Override public void copyReferencesFrom(PathwayElement srcDataNode) { super.copyReferencesFrom(srcDataNode); List srcStates = ((DataNode) srcDataNode).getStates(); for (int i = 0; i < getStates().size(); i++) { states.get(i).copyReferencesFrom(srcStates.get(i)); } } // ================================================================================ // Property Methods // ================================================================================ /** * Returns all static properties for this pathway object. * * @return result the set of static property for this pathway object. */ @Override public Set getStaticPropertyKeys() { Set result = super.getStaticPropertyKeys(); Set propsDataNode = EnumSet.of(StaticProperty.TEXTLABEL, StaticProperty.DATANODETYPE, StaticProperty.XREF, StaticProperty.ALIASREF); result.addAll(propsDataNode); return result; } /** * Returns static property value for given key. * * @param key the key. * @return the static property value. */ @Override public Object getStaticProperty(StaticProperty key) { Object result = super.getStaticProperty(key); if (result == null) { switch (key) { case TEXTLABEL: result = getTextLabel(); break; case DATANODETYPE: result = getType().getName(); break; case XREF: result = getXref(); break; case ALIASREF: result = getAliasRef(); break; default: // do nothing } } return result; } /** * This works so that o.setNotes(x) is the equivalent of o.setProperty("Notes", * x); * * Value may be null in some cases, e.g. graphRef * * @param key the key. * @param value the static property value. */ @Override public void setStaticProperty(StaticProperty key, Object value) { super.setStaticProperty(key, value); switch (key) { case TEXTLABEL: setTextLabel((String) value); break; case DATANODETYPE: if (value instanceof DataNodeType) { setType((DataNodeType) value); } else { setType(DataNodeType.fromName((String) value)); } break; case XREF: setXref((Xref) value); break; case ALIASREF: setAliasRef((Group) value); break; default: // do nothing } } // ================================================================================ // Inherited Methods // ================================================================================ /** * Sets the pathway model for this pathway element. NB: Only set when a pathway * model adds this pathway element. This method is not used directly. * * NB: This method is not used directly. It is called by * {@link PathwayModel#addPathwayObject}. * * @param pathwayModel the parent pathway model. */ @Override protected void setPathwayModelTo(PathwayModel pathwayModel) throws IllegalArgumentException, IllegalStateException { super.setPathwayModelTo(pathwayModel); // if data node has states, also add states to pathway model for (State state : states) { pathwayModel.addPathwayObject(state); } } /** * Terminates this data node and removes all links and references. */ @Override protected void terminate() { unsetAliasRef(); // unsets aliasRef removeStates(); unsetAllLinkableFroms(); unsetGroupRef(); super.terminate(); } // ================================================================================ // State Class // ================================================================================ /** * This class stores all information relevant to a State pathway element. * * @author finterly */ public class State extends ShapedElement implements Xrefable { private String textLabel; private StateType type; private double relX; private double relY; private Xref xref; // optional // ================================================================================ // Constructors // ================================================================================ /** * Instantiates a State pathway element given all possible parameters. * * @param textLabel the text label of the state. * @param type the type of the state, e.g. protein modification. * @param relX the relative x coordinates on the parent object, where 0,0 * is at the center of the object and 1,1 at the bottom-right * corner of the object. * @param relY the relative y coordinates on the parent object, where 0,0 * is at the center of the object and 1,1 at the bottom-right * corner of the object. * @param xref the state xref. */ private State(String textLabel, StateType type, double relX, double relY, Xref xref) { super(); this.textLabel = textLabel; this.type = type; setRelX(relX); setRelY(relY); this.xref = xref; } /** * Instantiates a State pathway element given all possible parameters except * xref. */ private State(String textLabel, StateType type, double relX, double relY) { this(textLabel, type, relX, relY, null); } // ================================================================================ // Accessors // ================================================================================ /** * Returns the object type of this pathway element. * * @return the object type. */ @Override public ObjectType getObjectType() { return ObjectType.STATE; } /** * Returns the parent data node, outer class, to which the state belongs. *

* NB: *

    *
  1. Returns the parent data node even if this state has been removed from the * data node states list. *
  2. In GPML2013a, elementRef was used to refer to the elementId of parent * data node, thus linking state to parent data node. *
* * @return dataNode the parent data node of the state. */ public DataNode getDataNode() { return DataNode.this; } /** * Returns the text of of this state. * * @return textLabel the text of of this state. * */ @Override public String getTextLabel() { return textLabel; } /** * Sets the text of of this shaped pathway element. * * @param v the text to set for this shaped pathway element. */ @Override public void setTextLabel(String v) { String value = (v == null) ? "" : v; if (!Utils.stringEquals(textLabel, value)) { textLabel = value; fireObjectModifiedEvent(PathwayObjectEvent.createSinglePropertyEvent(this, StaticProperty.TEXTLABEL)); } } /** * Returns the type of this state. * * @return type the type of this state, e.g. complex. */ public StateType getType() { return type; } /** * Sets the type of this state. * * @param v the type of this state, e.g. complex. */ public void setType(StateType v) { if (type != v && v != null) { type = v; fireObjectModifiedEvent(PathwayObjectEvent.createSinglePropertyEvent(this, StaticProperty.STATETYPE)); } } /** * Returns the relative x coordinate. When the given state is linked to a data * node, relX and relY are the relative coordinates on the data node, where 0,0 * is at the center of the data node and 1,1 at the bottom right corner of the * data node. * * @return relX the relative x coordinate. */ public double getRelX() { return relX; } /** * Sets the relative x coordinate. When the given state is linked to a data * node, relX and relY are the relative coordinates on the data node, where 0,0 * is at the center of the data node and 1,1 at the bottom right corner of the * data node. * * @param v the relative x coordinate. * @throws IllegalArgumentException if relX is not between -1.0 and 1.0. t */ public void setRelX(double v) { if (Math.abs(v) <= 1.0) { if (relX != v) { relX = v; updateCoordinates(); fireObjectModifiedEvent(PathwayObjectEvent.createCoordinatePropertyEvent(this)); } } else { throw new IllegalArgumentException("relX " + v + " should be between -1.0 and 1.0"); } } /** * Returns the relative y coordinate. When the given state is linked to a data * node, relX and relY are the relative coordinates on the data node, where 0,0 * is at the center of the data node and 1,1 at the bottom right corner of the * data node. * * @return relY the relative y coordinate. */ public double getRelY() { return relY; } /** * Sets the relative y coordinate. When the given state is linked to a data * node, relX and relY are the relative coordinates on the data node, where 0,0 * is at the center of the data node and 1,1 at the bottom right corner of the * data node. * * @param v the relative y coordinate. */ public void setRelY(double v) { if (Math.abs(v) <= 1.0) { if (relY != v) { relY = v; updateCoordinates(); fireObjectModifiedEvent(PathwayObjectEvent.createCoordinatePropertyEvent(this)); } } else { throw new IllegalArgumentException("relY " + v + " should be between -1.0 and 1.0"); } } /** * Returns the Xref for this state. * * @return xref the xref of this state. */ @Override public Xref getXref() { return xref; } /** * Sets the Xref for this state. * * @param v the xref of this state. */ @Override public void setXref(Xref v) { if (v != null) { xref = v; fireObjectModifiedEvent(PathwayObjectEvent.createSinglePropertyEvent(this, StaticProperty.XREF)); } } /** * Updates coordinates. */ private void updateCoordinates() { DataNode dn = getDataNode(); if (dn != null && pathwayModel != null) { double centerx = dn.getCenterX() + (getRelX() * dn.getWidth() / 2); double centery = dn.getCenterY() + (getRelY() * dn.getHeight() / 2); setCenterY(centery); setCenterX(centerx); } } /** * Updates coordinates, called by {@link PathwayModel#childModified} */ public void coordinatesChanged() { updateCoordinates(); } // ================================================================================ // Inherited Methods // ================================================================================ /** * Returns the z-order of this pathway element. * * NB: State z-order is always z-order of parent data node +1. This is because * z-order is not written out to the gpml file. * * @return zOrder the order of this pathway element. */ @Override public int getZOrder() { return getDataNode().getZOrder() + 1; } /** * Do nothing. State z-order is always z-order of parent data node +1. This is * because z-order is not written out to the gpml file. * * @param v the input */ @Override public void setZOrder(int v) { // do nothing } /** * Returns the parent group of the dataNode of this state. * * NB: A state should always belong to the same group as its parent data node. * * @return the parent group of this state and its parent dataNode. */ @Override public Group getGroupRef() { return DataNode.this.getGroupRef(); } /** * Do not allow groupRef to be set for this state. A state will always belong to * the same group as its parent data node. * * @param v the group. */ @Override public void setGroupRefTo(Group v) { // do nothing } /** * Sets the pathway model for this pathway element. * * NB: This method is not used directly. It is called by * {@link PathwayModel#addPathwayObject}. * * @param pathwayModel the parent pathway model. */ @Override protected void setPathwayModelTo(PathwayModel pathwayModel) throws IllegalArgumentException, IllegalStateException { if (pathwayModel == null) throw new IllegalArgumentException("Invalid pathway model."); if (pathwayModel == getDataNode().getPathwayModel()) { setPathwayModel(pathwayModel); } else { throw new IllegalArgumentException(this.getClass().getSimpleName() + " must be added to the same pathway model as its parent data node."); } } /** * Terminates this state and removes all links and references. */ @Override protected void terminate() { unsetAllLinkableFroms(); unsetGroupRef(); super.terminate(); } // ================================================================================ // Copy Methods // ================================================================================ /** * Copies values from the given source pathway element. * * @param src the source pathway element. */ public void copyValuesFrom(State src) { super.copyValuesFrom(src); textLabel = src.textLabel; type = src.type; relX = src.relX; relY = src.relY; xref = src.xref; fireObjectModifiedEvent(PathwayObjectEvent.createAllPropertiesEvent(this)); } /** * Copies this pathway element. * * NB: this method is never actually used. * * @return the copyElement for the new pathway element and this source pathway * element. */ @Override public CopyElement copy() { State result = new State(textLabel, type, relX, relX); result.copyValuesFrom(this); return new CopyElement(result, this); } // ================================================================================ // Property Methods // ================================================================================ /** * Returns all static properties for this pathway object. * * @return result the set of static property for this pathway object. */ @Override public Set getStaticPropertyKeys() { Set result = super.getStaticPropertyKeys(); Set propsState = EnumSet.of(StaticProperty.TEXTLABEL, StaticProperty.STATETYPE, StaticProperty.RELX, StaticProperty.RELY, StaticProperty.XREF); result.addAll(propsState); return result; } /** * Returns static property value for given key. * * @param key the key. * @return the static property value. */ @Override public Object getStaticProperty(StaticProperty key) { Object result = super.getStaticProperty(key); if (result == null) { switch (key) { case TEXTLABEL: result = getTextLabel(); break; case STATETYPE: result = getType().getName(); break; case RELX: result = getRelX(); break; case RELY: result = getRelY(); break; case XREF: result = getXref(); break; default: // do nothing } } return result; } /** * This works so that o.setNotes(x) is the equivalent of o.setProperty("Notes", * x); * * Value may be null in some cases, e.g. graphRef * * @param key the key. * @param value the static property value. */ @Override public void setStaticProperty(StaticProperty key, Object value) { super.setStaticProperty(key, value); switch (key) { case TEXTLABEL: setTextLabel((String) value); break; case STATETYPE: if (value instanceof StateType) { setType((StateType) value); } else { setType(StateType.fromName((String) value)); } break; case RELX: setRelX((Double) value); break; case RELY: setRelY((Double) value); break; case XREF: setXref((Xref) value); break; default: // do nothing } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy