/**
* Item.java
* Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
*
* 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 3 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, see .
*/
package org.expeditee.items;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.expeditee.actions.Actions;
import org.expeditee.actions.IncorrectUseOfStatementException;
import org.expeditee.actions.Javascript;
import org.expeditee.actions.Misc;
import org.expeditee.actions.Simple;
import org.expeditee.core.Anchoring;
import org.expeditee.core.Colour;
import org.expeditee.core.Cursor;
import org.expeditee.core.Dimension;
import org.expeditee.core.Fill;
import org.expeditee.core.Font;
import org.expeditee.core.GradientFill;
import org.expeditee.core.Point;
import org.expeditee.core.Stroke;
import org.expeditee.core.bounds.AxisAlignedBoxBounds;
import org.expeditee.core.bounds.Bounds;
import org.expeditee.core.bounds.EllipticalBounds;
import org.expeditee.core.bounds.PolygonBounds;
import org.expeditee.encryption.core.EncryptedImage;
import org.expeditee.encryption.io.EncryptedExpWriter;
import org.expeditee.encryption.items.KeyType;
import org.expeditee.encryption.items.UserAppliedEncryptionPermission;
import org.expeditee.encryption.items.surrogates.EncryptionDetail;
import org.expeditee.encryption.items.surrogates.EncryptionDetail.Type;
import org.expeditee.encryption.items.surrogates.Label.LabelInfo;
import org.expeditee.encryption.items.surrogates.Label.LabelResult;
import org.expeditee.encryption.items.surrogates.Label;
import org.expeditee.gio.EcosystemManager;
import org.expeditee.gio.GraphicsManager;
import org.expeditee.gio.gesture.StandardGestureActions;
import org.expeditee.gui.AttributeValuePair;
import org.expeditee.gui.DisplayController;
import org.expeditee.gui.Frame;
import org.expeditee.gui.FrameIO;
import org.expeditee.gui.FrameUtils;
import org.expeditee.gui.FreeItems;
import org.expeditee.gui.MessageBay;
import org.expeditee.gui.Overlay;
import org.expeditee.gui.Vector;
import org.expeditee.io.Conversion;
import org.expeditee.io.DefaultFrameWriter;
import org.expeditee.settings.UserSettings;
import org.expeditee.settings.legacy.LegacyFeatures;
import org.expeditee.simple.Context;
import org.expeditee.stats.AgentStats;
import org.expeditee.stats.Formatter;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
/**
* Represents everything that can be drawn on the screen (text, lines, dots,
* images). Each specific type is a subclass of Item.
*
* @author jdm18
*
*/
public abstract class Item implements Comparable, Runnable {
public enum HighlightMode {
None, // The item has no highlighting
Enclosed, // The item is part of the current enclosure
Connected, // The item is connected to the current item
Disconnect, // The item is a free item
Normal // The item is the current item
}
/** Which edge of the window things are anchored to. */
public enum AnchorEdgeType {
None, Left, Right, Top, Bottom
}
public static final float SIZE_NOT_APPLICABLE = Float.NaN;
public static final Float DEFAULT_THICKNESS = 2f;
public static final Float MINIMUM_THICKNESS = 0f;
public static final Float MINIMUM_PAINT_THICKNESS = 1f;
protected static final Stroke.JOIN DEFAULT_JOIN = Stroke.JOIN.ROUND;
protected static final Stroke.CAP DEFAULT_CAP = Stroke.CAP.BUTT;
protected static final Stroke DOT_STROKE = new Stroke(DEFAULT_THICKNESS, DEFAULT_CAP, DEFAULT_JOIN);
protected static final Stroke HIGHLIGHT_STROKE = new Stroke(MINIMUM_THICKNESS, DEFAULT_CAP, DEFAULT_JOIN);
public static final int LEFT_MARGIN = 13;
public static final int NEAR_DISTANCE = 15;
public static final int DEFAULT_HIGHLIGHT_THICKNESS = 2;
/** The default colour to draw highlighting in */
public static final Colour DEFAULT_HIGHLIGHT = Colour.RED;
public static final Colour DEPRESSED_HIGHLIGHT = Colour.GREEN;
public static final Colour ALTERNATE_HIGHLIGHT = Colour.BLUE;
public static final Colour LINK_COLOR = Colour.BLACK;
public static final Colour ACTION_COLOR = Colour.BLACK;
public static final Colour LINK_ACTION_COLOR = Colour.RED;
public static final Colour DEFAULT_FOREGROUND = Colour.BLACK;
public static final Colour DEFAULT_BACKGROUND = Colour.WHITE;
public static final Colour TRANSPARENT = new Colour(0, 0, 0, 0);
/** The number of pixels highlighting should extend around Items. */
public static final int XGRAVITY = 3;
public static final int MARGIN_RIGHT = 2;
public static final int MARGIN_LEFT = 15;
protected static final double DEFAULT_ARROWHEAD_RATIO = 0.3; // used to be 0.5
public static final double DEFAULT_ARROWHEAD_NIB_PERC = 0.75;
public static final Colour GREEN = Colour.GREEN.darker();
//public static final int UNCHANGED_CURSOR = -100;
public static final Cursor.CursorType DEFAULT_CURSOR = Cursor.CursorType.DEFAULT;
public static final Cursor.CursorType HIDDEN_CURSOR = Cursor.CursorType.CUSTOM;
public static final Cursor.CursorType TEXT_CURSOR = Cursor.CursorType.TEXT;
public static final Cursor.CursorType CROP_CURSOR = Cursor.CursorType.CROSSHAIR;
/** The default value for integer attributes */
public static final int DEFAULT_INTEGER = -1;
private static final int BRIGHTNESS = 185;
/** Contains all dots (including this one) that form an enclosure if this dot is part of an enclosing shape. */
private Collection _enclosure = null;
/** The area which this item covers (including its gravity). */
private Bounds _bounds = null;
/** The area this item covered before it was invalidated. */
private Bounds _oldBounds = null;
protected boolean _connectedToAnnotation = false;
protected boolean _save = true;
/** The angle of change for gradient colour fills (in radians). */
private double _gradientAngle = 0.0;
private Tooltip _tooltip = new Tooltip();
protected Anchoring _anchoring = new Anchoring();
/** The highlight mode for this item. */
protected HighlightMode _highlightMode = HighlightMode.None;
private Point _offset = new Point(0, 0);
protected float _x;
protected float _y;
private int _id;
private Item _editTarget = this;
private String _creationDate = null;
/** Whether or not this item should display a mark indicating it has a link. */
private boolean _linkMark = true;
/** Whether or not this item should display a mark indicating it has an action. */
private boolean _actionMark = true;
/** TODO: Appears unused? cts16 */
private boolean _highlight = true;
// private int _maxWidth = -1;
private String _owner = null;
private String _link = null;
private boolean _linkHistory = true;
private StringBuffer _tag = new StringBuffer();
private List _actionCursorEnter = null;
private List _actionCursorLeave = null;
private List _actionEnterFrame = null;
private List _actionLeaveFrame = null;
private PermissionTriple _permissionTriple = null;
private UserAppliedPermission _overlayPermission = null;
/** The primary fill colour of this item. A fill colour of null represents transparent. */
private Colour _fillColour = null;
/** The secondary fill colour if this item has a gradient fill. Null represents no gradient. */
private Colour _gradientColour = null;
/** The primary draw colour of this item. Null represents the default colour. */
private Colour _foregroundColour = null;
/** The colour to draw highlights on this item. */
protected Colour _highlightColour = DEFAULT_HIGHLIGHT;
/** The background colour for this item. */
private Colour _backgroundColour = null;
private Colour _colorBorder = null;
private Colour _colorTopShadow = null;
private Colour _colorBottomShadow = null;
/** The shape representing the circle drawn next to link/action items. */
private static EllipticalBounds _linkCircle = null;
/** The shape representing the cross drawn next to invalid links. */
private static PolygonBounds _linkCircleCross = null;
private Frame _parent = null;
private Frame _oldParent = null;
protected int _highlightThickness = 2;
protected int _vectorHighlightThickness = 1;
// arrowhead parameters
private float _arrowheadLength = 0;
private double _arrowheadRatio = DEFAULT_ARROWHEAD_RATIO;
private double _arrowheadNibPerc = DEFAULT_ARROWHEAD_NIB_PERC;
private PolygonBounds _arrowhead = null;
// the list of lines that this point is part of.
private List _lines = new ArrayList();
private int[] _linePattern = null;
private boolean _floating = false;
// list of points constrained with this point
private List _constraints = new ArrayList();
private List _actions = null;
private String _formula = null;
private String _link_frameset = null;
private String _link_template = null;
private String _fillPattern = null;
private boolean _visible = true;
private float _thickness = -1.0F;
protected Collection _enclosures = new HashSet();
private boolean _deleted = false;
private Overlay _overlay = null;
protected AttributeValuePair _attributeValuePair = null;
private Float _autoStamp = null;
private Item _magnetizedItemLeft = null;
private Item _magnetizedItemRight = null;
private Item _magnetizedItemTop = null;
private Item _magnetizedItemBottom = null;
private String _encryptionLabel = null;
protected DotType _type = DotType.square;
protected boolean _filled = true;
private Data _data = new Data();
// Used via reflection by AttributeUtils to determine if the boolean value is different from default.
public static final boolean acceptsKeyboardEnterDefault = false;
private boolean _acceptsKeyboardEnter = acceptsKeyboardEnterDefault;
private Item surrogateFor = null;
private Set surrogateItems = new HashSet();
private static Map primaryPropertyEncryptionDefault = new HashMap();
private static Map surrogatePropertyInheritanceDefault = new HashMap();
protected Map primaryPropertyEncryption = new HashMap(primaryPropertyEncryptionDefault);
protected Map surrogatePropertyInheritance = new HashMap(surrogatePropertyInheritanceDefault);
private KeyType keyType = KeyType.NotAKey;
{
EncryptionDetail unencryptedOnSave = new EncryptionDetail(EncryptionDetail.Type.UnencryptedOnSave);
for (String tag: DefaultFrameWriter.getItemTags().keySet()) {
if (tag == "T" || tag == "S") {
surrogatePropertyInheritanceDefault.put(tag, false);
} else {
surrogatePropertyInheritanceDefault.put(tag, true);
}
primaryPropertyEncryptionDefault.put(tag, unencryptedOnSave);
}
}
/** Just calls source.duplicateOnto(dest). */
public static void DuplicateItem(Item source, Item dest)
{
if (source == null) return;
source.duplicateOnto(dest);
}
/** Sets the properties of dest so that they match this item's properties. */
public void duplicateOnto(Item dest)
{
if (dest == null) return;
dest.setX(this.getX());
dest.setY(this.getY());
dest.setActions(this.getAction());
dest.setActionCursorEnter(this.getActionCursorEnter());
dest.setActionCursorLeave(this.getActionCursorLeave());
dest.setActionEnterFrame(this.getActionEnterFrame());
dest.setActionLeaveFrame(this.getActionLeaveFrame());
dest.setActionMark(this.getActionMark());
dest.setBackgroundColor(this.getBackgroundColor());
dest.setBottomShadowColor(this.getBottomShadowColor());
dest.setColor(this.getColor());
dest.setBorderColor(this.getBorderColor());
dest.setTooltips(this.getTooltip());
dest.setData(this.getData());
dest.setTag(this.getTag());
dest.setFillColor(this.getFillColor());
dest.setGradientColor(this.getGradientColor());
dest.setGradientAngle(this.getGradientAngle());
dest.setFillPattern(this.getFillPattern());
dest.setHighlight(this.getHighlight());
dest.setLink(this.getLink());
dest.setLinkFrameset(this.getLinkFrameset());
dest.setLinkMark(this.getLinkMark());
dest.setLinkTemplate(this.getLinkTemplate());
// dest.setWidth(this.getWidth());
dest.setOffset(this.getOffset());
// dest.setOwner(this.getOwner());
dest.setThickness(this.getThickness());
dest.setSize(this.getSize());
dest.setTopShadowColor(this.getTopShadowColor());
dest.setLinePattern(this.getLinePattern());
dest.setFloating(this.isFloating());
dest.setArrow(this.getArrowheadLength(), this.getArrowheadRatio(), this.getArrowheadNibPerc());
dest.setDotType(this.getDotType());
dest.setFilled(this.getFilled());
/*
* Calling the methods will move the item... This messes things up when
* the user uses backspace to delete a text line end
*/
// dest._anchorLeft = this._anchorLeft;
// dest._anchorRight = this._anchorRight;
// dest._anchorTop = this._anchorTop;
// dest._anchorBottom = this._anchorBottom;
dest.setFormula(this.getFormula());
dest._overlay = this._overlay;
dest._highlightMode = this._highlightMode;// SelectedMode.None;
// dest._highlightColor = this._highlightColor;
// dest.setHighlight(this.getHighlight());
dest._visible = this._visible;
Frame parent = DisplayController.getCurrentFrame();
if (parent == null) parent = this.getParentOrCurrentFrame();
dest.setParent(parent);
/*
* TODO MIKE says maybe we could tighten up and only give items ID's if
* their current ID is negative?
*/
if (parent != null) {
dest.setID(parent.getNextItemID());
}
String currentUser = UserSettings.UserName.get();
// if (parent != null && !currentUser.equals(parent.getOwner())) {
// //dest.setOwner(currentUser);
// } else {
// System.err.println("I have duplicated a item and made it owned by "
// + "current user, whereas the old code would not have "
// + "changed ownership at this time.");
// System.err.println("Item: " + dest + ", Class: " + dest.getClass());
// System.err.println("Current owner: " + dest.getOwner());
// System.err.println("Current user: " + currentUser);
// }
dest.setOwner(currentUser);
}
public void setDotType(DotType type) {
invalidateAll();
_type = type;
invalidateAll();
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.DOT_TYPE_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DOT_TYPE_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.DOT_TYPE_STR, inheritanceCheckOnSave);
}
}
}
public DotType getDotType() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.DOT_TYPE_STR)) {
return this.getPrimary().getDotType();
} else {
return _type;
}
}
public void setFilled(boolean filled) {
invalidateAll();
_filled = filled;
invalidateAll();
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.FILLED_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DOT_TYPE_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.FILLED_STR, inheritanceCheckOnSave);
}
}
}
public boolean getFilled() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.FILLED_STR)) {
return this.getPrimary().getFilled();
} else {
return _filled;
}
}
/**
* Sets the angle of colour change for gradient colour fills.
*
* @param gradientAngle The new angle of colour change.
*/
public void setGradientAngle(double gradientAngle) {
_gradientAngle = gradientAngle;
for (Line line : _lines) {
Item other = line.getOppositeEnd(this);
if (other.getGradientAngle() != gradientAngle) other.setGradientAngle(gradientAngle);
}
invalidateCommonTrait(ItemAppearence.GradientColor);
invalidateFill();
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.GRADIENT_ANGLE_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DOT_TYPE_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.GRADIENT_ANGLE_STR, inheritanceCheckOnSave);
}
}
}
/**
* Gets the angle of colour change for gradient fills.
*
* @return The angle of colour change.
*/
public double getGradientAngle() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.GRADIENT_ANGLE_STR)) {
return this.getPrimary().getGradientAngle();
} else {
return _gradientAngle;
}
}
/**
* Gets the gravity for this item. Gravity is the distance from the item at which mouse interaction
* applies to the item (like a small buffer zone so you don't need to click exactly on the item).
*
* @return The gravity distance for this item.
*/
public int getGravity()
{
if (isVectorItem()) return 2;
return UserSettings.Gravity.get();
}
/**
* Whether or not line highlights should be shown.
* TODO: Not really an item method is it? Goes straight to user settings. Refactor. cts16
*
* @return true if line highlighting should be shown, false otherwise.
*/
public static boolean shouldShowLineHighlight()
{
return UserSettings.LineHighlight.get();
}
/**
* Sets the highlight mode for this item.
*
* @param mode The new highlight mode.
*/
public void setHighlightMode(HighlightMode mode)
{
if (hasPermission(UserAppliedPermission.followLinks) || getEditTarget().hasPermission(UserAppliedPermission.followLinks)) {
if (_highlightMode != mode) {
_highlightMode = mode;
this.invalidateCommonTrait(ItemAppearence.HighlightModeChanged);
}
}
}
public void setOverlayPermission(UserAppliedPermission overlayPermission)
{
_overlayPermission = overlayPermission;
}
public void setPermission(PermissionTriple permissionPair) {
List groupMembers = getParent() != null ? getParent().getGroupMembers() : new ArrayList();
_permissionTriple = permissionPair;
if (_permissionTriple.getPermission(_owner, groupMembers) == UserAppliedPermission.denied) {
this.getParent().moveItemToBodyHiddenDueToPermission(this);
}
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.PERMISSION_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DOT_TYPE_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.PERMISSION_STR, inheritanceCheckOnSave);
}
}
}
public PermissionTriple getPermission() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.PERMISSION_STR)) {
return this.getPrimary().getPermission();
} else {
return _permissionTriple;
}
}
public UserAppliedPermission getUserAppliedPermission() {
List groupMembers = getParent() != null ? getParent().getGroupMembers() : new ArrayList();
String owner = _owner != null ? _owner : _parent != null ? _parent.getOwner() : null;
if(_permissionTriple != null) return _permissionTriple.getPermission(owner, groupMembers);
if(_overlayPermission != null) return _overlayPermission;
if(_parent != null) return _parent.getUserAppliedPermission();
return UserAppliedPermission.full;
}
public boolean hasPermission(UserAppliedPermission permission) {
return getUserAppliedPermission().ordinal() >= permission.ordinal();
}
protected Item() {
_creationDate = Formatter.getLongDateTime();
}
/**
* Adds an action to this Item.
*
* @param action
* The name of the action to add to this Item.
*/
public void addAction(String action)
{
if (action == null || action.equals("")) return;
if (_actions == null) {
_actions = new LinkedList();
}
_actions.add(action);
if (_actions.size() == 1) {
invalidateBounds();
invalidateCommonTrait(ItemAppearence.LinkChanged);
}
}
public void addAllConnected(Collection connected)
{
if (!connected.contains(this)) connected.add(this);
for (Item item : getConnected()) {
if (!connected.contains(item)) {
item.addAllConnected(connected);
}
}
}
/**
* Adds the given Constraint to this Dot
*
* @param c
* The Constraint to set this Dot as a member of.
*/
public void addConstraint(Constraint c)
{
// do not add duplicate constraint
if (_constraints.contains(c))
return;
_constraints.add(c);
}
/**
* Adds a given line to the list of lines that this Point is an end for.
*
* @param line
* The Line that this Point is an end of.
*/
public void addLine(Line line)
{
if (_lines.contains(line)) {
return;
}
_lines.add(line);
}
/**
* Items are sorted by their Y coordinate on the screen.
*
* @param i
* The Item to compare this Item to
* @return a negative integer, zero, or a positive integer as this object is
* less than, equal to, or greater than the specified object.
*/
public int compareTo(Item i)
{
return getY() - i.getY();
}
/**
* Every Item has an area around it defined by a Shape (typically a
* rectangle), this method returns true if the given x,y pair lies within
* the area and false otherwise.
*
* @param p
* The coordinate to check
* @return True if the Shape around this Item contains the given x,y pair,
* false otherwise.
*/
public boolean contains(Point p)
{
return getBounds().contains(p);
}
/**
* Returns a deep copy of this Item, note: it is up to the receiver to
* change the Item ID etc as necessary.
*
* @return A deep copy of this Item.
*/
public abstract Item copy();
public void delete()
{
_deleted = true;
}
@Override
public boolean equals(Object o)
{
if (o == null)
return false;
if (getClass().equals(o.getClass())) {
Item i = (Item) o;
return i.getID() == getID()
&& ((i.getParent() == _parent) || (i.getParent() != null && i
.getParent().equals(_parent)));
} else
return false;
}
/**
* Returns a list of any action code that is currently associated with this
* Item
*
* @return A List of action code associated with this Item, or null if none
* has been assigned.
*/
public List getAction() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_STR)) {
return this.getPrimary().getAction();
} else {
return _actions;
}
}
public List getData() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.DATA_STR)) {
return this.getPrimary().getData();
} else {
return _data.getData();
}
}
public List getActionCursorEnter() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_CURSOR_ENTER_STR)) {
return this.getPrimary().getActionCursorEnter();
} else {
return _actionCursorEnter;
}
}
public List getActionCursorLeave() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_CURSOR_LEAVE_STR)) {
return this.getPrimary().getActionCursorLeave();
} else {
return _actionCursorLeave;
}
}
public List getActionEnterFrame() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_ENTER_FRAME_STR)) {
return this.getPrimary().getActionEnterFrame();
} else {
return _actionEnterFrame;
}
}
public List getActionLeaveFrame() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_LEAVE_FRAME_STR)) {
return this.getPrimary().getActionLeaveFrame();
} else {
return _actionLeaveFrame;
}
}
public boolean getActionMark() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_MARK_STR)) {
return this.getPrimary().getActionMark();
} else {
return _actionMark;
}
}
/**
* Gets all the items connected to this item. Uses a recursive approach to
* search connected points.
*
* @return
*/
public Collection getAllConnected()
{
Collection list = new LinkedHashSet();
addAllConnected(list);
return list;
}
/* public Area getArea() {
return new Area(getPolygon());
}*/
public String getArrow() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ARROW_STR)) {
return this.getPrimary().getArrow();
} else {
if (!hasVisibleArrow())
return null;
String ratio = "" + getArrowheadRatio();
if (ratio.length() - ratio.indexOf(".") > 2)
ratio = ratio.substring(0, ratio.indexOf(".") + 3);
return getArrowheadLength() + " " + ratio + " " + getArrowheadNibPerc();
}
}
public PolygonBounds getArrowhead()
{
return _arrowhead;
}
public float getArrowheadLength()
{
return _arrowheadLength;
}
public double getArrowheadRatio()
{
return _arrowheadRatio;
}
public double getArrowheadNibPerc()
{
return _arrowheadNibPerc;
}
public Colour getBackgroundColor() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.BACKGROUND_COLOR_STR)) {
return this.getPrimary().getBackgroundColor();
} else {
return _backgroundColour;
}
}
public Colour getBorderColor() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.BORDER_COLOR_STR)) {
return this.getPrimary().getBorderColor();
} else {
return _colorBorder;
}
}
/**
* Returns the Color being used to shade the bottom half of this Item's
* border. This can be NULL if no Color is being used
*
* @return The Color displayed on the bottom\right half of this Item's
* border.
*/
public Colour getBottomShadowColor()
{
return _colorBottomShadow;
}
/**
* Returns the height (in pixels) of this Item's surrounding area.
*
* @return The height (in pixels) of this Item's surrounding area as
* returned by getArea().
*/
public int getBoundsHeight()
{
return AxisAlignedBoxBounds.getEnclosing(getBounds()).getHeight();
}
/**
* Returns the width (in pixels) of this Item's surrounding area.
*
* @return The width (in pixels) of this Item's surrounding area as returned
* by getArea().
*/
public int getBoundsWidth()
{
return AxisAlignedBoxBounds.getEnclosing(getBounds()).getWidth();
}
// TODO: Remove magic constants. cts16
public EllipticalBounds getLinkBounds()
{
if (_linkCircle == null) {
_linkCircle = new EllipticalBounds(new Point(6, 3), 7);
}
return _linkCircle;
}
protected PolygonBounds getCircleCross()
{
if (_linkCircleCross == null) {
_linkCircleCross = new PolygonBounds();
EllipticalBounds poly = getLinkBounds();
int x1 = poly.getMinX();
int x2 = poly.getMaxX();
int y1 = poly.getMinY();
int y2 = poly.getMaxY();
int midX = (x2 + x1) / 2;
int midY = (y2 + y1) / 2;
_linkCircleCross.addPoint(new Point(x1, y1));
_linkCircleCross.addPoint(new Point(x2, y2));
_linkCircleCross.addPoint(new Point(midX, midY));
_linkCircleCross.addPoint(new Point(x1, y2));
_linkCircleCross.addPoint(new Point(x2, y1));
_linkCircleCross.addPoint(new Point(midX, midY));
}
return _linkCircleCross;
}
public Colour getColor() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.COLOR_STR)) {
return this.getPrimary().getColor();
} else {
return _foregroundColour;
}
}
public Collection getConnected()
{
List conn = new LinkedList();
conn.add(this);
conn.addAll(getEnclosures());
conn.addAll(getLines());
return conn;
}
public String getConstraintIDs() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.CONSTRAINT_IDS_STR)) {
return this.getPrimary().getConstraintIDs();
} else {
if (_constraints == null || _constraints.size() == 0)
return null;
String cons = "";
for (Constraint c : _constraints)
cons += c.getID() + " ";
return cons.trim();
}
}
/*
* public void setLinkValid(boolean val) { _isValidLink = val; }
*/
/**
* Returns a List of any Constraints that this Dot is a memeber of.
*
* @return a List of Constraints that this Dot is a member of.
*/
public List getConstraints()
{
return _constraints;
}
public String getTag()
{
if (_tag != null && _tag.length() > 0)
return _tag.toString();
return null;
}
public String getDateCreated() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.DATE_CREATED_STR)) {
return this.getPrimary().getDateCreated();
} else {
return _creationDate;
}
}
public Colour getFillColor() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.FILL_COLOR_STR)) {
return this.getPrimary().getFillColor();
} else {
return _fillColour;
}
}
public String getFillPattern() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.FILL_PATTERN_STR)) {
return this.getPrimary().getFillPattern();
} else {
return _fillPattern;
}
}
public String getFirstAction()
{
if (_actions == null || _actions.size() == 0)
return null;
return _actions.get(0);
}
/**
* Gets the value of _highlight for this item.
* TODO: Appears unused? cts16.
*
* @return The value of _highlight.
*/
public boolean getHighlight() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.HIGHLIGHT_STR)) {
return this.getPrimary().getHighlight();
} else {
return _highlight;
}
}
public Colour getHighlightColor()
{
if (_highlightColour.equals(getPaintColor())) return getAlternateHighlightColor();
return getDefaultHighlightColor();
}
/**
* Returns the ID of this Item, which must be unique for the Frame.
*
* @return The ID of this Item.
*
* TODO: What does it mean to have a negative ID# (as used in TDFC)? cts16
*/
public int getID() {
return _id;
}
/**
* Returns the list of IDs of the Lines that this Dot is an end of.
*
* @return The list of Line IDs that this point is part of.
*/
public String getLineIDs() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINE_IDS_STR)) {
return this.getPrimary().getLineIDs();
} else {
String lineID = null;
if (_lines.size() > 0) {
lineID = "" + _lines.get(0).getID();
for (int i = 1; i < _lines.size(); i++)
lineID += " " + _lines.get(i).getID();
}
return lineID;
}
}
public int[] getLinePattern() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINE_PATTERN_STR)) {
return this.getPrimary().getLinePattern();
} else {
return _linePattern;
}
}
/**
* Returns a list of Lines where this Dot is an end.
*
* @return A list of the Lines that this Dot is an end for or null if no
* Lines have been added.
*/
public List getLines()
{
return _lines;
}
/**
* Returns the name of a Frame that this Item links to, or null if this Item
* has no link.
*
* @return The name of a Frame that this Item links to (if any) or null if
* this Item does not link to anything.
*/
public String getLink() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINK_STR)) {
return this.getPrimary().getLink();
} else {
return _link;
}
}
public String getFormula() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.FORMULA_STR)) {
return this.getPrimary().getFormula();
} else {
return _formula;
}
}
public boolean hasFormula()
{
return _formula != null;
}
public boolean hasAttributeValuePair()
{
return _attributeValuePair != null && _attributeValuePair.hasPair();
}
public void setFormula(String formula) {
_formula = formula;
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.FORMULA_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.FORMULA_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.FORMULA_STR, inheritanceCheckOnSave);
}
}
}
public boolean calculate(String formula)
{
setFormula(formula);
return true;
}
public String getLinkFrameset() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINK_FRAMESET_STR)) {
return this.getPrimary().getLinkFrameset();
} else {
return _link_frameset;
}
}
public boolean getLinkMark() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINK_MARK_STR)) {
return this.getPrimary().getLinkMark();
} else {
return _linkMark;
}
}
public String getLinkTemplate() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINK_TEMPLATE_STR)) {
return this.getPrimary().getLinkTemplate();
} else {
return _link_template;
}
}
public Point getOffset()
{
return _offset;
}
public String getOwner() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.OWNER_STR)) {
return this.getPrimary().getOwner();
} else {
return _owner;
}
}
public Colour getPaintBackgroundColor()
{
Colour colorBackground = getBackgroundColor();
if (colorBackground == null) {
if (getParent() != null && getParent().getBackgroundColor() != null)
return getParent().getBackgroundColor();
return DEFAULT_BACKGROUND;
}
return colorBackground;
}
/**
* Returns the foreground Color of this Item.
*
* @return The Color of this item (foreground)
*/
public final Colour getPaintColor()
{
// If color is null then get the paint foregroundColor for the frame the
// item is on which is a color adjusted to suit the background
Colour color = getColor();
if (color == null) {
if (getParent() != null)
return getParent().getPaintForegroundColor();
Frame current = DisplayController.getCurrentFrame();
if (current == null) {
return DEFAULT_FOREGROUND;
}
return current.getPaintForegroundColor();
}
return color;
}
public final Colour getPaintBorderColor()
{
// If color is null then get the paint foregroundColor for the frame the
// item is on which is a color adjusted to suit the background
Colour color = getBorderColor();
if (color == null) {
if (getParent() != null)
return getParent().getPaintForegroundColor();
Frame current = DisplayController.getCurrentFrame();
if (current == null) {
return DEFAULT_FOREGROUND;
}
return current.getPaintForegroundColor();
}
return color;
}
protected Colour getPaintHighlightColor()
{
Colour highlightColor = getDefaultHighlightColor();
if (hasVisibleBorder()) {
if (getPaintBorderColor().equals(highlightColor)) {
highlightColor = getDefaultHighlightColor();
}
} else if (getPaintBackgroundColor().equals(highlightColor)) {
highlightColor = getDefaultHighlightColor();
}
if (getParent() != null && getParent().getPaintBackgroundColor().equals(highlightColor)) {
highlightColor = getParent().getPaintForegroundColor();
}
if (hasVisibleBorder()) {
if (highlightColor.equals(getBorderColor()) && getThickness() == getHighlightThickness()) {
highlightColor = highlightColor.clone();
highlightColor.setAlpha(Colour.FromComponent255(150));
}
}
return highlightColor;
}
protected Colour getDefaultHighlightColor()
{
if (isVectorItem() && !this.contains(EcosystemManager.getInputManager().getCursorPosition())) {
return Colour.FromRGB255(255, BRIGHTNESS, BRIGHTNESS);
}
return _highlightColour;
}
protected Colour getAlternateHighlightColor()
{
if (isVectorItem() && !this.contains(EcosystemManager.getInputManager().getCursorPosition())) {
return Colour.FromRGB255(BRIGHTNESS, BRIGHTNESS, 255);
}
return ALTERNATE_HIGHLIGHT;
}
protected int getHighlightThickness()
{
if (isVectorItem()) return _vectorHighlightThickness;
return _highlightThickness;
}
public final Frame getParent()
{
return _parent;
}
/** Gets the position of this item. */
public final Point getPosition() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.POSITION_STR)) {
return this.getPrimary().getPosition();
} else {
return new Point(getX(), getY());
}
}
/**
* Returns the size of this Item. For Text this is the Font size, for Lines
* and Dots this is the thickness.
*
* @return The size of this Item.
*/
public float getSize()
{
return SIZE_NOT_APPLICABLE;
}
/**
* Returns the Color being used to shade the top half of this Item's border.
* This can be NULL if no Color is being used
*
* @return The Color displayed on the top\left half of this Item's border.
*/
public Colour getTopShadowColor()
{
return _colorTopShadow;
}
public String getTypeAndID() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.TYPE_AND_ID_STR)) {
return this.getPrimary().getTypeAndID();
} else {
return "T " + getID();
}
}
public Integer getWidthToSave() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.WIDTH_TO_SAVE_STR)) {
return this.getPrimary().getWidthToSave();
} else {
return getWidth();
}
}
public Integer getMinWidthToSave() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MIN_WIDTH_TO_SAVE_STR)) {
return this.getPrimary().getMinWidthToSave();
} else {
return getMinWidth();
}
}
public Integer getWidth()
{
return null;
}
public Integer getMinWidth() {
return null;
}
public int getHeight()
{
return 0;
}
/**
* Returns the X coordinate of this Item on the screen
*
* @return The X coordinate of this Item on the screen
*/
public int getX() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.POSITION_STR)) {
return this.getPrimary().getX();
} else {
return Math.round(_x);
}
}
/**
* Returns the Y coordinate of this Item on the screen
*
* @return The Y coordinate of this Item on the screen
*/
public int getY() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.POSITION_STR)) {
return this.getPrimary().getY();
} else {
return Math.round(_y);
}
}
public boolean hasVisibleArrow()
{
return isLineEnd() && getArrowheadRatio() != 0 && getArrowheadLength() != 0;
}
/**
* Checks if the given Shape intersects with the Shape around this Item.
*
* @param s
* The Shape to check.
* @return True if the two Shapes overlap, False otherwise.
*/
public boolean intersects(PolygonBounds otherBounds)
{
if (otherBounds == null) return false;
Bounds thisBounds = getBounds();
// Need to do this check for circles
if (otherBounds.equals(thisBounds)) return true;
boolean intersects = otherBounds.intersects(thisBounds);
/*if (intersects) {
System.err.println("Found intersection between this item (" + this + ") with bounds: " + thisBounds + "...and...");
System.err.println("item with bounds: " + otherBounds.toString());
}*/
return intersects;
// Need to check the second equality so that we dont pick up circles
// inside other circles
//return !a.isEmpty() && !a.equals(new Area(p));
}
/**
* Note: Pictures always return False, as they should be drawn even when no
* other annotation Items are.
*
* @return True if this Item is an annotation, False otherwise.
*/
public boolean isAnnotation()
{
return false;
}
public boolean isFloating()
{
return _floating;
}
public boolean isFrameName()
{
if (this.getParent() == null || this.getParent().getNameItem() != this)
return false;
return true;
}
public boolean isFrameTitle()
{
if (this.getParent() == null || this.getParent().getTitleItem() != this)
return false;
return true;
}
/**
* Returns True if this Item is currently highlighted.
*
* @return True if this Item is currently highlighted on the screen, False
* otherwise.
*/
public boolean isHighlighted()
{
if (isFloating())
return false;
return _highlightMode != HighlightMode.None;
}
/**
* Tests if the item link is a valid framename, that is, the String must
* begin with a character, end with a number with 0 or more letters and
* numbers in between. If there is a dot in the framename all the chars
* after it must be digits.
*
* @return True if the given framename is proper, false otherwise.
*/
public boolean isLinkValid()
{
if (FrameIO.isPositiveInteger(getLink()))
return true;
if (FrameIO.isValidFrameName(getLink()))
return true;
return false;
}
/**
* Checks if the given point is 'near' to the item. Here 'near' means within a certain distance
* of the axis-aligned box bounding the item's polygon.
*
* @param x
* The x-coordinate of the point to check.
*
* @param y
* The y-coordinate of the point to check.
*
* @return
* True if the given point is 'near' to the item, false otherwise.
*/
public boolean isNear(int x, int y)
{
AxisAlignedBoxBounds box = ItemUtils.expandRectangle(getBoundingBox(), NEAR_DISTANCE * 2);
return box.contains(x, y);
}
public boolean isOldTag()
{
if (this instanceof Text)
if (((Text) this).getTextList().get(0).toLowerCase().equals("@old"))
return true;
return false;
}
/**
* Merges this Item with the given Item. The merger Item should be left
* unchanged after this method. The merger may or may not be the same class
* as this Item, exact behaviour depends on the subclass, No-op is allowed.
*
* @param merger
* The Item to merge with
* @return any Item that should remain on the cursor
*/
public abstract Item merge(Item merger, int mouseX, int mouseY);
/**
* Displays this item directly on the screen. Note: All Items are
* responsible for their own drawing, buffering, etc.
*
* @param g
* The Graphics to draw this Item on.
*/
public abstract void paint();
public void setTooltips(final List tooltips)
{
if (tooltips == null || tooltips.size() == 0) {
_tooltip = new Tooltip();
} else {
for (final String content: tooltips) _tooltip.addTooltip(content, this);
}
}
public void setTooltip(final String tooltip) {
if(tooltip != null && tooltip.trim().length() > 0) {
_tooltip.addTooltip(tooltip, this);
}
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.TOOLTIP_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.TOOLTIP_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.TOOLTIP_STR, inheritanceCheckOnSave);
}
}
}
public List getTooltip() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.TOOLTIP_STR)) {
return this.getPrimary().getTooltip();
} else {
return _tooltip.asStringList();
}
}
public Collection getTooltipItems()
{
return _tooltip.getTooltips();
}
public void clearTooltips()
{
final Frame frame = this.getParent();
if(_tooltip != null) {
for(final Text tooltip: _tooltip.getTooltips()) frame.removeItem(tooltip);
}
}
public void paintTooltip()
{
final Bounds bounds = AxisAlignedBoxBounds.getEnclosing(this.getBoundingBox());
Dimension frameSize = DisplayController.getFramePaintAreaSize();
int x = bounds.getMaxX();
// If the tooltip goes off the right side of the window, move it left so it's completely on
if(x + _tooltip.getWidth() > frameSize.getWidth()) {
x = frameSize.getWidth() - _tooltip.getWidth();
}
int y = bounds.getMaxY();
if(y + _tooltip.getCollectiveHeight() > frameSize.getHeight()) {
y = (bounds.getMinY() + bounds.getMaxY()) / 2 - _tooltip.getCollectiveHeight();
}
for(final Text tooltip : _tooltip.getTooltips()) {
this.getParent().addItem(tooltip);
tooltip.setPosition(x, y);
tooltip.paint();
y += tooltip.getHeight();
}
}
public void paintFill() {
Colour fillColor = getFillColor();
if (fillColor != null && getEnclosingDots() != null) {
Fill fill = getFill();
EcosystemManager.getGraphicsManager().drawPolygon(getEnclosedShape(), null, null, 0.0f, fill, null, null);
}
}
protected Fill getFill() {
Fill fill;
Colour fillColour = getFillColor();
if (isFloating()) {
// TODO experiment with adding alpha when picking up filled
// items... Slows things down quite alot!!
// TODO: Does nothing as it stands... cts16
fillColour = new Colour(fillColour.getRed(), fillColour.getGreen(),
fillColour.getBlue(), fillColour.getAlpha());
}
Colour gradientColor = getGradientColor();
PolygonBounds poly = getEnclosedShape();
if (gradientColor != null && poly != null) {
/*
* It is slow when painting gradients... modify so this is only done
* once unless it is resized...
*/
AxisAlignedBoxBounds b = AxisAlignedBoxBounds.getEnclosing(poly);
double rads = getGradientAngle();
double cos = Math.cos(rads);
double sin = Math.sin(rads);
Point fromPoint = new Point((int) (b.getMinX() + b.getWidth() * (0.2 * cos + 0.5)), (int) (b.getMinY() + b.getHeight() * (0.2 * sin + 0.5)));
Point toPoint = new Point((int) (b.getMinX() + b.getWidth() * (-0.8 * cos + 0.5)), (int) (b.getMinY() + b.getHeight() * (-0.8 * sin + 0.5)));
fill = new GradientFill(fillColour, fromPoint, gradientColor, toPoint);
} else {
fill = new Fill(fillColour);
}
return fill;
}
/**
* This method performs all the actions in an items list. If it contains a
* link as well the link is used as the source frame for all actions.
*/
public void performActions() {
Frame sourceFrame = null;
Item sourceItem = FreeItems.getItemAttachedToCursor();
if (sourceItem == null) {
sourceItem = this;
} else {
for (Item i : sourceItem.getAllConnected()) {
if (i instanceof Text) {
sourceItem = i;
break;
}
}
}
// TODO decide whether to have items or
// if a link exists make it the source frame for this action
if (getLink() != null) {
sourceFrame = FrameUtils.getFrame(getAbsoluteLink());
}
// if no link exists or the link is bad then use the
// currently displayed frame as the source frame for the
// action
if (sourceFrame == null) {
// For actions like format they rely on this being set to the
// current frame incase the item being activated is on an overlay
sourceFrame = DisplayController.getCurrentFrame();
}
for (String s : getAction()) {
Object returnValue;
if (LegacyFeatures.UseLegacyActionArgumentMapping.get()) {
returnValue = Actions.LegacyPerformActionCatchErrors(sourceFrame, sourceItem, s);
} else {
returnValue = Actions.PerformActionCatchErrors(sourceFrame, sourceItem, s, this);
}
if (returnValue != null) {
FreeItems.getInstance().clear();
if (returnValue instanceof Item) {
Misc.attachToCursor(((Item) returnValue).getAllConnected());
} else if (returnValue instanceof Collection) {
try {
Misc.attachToCursor((Collection) returnValue);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Misc.attachStatsToCursor(returnValue.toString());
}
}
}
}
/**
* Removes all constraints that this item has.
*
*/
public void removeAllConstraints() {
while (_constraints.size() > 0) {
Constraint c = _constraints.get(0);
c.getEnd().removeConstraint(c);
c.getStart().removeConstraint(c);
}
}
/**
* Clears the list of Lines that this Dot is an end of. Note: This only
* clears this Dot's list and does not have any affect on the Lines or other
* Dots.
*/
public void removeAllLines() {
for (Line l : _lines) {
l.invalidateAll();
}
_lines.clear();
}
/**
* Removes the given Constraint from the list of constraints that this Dot
* is a part of.
*
* @param c
* The Constraint that this Dot is no longer a part of.
*/
public void removeConstraint(Constraint c) {
_constraints.remove(c);
}
/**
* Removes the given Line from the list of lines that this Dot is an end
* for.
*
* @param line
* The Line that this Dot is no longer an end of.
*/
public void removeLine(Line line) {
if (_lines.remove(line))
line.invalidateAll();
}
public void run() {
try {
List action = this.getAction();
if (action != null) {
String action_name = action.get(0);
if (action_name.equalsIgnoreCase("RunJavascriptFrame")){
// Associate a new Context with this thread
org.mozilla.javascript.Context javascript_context = org.mozilla.javascript.Context.enter();
try {
Scriptable javascript_scope = javascript_context.initStandardObjects();
Context simple_context = new Context();
//Object jsDisplayIO = org.mozilla.javascript.Context.javaToJS(org.expeditee.gui.DisplayIO, javascript_scope);
//ScriptableObject.putProperty(javascript_scope, "displayIO", jsDisplayIO);
Object jsSimpleContext = org.mozilla.javascript.Context.javaToJS(simple_context, javascript_scope);
ScriptableObject.putProperty(javascript_scope, "simpleContext", jsSimpleContext);
Object jsErr = org.mozilla.javascript.Context.javaToJS(System.err, javascript_scope);
ScriptableObject.putProperty(javascript_scope, "err", jsErr);
Object jsOut = org.mozilla.javascript.Context.javaToJS(System.out, javascript_scope);
ScriptableObject.putProperty(javascript_scope, "out", jsOut);
Javascript.ProgramStarted();
Javascript.RunFrameAndReportError(this, javascript_context,javascript_scope);
MessageBay.displayMessage(AgentStats.getStats(), GREEN);
}
finally {
org.mozilla.javascript.Context.exit();
}
}
}
else {
// assume it is a simple program that is to be run
Simple.ProgramStarted();
Context simple_context = new Context();
Simple.RunFrameAndReportError(this, simple_context);
MessageBay.displayMessage(AgentStats.getStats(), GREEN);
}
} catch (ConcurrentModificationException ce) {
ce.printStackTrace();
} catch (IncorrectUseOfStatementException ise) {
MessageBay.linkedErrorMessage(ise.getMessage());
MessageBay.displayMessage("See SIMPLE doc for ["
+ ise.getStatement() + "] statement", ise.getStatement()
+ "1", Colour.CYAN.darker(), true, null);
} catch (Exception e) {
MessageBay.linkedErrorMessage(e.getMessage());
}
Simple.ProgramFinished();
// Need to repaint any highlights etc
DisplayController.requestRefresh(true);
}
/**
* Check if it has a relative link if so make it absolute.
*
*/
public void setAbsoluteLink() {
String link = getLink();
if (link == null)
return;
// Check if all the characters are digits and hence it is a relative
// link
if (!FrameIO.isPositiveInteger(link))
return;
// Make it an absolute link
String framesetName;
if (_parent == null)
framesetName = DisplayController.getCurrentFrame().getFramesetName();
else
framesetName = _parent.getFramesetName();
setLink(framesetName + link);
}
/**
* Sets any action code that should be associated with this Item Each entry
* in the list is one line of code
*
* @param actions
* The lines of code to associate with this Item
*/
public void setActions(List actions) {
if (actions == null || actions.size() == 0) {
invalidateCommonTrait(ItemAppearence.LinkChanged);
_actions = null;
} else {
_actions = new LinkedList(actions);
}
// Want to resize the highlight box for text items if actions have been added
invalidateBounds();
invalidateCommonTrait(ItemAppearence.LinkChanged);
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_STR, inheritanceCheckOnSave);
}
}
}
public void setData(List data) {
_data.setData(data);
}
public void setData(String data) {
_data.setData(data);
}
public void addToData(String dataItem) {
_data.addToData(dataItem);
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.DATA_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DATA_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.DATA_STR, inheritanceCheckOnSave);
}
}
}
public boolean hasData(String dataItem) {
return _data.hasData(dataItem);
}
public void setActionCursorEnter(List enter) {
_actionCursorEnter = enter;
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_CURSOR_ENTER_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_CURSOR_ENTER_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_CURSOR_ENTER_STR, inheritanceCheckOnSave);
}
}
}
public void setActionCursorLeave(List leave) {
_actionCursorLeave = leave;
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_CURSOR_LEAVE_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_CURSOR_LEAVE_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_CURSOR_LEAVE_STR, inheritanceCheckOnSave);
}
}
}
public void setActionEnterFrame(List enter) {
_actionEnterFrame = enter;
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_ENTER_FRAME_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_ENTER_FRAME_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_ENTER_FRAME_STR, inheritanceCheckOnSave);
}
}
}
public void setActionLeaveFrame(List leave) {
_actionLeaveFrame = leave;
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_LEAVE_FRAME_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_LEAVE_FRAME_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_LEAVE_FRAME_STR, inheritanceCheckOnSave);
}
}
}
public void setActionMark(boolean val) {
if (!val) invalidateCommonTrait(ItemAppearence.LinkChanged);
invalidateBounds();
_actionMark = val;
if (val) invalidateCommonTrait(ItemAppearence.LinkChanged);
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_MARK_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_MARK_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_MARK_STR, inheritanceCheckOnSave);
}
}
}
/**
* Sets whether this Item is an Annotation.
*
* @param val
* True if this Item is an Annotation, False otherwise.
*/
public abstract void setAnnotation(boolean val);
/**
* Used to set this Line as an Arrow. If length and ratio are 0, no arrow is
* shown.
*
* @param length
* The how far down the shaft of the line the arrowhead should
* come.
* @param ratio
* The ratio of the arrow's length to its width.
*/
public void setArrow(float length, double ratio, double nib_perc) {
_arrowheadLength = length;
_arrowheadRatio = ratio;
_arrowheadNibPerc = nib_perc;
updateArrowPolygon();
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.ARROW_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ARROW_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.ARROW_STR, inheritanceCheckOnSave);
}
}
}
public void setArrow(float length, double ratio) {
setArrow(length,ratio,DEFAULT_ARROWHEAD_NIB_PERC);
}
public void setArrowhead(PolygonBounds arrow) {
_arrowhead = arrow;
}
public void setArrowheadLength(float length) {
_arrowheadLength = length;
updateArrowPolygon();
}
public void setArrowheadRatio(double ratio) {
_arrowheadRatio = ratio;
updateArrowPolygon();
}
public void setArrowheadNibPerc(double perc) {
_arrowheadNibPerc = perc;
updateArrowPolygon();
}
public void setBackgroundColor(Colour c) {
if (c != _backgroundColour) {
_backgroundColour = c;
invalidateCommonTrait(ItemAppearence.BackgroundColorChanged);
}
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.BACKGROUND_COLOR_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.BACKGROUND_COLOR_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.BACKGROUND_COLOR_STR, inheritanceCheckOnSave);
}
}
}
public void setBorderColor(Colour c) {
if (c != _colorBorder) {
_colorBorder = c;
invalidateCommonTrait(ItemAppearence.BorderColorChanged);
}
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.BORDER_COLOR_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.BORDER_COLOR_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.BORDER_COLOR_STR, inheritanceCheckOnSave);
}
}
}
/**
* Sets the Color to use on the bottom and right sections of this Item's
* border. If top is NULL, then the Item's background Color will be used.
*
* @param top
* The Color to display in the bottom and right sections of this
* Item's border.
*/
public void setBottomShadowColor(Colour bottom) {
_colorBottomShadow = bottom;
}
/**
* Sets the foreground Color of this Item to the given Color.
*
* @param c
*/
public void setColor(Colour c) {
if (c != _foregroundColour) {
_foregroundColour = c;
invalidateCommonTrait(ItemAppearence.ForegroundColorChanged);
if (hasVector()) {
// TODO make this more efficient so it only repaints the items
// for this vector
StandardGestureActions.Refresh();
}
}
}
public void setConstraintIDs(String IDs) {
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.CONSTRAINT_IDS_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.CONSTRAINT_IDS_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.CONSTRAINT_IDS_STR, inheritanceCheckOnSave);
}
}
}
public void setConstraints(List constraints) {
_constraints = constraints;
}
public void setTag(String newData) {
if (newData != null)
_tag = new StringBuffer(newData);
else
_tag = null;
}
/**
* Sets the created date of this Frame to the given String.
*
* @param date
* The date to use for this Frame.
*/
public void setDateCreated(String date) {
_creationDate = date;
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.DATE_CREATED_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DATE_CREATED_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.DATE_CREATED_STR, inheritanceCheckOnSave);
}
}
}
public void setFillColor(Colour c) {
_fillColour = c;
for (Line line : _lines) {
Item other = line.getOppositeEnd(this);
if (other.getFillColor() != c) {
other.setFillColor(c);
}
}
invalidateCommonTrait(ItemAppearence.FillColor);
invalidateFill();
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.FILL_COLOR_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.FILL_COLOR_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.FILL_COLOR_STR, inheritanceCheckOnSave);
}
}
}
public void setGradientColor(Colour c) {
_gradientColour = c;
for (Line line : _lines) {
Item other = line.getOppositeEnd(this);
if (other.getGradientColor() != c)
other.setGradientColor(c);
}
invalidateCommonTrait(ItemAppearence.GradientColor);
invalidateFill();
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.GRADIENT_COLOR_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.GRADIENT_COLOR_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.GRADIENT_COLOR_STR, inheritanceCheckOnSave);
}
}
}
public Colour getGradientColor() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.GRADIENT_COLOR_STR)) {
return this.getPrimary().getGradientColor();
} else {
return _gradientColour;
}
}
public void setFillPattern(String patternLink) {
_fillPattern = patternLink;
invalidateCommonTrait(ItemAppearence.FillPattern);
invalidateFill();
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.FILL_PATTERN_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.FILL_PATTERN_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.FILL_PATTERN_STR, inheritanceCheckOnSave);
}
}
}
public void setFloating(boolean val) {
_floating = val;
}
/**
* Sets the value _highlight for this item.
* TODO: Appears unused? cts16
*
* @param val The new value for _highlight.
*/
public void setHighlight(boolean val) {
_highlight = val;
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.HIGHLIGHT_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.HIGHLIGHT_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.HIGHLIGHT_STR, inheritanceCheckOnSave);
}
}
}
/**
* Sets the ID of this Item to the given Integer. Note: Items with ID's < 0
* are not saved
*
* @param newID
* The new ID to assign this Item.
*/
public void setID(int newID) {
_id = newID;
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.TYPE_AND_ID_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.TYPE_AND_ID_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.TYPE_AND_ID_STR, inheritanceCheckOnSave);
}
}
}
/**
* Function called when a user attempts to set the ID of a Item. Simply provides
* feedback to the user telling them that they are not allowed to do this. This
* function is provided so that users are able to get the ID of a item when
* extracting properties. See {@link org.expeditee.gui.AttributeUtils}.
*
* @param newID The requested new ID that will be ignored.
*/
public void setIDFail(int newID) {
MessageBay.displayMessage("A user cannot change the ID of an item.");
}
/**
* Sets the list of lines that this point is part of (may be set to null).
*
* @param lineID
* A String of line ID numbers separated by spaces.
*/
public void setLineIDs(String lineID) {
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.LINE_IDS_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINE_IDS_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINE_IDS_STR, inheritanceCheckOnSave);
}
}
}
public void setLinePattern(int[] pattern) {
_linePattern = pattern;
for (Line line : getLines())
line.setLinePattern(pattern);
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.LINE_PATTERN_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINE_PATTERN_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINE_PATTERN_STR, inheritanceCheckOnSave);
}
}
}
public void setLines(List lines) {
_lines = lines;
for (Line line : lines)
line.setLinePattern(getLinePattern());
}
/**
* Links this item to the given Frame, this may be set to null to remove a
* link.
*
* @param frameName
* The name of the Frame to link this item to.
*/
public void setLink(String frameName) {
if (frameName == null) invalidateCommonTrait(ItemAppearence.LinkChanged);
// If a link is being removed or set then need to reset _bounds so the
// highlighting is drawn with the correct width
if (frameName == null || getLink() == null) invalidateBounds();
if (FrameIO.isValidLink(frameName)) {
_link = frameName;
} else {
MessageBay.errorMessage("[" + frameName + "] is not a valid frame name");
}
// TODO make this throw exceptions etc...
invalidateCommonTrait(ItemAppearence.LinkChanged);
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.LINK_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINK_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINK_STR, inheritanceCheckOnSave);
}
}
}
public void setLinkHistory(boolean value) {
_linkHistory = value;
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.LINK_HISTORY_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINK_HISTORY_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINK_HISTORY_STR, inheritanceCheckOnSave);
}
}
}
public boolean getLinkHistory() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINK_HISTORY_STR)) {
return this.getPrimary().getLinkHistory();
} else {
return _linkHistory;
}
}
public void setLinkFrameset(String frameset)
{
if (frameset == null || FrameIO.isValidFramesetName(frameset)) {
_link_frameset = frameset;
} else {
MessageBay.errorMessage("[" + frameset + "] is not a valid frameset name");
}
// TODO make this throw exceptions etc...
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.LINK_FRAMESET_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINK_FRAMESET_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINK_FRAMESET_STR, inheritanceCheckOnSave);
}
}
}
public void setLinkMark(boolean val) {
if (!val) invalidateCommonTrait(ItemAppearence.LinkChanged);
invalidateBounds();
_linkMark = val;
if (val) invalidateCommonTrait(ItemAppearence.LinkChanged);
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.LINK_MARK_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINK_MARK_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINK_MARK_STR, inheritanceCheckOnSave);
}
}
}
public void setLinkTemplate(String template) {
if (FrameIO.isValidLink(template)) {
_link_template = template;
} else {
MessageBay.errorMessage("[" + template + "] is not a valid frame name");
}
// TODO make this throw exceptions etc...
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.LINK_TEMPLATE_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINK_TEMPLATE_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINK_TEMPLATE_STR, inheritanceCheckOnSave);
}
}
}
// /**
// * Sets the maximum coordinates on the screen that this item may occupy.
// * This is used by Text items to compute word-wrapping lengths.
// *
// * @param d
// * The Maximum size of the Frame containing this Item.
// */
// public void setMaxWidth(int width) {
// if (width > 0) {
// _maxWidth = width;
// updatePolygon();
// }
// }
public void setOffset(int x, int y) {
_offset.set(x, y);
}
public void setOffset(Point p) {
_offset.set(p);
}
public void setOwner(String own) {
_owner = own;
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.OWNER_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.OWNER_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.OWNER_STR, inheritanceCheckOnSave);
}
}
}
public void setParent(Frame frame) {
_oldParent = _parent;
_parent = frame;
if (_parent == null) { return; }
final String currentUser = UserSettings.UserName.get();
final String existingOwner = _parent.getOwner();
if (currentUser != null && (existingOwner == null || currentUser.compareTo(existingOwner) != 0)) {
setOwner(currentUser);
}
}
/**
* Invalidates this, connected lines and fill
*
* @param trait
*/
private void invalidateCommonTraitForAll(ItemAppearence trait) {
invalidateCommonTrait(trait);
if (isLineEnd()) {
boolean hasLinePattern = getLines().get(0).getLinePattern() != null;
if (hasLinePattern) {
for (Item i : getAllConnected()) {
if (i instanceof Line) {
((Line) i).invalidateCommonTrait(trait);
}
}
} else {
for (Line line : getLines()) {
line.invalidateCommonTrait(trait);
}
}
}
if (_fillColour != null) {
invalidateFill(); // only invalidates if has fill
}
for (XRayable x : getEnclosures()) {
x.invalidateCommonTrait(trait);
}
}
protected void anchorConstraints()
{
// update the position of any dots that are constrained by this one
for (Constraint c : _constraints) {
Item other = c.getOppositeEnd(this);
// only set position if the other dot is still fixed to the
// frame
if (/* this.isFloating() && */!other.isFloating()) {
if (c.getType() == Constraint.HORIZONTAL) {
if (isAnchoredY()) {
// Make the 'other' item have the same anchor top/bottom values as this
other._anchoring.setYAnchor(this._anchoring);
}
} else if (c.getType() == Constraint.VERTICAL) {
if (isAnchoredX()) {
// Make the 'other' item have the same anchor left/right values as this
other._anchoring.setXAnchor(this._anchoring);
}
} else if (c.isDiagonal()) {
System.err.println("Warning: anchorConstraints() not implement for Diagonal setting");
}
}
}
}
/**
* Sets the position of this item on the screen
*
* @param x
* The new X coordinate
* @param y
* The new Y coordinate
*/
public void setPosition(float x, float y) {
float deltaX = x - _x;
float deltaY = y - _y;
if (deltaX == 0 && deltaY == 0) return;
invalidateCommonTraitForAll(ItemAppearence.PreMoved);
_x = x;
_y = y;
for (Item i : getEnclosures()) {
i.invalidateBounds();
}
invalidateBounds();
// update the position of any dots that are constrained by this one
for (Constraint c : _constraints) {
Item other = c.getOppositeEnd(this);
// only set position if the other dot is still fixed to the
// frame
if (/* this.isFloating() && */!other.isFloating()) {
if (c.getType() == Constraint.HORIZONTAL) {
if (other._y != y) {
other.setY(y);
}
} else if (c.getType() == Constraint.VERTICAL) {
if (other._x != x) {
other.setX(x);
}
} else if (c.isDiagonal()) {
if (Math.abs(other._x - x) != Math.abs(other._y - y)) {
float m1 = c.getGradient();
float c1 = y - m1 * x;
// Now work out the equation for the second line
// Get the first line the other end is attached to that
// is not the diagonal line
List lines = other.getLines();
// If there is only one line...
if (lines.size() == 1) {
if (m1 != 0) {
if (Math.abs(deltaX) > Math.abs(deltaY)) {
other.setX((other._y - c1) / m1);
} else {
other.setY(m1 * other._x + c1);
}
}
} else if (lines.size() > 1) {
Line otherLine = lines.get(0);
Item end = otherLine.getOppositeEnd(other);
if (end.equals(this)) {
otherLine = lines.get(1);
end = otherLine.getOppositeEnd(other);
assert (!end.equals(this));
}
float xDiff = end._x - other._x;
float yDiff = end._y - other._y;
if (xDiff == 0) {
other.setY(m1 * other._x + c1);
} else if (Math.abs(xDiff) == Math.abs(yDiff)
&& !this.isFloating() && deltaX == 0
&& deltaY == 0) {
if (deltaX == 0) {
_x = (_y - other._y) * m1 + other._x;
} else {
_y = (_x - other._x) * m1 + other._y;
}
} else {
float m2 = yDiff / xDiff;
float c2 = end._y - m2 * end._x;
float mDiff = m1 - m2;
if (Math.abs(mDiff) < 0.000001) {
assert (false);
// TODO how do I handle this case!!
} else {
float newX = (c2 - c1) / mDiff;
float newY = m1 * newX + c1;
if (other._x != newX
/* && other._y != newY */) {
other.setPosition(newX, newY);
}
}
}
}
// Do simultaneous equations to get the new postion for
// the other end of the diagonal line
}
}
}
}
for (Line line : getLines()) {
line.invalidateBounds();
}
// for (Item item : getAllConnected()) {
// item.updatePolygon();
// }
invalidateCommonTraitForAll(ItemAppearence.PostMoved);
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.POSITION_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.POSITION_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.POSITION_STR, inheritanceCheckOnSave);
}
}
}
public void setPosition(Point position) {
setPosition(position.getX(), position.getY());
}
public void setRelativeLink() {
String link = getLink();
if (link == null)
return;
assert (_parent != null);
if (FrameIO.isPositiveInteger(link))
return;
// Check if the link is for the current frameset
if (_parent.getFramesetName().equalsIgnoreCase(
Conversion.getFramesetName(link))) {
setLink("" + Conversion.getFrameNumber(link));
}
}
/**
* Sets the size of this Item. For Text this is the Font size. For Lines and
* Dots this is the thickness.
*/
public void setSize(float size) {
}
/**
* Sets the thickness of the item.
*
* @param thick
*/
public final void setThickness(float thick) {
setThickness(thick, true);
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.THICKNESS_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.THICKNESS_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.THICKNESS_STR, inheritanceCheckOnSave);
}
}
}
/**
* Sets the thickness of this item.
*
* @param thick
* the new thickness for the item
* @param setConnectedThickness
* true if all items connected to this item should also have
* their thickness set
*/
public void setThickness(float thick, boolean setConnectedThickness)
{
if (thick == _thickness) return;
boolean bigger = thick > _thickness;
if (!bigger) {
if (setConnectedThickness) {
// TODO is there a more efficient way of doing this?
for (Item i : getConnected()) i.invalidateCommonTrait(ItemAppearence.Thickness);
} else {
invalidateCommonTrait(ItemAppearence.Thickness);
}
}
_thickness = thick;
// update the size of any lines
/*
* TODO: Revise the way line thickness is set to make it more efficient
* etc...
*/
for (Line line : getLines()) line.setThickness(thick, setConnectedThickness);
if (setConnectedThickness) invalidateBounds();
if (bigger) {
if (setConnectedThickness) {
for (Item i : getConnected()) i.invalidateCommonTrait(ItemAppearence.Thickness);
} else {
invalidateCommonTrait(ItemAppearence.Thickness);
}
}
}
/**
* Returns the thickness (in pixels) of this Dot.
*
* @return The 'thickness' of this Dot. (returns -1 if the thickness is not
* set).
*/
public float getThickness() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.THICKNESS_STR)) {
return this.getPrimary().getThickness();
} else {
return _thickness;
}
}
/**
* Sets the Color to use on the top and left sections of this Item's border.
* If top is NULL, then the Item's background Color will be used.
*
* @param top
* The Color to display in the top and left sections of this
* Item's border.
*/
public void setTopShadowColor(Colour top) {
_colorTopShadow = top;
}
public void setWidth(Integer width) throws UnsupportedOperationException
{
throw new UnsupportedOperationException("Item type does not support width attribute!");
}
public void setMinWidth(final Integer width) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Item type does not support minwidth attribute.");
}
public void setMaxWidth(Integer width) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Item type does not support maxwidth attribute");
}
public void setRightMargin(int rightEdgeToFitTo, boolean fixWidth)
{
int itemXLeft = getX();
int adjustedRightEdgeToFitTo = rightEdgeToFitTo - Item.MARGIN_LEFT;
if (itemXLeft < adjustedRightEdgeToFitTo) {
int newWidth = adjustedRightEdgeToFitTo - itemXLeft;
if (!fixWidth) {
newWidth *= -1;
}
setWidth(newWidth);
} else if (fixWidth) {
System.err.println(
"Item::setRightMargin() called to set right margin outside of writable area but with fixWidth set to true.");
System.err.println(this);
}
}
/**
* Sets the position of this Item on the X axis
*
* @param newX
* The position on the X axis to assign to this Item
*/
public void setX(float newX) {
setPosition(newX, getY());
// if (isSurrogate()) {
// surrogatePropertyInheritance.put(DefaultFrameWriter.POSITION_STR, false);
// Item primary = getPrimary();
// if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.POSITION_STR)) {
// EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
// primary.primaryPropertyEncryption.put(DefaultFrameWriter.POSITION_STR, inheritanceCheckOnSave);
// }
// }
}
/**
* Sets the position of this Item on the Y axis
*
* @param newY
* The position on the Y axis to assign to this Item
*/
public void setY(float newY) {
setPosition(getX(), newY);
// if (isSurrogate()) {
// surrogatePropertyInheritance.put(DefaultFrameWriter.POSITION_STR, false);
// Item primary = getPrimary();
// if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.POSITION_STR)) {
// EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
// primary.primaryPropertyEncryption.put(DefaultFrameWriter.POSITION_STR, inheritanceCheckOnSave);
// }
// }
}
/**
* Paints any highlighting of this Item. This may include changing the
* thickness (lines) or painting a box around the item (Text, Images). If
* val is True then the Graphics Color is changed to the highlight Color, if
* False then the Graphics Color is left unchanged (for clearing of
* highlighting).
*
* @param val
* True if this Item should be highlighted, false if the
* highlighting is being cleared.
* @return The desired mouse cursor when this Item is highlighted (negative
* means no change)
*/
/**
*
*
* @return
*/
public void setHighlightColorToDefault() {
setHighlightColor(DEFAULT_HIGHLIGHT);
}
public void setHighlightColor(Colour c) {
if (c == null) return;
if (!this.isVisible() && this.hasVector()) {
for (Item i : this.getParentOrCurrentFrame().getVectorItems()) {
if (i.getEditTarget() == this) {
i.setHighlightColor(c);
}
}
}
_highlightThickness = DEFAULT_HIGHLIGHT_THICKNESS;
Colour selColor = (c != null) ? c : DEFAULT_HIGHLIGHT;
if (_highlightColour != c) {
_highlightColour = selColor;
this.invalidateCommonTrait(ItemAppearence.HighlightColorChanged);
}
}
private void updateArrowPolygon() {
if (getArrowheadLength() < 0 || getArrowheadRatio() < 0 || getArrowheadNibPerc() < 0)
_arrowhead = null;
else {
_arrowhead = Line.createArrowheadPolygon(getX(),getY(),getArrowheadLength(),getArrowheadRatio(),getArrowheadNibPerc());
}
}
/** Returns a Bounds which represents the area covered by the item (including its gravity). */
public abstract Bounds updateBounds();
public void setHidden(boolean state) {
this._visible = !state;
}
public void setVisible(boolean state) {
this._visible = state;
}
public boolean isVisible() {
return _visible && !_deleted;
}
/**
* Raised whenever the item is removed, added, no longer in view (That is,
* when it is not on any of the current frames, of overlays of the current
* frames) or has become visible. That is, when it is either on a current
* frame, or an overlay of a current frame.
*
* @param e
* The event
*/
public void onParentStateChanged(ItemParentStateChangedEvent e) {
}
/**
* Sets the highlight mode and colour at the same time.
*
* @param mode The new highlight mode.
* @param colour The new highlight colour.
*/
public void setHighlightModeAndColour(HighlightMode mode, Colour colour)
{
setHighlightMode(mode);
setHighlightColor(colour);
}
public HighlightMode getHighlightMode() {
return _highlightMode;
}
public void anchor() {
Frame current = getParentOrCurrentFrame();
// only set the id if we've moved to a different frame, or if the frame already has an item with that id
if(!current.equals(_oldParent) || current.getItemWithID(getID()) != null) {
setID(current.getNextItemID());
} else {
// System.out.println(this + " - Kept old ID of " + _id);
}
setOffset(0, 0);
setParent(current);
current.addItem(this, false);
current.invalidateSorted();
setRelativeLink();
setFloating(false);
// // If its an unconstrained line end check if we should add a
// constraint
// if (isLineEnd() && getLines().size() <= 2
// && getConstraints().size() <= 1) {
// Constraint existingConstraint = null;
// List constraints = getConstraints();
// // Get the existing constraint
// if (constraints.size() > 0) {
// existingConstraint = constraints.get(0);
// }
// for (Line line : getLines()) {
// Integer constraintType = line.getPossibleConstraint();
// if (constraintType != null) {
// Item oppositeEnd = line.getOppositeEnd(this);
// if (existingConstraint == null
// || !existingConstraint.contains(oppositeEnd)) {
// new Constraint(this, oppositeEnd,
// getParentOrCurrentFrame().getNextItemID(),
// constraintType);
// }
// }
// }
// }
}
/**
* Gets the parent frame if it is set or the current frame if this item does
* not have a parent set.
*
* @return
*/
public Frame getParentOrCurrentFrame() {
// if the item is from an overlay the parent will NOT be null
if (getParent() == null) {
return DisplayController.getCurrentFrame();
}
return getParent();
}
/**
* Sets the list of Dots (including this one) that form a closed shape.
* Passing null sets this dot back to its normal (non-enclosed) state.
*
* @param enclosed
* The List of Dots including this one that form a closed shape,
* or null.
*/
public void setEnclosedList(Collection enclosed) {
boolean changed = (_enclosure == null && enclosed != null);
if (_enclosure != null && enclosed == null) {
invalidateFill();
}
_enclosure = enclosed;
if (changed) {
invalidateFill();
;
}
}
/**
* Returns the polygon that represents the shape created by all the Dots in
* this Dot's enclosed list. If the list is null, then null is returned.
*
* @return A Polygon the same shape and position as created by the Dots in
* the enclosed list.
*/
public PolygonBounds getEnclosedShape()
{
if (_enclosure == null) return null;
PolygonBounds poly = new PolygonBounds();
for (Item d : _enclosure) {
poly.addPoint(new Point(d.getX(), d.getY()));
}
return poly;
}
/**
* Returns the list of Dots that, along with this Dot, form an enclosed
* polygon. If this Dot is not part of an enclosure null may be returned.
*
* @return The List of Dots that form an enclosed shape with this Dot, or
* null if this Dot is not part of an enclosure.
*/
public Collection getEnclosingDots() {
return _enclosure;
}
/**
* Returns whether this Dot has an assigned enclosure list of other Dots.
* The result is the same as getEnclosedShape() != null.
*
* @return True if this Dot has an enclosure list of other Dots, false
* otherwise.
*/
public boolean isEnclosed() {
return _enclosure != null;
}
/**
* True if this item is the end of a line.
*
* @return
*/
public boolean isLineEnd() {
// TODO this will need to be redone when enclosure class is added...
// At the moment enclosures are only circles...we don't want circle
// centres to be lineEnds
return _lines.size() > 0;
}
public boolean hasEnclosures() {
return _enclosures.size() > 0;
}
/**
* Method that is called to notify an item that is on the end of a line that
* its line has changed color.
*
* @param c
* the new color for the line
*/
protected void lineColorChanged(Colour c) {
for (Line l : getLines()) {
if (l.getColor() != c)
l.setColor(c);
}
}
/**
* Checks if this item is off the left or top of the screen
*
* @return
*/
public boolean offScreenTopOrLeft() {
Bounds bounds = getBoundingBox();
// Check that the bottom right corner of this item is on the screen
if (bounds.getMaxX() >= 0 && bounds.getMaxY() >= 0) {
return false;
}
// Check if all the items it is connected to are offscreen
for (Item i : getAllConnected()) {
bounds = i.getBoundingBox();
// Check that the bottom right corner of this item is on the screen
if (bounds.getMaxX() >= 0 && bounds.getMaxY() >= 0) {
return false;
}
}
return true;
}
public void setConnectedToAnnotation(boolean val) {
_connectedToAnnotation = val;
}
public boolean isConnectedToAnnotation() {
return _connectedToAnnotation;
}
public boolean hasAction() {
List actions = getAction();
return actions != null && actions.size() > 0;
}
public void setAction(String action)
{
// Want to resize the highlight box for text items if actions are been added
if (action == null || action.length() == 0) {
invalidateCommonTrait(ItemAppearence.LinkChanged);
}
if (_actions == null || _actions.size() == 0) {
invalidateBounds();
_actions = new LinkedList();
} else {
_actions.clear();
}
if (action != null && action.length() > 0) _actions.add(action);
invalidateCommonTrait(ItemAppearence.LinkChanged);
}
protected int getLinkYOffset() {
return 0;
}
protected AxisAlignedBoxBounds getLinkDrawArea() {
return getLinkDrawArea(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
}
/**
* TODO: Revise - it would be good to have a member that defines the link
* dimensions.
*
* @param x
* Left of graphic (i.e not centered)
* @param y
* Above graphic (i.e not centered)
*
* @return The drawing area of the link at the given coordinates.
*/
public AxisAlignedBoxBounds getLinkDrawArea(int x, int y) {
return new AxisAlignedBoxBounds(x + 2, y - 1, 8, 8);
}
/**
* Paint the link symbol for the item if it is a
*
* @param g
*/
protected void paintLink() {
paintLinkGraphic(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
paintKeyGraphic(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
paintPadlockGraphic(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
}
/**
* Paint the link symbol for the item at a given position.
*
* @see #paintLink
*
* @param g
* The graphics to paint with
*
* @param x
* The x position of the link. Left of graphic (i.e not centered)
*
* @param y
* The y position of the link. Above of graphic (i.e not
* centered)
*/
public void paintLinkGraphic(int x, int y) {
boolean hasLink = hasLink();
boolean hasAction = hasAction();
if (hasLink || hasAction) {
GraphicsManager g = EcosystemManager.getGraphicsManager();
Fill fill = new Fill();
Colour colour = null;
Point offset = new Point(x, y);
if (hasLink && hasAction) {
colour = LINK_ACTION_COLOR;
} else if (hasLink) {
colour = LINK_COLOR;
} else if (hasAction) {
colour = ACTION_COLOR;
}
fill.setColour(colour);
// Small circles look rubbish without AA. cts16
g.setAntialiasing(true);
if (hasLink && getLinkMark()) {
g.drawOval(offset, getLinkBounds().getDiameters(), 0.0f, null, colour, HIGHLIGHT_STROKE);
// if the link is not valid, cross out the circle
if (!isLinkValid()) {
g.drawPolygon(getCircleCross(), offset, null, 0.0f, null, colour, HIGHLIGHT_STROKE);
}
}
if (hasAction && getActionMark()) {
g.drawOval(offset, getLinkBounds().getDiameters(), 0.0f, fill, colour, HIGHLIGHT_STROKE);
// if the link is not valid, cross out the circle
if (!isLinkValid() && getLink() != null) {
g.drawPolygon(getCircleCross(), offset, null, 0.0f, null, getParent().getPaintBackgroundColor(), HIGHLIGHT_STROKE);
}
}
g.setAntialiasing(false);
}
}
protected void paintKeyGraphic(int x, int y) {
Colour fontColour = null;
switch (this.keyType()) {
case PartialKey:
fontColour = Colour.LIGHT_GRAY;
break;
case FullKey:
fontColour = Colour.BLACK;
break;
default:
return;
}
GraphicsManager g = EcosystemManager.getGraphicsManager();
g.setAntialiasing(true);
Font font = new Font();
g.drawString("\uD83D\uDD11", new Point(x,y), font, fontColour);
g.setAntialiasing(false);
}
protected void paintPadlockGraphic(int x, int y) {
String encryptionLabel = this.getEncryptionLabel();
if (encryptionLabel != null && encryptionLabel.length() > 0) {
GraphicsManager g = EcosystemManager.getGraphicsManager();
g.setAntialiasing(true);
Font font = new Font();
g.drawString("\uD83D\uDD12", new Point(x,y), font, Colour.BLACK);
g.setAntialiasing(false);
}
}
public KeyType keyType() {
return keyType;
}
public void setKeyType(String s) {
try {
keyType = KeyType.valueOf(s);
} catch (IllegalArgumentException e) {
keyType = KeyType.NotAKey;
}
}
/**
* Gets the distance between the start of the text and the left border of
* the item. This distance changes depending on whether or not the item is
* linked or has an associated action.
*
* @return the gap size in pixels
*/
protected int getLeftMargin() {
return ((getLinkMark() && getLink() != null)
|| (getActionMark() && getAction() != null) ? MARGIN_LEFT
- MARGIN_RIGHT : MARGIN_RIGHT);
}
public String getName() {
return getText();
}
final public String getAbsoluteLinkTemplate() {
return getAbsoluteLink(getLinkTemplate());
}
final public String getAbsoluteLinkFrameset() {
return getAbsoluteLink(getLinkFrameset());
}
final public String getAbsoluteLink() {
return getAbsoluteLink(getLink());
}
/**
* @param link
* @return
*/
private String getAbsoluteLink(String link) {
if (link == null)
return null;
// assert (_parent!= null);
Frame parent = getParentOrCurrentFrame();
if (_parent == null) {
// if parent is null it is an item on the message box
// so it must already be absolute
// assert (!FrameIO.isPositiveInteger(link));
// return link;
}
// if its a relative link then return absolute
if (FrameIO.isPositiveInteger(link)) {
return parent.getFramesetName() + link;
}
return link;
}
public static String convertToAbsoluteLink(String link) {
if (link == null)
return null;
// assert (_parent!= null);
Frame parent = DisplayController.getCurrentFrame();
assert (parent != null);
// if its a relative link then return absolute
if (FrameIO.isPositiveInteger(link)) {
return parent.getFramesetName() + link;
}
return link;
}
/**
* Sets the x and y values of this item ignoring constraints.
*
* @param x
* new x position
* @param y
* new y position
*/
public void setXY(float x, float y) {
_x = x;
_y = y;
}
/**
* Recursive function for getting the path around a shape. This is used to
* get the path that is painted on the screen.
*
* @param visited
* @param points
* @param addToEnd
* @param toExplore
*/
public void appendPath(Collection visited, LinkedList points,
boolean addToEnd, Collection toExplore) {
if (addToEnd) {
// put the start item points into our list
points.addLast(getPosition());
} else {
points.addFirst(getPosition());
}
// Find the line that has not been added yet
LinkedList lines = new LinkedList();
lines.addAll(getLines());
while (!lines.isEmpty()) {
Line l = lines.remove();
// if we haven't visited the line yet visit it
if (!visited.contains(l)) {
visited.add(l);
Item otherEnd = l.getOppositeEnd(this);
// Add all the unexplored lines to our list
while (!lines.isEmpty()) {
l = lines.remove();
// Get the paths for the rest of the lines to be explored
// later
if (!toExplore.contains(l) && !visited.contains(l)) {
toExplore.add(l);
}
}
otherEnd.appendPath(visited, points, addToEnd, toExplore);
}
}
}
/**
* Gets the size of the enclosure that this item is part of. Used to
* determine the paint order of items, with smaller items being painted
* first.
*
* @return the area of the box surrounding the enclosed shape that this item
* is part of
*/
public double getEnclosedArea()
{
AxisAlignedBoxBounds box = getEnclosedBox();
if (box == null) return 0.0;
return box.getWidth() * box.getHeight();
}
/**
* Gets the box encompassing all points that form an enclosure with this item.
*
* @return An axis-aligned box around all enclosure points.
*/
public AxisAlignedBoxBounds getEnclosedBox()
{
if (_enclosure == null) return null;
return AxisAlignedBoxBounds.getEnclosing(getEnclosedShape());
}
public int getEnclosureID()
{
return _enclosure == null ? 0 : _enclosure.hashCode();
}
/**
* Returns the Bounds that surrounds this Item representing this Item's
* 'gravity'.
*
* @return The Bounds surrounding this Item, which represents
* this Items 'gravity'.
*/
public final Bounds getBounds()
{
if (_bounds == null) _bounds = updateBounds();
// DEBUG
if (_bounds == null) {
//System.out.println("updateBounds failed!");
}
return _bounds;
}
public final Bounds getOldBounds()
{
return _oldBounds;
}
public final void invalidateBounds()
{
if (_bounds != null) _oldBounds = _bounds;
_bounds = null;
for (Item surrogate: this.getSurrogates()) {
surrogate.invalidateBounds();
}
}
public final AxisAlignedBoxBounds getBoundingBox()
{
return AxisAlignedBoxBounds.getEnclosing(getBounds());
}
/**
* Shifts the position of the item along the line between this items
* location and a specified point.
*
* @param origin
* @param ratio
*/
public void translate(Point origin, double ratio) {
invalidateCommonTraitForAll(ItemAppearence.PreMoved);
_x = (float) (origin.getX() + ratio * (_x - origin.getX()));
_y = (float) (origin.getY() + ratio * (_y - origin.getY()));
invalidateBounds();
for (Line line : getLines())
line.invalidateBounds();
invalidateCommonTraitForAll(ItemAppearence.PostMoved);
}
private static int[] LinePatterns = new int[] { 0, 10, 20 };
/**
* The rotates through a wheel of dashed lines.
*
* @param amount
* number of rotations around the wheel to toggle by.
*/
public void toggleDashed(int amount) {
// find the index of the current line pattern
int[] currentPattern = getLinePattern();
// Find the current pattern and move to the next pattern in the wheel
for (int i = 0; i < LinePatterns.length; i++) {
if (currentPattern == null || currentPattern[0] == LinePatterns[i]) {
i += LinePatterns.length + amount;
i %= LinePatterns.length;
// if we are at the start of the wheel make it 'null' (solid
// line)
if (i == 0) {
setLinePattern(null);
} else {
setLinePattern(new int[] { LinePatterns[i], LinePatterns[i] });
}
invalidateCommonTrait(ItemAppearence.ToggleDashed);
return;
}
}
}
/**
* For now there can only be one enclosure per item
*
* @param enclosure
*/
public void addEnclosure(XRayable enclosure) {
_enclosures.clear();
_enclosures.add(enclosure);
}
/**
* Gets any XRayable items that have this item as a source.
*
* @return the collection of items that are linked to this item as source.
* Guaranteed not to be null.
*/
public Collection extends XRayable> getEnclosures() {
return _enclosures;
}
public void removeEnclosure(Item i) {
_enclosures.remove(i);
}
public boolean isDeleted() {
return _deleted;
}
/**
* @return The full canvas that this item draws to. Must include
* highlighting bounds
*/
public AxisAlignedBoxBounds getDrawingArea() {
final AxisAlignedBoxBounds boundingBox = getBoundingBox();
return ItemUtils.expandRectangle(
boundingBox,
(int) Math.ceil(Math.max(_highlightThickness, getThickness())) + 1 // + 1 to make sure
);
}
/**
*
* @param area
* @return True if area intersects with this items drawing area.
*/
public final boolean isInDrawingArea(AxisAlignedBoxBounds area)
{
AxisAlignedBoxBounds drawingArea = getDrawingArea();
if (drawingArea == null) return false;
return drawingArea.intersects(area);
}
/**
* Completely invalidates the item - so that it should be redrawn. Note:
* This is handled internally, it should be rare to invoke this externally
*/
public final void invalidateAll()
{
invalidate(getDrawingArea());
}
/**
* Invalidates areas on the parent frame. Purpose: to be called on specific
* areas of the item that needs redrawing.
*
* @param damagedAreas
*/
protected final void invalidate(Bounds[] damagedAreas)
{
if (damagedAreas != null) for (Bounds b : damagedAreas) invalidate(b);
}
/**
* Invalidates areas on the parent frame. Purpose: to be called on specific
* areas of the item that needs redrawing.
*
* @param damagedAreas
*/
protected final void invalidate(Bounds damagedArea)
{
if (damagedArea != null) DisplayController.invalidateItem(this, damagedArea);
}
/**
* Used to invalidate visual traits commonly shared by all items.
*
* @param trait
*/
public final void invalidateCommonTrait(ItemAppearence trait)
{
invalidate(getDamagedArea(trait));
if (_fillColour != null && (trait == ItemAppearence.Added || trait == ItemAppearence.Removed)) {
invalidateFill();
}
}
/**
* Invalidates fill if has one, even if no color is set.
*/
public void invalidateFill()
{
if (isLineEnd() && _enclosure != null) {
invalidate(getEnclosedBox());
}
}
/**
* Default implementation always uses drawing area except for links, where
* the link drawing area is used. Override to make item drawing more
* efficient - defining only parts of the item that needs redrawing.
*
* @see Item.getDrawingArea
*
* @param trait
* The visual trait that has changed.
*
* @return The damaged area according to the visual trait that has changed.
*/
protected AxisAlignedBoxBounds getDamagedArea(ItemAppearence trait)
{
if (trait == ItemAppearence.LinkChanged)
return getLinkDrawArea(); // Invalidate area where link is drawn
return getDrawingArea();
}
public boolean hasVector() {
return _overlay instanceof Vector;
}
public boolean hasOverlay() {
return _overlay != null;
}
public Vector getVector() {
if (_overlay instanceof Vector)
return (Vector) _overlay;
return null;
}
public void setOverlay(Overlay overlay) {
_overlay = overlay;
}
public boolean dontSave() {
/*
* TODO Mike says: checkout if the ID check is still needed- When will
* ID still be -1 when saving a frame? assert (i != null);
*/
// make it save stuff that's off the screen so stuff isn't deleted by panning - jts21
return !_save || !isVisible() || getID() < 0; // || offScreenTopOrLeft();
}
public void setAnchorLeft(Integer anchor) {
this._anchoring.setLeftAnchor(anchor);
if (anchor != null) {
anchorConstraints();
setX(anchor);
}
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_LEFT_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_LEFT_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_LEFT_STR, inheritanceCheckOnSave);
}
}
}
public void setAnchorRight(Integer anchor) {
this._anchoring.setRightAnchor(anchor);
if (anchor != null) {
anchorConstraints();
int width = Math.abs(getBoundsWidth());
//System.err.println("Item::setAnchorRight::Text Content= " + getText() + "; width=" + width);
setX(DisplayController.getFramePaintArea().getMaxX() - anchor - width);
}
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_RIGHT_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_RIGHT_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_RIGHT_STR, inheritanceCheckOnSave);
}
}
}
public void setAnchorTop(Integer anchor) {
this._anchoring.setTopAnchor(anchor);
if (anchor != null) {
anchorConstraints();
setY(anchor);
}
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_TOP_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_TOP_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_TOP_STR, inheritanceCheckOnSave);
}
}
}
public void setAnchorBottom(Integer anchor) {
this._anchoring.setBottomAnchor(anchor);
if (anchor != null) {
anchorConstraints();
setY(DisplayController.getFramePaintArea().getMaxY() - anchor);
}
if (isSurrogate()) {
surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_BOTTOM_STR, false);
Item primary = getPrimary();
if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_BOTTOM_STR)) {
EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_BOTTOM_STR, inheritanceCheckOnSave);
}
}
}
public boolean isAnchored()
{
return _anchoring.isAnchored();
}
public boolean isAnchoredX() {
return _anchoring.isXAnchored();
}
public boolean isAnchoredY() {
return _anchoring.isYAnchored();
}
public Integer getAnchorLeft() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_LEFT_STR)) {
return this.getPrimary().getAnchorLeft();
} else {
return _anchoring.getLeftAnchor();
}
}
public Integer getAnchorRight() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_RIGHT_STR)) {
return this.getPrimary().getAnchorRight();
} else {
return _anchoring.getRightAnchor();
}
}
public Integer getAnchorTop() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_TOP_STR)) {
return this.getPrimary().getAnchorTop();
} else {
return _anchoring.getTopAnchor();
}
}
public Integer getAnchorBottom() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_BOTTOM_STR)) {
return this.getPrimary().getAnchorBottom();
} else {
return _anchoring.getBottomAnchor();
}
}
public String getText() {
if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.TEXT_STR)) {
return this.getPrimary().getText();
} else {
return "@" + getClass().getSimpleName() + ":" + getID();
}
}
public void setText(String text) {
}
public boolean recalculateWhenChanged() {
return false;
}
public boolean update() {
return calculate(getText());
}
public Collection getEnclosedItems() {
return FrameUtils.getItemsEnclosedBy(this.getParentOrCurrentFrame(),
this.getEnclosedShape());
}
public Collection getEnclosedNonAnnotationText() {
Collection items = new LinkedHashSet();
for (Item t : getEnclosedItems()) {
if (t instanceof Text && !t.isAnnotation())
items.add((Text) t);
}
return items;
}
public void dispose() {
setParent(null);
}
/**
* @return
*/
protected boolean hasVisibleBorder() {
return getThickness() > 0 && !isLineEnd() && getBorderColor() != null;
}
public Frame getChild() {
String childName = getAbsoluteLink();
if (childName != null) {
return FrameIO.LoadFrame(childName);
}
return null;
}
public boolean hasLink() {
return _link != null;
}
protected void anchorConnectedOLD(AnchorEdgeType anchorEdgeType, Float delta) {
// Check for a more efficient way to do this!!
// Invalidate all the items
for (Item i : this.getAllConnected()) {
i.invalidateAll();
}
// Move the items
for (Item i : this.getAllConnected()) {
if (i.isLineEnd()) {
if (delta != null) {
if ((anchorEdgeType == AnchorEdgeType.Left) || (anchorEdgeType == AnchorEdgeType.Right)) {
// 'delta' encodes a horizontal (x) move
if (anchorEdgeType == AnchorEdgeType.Left) {
i.setAnchorLeft(null);
}
else {
// must be Right
i.setAnchorRight(null);
}
i.setXY(i.getX() + delta, i.getY());
}
if ((anchorEdgeType == AnchorEdgeType.Top) || (anchorEdgeType == AnchorEdgeType.Bottom)) {
// 'delta; encodes a vertical (y) move
if (anchorEdgeType == AnchorEdgeType.Top) {
i.setAnchorTop(null);
}
else {
// must be Bottom
i.setAnchorBottom(null);
}
i.setXY(i.getX(), i.getY() + delta);
}
}
}
}
// Invalidate them again!!
for (Item i : this.getAllConnected()) {
i.invalidateBounds();
i.invalidateAll();
}
}
protected void anchorConnected(AnchorEdgeType anchorEdgeType, Float delta) {
// Check for a more efficient way to do this!!
// Invalidate all the items
for (Item i : this.getAllConnected()) {
i.invalidateAll();
}
// Move the items
for (Item i : this.getAllConnected()) {
if (i.isLineEnd()) {
if (delta != null) {
if ((anchorEdgeType == AnchorEdgeType.Left) || (anchorEdgeType == AnchorEdgeType.Right)) {
// 'delta' encodes a horizontal (x) move
if (anchorEdgeType == AnchorEdgeType.Left) {
// Processing a Left anchor
// => Anything connected that is *not* anchored to the right should be moved by 'delta'
if (i.getAnchorRight()==null) {
i.setXY(i.getX() + delta, i.getY());
}
}
else {
// Processing a Right anchor
// => Anything connected that is *not* anchored to the left should be moved by 'delta'
if (i.getAnchorLeft()==null) {
i.setXY(i.getX() + delta, i.getY());
}
}
}
if ((anchorEdgeType == AnchorEdgeType.Top) || (anchorEdgeType == AnchorEdgeType.Bottom)) {
// 'delta; encodes a vertical (y) move
if (anchorEdgeType == AnchorEdgeType.Top) {
// Processing a Top anchor
// => Anything connected that is *not* anchored to the bottom should be moved by 'delta'
if (i.getAnchorBottom()==null) {
i.setXY(i.getX(), i.getY() + delta);
}
}
else {
// Processing a Bottom anchor
// => Anything connected that is *not* anchored to the top should be moved by 'delta'
if (i.getAnchorTop()==null) {
// must be Bottom
//i.setAnchorBottom(null);
i.setXY(i.getX(), i.getY() + delta);
}
}
}
}
}
}
anchorConstraints();
// Invalidate them again!!
for (Item i : this.getAllConnected()) {
i.invalidateBounds();
i.invalidateAll();
}
}
/**
* Sets the item to pickup when the user attempts to pick this item up.
* EditTarget has a value of 'this' by default but may be set to other
* values if this item is on a vector.
*
* @param target
* the item to be copied or picked up when the user attempts to
* edit this item.
*/
public void setEditTarget(Item target) {
_editTarget = target;
}
/**
* Gets the item to pickup when the user attempts to pick this item up.
* EditTarget has a value of 'this' by default but may be set to other
* values if this item is on a vector.
*/
public Item getEditTarget() {
return _editTarget;
}
public void scale(Float scale, int originX, int originY) {
setXY((getX() - originX) * scale + originX, (getY() - originY) * scale + originY);
setArrowheadLength(getArrowheadLength() * scale);
float thickness = getThickness();
if (thickness > 0)
setThickness(thickness * scale, false);
// DONT PUT SIZE IN HERE CAUSE IT STUFFS UP CIRCLES
invalidateBounds();
}
protected boolean isVectorItem() {
return _editTarget != this;
}
public AttributeValuePair getAttributeValuePair() {
if (_attributeValuePair == null) {
_attributeValuePair = new AttributeValuePair(getText());
}
return _attributeValuePair;
}
/*
* private static Set