/*
*------------------------------------------------------------------------------
* Copyright (C) 2006-2007 University of Dundee. All rights reserved.
*
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*------------------------------------------------------------------------------
*/
package org.openmicroscopy.shoola.util.roi.io;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import net.n3.nanoxml.IXMLElement;
import net.n3.nanoxml.IXMLParser;
import net.n3.nanoxml.IXMLReader;
import net.n3.nanoxml.StdXMLReader;
import net.n3.nanoxml.XMLParserFactory;
import org.jhotdraw.draw.AttributeKey;
import org.jhotdraw.geom.BezierPath.Node;
import org.openmicroscopy.shoola.util.roi.ROIComponent;
import org.openmicroscopy.shoola.util.roi.model.ROI;
import org.openmicroscopy.shoola.util.roi.model.ROIShape;
import org.openmicroscopy.shoola.util.roi.model.annotation.AnnotationKey;
import org.openmicroscopy.shoola.util.roi.model.annotation.MeasurementAttributes;
import org.openmicroscopy.shoola.util.roi.model.util.Coord3D;
import org.openmicroscopy.shoola.util.roi.exception.NoSuchROIException;
import org.openmicroscopy.shoola.util.roi.exception.ParsingException;
import org.openmicroscopy.shoola.util.roi.exception.ROICreationException;
import org.openmicroscopy.shoola.util.roi.figures.MeasureBezierFigure;
import org.openmicroscopy.shoola.util.roi.figures.MeasureEllipseFigure;
import org.openmicroscopy.shoola.util.roi.figures.MeasureLineConnectionFigure;
import org.openmicroscopy.shoola.util.roi.figures.MeasureLineFigure;
import org.openmicroscopy.shoola.util.roi.figures.MeasurePointFigure;
import org.openmicroscopy.shoola.util.roi.figures.MeasureRectangleFigure;
import org.openmicroscopy.shoola.util.roi.figures.MeasureTextFigure;
import org.openmicroscopy.shoola.util.roi.figures.ROIFigure;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGAttributeParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGFillParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGFillRuleParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGFontFamilyParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGFontSizeParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGFontStyleAttribute;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGFontWeightParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGMiterLimitParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGNullParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGStrokeDashArrayParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGStrokeDashOffsetParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGStrokeLineCapParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGStrokeLineJoinParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGStrokeOpacityParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGStrokeParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGStrokeWidthParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.SVGTransformParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.ShowMeasurementParser;
import org.openmicroscopy.shoola.util.roi.io.attributeparser.ShowTextParser;
import omero.gateway.model.ShapeSettingsData;
/**
*
*
* @author Jean-Marie Burel
* <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author Donald MacDonald
* <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a>
* @version 3.0
* @since OME3.0
*/
public class InputStrategy
{
/**
* The hashmap of the default values of each object along with the keys
* used.
*/
private final static Map<AttributeKey, Object> defaultAttributes;
static
{
defaultAttributes=new HashMap<AttributeKey, Object>();
defaultAttributes.put(MeasurementAttributes.FILL_COLOR,
ShapeSettingsData.DEFAULT_FILL_COLOUR);
defaultAttributes.put(MeasurementAttributes.STROKE_COLOR,
ShapeSettingsData.DEFAULT_STROKE_COLOUR);
defaultAttributes.put(MeasurementAttributes.TEXT_COLOR,
ShapeSettingsData.DEFAULT_STROKE_COLOUR);
defaultAttributes.put(MeasurementAttributes.FONT_SIZE,
new Double(ShapeSettingsData.DEFAULT_FONT_SIZE));
defaultAttributes.put(MeasurementAttributes.FONT_BOLD,
Boolean.valueOf(false));
defaultAttributes.put(MeasurementAttributes.STROKE_WIDTH,
ShapeSettingsData.DEFAULT_STROKE_WIDTH);
defaultAttributes.put(MeasurementAttributes.TEXT,
ROIFigure.DEFAULT_TEXT);
defaultAttributes.put(MeasurementAttributes.MEASUREMENTTEXT_COLOUR,
ShapeSettingsData.DEFAULT_STROKE_COLOUR);
defaultAttributes.put(MeasurementAttributes.SHOWMEASUREMENT,
Boolean.valueOf(false));
defaultAttributes.put(MeasurementAttributes.SHOWTEXT,
Boolean.valueOf(false));
defaultAttributes.put(MeasurementAttributes.SCALE_PROPORTIONALLY,
Boolean.valueOf(false));
}
/**
* Map used to map attribute with the object to parse that attribute.
*/
private final static HashMap<String, SVGAttributeParser> attributeParserMap;
static
{
attributeParserMap=new HashMap<String, SVGAttributeParser>();
attributeParserMap.put(IOConstants.ATTRIBUTE_SHOWTEXT,
new ShowTextParser());
attributeParserMap.put(IOConstants.ATTRIBUTE_SHOWMEASUREMENT,
new ShowMeasurementParser());
attributeParserMap.put(IOConstants.SVG_FILL_ATTRIBUTE,
new SVGFillParser());
attributeParserMap.put(IOConstants.SVG_FILL_OPACITY_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_FILL_RULE_ATTRIBUTE,
new SVGFillRuleParser());
attributeParserMap.put(IOConstants.SVG_STROKE_ATTRIBUTE,
new SVGStrokeParser());
attributeParserMap.put(IOConstants.SVG_STROKE_OPACITY_ATTRIBUTE,
new SVGStrokeOpacityParser());
attributeParserMap.put(IOConstants.SVG_STROKE_WIDTH_ATTRIBUTE,
new SVGStrokeWidthParser());
attributeParserMap.put(IOConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE,
new SVGStrokeDashOffsetParser());
attributeParserMap.put(IOConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE,
new SVGStrokeDashArrayParser());
attributeParserMap.put(IOConstants.SVG_STROKE_LINECAP_ATTRIBUTE,
new SVGStrokeLineCapParser());
attributeParserMap.put(IOConstants.SVG_STROKE_LINEJOIN_ATTRIBUTE,
new SVGStrokeLineJoinParser());
attributeParserMap.put(IOConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE,
new SVGMiterLimitParser());
attributeParserMap.put(IOConstants.SVG_COLOR_INTERPOLATION_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_COLOR_RENDERING_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_OPACITY_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_MARKER_END_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_MARKER_MID_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_MARKER_START_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_FONT_FAMILY_ATTRIBUTE,
new SVGFontFamilyParser());
attributeParserMap.put(IOConstants.SVG_MARKER_START_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_FONT_SIZE_ATTRIBUTE,
new SVGFontSizeParser());
attributeParserMap.put(IOConstants.SVG_MARKER_START_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_FONT_SIZE_ADJUST_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_FONT_STRETCH_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_FONT_STYLE_ATTRIBUTE,
new SVGFontStyleAttribute());
attributeParserMap.put(IOConstants.SVG_FONT_VARIANT_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_FONT_WEIGHT_ATTRIBUTE,
new SVGFontWeightParser());
attributeParserMap.put(IOConstants.SVG_ALIGNMENT_BASELINE_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_BASELINE_SHIFT_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_DIRECTION_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_DOMINANT_BASELINE_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(
IOConstants.SVG_GLYPH_ORIENTATION_HORIZONTAL_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(
IOConstants.SVG_GLYPH_ORIENTATION_VERTICAL_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_KERNING_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_LETTER_SPACING_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_TEXT_ANCHOR_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_TEXT_DECORATION_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_UNICODE_BIDI_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_WORD_SPACING_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_ROTATE_ATTRIBUTE,
new SVGNullParser());
attributeParserMap.put(IOConstants.SVG_TRANSFORM_ATTRIBUTE,
new SVGTransformParser());
}
/**
* The map to determine if an attribute is an annotation or basic SVG
* attribute.
*/
private final static HashMap<String, Boolean> basicSVGAttribute;
static
{
basicSVGAttribute=new HashMap<String, Boolean>();
basicSVGAttribute.put(IOConstants.DATATYPE_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.SIZE_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.VALUE_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.POINTS_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.CONNECTION_TO_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.CONNECTION_FROM_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.X_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.X1_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.X2_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.Y1_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.Y2_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.CX_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.CY_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.RX_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.RY_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.Z_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.C_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.T_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.WIDTH_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.HEIGHT_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.RED_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.BLUE_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.GREEN_ATTRIBUTE, true);
basicSVGAttribute.put(IOConstants.ALPHA_ATTRIBUTE, true);
}
/**
* Holds the document that is currently being read.
*/
private IXMLElement document;
/**
* Holds the ROIs which have been created.
*/
private List<ROI> roiList;
/**
* The current coord of the shape being created.
*/
private Coord3D currentCoord;
/**
* The current roi of the shape being created.
*/
private long currentROI;
/**
* The ROIComponent
*/
private ROIComponent component;
/**
* Set the current coordinate being parsed to the coord.
* @param coord see above.
*/
private void setCurrentCoord(Coord3D coord)
{
currentCoord=coord;
}
/**
* Get the current plane being parsed in the file.
* @return see above.
*/
private Coord3D getCurrentCoord()
{
return currentCoord;
}
/**
* Set the current ROI id being worked on to id.
* @param ROIid see above.
*/
private void setCurrentROI(long ROIid)
{
currentROI = ROIid;
}
/**
* Get the current id of the ROI being worked on.
* @return see above.
*/
private long getCurrentROI()
{
return currentROI;
}
/**
* Create an ROI from the XML element add to component
* @param roiElement the XML element being parsed to create ROI.
* @param component the ROI component to add the created ROI to.
* @return the new ROI.
* @throws NoSuchROIException thrown if there is a bad ref to another ROI
* in the XML.
* @throws ParsingException thrown if there is badly formed xml
* @throws ROICreationException thrown if the ROI cannot be created.
*/
private ROI createROI(IXMLElement roiElement, ROIComponent component)
throws NoSuchROIException, ParsingException, ROICreationException
{
if (!roiElement.hasAttribute(IOConstants.ROI_ID_ATTRIBUTE)) return null;
long id = Long.valueOf(
roiElement.getAttribute(IOConstants.ROI_ID_ATTRIBUTE, "-1"));
if (currentROI == id) return null;
setCurrentROI(id);
ROI newROI = component.createROI(id);
List<IXMLElement> roiShapeList =
roiElement.getChildrenNamed(IOConstants.ROISHAPE_TAG);
List<IXMLElement> annotationElementList =
roiElement.getChildrenNamed(IOConstants.ANNOTATION_TAG);
List<IXMLElement> annotationList;
for (IXMLElement annotationTagElement : annotationElementList)
{
annotationList = annotationTagElement.getChildren();
for (IXMLElement annotation : annotationList)
addAnnotation(annotation, newROI);
}
ROIShape shape, returnedShape;
for (IXMLElement roiShape : roiShapeList)
{
shape = createROIShape(roiShape, newROI);
shape.getFigure().setMeasurementUnits(
component.getMeasurementUnits());
component.addShape(newROI.getID(), shape.getCoord3D(), shape);
try
{
returnedShape =
component.getShape(newROI.getID(), shape.getCoord3D());
}
catch (NoSuchROIException e)
{
throw new NoSuchROIException("No shape: ", e);
}
}
return newROI;
}
/**
* Create an ROIShape from the XML element add to ROI
* @param shapeElement the XML element being parsed to create ROIShape.
* @param newROI the ROI to add the created ROIShape to.
* @return the new ROI.
* @throws ParsingException thrown if there is badly formed xml
*/
private ROIShape createROIShape(IXMLElement shapeElement, ROI newROI)
throws ParsingException
{
int t = Integer.valueOf(
shapeElement.getAttribute(IOConstants.T_ATTRIBUTE, "0"));
int z = Integer.valueOf(
shapeElement.getAttribute(IOConstants.Z_ATTRIBUTE, "0"));
Coord3D coord = new Coord3D(z, t);
setCurrentCoord(coord);
IXMLElement figureElement =
shapeElement.getFirstChildNamed(IOConstants.SVG_TAG);
ROIFigure fig = createFigure(figureElement);
ROIShape shape = new ROIShape(newROI, coord, fig, fig.getBounds());
List<IXMLElement> annotationElementList =
shapeElement.getChildrenNamed(IOConstants.ANNOTATION_TAG);
List<IXMLElement> annotationList;
for (IXMLElement annotationTagElement : annotationElementList)
{
annotationList=annotationTagElement.getChildren();
for (IXMLElement annotation : annotationList)
addAnnotation(annotation, shape);
}
return shape;
}
/**
* Add the annotation to the shape from the XML element.
* @param annotationElement the element.
* @param shape the ROI shape.
*/
private void addAnnotation(IXMLElement annotationElement, ROIShape shape)
{
if (annotationElement == null || shape == null) return;
String key = annotationElement.getName();
AnnotationKey v = new AnnotationKey(key);
shape.setAnnotation(v, createAnnotationData(annotationElement));
}
/**
* Parse the dataType attribute in the annotationElement and create an
* object of that type, populate it with values from the data in the
* annotation element.
* @param annotationElement see above.
* @return see above.
*/
Object createAnnotationData(IXMLElement annotationElement)
{
String dataType =
annotationElement.getAttribute(IOConstants.DATATYPE_ATTRIBUTE,
IOConstants.VALUE_NULL);
if (IOConstants.ATTRIBUTE_DATATYPE_STRING.equals(dataType))
{
return annotationElement.getAttribute(IOConstants.VALUE_ATTRIBUTE,
IOConstants.VALUE_NULL);
}
else if (IOConstants.ATTRIBUTE_DATATYPE_INTEGER.equals(dataType))
{
String value =
annotationElement.getAttribute(IOConstants.VALUE_ATTRIBUTE,
IOConstants.VALUE_NULL);
if (IOConstants.VALUE_NULL.equals(value)) return 0;
return Integer.valueOf(value);
}
else if (IOConstants.ATTRIBUTE_DATATYPE_BOOLEAN.equals(dataType))
{
String value =
annotationElement.getAttribute(IOConstants.VALUE_ATTRIBUTE,
IOConstants.VALUE_NULL);
if (IOConstants.VALUE_NULL.equals(value)) return 0;
return Boolean.valueOf(value);
}
else if (IOConstants.ATTRIBUTE_DATATYPE_LONG.equals(dataType))
{
String value =
annotationElement.getAttribute(IOConstants.VALUE_ATTRIBUTE,
IOConstants.VALUE_NULL);
if (IOConstants.VALUE_NULL.equals(value)) return 0;
return Long.valueOf(value);
}
else if (IOConstants.ATTRIBUTE_DATATYPE_FLOAT.equals(dataType))
{
String value =
annotationElement.getAttribute(IOConstants.VALUE_ATTRIBUTE,
IOConstants.VALUE_NULL);
if (IOConstants.VALUE_NULL.equals(value)) return 0;
return Float.valueOf(value);
}
else if (IOConstants.ATTRIBUTE_DATATYPE_DOUBLE.equals(dataType))
{
String value =
annotationElement.getAttribute(IOConstants.VALUE_ATTRIBUTE,
IOConstants.VALUE_NULL);
if (IOConstants.VALUE_NULL.equals(value)) return 0;
return Double.valueOf(value);
}
else if (IOConstants.ATTRIBUTE_DATATYPE_POINT2D.equals(dataType))
{
String xValue =
annotationElement.getAttribute(IOConstants.X_ATTRIBUTE,
IOConstants.VALUE_NULL);
String yValue =
annotationElement.getAttribute(IOConstants.Y_ATTRIBUTE,
IOConstants.VALUE_NULL);
if (IOConstants.VALUE_NULL.equals(xValue)
|| IOConstants.VALUE_NULL.equals(yValue))
return new Point2D.Double(0, 0);
return new Point2D.Double(Double.valueOf(xValue),
Double.valueOf(yValue));
}
else if (IOConstants.ATTRIBUTE_DATATYPE_RECTANGLE2D.equals(dataType)
|| IOConstants.ATTRIBUTE_DATATYPE_ELLIPSE2D.equals(dataType))
{
String xValue =
annotationElement.getAttribute(IOConstants.X_ATTRIBUTE,
IOConstants.VALUE_NULL);
String yValue =
annotationElement.getAttribute(IOConstants.Y_ATTRIBUTE,
IOConstants.VALUE_NULL);
String widthValue =
annotationElement.getAttribute(IOConstants.WIDTH_ATTRIBUTE,
IOConstants.VALUE_NULL);
String heightValue =
annotationElement.getAttribute(
IOConstants.HEIGHT_ATTRIBUTE, IOConstants.VALUE_NULL);
if (IOConstants.VALUE_NULL.equals(yValue)
|| IOConstants.VALUE_NULL.equals(xValue)
||IOConstants.VALUE_NULL.equals(widthValue)
||IOConstants.VALUE_NULL.equals(heightValue))
{
if (IOConstants.ATTRIBUTE_DATATYPE_RECTANGLE2D.equals(dataType))
return new Rectangle2D.Double();
return new Ellipse2D.Double();
}
if (IOConstants.ATTRIBUTE_DATATYPE_RECTANGLE2D.equals(dataType))
new Rectangle2D.Double(
new Double(xValue), new Double(yValue), new Double(widthValue),
new Double(heightValue));
if (IOConstants.ATTRIBUTE_DATATYPE_ELLIPSE2D.equals(dataType))
return new Ellipse2D.Double(
Double.valueOf(xValue), Double.valueOf(yValue),
Double.valueOf(widthValue), Double.valueOf(heightValue));
}
else if (IOConstants.ATTRIBUTE_DATATYPE_COORD3D.equals(dataType))
{
String zValue =
annotationElement.getAttribute(IOConstants.Z_ATTRIBUTE,
IOConstants.VALUE_NULL);
String tValue =
annotationElement.getAttribute(IOConstants.T_ATTRIBUTE,
IOConstants.VALUE_NULL);
if (IOConstants.VALUE_NULL.equals(zValue)
||IOConstants.VALUE_NULL.equals(tValue))
return new Coord3D(0, 0);
return new Coord3D(Integer.valueOf(zValue), Integer.valueOf(tValue));
}
else if (IOConstants.ATTRIBUTE_DATATYPE_ARRAYLIST.equals(dataType))
{
List list = new ArrayList();
List<IXMLElement> arrayListElement =
annotationElement.getChildren();
for (IXMLElement dataElement : arrayListElement)
list.add(createAnnotationData(dataElement));
return list;
}
return null;
}
/**
* Parse the annotationElement, create an attrbute key and add it to the roi.
* @param annotationElement
* @param roi see above.
*/
private void addAnnotation(IXMLElement annotationElement, ROI roi)
{
String key=annotationElement.getName();
AnnotationKey annotation = new AnnotationKey(key);
roi.setAnnotation(annotation, createAnnotationData(annotationElement));
}
/**
* Create an roiFigure of the correct type from the svgElement and
* add any attributes as required.
* @param svgElement see above.
* @return the new ROIFigure.
* @throws ParsingException thrown if the svg is badly formed.
*/
private ROIFigure createFigure(IXMLElement svgElement)
throws ParsingException
{
IXMLElement parentElement=svgElement.getChildAtIndex(0);
IXMLElement textElement;
ROIFigure figure=createParentFigure(parentElement);
// Check that the parent element is not a text element, as they have not
// got any other text associated with them.
if (!parentElement.getName().equals(IOConstants.TEXT_TAG))
{
textElement=svgElement.getChildAtIndex(1);
addTextElementToFigure(figure, textElement);
}
addMissingAttributes(figure);
return figure;
}
/**
* Create the Parent figure, as the parser will allow multiple Figure
* elements to be aggregated together.
* @param figureElement see above.
* @return the ROIFogure.
* @throws ParsingException thrown if bad svg.
*/
private ROIFigure createParentFigure(IXMLElement figureElement)
throws ParsingException
{
ROIFigure figure=null;
if (figureElement.getName().equals(IOConstants.RECT_TAG)) figure=
createRectangleFigure(figureElement);
if (figureElement.getName().equals(IOConstants.LINE_TAG)) figure=
createLineFigure(figureElement);
if (figureElement.getName().equals(IOConstants.ELLIPSE_TAG)) figure=
createEllipseFigure(figureElement);
if (figureElement.getName().equals(IOConstants.POINT_TAG)) figure=
createPointFigure(figureElement);
if (figureElement.getName().equals(IOConstants.TEXT_TAG)) figure=
createTextFigure(figureElement);
if (figureElement.getName().equals(IOConstants.POLYLINE_TAG)) figure=
createBezierFigure(figureElement, false);
if (figureElement.getName().equals(IOConstants.POLYGON_TAG)) figure=
createBezierFigure(figureElement, true);
return figure;
}
/**
* Created from the create Parent figure method, this will create a
* bezier figure.
* @param bezierElement the bezier element.
* @param closed should this be a piolygon.
* @return the figure.
* @throws ParsingException thrown if the svg is badly formed.
*/
public MeasureBezierFigure createBezierFigure(IXMLElement bezierElement,
boolean closed) throws ParsingException
{
MeasureBezierFigure fig=new MeasureBezierFigure(closed);
Point2D.Double[] points=null;
Point2D.Double[] points1=null;
Point2D.Double[] points2=null;
Integer []mask=null;
if (bezierElement.hasAttribute(IOConstants.POINTS_ATTRIBUTE))
{
String pointsValues=
bezierElement.getAttribute(IOConstants.POINTS_ATTRIBUTE,
IOConstants.VALUE_NULL);
points=toPoints(pointsValues);
}
if (bezierElement.hasAttribute(IOConstants.POINTS_CONTROL1_ATTRIBUTE))
{
String pointsValues=
bezierElement.getAttribute(IOConstants.POINTS_CONTROL1_ATTRIBUTE,
IOConstants.VALUE_NULL);
points1=toPoints(pointsValues);
}
if (bezierElement.hasAttribute(IOConstants.POINTS_CONTROL2_ATTRIBUTE))
{
String pointsValues=
bezierElement.getAttribute(IOConstants.POINTS_CONTROL2_ATTRIBUTE,
IOConstants.VALUE_NULL);
points2=toPoints(pointsValues);
}
if (bezierElement.hasAttribute(IOConstants.POINTS_MASK_ATTRIBUTE))
{
String pointsValues=
bezierElement.getAttribute(IOConstants.POINTS_MASK_ATTRIBUTE,
IOConstants.VALUE_NULL);
mask=toIntArray(pointsValues);
}
if(points==null || points1==null || points2==null || mask == null
|| (points.length!=points1.length) || (points.length!=points2.length)
|| (points.length!=mask.length))
{
throw new ParsingException("Error parsing points attributes in ROI : " +
currentROI + " ROIShape Coord t : " +
currentCoord.getTimePoint() + " z : " +
currentCoord.getZSection());
}
for (int i=0; i<points.length; i++)
{
Node newNode = new Node(mask[i], points[i], points1[i], points2[i]);
fig.addNode(newNode);
}
addAttributes(fig, bezierElement);
return fig;
}
/**
* Created from the create Parent figure method, this will create a
* text figure.
* @param textElement the text element.
* @return the figure.
*/
private MeasureTextFigure createTextFigure(IXMLElement textElement)
{
String xValue=
textElement.getAttribute(IOConstants.X_ATTRIBUTE,
IOConstants.VALUE_NULL);
String yValue=
textElement.getAttribute(IOConstants.Y_ATTRIBUTE,
IOConstants.VALUE_NULL);
MeasureTextFigure textFigure=
new MeasureTextFigure(new Double(xValue), new Double(yValue));
addAttributes(textFigure, textElement);
return textFigure;
}
/**
* Created from the create Parent figure method, this will create an
* Ellipse figure.
* @param ellipseElement the text element.
* @return the figure.
*/
private MeasureEllipseFigure createEllipseFigure(
IXMLElement ellipseElement)
{
String cxValue=
ellipseElement.getAttribute(IOConstants.CX_ATTRIBUTE,
IOConstants.VALUE_NULL);
String cyValue=
ellipseElement.getAttribute(IOConstants.CY_ATTRIBUTE,
IOConstants.VALUE_NULL);
String rxValue=
ellipseElement.getAttribute(IOConstants.RX_ATTRIBUTE,
IOConstants.VALUE_NULL);
String ryValue=
ellipseElement.getAttribute(IOConstants.RY_ATTRIBUTE,
IOConstants.VALUE_NULL);
double cx=new Double(cxValue);
double cy=new Double(cyValue);
double rx=new Double(rxValue);
double ry=new Double(ryValue);
double x=cx-rx;
double y=cy-ry;
double width=rx*2d;
double height=ry*2d;
MeasureEllipseFigure ellipseFigure= new MeasureEllipseFigure();
ellipseFigure.setEllipse(x, y, width, height);
addAttributes(ellipseFigure, ellipseElement);
return ellipseFigure;
}
/**
* Created from the create Parent figure method, this will create an
* Point figure.
* @param pointElement the text element.
* @return the figure.
*/
private MeasurePointFigure createPointFigure(IXMLElement pointElement)
{
String cxValue=
pointElement.getAttribute(IOConstants.CX_ATTRIBUTE,
IOConstants.VALUE_NULL);
String cyValue=
pointElement.getAttribute(IOConstants.CY_ATTRIBUTE,
IOConstants.VALUE_NULL);
String rxValue=
pointElement.getAttribute(IOConstants.RX_ATTRIBUTE,
IOConstants.VALUE_NULL);
String ryValue=
pointElement.getAttribute(IOConstants.RY_ATTRIBUTE,
IOConstants.VALUE_NULL);
double cx=new Double(cxValue);
double cy=new Double(cyValue);
double rx=new Double(rxValue);
double ry=new Double(ryValue);
double x=cx-rx;
double y=cy-ry;
double width=rx*2;
double height=ry*2;
MeasurePointFigure pointFigure=
new MeasurePointFigure(x, y, width, height);
addAttributes(pointFigure, pointElement);
return pointFigure;
}
/**
* Created from the create Parent figure method, this will create an
* Rectangle figure.
* @param rectElement the text element.
* @return the figure.
*/
private MeasureRectangleFigure createRectangleFigure(IXMLElement rectElement)
{
String xValue=
rectElement.getAttribute(IOConstants.X_ATTRIBUTE,
IOConstants.VALUE_NULL);
String yValue=
rectElement.getAttribute(IOConstants.Y_ATTRIBUTE,
IOConstants.VALUE_NULL);
String widthValue=
rectElement.getAttribute(IOConstants.WIDTH_ATTRIBUTE,
IOConstants.VALUE_NULL);
String heightValue=
rectElement.getAttribute(IOConstants.HEIGHT_ATTRIBUTE,
IOConstants.VALUE_NULL);
MeasureRectangleFigure rectFigure=
new MeasureRectangleFigure(new Double(xValue),
new Double(yValue), new Double(widthValue), new Double(
heightValue));
addAttributes(rectFigure, rectElement);
return rectFigure;
}
/**
* Created from the create Parent figure method, this will create an
* Line figure either a line figure or conneciton figure depending on
* the attributes.
* @param lineElement the text element.
* @return the figure.
* @throws ParsingException thrown if the svg is badly formed.
*/
private ROIFigure createLineFigure(IXMLElement lineElement)
throws ParsingException
{
if (lineElement.hasAttribute(IOConstants.CONNECTION_TO_ATTRIBUTE))
return createLineConnectionFigure(lineElement);
else return createBasicLineFigure(lineElement);
}
/**
* Created from the create Parent figure method, this will create
* a line connection figure.
* @param lineElement the text element.
* @return the figure.
* @throws ParsingException thrown if the svg is badly formed.
*/
private MeasureLineConnectionFigure createLineConnectionFigure(
IXMLElement lineElement) throws ParsingException
{
MeasureLineConnectionFigure lineFigure=
new MeasureLineConnectionFigure();
long toROIid =
new Long(lineElement
.getAttribute(IOConstants.CONNECTION_TO_ATTRIBUTE,
IOConstants.VALUE_NULL));
long fromROIid =
new Long(lineElement.getAttribute(
IOConstants.CONNECTION_FROM_ATTRIBUTE,
IOConstants.VALUE_NULL));
ROI toROI, fromROI;
try
{
toROI = component.getROI(toROIid);
fromROI = component.getROI(fromROIid);
ROIFigure toFigure = toROI.getFigure(getCurrentCoord());
ROIFigure fromFigure=fromROI.getFigure(getCurrentCoord());
if (lineElement.hasAttribute(IOConstants.POINTS_ATTRIBUTE))
{
lineFigure.removeAllNodes();
String pointsValues =
lineElement.getAttribute(IOConstants.POINTS_ATTRIBUTE,
IOConstants.VALUE_NULL);
Point2D.Double[] points=toPoints(pointsValues);
for (int i=0; i<points.length; i++)
lineFigure.addNode(new Node(points[i].x, points[i].y));
lineFigure.setStartConnector(toFigure.findCompatibleConnector(
lineFigure.getStartConnector(), true));
lineFigure.setEndConnector(fromFigure.findCompatibleConnector(
lineFigure.getEndConnector(), false));
}
else
{
lineFigure.setStartConnector(toFigure.findCompatibleConnector(
lineFigure.getStartConnector(), true));
lineFigure.setEndConnector(fromFigure.findCompatibleConnector(
lineFigure.getEndConnector(), false));
}
}
catch (Exception e)
{
throw new ParsingException("In Line connection figure, "
+"with ROI :"+getCurrentROI()+" on Coord :"
+getCurrentCoord()+" Connection <to>/<from> tag invalid.");
}
addAttributes(lineFigure, lineElement);
return lineFigure;
}
/**
* Created from the create Parent figure method, this will create
* a line figure.
* @param lineElement the text element.
* @return the figure.
*/
private MeasureLineFigure createBasicLineFigure(IXMLElement lineElement)
{
MeasureLineFigure lineFigure=new MeasureLineFigure();
if (lineElement.hasAttribute(IOConstants.POINTS_ATTRIBUTE))
{
lineFigure.removeAllNodes();
String pointsValues=
lineElement.getAttribute(IOConstants.POINTS_ATTRIBUTE,
IOConstants.VALUE_NULL);
Point2D.Double[] points=toPoints(pointsValues);
for (int i=0; i<points.length; i++)
lineFigure.addNode(new Node(points[i].x, points[i].y));
}
else
{
String x1Value=
lineElement.getAttribute(IOConstants.X1_ATTRIBUTE,
IOConstants.VALUE_NULL);
String y1Value=
lineElement.getAttribute(IOConstants.Y1_ATTRIBUTE,
IOConstants.VALUE_NULL);
String x2Value=
lineElement.getAttribute(IOConstants.X2_ATTRIBUTE,
IOConstants.VALUE_NULL);
String y2Value=
lineElement.getAttribute(IOConstants.Y2_ATTRIBUTE,
IOConstants.VALUE_NULL);
lineFigure.removeAllNodes();
lineFigure.addNode(new Node(new Double(x1Value),
new Double(y1Value)));
lineFigure.addNode(new Node(new Double(x2Value),
new Double(y2Value)));
}
addAttributes(lineFigure, lineElement);
return lineFigure;
}
/**
* Returns a value as a Point2D.Double array.
* as specified in http://www.w3.org/TR/SVGMobile12/shapes.html#PointsBNF
* @param str see above.
* @return See above.
*/
private Point2D.Double[] toPoints(String str)
{
StringTokenizer tt=new StringTokenizer(str, " ,");
Point2D.Double[] points=new Point2D.Double[tt.countTokens()/2];
for (int i=0; i<points.length; i++)
points[i]=
new Point2D.Double(new Double(tt.nextToken()), new Double(
tt.nextToken()));
return points;
}
/**
* Returns a value as a Point2D.Double array.
* as specified in http://www.w3.org/TR/SVGMobile12/shapes.html#PointsBNF
* @param str see above.
* @return See above.
*/
private Integer[] toIntArray(String str)
{
StringTokenizer tt=new StringTokenizer(str, " ,");
Integer[] points=new Integer[tt.countTokens()];
for (int i=0; i<points.length; i++)
points[i]=
new Integer(tt.nextToken());
return points;
}
/**
* Add the attributes to the figure from the xmlElement.
* @param figure see above.
* @param figureElement see above.
*/
private void addAttributes(ROIFigure figure, IXMLElement figureElement)
{
Properties attributes=figureElement.getAttributes();
Iterator attributeKeys=attributes.keySet().iterator();
String attribute;
String value;
while (attributeKeys.hasNext())
{
attribute=(String) attributeKeys.next();
value=figureElement.getAttribute(attribute, IOConstants.VALUE_NULL);
addAttribute(figure, figureElement, attribute, value);
}
}
/**
* Is the string passed a basic SVG Attribute, if so return true.
*
* @param attribute String which may be an attribute.
*
* @return See above.
*/
private boolean isBasicSVGAttribute(String attribute)
{
return basicSVGAttribute.containsKey(attribute);
}
/**
* Is the string passed an SVG Attribute, if so return true.
*
* @param attribute String which may be an attribute.
*
* @return See above.
*/
private boolean isSVGAttribute(String attribute)
{
return attributeParserMap.containsKey(attribute);
}
/**
* Parse the attribute in figureElement annd get the
* @param figure see above.
* @param figureElement see above.
* @param attribute see above.
* @param value see above.
*/
private void parseAttribute(ROIFigure figure, IXMLElement figureElement,
String attribute, String value)
{
SVGAttributeParser parser=attributeParserMap.get(attribute);
parser.parse(figure, figureElement, value);
}
/**
* Add an attribute to the figure from the figureElement.
* @param figure see above.
* @param figureElement see above.
* @param attribute see above.
* @param value see above.
*/
private void addAttribute(ROIFigure figure, IXMLElement figureElement,
String attribute, String value)
{
if (isBasicSVGAttribute(attribute)) return;
if (isSVGAttribute(attribute)) parseAttribute(figure, figureElement,
attribute, value);
}
/**
* Add a text figure to a composite figure. ** NOT USED JUST NOW. **
* @param figure
* @param textElement
*/
private void addTextElementToFigure(ROIFigure figure,
IXMLElement textElement)
{
String text=textElement.getContent();
setText(figure, text);
addAttributes(figure, textElement);
}
/**
* Set the text of the figure from the text.
* @param fig see above.
* @param text see above.
*/
private void setText(ROIFigure fig, String text)
{
MeasurementAttributes.TEXT.set(fig, text);
}
/**
* Add any missing basic attributes from the default attributes map,
* to the figure.
* @param figure see above.
*/
private void addMissingAttributes(ROIFigure figure)
{
Map<AttributeKey, Object> attributes=figure.getAttributes();
Iterator<AttributeKey> iterator=defaultAttributes.keySet().iterator();
AttributeKey key;
while (iterator.hasNext())
{
key=iterator.next();
if (!attributes.containsKey(key)) key.set(figure, defaultAttributes
.get(key));
}
}
/** Create instance. */
InputStrategy()
{
reset();
}
/**
* Read the input stream and creat ROI from it, add to ROIComponent.
* @param in input stream.
* @param component ROIComponent.
* @return see above.
* @throws ParsingException if any malformed xml encountered.
* @throws ROICreationException if roi cannot be created.
* @throws NoSuchROIException if there is an error creating line connection
* figure.
*/
List<ROI> readROI(InputStream in, ROIComponent component)
throws ParsingException, ROICreationException,
NoSuchROIException
{
roiList = new ArrayList<ROI>();
this.component = component;
IXMLParser parser;
try
{
parser=XMLParserFactory.createDefaultXMLParser();
}
catch (Exception ex)
{
InternalError e=
new InternalError("Unable to instantiate NanoXML Parser");
e.initCause(ex);
throw e;
}
try
{
IXMLReader reader = new StdXMLReader(in);
parser.setReader(reader);
document=(IXMLElement) parser.parse();
}
catch (Exception ex)
{
ParsingException e = new ParsingException(ex.getMessage());
e.initCause(ex);
throw e;
}
List<IXMLElement> roiElements =
document.getChildrenNamed(IOConstants.ROI_TAG);
for (IXMLElement roi : roiElements)
roiList.add(createROI(roi, component));
return roiList;
}
/** Indicates to reset the identifier when loading from local file.*/
void reset()
{
currentROI = -1;
currentCoord = null;
}
}