/*
* Copyright 2006-2017 ICEsoft Technologies Canada Corp.
*
* 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.icepdf.core.pobjects.annotations;
import org.icepdf.core.pobjects.*;
import org.icepdf.core.pobjects.graphics.Shapes;
import org.icepdf.core.pobjects.graphics.commands.*;
import org.icepdf.core.util.Library;
import java.awt.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Logger;
/**
* The purpose of a line annotation (PDF 1.3) is to display a single straight
* line on the page. When opened, it shall display a pop-up window containing
* the text of the associated note. Table 175 shows the annotation dictionary
* entries specific to this type of annotation.
*
* @since 5.0
*/
public class LineAnnotation extends MarkupAnnotation {
private static final Logger logger =
Logger.getLogger(LineAnnotation.class.toString());
/**
* (Required) An array of four numbers, [x1 y1 x2 y2], specifying the starting
* and ending coordinates of the line in default user space.
* <br>
* If the LL entry is present, this value shall represent the endpoints of
* the leader lines rather than the endpoints of the line itself; see Figure 60.
*/
public static final Name L_KEY = new Name("L");
/**
* (Optional; PDF 1.4) An array of two names specifying the line ending styles
* that shall be used in drawing the line. The first and second elements of
* the array shall specify the line ending styles for the endpoints defined,
* respectively, by the first and second pairs of coordinates, (x1, y1) and
* (x2, y2), in the L array. Table 176 shows the possible values.
* <br>
* Default value: [/None /None].
*/
public static final Name LE_KEY = new Name("LE");
/**
* (Required if LLE is present, otherwise optional; PDF 1.6) The length of
* leader lines in default user space that extend from each endpoint of the
* line perpendicular to the line itself, as shown in Figure 60. A positive
* value shall mean that the leader lines appear in the direction that is
* clockwise when traversing the line from its starting point to its ending
* point (as specified by L); a negative value shall indicate the opposite
* direction.
* <br>
* Default value: 0 (no leader lines).
*/
public static final Name LL_KEY = new Name("LL");
/**
* (Optional; PDF 1.6) A non-negative number that shall represents the
* length of leader line extensions that extend from the line proper 180
* degrees from the leader lines, as shown in Figure 60.
* <br>
* Default value: 0 (no leader line extensions).
*/
public static final Name LLE_KEY = new Name("LLE");
/**
* (Optional; PDF 1.4) An array of numbers in the range 0.0 to 1.0 specifying
* the interior color that shall be used to fill the annotation’s line endings
* (see Table 176). The number of array elements shall determine the colour
* space in which the colour is defined:
* 0 - No colour; transparent
* 1 - DeviceGray
* 3 - DeviceRGB
* 4 - DeviceCMYK
*/
public static final Name IC_KEY = new Name("IC");
/**
* (Optional; PDF 1.6) If true, the text specified by the Contents or RC
* entries shall be replicated as a caption in the appearance of the line,
* as shown in Figure 61 and Figure 62. The text shall be rendered in a
* manner appropriate to the content, taking into account factors such as
* writing direction.
* <br>
* Default value: false.
*/
public static final Name CAP_KEY = new Name("Cap");
/**
* (Optional; PDF 1.7) A non-negative number that shall represent the length
* of the leader line offset, which is the amount of empty space between the
* endpoints of the annotation and the beginning of the leader lines.
*/
public static final Name LLO_KEY = new Name("LLO");
/**
* (Optional; PDF 1.6) A name describing the intent of the line annotation
* (see also Table 170). Valid values shall be LineArrow, which means that
* the annotation is intended to function as an arrow, and LineDimension,
* which means that the annotation is intended to function as a dimension line.
*/
// public static final Name IT_KEY = new Name("IT");
/**
* (Optional; meaningful only if Cap is true; PDF 1.7) A name describing the
* annotation’s caption positioning. Valid values are Inline, meaning the
* caption shall be centered inside the line, and Top, meaning the caption
* shall be on top of the line.
* <br>
* Default value: Inline
*/
public static final Name CP_KEY = new Name("CP");
/**
* (Optional; PDF 1.7) A measure dictionary (see Table 261) that shall
* specify the scale and units that apply to the line annotation.
*/
public static final Name MEASURE_KEY = new Name("Measure");
/**
* (Optional; meaningful only if Cap is true; PDF 1.7) An array of two numbers
* that shall specify the offset of the caption text from its normal position.
* The first value shall be the horizontal offset along the annotation line
* from its midpoint, with a positive value indicating offset to the right
* and a negative value indicating offset to the left. The second value shall
* be the vertical offset perpendicular to the annotation line, with a
* positive value indicating a shift up and a negative value indicating a
* shift down.
* <br>
* Default value: [0, 0] (no offset from normal positioning)
*/
public static final Name CO_KEY = new Name("CO");
/**
* A square filled with the annotation’s interior color, if any
*/
public static final Name LINE_END_NONE = new Name("None");
/**
* A circle filled with the annotation’s interior color, if any
*/
public static final Name LINE_END_SQUARE = new Name("Square");
/**
* A diamond shape filled with the annotation’s interior color, if any
*/
public static final Name LINE_END_CIRCLE = new Name("Circle");
/**
* Two short lines meeting in an acute angle to form an open arrowhead
*/
public static final Name LINE_END_DIAMOND = new Name("Diamond");
/**
* Two short lines meeting in an acute angle as in the OpenArrow style and
* connected by a third line to form a triangular closed arrowhead filled
* with the annotation’s interior color, if any
*/
public static final Name LINE_END_OPEN_ARROW = new Name("OpenArrow");
/**
* No line ending
*/
public static final Name LINE_END_CLOSED_ARROW = new Name("ClosedArrow");
protected Point2D startOfLine;
protected Point2D endOfLine;
protected Color interiorColor;
// default line caps.
protected Name startArrow = LINE_END_NONE;
protected Name endArrow = LINE_END_NONE;
public LineAnnotation(Library l, HashMap h) {
super(l, h);
}
/**
* Gets an instance of a LineAnnotation that has valid Object Reference.
*
* @param library document library
* @param rect bounding rectangle in user space
* @return new LineAnnotation Instance.
*/
public static LineAnnotation getInstance(Library library,
Rectangle rect) {
// state manager
StateManager stateManager = library.getStateManager();
// create a new entries to hold the annotation properties
HashMap<Name, Object> entries = new HashMap<Name, Object>();
// set default link annotation values.
entries.put(Dictionary.TYPE_KEY, Annotation.TYPE_VALUE);
entries.put(Dictionary.SUBTYPE_KEY, Annotation.SUBTYPE_LINE);
// coordinates
if (rect != null) {
entries.put(Annotation.RECTANGLE_KEY,
PRectangle.getPRectangleVector(rect));
} else {
entries.put(Annotation.RECTANGLE_KEY, new Rectangle(10, 10, 50, 100));
}
// create the new instance
LineAnnotation lineAnnotation = null;
try {
lineAnnotation = new LineAnnotation(library, entries);
lineAnnotation.init();
lineAnnotation.setPObjectReference(stateManager.getNewReferencNumber());
lineAnnotation.setNew(true);
} catch (InterruptedException e) {
logger.fine("Line annotation instance creation was interrupted");
}
return lineAnnotation;
}
public static Logger getLogger() {
return logger;
}
public static void drawLineStart(Graphics2D g, Name lineEnding,
Point2D startOfLine, Point2D endOfLine,
Color lineColor, Color interiorColor) {
if (lineEnding.equals(LineAnnotation.LINE_END_OPEN_ARROW)) {
drawOpenArrowStart(g, startOfLine, endOfLine, lineColor, interiorColor);
} else if (lineEnding.equals(LineAnnotation.LINE_END_CLOSED_ARROW)) {
drawClosedArrowStart(g, startOfLine, endOfLine, lineColor, interiorColor);
} else if (lineEnding.equals(LineAnnotation.LINE_END_CIRCLE)) {
drawCircle(g, startOfLine, startOfLine, endOfLine, lineColor, interiorColor);
} else if (lineEnding.equals(LineAnnotation.LINE_END_DIAMOND)) {
drawDiamond(g, startOfLine, startOfLine, endOfLine, lineColor, interiorColor);
} else if (lineEnding.equals(LineAnnotation.LINE_END_SQUARE)) {
drawSquare(g, startOfLine, startOfLine, endOfLine, lineColor, interiorColor);
}
}
public static void drawLineEnd(Graphics2D g, Name lineEnding,
Point2D startOfLine, Point2D endOfLine,
Color lineColor, Color interiorColor) {
if (lineEnding.equals(LineAnnotation.LINE_END_OPEN_ARROW)) {
drawOpenArrowEnd(g, startOfLine, endOfLine, lineColor, interiorColor);
} else if (lineEnding.equals(LineAnnotation.LINE_END_CLOSED_ARROW)) {
drawClosedArrowEnd(g, startOfLine, endOfLine, lineColor, interiorColor);
} else if (lineEnding.equals(LineAnnotation.LINE_END_CIRCLE)) {
drawCircle(g, endOfLine, startOfLine, endOfLine, lineColor, interiorColor);
} else if (lineEnding.equals(LineAnnotation.LINE_END_DIAMOND)) {
drawDiamond(g, endOfLine, startOfLine, endOfLine, lineColor, interiorColor);
} else if (lineEnding.equals(LineAnnotation.LINE_END_SQUARE)) {
drawSquare(g, endOfLine, startOfLine, endOfLine, lineColor, interiorColor);
}
}
public static void circleDrawOps(Shapes shapes,
Point2D point, Point2D start,
Point2D end, Color lineColor,
Color internalColor) {
AffineTransform af = createRotation(point, start, end);
shapes.add(new TransformDrawCmd(af));
shapes.add(new ColorDrawCmd(lineColor));
shapes.add(new ShapeDrawCmd(createCircleEnd()));
shapes.add(new FillDrawCmd());
}
private static Shape createCircleEnd() {
return new Ellipse2D.Double(-4, -4, 8, 8);
}
private static void drawCircle(Graphics2D g, Point2D point,
Point2D startOfLine, Point2D endOfLine,
Color lineColor, Color interiorColor) {
AffineTransform oldAf = g.getTransform();
AffineTransform af = createRotation(point, startOfLine, endOfLine);
AffineTransform gAf = g.getTransform();
gAf.concatenate(af);
g.setTransform(gAf);
g.setColor(lineColor);
g.fill(createCircleEnd());
g.setTransform(oldAf);
}
public static void diamondDrawOps(Shapes shapes,
Point2D point, Point2D start,
Point2D end, Color lineColor,
Color internalColor) {
AffineTransform tx = new AffineTransform();
Line2D.Double line = new Line2D.Double(start, end);
tx.setToIdentity();
double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1);
tx.translate(point.getX(), point.getY());
tx.rotate(angle - (Math.PI / 4));
AffineTransform af = createRotation(point, start, end);
shapes.add(new TransformDrawCmd(af));
shapes.add(new ColorDrawCmd(lineColor));
shapes.add(new ShapeDrawCmd(createSquareEnd()));
shapes.add(new FillDrawCmd());
}
private static void drawDiamond(Graphics2D g, Point2D point,
Point2D startOfLine, Point2D endOfLine,
Color lineColor, Color interiorColor) {
AffineTransform oldAf = g.getTransform();
AffineTransform tx = new AffineTransform();
Line2D.Double line = new Line2D.Double(startOfLine, endOfLine);
tx.setToIdentity();
double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1);
tx.translate(point.getX(), point.getY());
// quarter rotation
tx.rotate(angle - (Math.PI / 4));
AffineTransform gAf = g.getTransform();
gAf.concatenate(tx);
g.setTransform(gAf);
g.setColor(lineColor);
g.fill(createSquareEnd());
g.setTransform(oldAf);
}
public static void squareDrawOps(Shapes shapes,
Point2D point, Point2D start,
Point2D end, Color lineColor,
Color internalColor) {
AffineTransform af = createRotation(point, start, end);
shapes.add(new TransformDrawCmd(af));
shapes.add(new ColorDrawCmd(lineColor));
shapes.add(new ShapeDrawCmd(createSquareEnd()));
shapes.add(new FillDrawCmd());
}
private static Shape createSquareEnd() {
return new Rectangle2D.Double(-4, -4, 8, 8);
}
private static void drawSquare(Graphics2D g, Point2D point,
Point2D startOfLine, Point2D endOfLine,
Color lineColor, Color interiorColor) {
AffineTransform oldAf = g.getTransform();
AffineTransform af = createRotation(point, startOfLine, endOfLine);
AffineTransform gAf = g.getTransform();
gAf.concatenate(af);
g.setTransform(gAf);
g.setColor(lineColor);
g.fill(createSquareEnd());
g.setTransform(oldAf);
}
public static void openArrowEndDrawOps(Shapes shapes,
Point2D start, Point2D end,
Color lineColor, Color internalColor) {
AffineTransform af = createRotation(end, start, end);
shapes.add(new TransformDrawCmd(af));
shapes.add(new ColorDrawCmd(lineColor));
shapes.add(new ShapeDrawCmd(createOpenArrowEnd()));
shapes.add(new DrawDrawCmd());
}
private static Shape createOpenArrowEnd() {
GeneralPath arrowHead = new GeneralPath();
arrowHead.moveTo(0, 0);
arrowHead.lineTo(5, -10);
arrowHead.moveTo(0, 0);
arrowHead.lineTo(-5, -10);
arrowHead.closePath();
return arrowHead;
}
private static void drawOpenArrowEnd(Graphics2D g,
Point2D startOfLine, Point2D endOfLine,
Color lineColor, Color interiorColor) {
Shape arrowHead = createOpenArrowEnd();
AffineTransform oldAf = g.getTransform();
AffineTransform af = createRotation(endOfLine, startOfLine, endOfLine);
AffineTransform gAf = g.getTransform();
gAf.concatenate(af);
g.setTransform(gAf);
g.setColor(lineColor);
g.draw(arrowHead);
g.setTransform(oldAf);
}
public static void openArrowStartDrawOps(Shapes shapes,
Point2D start, Point2D end,
Color lineColor, Color internalColor) {
AffineTransform af = createRotation(start, start, end);
shapes.add(new TransformDrawCmd(af));
shapes.add(new ColorDrawCmd(lineColor));
shapes.add(new ShapeDrawCmd(createOpenArrowStart()));
shapes.add(new DrawDrawCmd());
}
private static Shape createOpenArrowStart() {
GeneralPath arrowHead = new GeneralPath();
arrowHead.moveTo(0, 0);
arrowHead.lineTo(5, 10);
arrowHead.moveTo(0, 0);
arrowHead.lineTo(-5, 10);
arrowHead.closePath();
return arrowHead;
}
private static void drawOpenArrowStart(Graphics2D g,
Point2D startOfLine, Point2D endOfLine,
Color lineColor, Color interiorColor) {
Shape arrowHead = createOpenArrowStart();
AffineTransform oldAf = g.getTransform();
AffineTransform af = createRotation(startOfLine, startOfLine, endOfLine);
AffineTransform gAf = g.getTransform();
gAf.concatenate(af);
g.setTransform(gAf);
g.setColor(lineColor);
g.draw(arrowHead);
g.setTransform(oldAf);
}
public static void closedArrowStartDrawOps(Shapes shapes,
Point2D start, Point2D end,
Color lineColor, Color internalColor) {
AffineTransform af = createRotation(start, start, end);
shapes.add(new TransformDrawCmd(af));
if (internalColor != null) {
shapes.add(new ColorDrawCmd(internalColor));
shapes.add(new ShapeDrawCmd(createClosedArrowStart()));
shapes.add(new FillDrawCmd());
}
shapes.add(new ColorDrawCmd(lineColor));
shapes.add(new ShapeDrawCmd(createClosedArrowStart()));
shapes.add(new DrawDrawCmd());
}
private static Shape createClosedArrowStart() {
Polygon arrowHead = new Polygon();
arrowHead.addPoint(0, -5);
arrowHead.addPoint(-5, 5);
arrowHead.addPoint(5, 5);
return arrowHead;
}
private static void drawClosedArrowStart(Graphics2D g,
Point2D startOfLine, Point2D endOfLine,
Color lineColor, Color interiorColor) {
Shape arrowHead = createClosedArrowStart();
AffineTransform oldAf = g.getTransform();
AffineTransform af = createRotation(startOfLine, startOfLine, endOfLine);
AffineTransform gAf = g.getTransform();
gAf.concatenate(af);
g.setTransform(gAf);
if (interiorColor != null) {
g.setColor(interiorColor);
g.fill(arrowHead);
}
g.setColor(lineColor);
g.draw(arrowHead);
g.setTransform(oldAf);
}
public static void closedArrowEndDrawOps(Shapes shapes,
Point2D start, Point2D end,
Color lineColor, Color internalColor) {
AffineTransform af = createRotation(end, start, end);
shapes.add(new TransformDrawCmd(af));
if (internalColor != null) {
shapes.add(new ColorDrawCmd(internalColor));
shapes.add(new ShapeDrawCmd(createClosedArrowEnd()));
shapes.add(new FillDrawCmd());
}
shapes.add(new ColorDrawCmd(lineColor));
shapes.add(new ShapeDrawCmd(createClosedArrowEnd()));
shapes.add(new DrawDrawCmd());
}
private static Shape createClosedArrowEnd() {
Polygon arrowHead = new Polygon();
arrowHead.addPoint(0, 5);
arrowHead.addPoint(-5, -5);
arrowHead.addPoint(5, -5);
return arrowHead;
}
private static void drawClosedArrowEnd(Graphics2D g,
Point2D startOfLine, Point2D endOfLine,
Color lineColor, Color interiorColor) {
Shape arrowHead = createClosedArrowEnd();
AffineTransform oldAf = g.getTransform();
AffineTransform af = createRotation(endOfLine, startOfLine, endOfLine);
AffineTransform gAf = g.getTransform();
gAf.concatenate(af);
g.setTransform(gAf);
if (interiorColor != null) {
g.setColor(interiorColor);
g.fill(arrowHead);
}
g.setColor(lineColor);
g.draw(arrowHead);
g.setTransform(oldAf);
}
private static AffineTransform createRotation(Point2D point,
Point2D startOfLine,
Point2D endOfLine) {
AffineTransform tx = new AffineTransform();
Line2D.Double line = new Line2D.Double(startOfLine, endOfLine);
tx.setToIdentity();
double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1);
tx.translate(point.getX(), point.getY());
tx.rotate(angle - (Math.PI / 2));
return tx;
}
@SuppressWarnings("unchecked")
public void init() throws InterruptedException {
super.init();
// line points
List<Number> value = library.getArray(entries, L_KEY);
if (value != null) {
startOfLine = new Point2D.Float(value.get(0).floatValue(), value.get(1).floatValue());
endOfLine = new Point2D.Float(value.get(2).floatValue(), value.get(3).floatValue());
}
// line ends.
List value2 = library.getArray(entries, LE_KEY);
if (value2 != null) {
startArrow = (Name) value2.get(0);
endArrow = (Name) value2.get(1);
}
// parse out interior colour, specific to link annotations.
interiorColor = null; // we default to black but probably should be null
List C = (List) getObject(IC_KEY);
// parse thought rgb colour.
if (C != null && C.size() >= 3) {
float red = ((Number) C.get(0)).floatValue();
float green = ((Number) C.get(1)).floatValue();
float blue = ((Number) C.get(2)).floatValue();
red = Math.max(0.0f, Math.min(1.0f, red));
green = Math.max(0.0f, Math.min(1.0f, green));
blue = Math.max(0.0f, Math.min(1.0f, blue));
interiorColor = new Color(red, green, blue);
}
// check if there is an AP entry, if no generate the shapes data
// from the other properties.
if (!hasAppearanceStream() && startOfLine != null && endOfLine != null) {
Object tmp = getObject(RECTANGLE_KEY);
Rectangle2D.Float rectangle = null;
if (tmp instanceof List) {
rectangle = library.getRectangle(entries, RECTANGLE_KEY);
}
if (rectangle != null) {
setBBox(rectangle.getBounds());
}
resetAppearanceStream(new AffineTransform());
}
// try and generate an appearance stream.
resetNullAppearanceStream();
}
/**
* Resets the annotations appearance stream.
*/
public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) {
// nothing to reset, creating new annotation.
if (startOfLine == null || endOfLine == null) {
return;
}
Appearance appearance = appearances.get(currentAppearance);
AppearanceState appearanceState = appearance.getSelectedAppearanceState();
AffineTransform matrix = appearanceState.getMatrix();
// reset transform and shapes.
appearanceState.setMatrix(new AffineTransform());
appearanceState.setShapes(new Shapes());
// adjust the line's start and end points for any potential move
AffineTransform af = new AffineTransform();
af.setToTranslation(dx * pageTransform.getScaleX(), -dy * pageTransform.getScaleY());
af.transform(startOfLine, startOfLine);
af.transform(endOfLine, endOfLine);
setStartOfLine(startOfLine);
setEndOfLine(endOfLine);
Rectangle2D bbox = appearanceState.getBbox();
bbox.setRect(userSpaceRectangle.x, userSpaceRectangle.y, userSpaceRectangle.width, userSpaceRectangle.height);
setUserSpaceRectangle(userSpaceRectangle);
setModifiedDate(PDate.formatDateTime(new Date()));
// draw the basic line.
Stroke stroke = getBorderStyleStroke();
GeneralPath line = new GeneralPath();
line.moveTo((float) startOfLine.getX(), (float) startOfLine.getY());
line.lineTo((float) endOfLine.getX(), (float) endOfLine.getY());
line.closePath();
Shapes shapes = appearanceState.getShapes();
// shapes.add(new GraphicsStateCmd(EXT_GSTATE_NAME));
shapes.add(new AlphaDrawCmd(
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity)));
shapes.add(new ShapeDrawCmd(line));
shapes.add(new StrokeDrawCmd(stroke));
shapes.add(new ColorDrawCmd(color));
shapes.add(new DrawDrawCmd());
// check for a ending end cap.
if (startArrow.equals(LineAnnotation.LINE_END_OPEN_ARROW)) {
openArrowStartDrawOps(
shapes, startOfLine, endOfLine, color, interiorColor);
} else if (startArrow.equals(LineAnnotation.LINE_END_CLOSED_ARROW)) {
closedArrowStartDrawOps(
shapes, startOfLine, endOfLine, color, interiorColor);
} else if (startArrow.equals(LineAnnotation.LINE_END_CIRCLE)) {
circleDrawOps(
shapes, startOfLine, startOfLine, endOfLine, color, interiorColor);
} else if (startArrow.equals(LineAnnotation.LINE_END_DIAMOND)) {
diamondDrawOps(
shapes, startOfLine, startOfLine, endOfLine, color, interiorColor);
} else if (startArrow.equals(LineAnnotation.LINE_END_SQUARE)) {
squareDrawOps(
shapes, startOfLine, startOfLine, endOfLine, color, interiorColor);
}
// check for a starting end cap.
if (endArrow.equals(LineAnnotation.LINE_END_OPEN_ARROW)) {
openArrowEndDrawOps(
shapes, startOfLine, endOfLine, color, interiorColor);
} else if (endArrow.equals(LineAnnotation.LINE_END_CLOSED_ARROW)) {
closedArrowEndDrawOps(
shapes, startOfLine, endOfLine, color, interiorColor);
} else if (endArrow.equals(LineAnnotation.LINE_END_CIRCLE)) {
circleDrawOps(
shapes, endOfLine, startOfLine, endOfLine, color, interiorColor);
} else if (endArrow.equals(LineAnnotation.LINE_END_DIAMOND)) {
diamondDrawOps(
shapes, endOfLine, startOfLine, endOfLine, color, interiorColor);
} else if (endArrow.equals(LineAnnotation.LINE_END_SQUARE)) {
squareDrawOps(
shapes, endOfLine, startOfLine, endOfLine, color, interiorColor);
}
shapes.add(new AlphaDrawCmd(
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)));
// remove appearance stream if it exists on an existing edit.
entries.remove(APPEARANCE_STREAM_KEY);
// we don't write out an appearance stream for line annotation, we just regenerate it from properties
// mark the change.
StateManager stateManager = library.getStateManager();
stateManager.addChange(new PObject(this, this.getPObjectReference()));
}
public Point2D getStartOfLine() {
return startOfLine;
}
public void setStartOfLine(Point2D startOfLine) {
this.startOfLine = startOfLine;
}
public Point2D getEndOfLine() {
return endOfLine;
}
public void setEndOfLine(Point2D endOfLine) {
this.endOfLine = endOfLine;
List<Number> pointArray = new ArrayList<Number>(4);
pointArray.add((float) startOfLine.getX());
pointArray.add((float) startOfLine.getY());
pointArray.add((float) endOfLine.getX());
pointArray.add((float) endOfLine.getY());
entries.put(L_KEY, pointArray);
}
public Color getInteriorColor() {
return interiorColor;
}
public void setInteriorColor(Color interiorColor) {
this.interiorColor = interiorColor;
float[] compArray = new float[3];
this.interiorColor.getColorComponents(compArray);
List<Float> colorValues = new ArrayList<Float>(compArray.length);
for (float comp : compArray) {
colorValues.add(comp);
}
entries.put(IC_KEY, colorValues);
}
public Name getStartArrow() {
return startArrow;
}
public void setStartArrow(Name startArrow) {
this.startArrow = startArrow;
List<Name> endNameArray = new ArrayList<Name>(2);
endNameArray.add(startArrow);
endNameArray.add(endArrow);
entries.put(LE_KEY, endNameArray);
}
public Name getEndArrow() {
return endArrow;
}
public void setEndArrow(Name endArrow) {
this.endArrow = endArrow;
List<Name> endNameArray = new ArrayList<Name>(2);
endNameArray.add(startArrow);
endNameArray.add(endArrow);
entries.put(LE_KEY, endNameArray);
}
}