/*
* Copyright 2006-2012 ICEsoft Technologies Inc.
*
* 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.Memento;
import org.icepdf.core.pobjects.Document;
import org.icepdf.core.pobjects.Name;
import org.icepdf.core.pobjects.Page;
import org.icepdf.core.pobjects.PageTree;
import org.icepdf.core.views.AnnotationComponent;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.Vector;
/**
* Stores state paramaters for annotation objects to be used in conjuction
* with a care taker as part of the memento pattern.
*
* @since 4.0
*/
public class AnnotationState implements Memento {
// simple normalized version of properties
protected Integer linkType;
protected String highlightStyle;
protected float lineThickness;
protected String lineStyle;
protected Color color;
// annotation bounding rectangle in user space.
protected Rectangle2D.Float userSpaceRectangle;
// original rectangle reference.
protected AnnotationComponent annotationComponent;
/**
* Stores the annotation state associated with the AnnotationComponents
* annotation object. When a new instance of this object is created
* the annotation's proeprties are saved.
*
* @param annotationComponent annotation component who's state will be stored.
*/
public AnnotationState(AnnotationComponent annotationComponent) {
// reference to component so we can apply the state parameters if
// restore() is called.
this.annotationComponent = annotationComponent;
// test to store previous border color, more properties to follow.
if (this.annotationComponent != null &&
this.annotationComponent.getAnnotation() != null) {
Annotation annotation = this.annotationComponent.getAnnotation();
// link type, visible, invisible
linkType = annotation.getLinkType();
if (annotation instanceof LinkAnnotation) {
highlightStyle = ((LinkAnnotation) annotation).getHighlightMode();
}
lineThickness = annotation.getLineThickness();
lineStyle = annotation.getLineStyle();
Color tmpColor = annotation.getColor();
if (tmpColor != null) {
color = new Color(tmpColor.getRGB());
}
// store user space rectangle SpaceRectangle.
Rectangle2D.Float rect = annotation.getUserSpaceRectangle();
userSpaceRectangle = new Rectangle2D.Float(rect.x, rect.y,
rect.width, rect.height);
}
}
public AnnotationState(Integer linkType, String highlightStyle,
float lineThickness, String lineStyle, Color color) {
this.linkType = linkType;
this.highlightStyle = highlightStyle;
this.lineThickness = lineThickness;
this.lineStyle = lineStyle;
if (color != null){
this.color = new Color(color.getRGB());
}
}
public void apply(AnnotationState applyState) {
// apply the new state vars.
this.linkType = applyState.linkType;
this.highlightStyle = applyState.highlightStyle;
this.lineThickness = applyState.lineThickness;
this.lineStyle = applyState.lineStyle;
if (applyState.color != null){
this.color = new Color(applyState.color.getRGB());
}
// otherwise aassign a default color.
else{
this.color = Color.BLACK;
}
// store user space rectangle SpaceRectangle.
Rectangle2D.Float rect = applyState.userSpaceRectangle;
if (rect != null) {
userSpaceRectangle = new Rectangle2D.Float(rect.x, rect.y,
rect.width, rect.height);
}
// apply the new state to the annotation and schedule a sync
restore();
}
/**
* Restores the AnnotationComponents state to the state stored during the
* construction of this object.
*/
public void restore() {
if (annotationComponent!= null &&
annotationComponent.getAnnotation() != null) {
// get reference to annotation
Annotation annotation = annotationComponent.getAnnotation();
restore(annotation);
// update the document with current state.
synchronizeState();
}
}
/**
* Restores the annotation state in this instance to the Annotation
* specified as a param. This method is ment to bue used in
* {@link #AnnotationState(Integer, String, float, String, java.awt.Color)}
* @param annotation annotation to retore state to.
*/
public void restore(Annotation annotation){
// create a new Border style entry as an inline dictionary
if (annotation.getBorderStyle() == null) {
annotation.setBorderStyle(new BorderStyle());
}
// get the easy stuff out of the way
// apply old border color
if (color != null) {
annotation.setColor(color);
}
// apply old user rectangle
annotation.setUserSpaceRectangle(userSpaceRectangle);
restoreLineThickness(annotation);
restoreHighlightStyle(annotation);
restoreLineStyle(annotation);
// we do this last as it set the line thickness to zero regardless
// of restore values if linkType == Annotation.INVISIBLE_RECTANGLE
applyInvisibleLinkType(annotation);
}
public void synchronizeState() {
// update the document with this change.
int pageIndex = annotationComponent.getPageIndex();
Document document = annotationComponent.getDocument();
Annotation annotation = annotationComponent.getAnnotation();
PageTree pageTree = document.getPageTree();
Page page = pageTree.getPage(pageIndex, this);
// state behind draw state.
if (!annotation.isDeleted()) {
page.updateAnnotation(annotation);
// refresh bounds for any resizes
annotationComponent.refreshDirtyBounds();
}
// special case for an undelete as we need to to make the component
// visible again.
else {
// mark it as not deleted
annotation.setDeleted(false);
// re-add it to the page
page.addAnnotation(annotation);
// finally update the pageComponent so we can see it again.
((Component)annotationComponent).setVisible(true);
// refresh bounds for any resizes
annotationComponent.refreshDirtyBounds();
}
pageTree.releasePage(page, this);
}
private void restoreLineThickness(Annotation annotation) {
// check if we need to set line thickness to default value
if (linkType == Annotation.VISIBLE_RECTANGLE &&
lineThickness == 0) {
lineThickness = 1f;
}
// update the border width line thickness
Object border = annotation.getObject(Annotation.BORDER_KEY);
if (border != null && border instanceof Vector) {
Vector borderProps = (Vector) border;
if (borderProps.size() >= 3) {
borderProps.set(2, lineThickness);
}
}
// check for a border style
if (annotation.getBorderStyle() != null) {
BorderStyle borderStyle = annotation.getBorderStyle();
borderStyle.setStrokeWidth(lineThickness);
}
}
private void restoreHighlightStyle(Annotation annotation) {
if (annotation instanceof LinkAnnotation) {
LinkAnnotation linkAnnotation = (LinkAnnotation) annotation;
Object object = linkAnnotation.getObject(
LinkAnnotation.HIGHLIGHT_MODE_KEY);
// update the entry
if (object != null && object instanceof Name) {
linkAnnotation.getEntries().put(
LinkAnnotation.HIGHLIGHT_MODE_KEY,
new Name(highlightStyle));
} else {
// add the new entry
linkAnnotation.getEntries().put(
LinkAnnotation.HIGHLIGHT_MODE_KEY,
new Name(highlightStyle));
}
}
}
private void restoreLineStyle(Annotation annotation) {
Object border = annotation.getObject(Annotation.BORDER_KEY);
BorderStyle borderStyle = annotation.getBorderStyle();
borderStyle.setBorderStyle(lineStyle);
// remove the dashed border dashed entry if any as we will use
// border style going forward and not the older border entry.
// that said we will keep the border entry first 3 digits .
if (border != null && border instanceof Vector) {
Vector borderProps = (Vector) border;
if (borderProps.size() == 4) {
borderProps.remove(Annotation.BORDER_DASH);
}
}
}
private void applyInvisibleLinkType(Annotation annotation) {
// clear border thickness
if (linkType == Annotation.INVISIBLE_RECTANGLE) {
Object border = annotation.getObject(Annotation.BORDER_KEY);
if (border != null && border instanceof Vector) {
Vector borderProps = (Vector) border;
if (borderProps.size() >= 3) {
borderProps.set(2, 0);
}
}
// check for a border style
if (annotation.getBorderStyle() != null) {
BorderStyle borderStyle = annotation.getBorderStyle();
borderStyle.setStrokeWidth(0);
}
}
}
}