/** * 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 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 _locks = new HashSet(); * * public static void lock(Object itemToLock) { _locks.add(itemToLock); } * * public static void unlock(Object itemToUnlock) { * _locks.remove(itemToUnlock); } * * public static boolean isLocked(Object item) { return * _locks.contains(item); } */ public void setSave(boolean state) { _save = state; } public boolean getSave() { return _save; } public void setAutoStamp(Float rate) { _autoStamp = rate; } public Float getAutoStamp() { return _autoStamp; } public boolean isAutoStamp() { return _autoStamp != null && _autoStamp >= 0.0; } public int getMagnetizedItemLeft() { if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR)) { return this.getPrimary().getMagnetizedItemLeft(); } else { if(_magnetizedItemLeft != null) return _magnetizedItemLeft.getID(); else return -1; } } public void setMagnetizedItemLeft(final Item item) { _magnetizedItemLeft = item; } public void setMagnetizedItemLeft(final int id) { setMagnetizedItemLeft(this.getParent().getItemWithID(id)); if (isSurrogate()) { surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR, false); Item primary = getPrimary(); if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR)) { EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave); primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR, inheritanceCheckOnSave); } } } public int getMagnetizedItemRight() { if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR)) { return this.getPrimary().getMagnetizedItemRight(); } else { if(_magnetizedItemRight != null) return _magnetizedItemRight.getID(); else return -1; } } public void setMagnetizedItemRight(final Item item) { _magnetizedItemRight = item; } public void setMagnetizedItemRight(final int id) { setMagnetizedItemRight(this.getParent().getItemWithID(id)); if (isSurrogate()) { surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR, false); Item primary = getPrimary(); if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR)) { EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave); primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR, inheritanceCheckOnSave); } } } public int getMagnetizedItemTop() { if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR)) { return this.getPrimary().getMagnetizedItemTop(); } else { if(_magnetizedItemTop != null) return _magnetizedItemTop.getID(); else return -1; } } public void setMagnetizedItemTop(final Item item) { _magnetizedItemTop = item; } public void setMagnetizedItemTop(final int id) { setMagnetizedItemTop(this.getParent().getItemWithID(id)); if (isSurrogate()) { surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR, false); Item primary = getPrimary(); if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR)) { EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave); primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR, inheritanceCheckOnSave); } } } public int getMagnetizedItemBottom() { if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR)) { return this.getPrimary().getMagnetizedItemBottom(); } else { if(_magnetizedItemBottom != null) return _magnetizedItemBottom.getID(); else return -1; } } public void setMagnetizedItemBottom(final Item item) { _magnetizedItemBottom = item; } public void setMagnetizedItemBottom(final int id) { setMagnetizedItemBottom(this.getParent().getItemWithID(id)); if (isSurrogate()) { surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR, false); Item primary = getPrimary(); if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR)) { EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave); primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR, inheritanceCheckOnSave); } } } public String getEncryptionLabel() { if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ENCRYPTION_LABEL_STR)) { return this.getPrimary().getEncryptionLabel(); } else { return _encryptionLabel; } } public void setEncryptionLabel(String label) { if (label == null) { _encryptionLabel = null; return; } if (this.getParent().getFrameEncryptionLabel() == null) { MessageBay.displayMessage("Items can only be entrypted if the frame they are on is."); return; } LabelInfo labelResult = Label.getLabel(label); if (!labelResult.is(LabelResult.SuccessResolveLabelToKey)) { MessageBay.displayMessage(labelResult.toString()); return; } String errorMessage = "You do not have sufficient permissions to set the encryption label to " + label; UserAppliedEncryptionPermission p = getParent().getEncryptionPermission().getPermission(getParent().getOwner(), getParent().getGroupMembers()); String homogeneousEncryptionLabel = getParent().getHomogeneousEncryptionLabel(); if (homogeneousEncryptionLabel == null) { homogeneousEncryptionLabel = getParent().getFrameEncryptionLabel(); } if (homogeneousEncryptionLabel == null) { homogeneousEncryptionLabel = EncryptedExpWriter.getLabelNone(); } List hetrogeneousFrameOwnerLabels = getParent().getHetrogeneousFrameOwnerLabels(); switch(p) { case none: MessageBay.errorMessage(errorMessage); return; case homogeneous: if (!homogeneousEncryptionLabel.equals(label)) { MessageBay.errorMessage(errorMessage); return; } break; case hetrogeneous_owner: if (!homogeneousEncryptionLabel.equals(label) && !hetrogeneousFrameOwnerLabels.contains(label)) { MessageBay.errorMessage(errorMessage); return; } break; case hetrogeneous: break; } this.getSurrogates().clear(); this._encryptionLabel = label; //Setup surrogate items. generateSurrogate(labelResult); } public void setEncryptionLabelOnLoad(String label) { this._encryptionLabel = label; } /** * Replaces the given dot item with a text item displaying the given character. * * @param dot * The Dot item to replace. * * @param ch * The character to display as the text for the created Text item. * * @return * The created Text item. */ public static Text replaceDot(Item dot, char ch) { // TODO: Should this make sure 'dot' is actually a Dot and not some other item? cts16 Text text = Text.createText(ch); Item.DuplicateItem(dot, text); FrameUtils.setLastEdited(text); // Copy the lines list so it can be modified List lines = new LinkedList(dot.getLines()); for (Line line : lines) line.replaceLineEnd(dot, text); Frame current = dot.getParentOrCurrentFrame(); current.removeItem(dot); ItemUtils.EnclosedCheck(current.getSortedItems()); return text; // TODO: Should this add the newly-created Text item to the frame? cts16 } /** * Replaces the given text item with a dot */ public static Item replaceText(Item text) { Item dot = new Dot(text.getX(), text.getY(), text.getID()); Item.DuplicateItem(text, dot); List lines = new LinkedList(); lines.addAll(text.getLines()); if (lines.size() > 0) dot.setColor(lines.get(0).getColor()); for (Line line : lines) { line.replaceLineEnd(text, dot); } text.delete(); Frame current = text.getParentOrCurrentFrame(); current.addItem(dot); DisplayController.setCursor(Item.DEFAULT_CURSOR); ItemUtils.EnclosedCheck(current.getSortedItems()); return dot; } public Set getSurrogates() { return surrogateItems; } private void setAsSurrogateFor(Item primary) { this.surrogateFor = primary; } public void addToSurrogates(Item surrogate) { if (this.getEncryptionLabel() == null) { MessageBay.displayMessage("Only Items with encryption labels can have surrogates."); return; } this.getParent().removeItem(surrogate); this.surrogateItems.add(surrogate); surrogate.setAsSurrogateFor(this); this.getParent().addItem(surrogate); EncryptionDetail reencryptOnSave = new EncryptionDetail(EncryptionDetail.Type.ReencryptOnSave); EncryptionDetail unencryptedOnSave = new EncryptionDetail(EncryptionDetail.Type.UnencryptedOnSave); for (Character tag: DefaultFrameWriter.getItemCharTags().keySet()) { if (tag == 'T') { primaryPropertyEncryption.put(tag + "", reencryptOnSave.clone()); } else { primaryPropertyEncryption.put(tag + "", unencryptedOnSave.clone()); } if (tag == 'T' || tag == 'S') { surrogate.surrogatePropertyInheritance.put(tag + "", false); } else { surrogate.surrogatePropertyInheritance.put(tag + "", true); } } for (String tag: DefaultFrameWriter.getItemStrTags().keySet()) { primaryPropertyEncryption.put(tag, unencryptedOnSave.clone()); surrogate.surrogatePropertyInheritance.put(tag + "", true); } } public boolean isSurrogate() { return this.surrogateFor != null; } public Item getPrimary() { return this.surrogateFor; } public EncryptionDetail getEncryptionDetailForTag(String tag) { EncryptionDetail encryptionDetail = primaryPropertyEncryption.get(tag); if (encryptionDetail == null) { EncryptionDetail unencryptedOnSave = new EncryptionDetail(EncryptionDetail.Type.UnencryptedOnSave); return unencryptedOnSave; } else { return encryptionDetail; } } public void setEncryptionDetailForTag(String tag, EncryptionDetail encryptionDetail) { primaryPropertyEncryption.put(tag, encryptionDetail); } public boolean isTagInherited(String tag) { return surrogatePropertyInheritance.get(tag); } public void setTagNotInherited(String tag) { surrogatePropertyInheritance.put(tag, false); } public boolean hasAccessToItemAsPrimary() { String label = this.getEncryptionLabel(); if (this.isSurrogate() || label == null || label.length() == 0) { return true; } return Label.getLabel(label).is(LabelResult.SuccessResolveLabelToKey); } /** * If when setting a property, we find that the primary has a undeciphered value, when we must continue using that undeciphered value * when eventually saving. * @return */ protected boolean subjectToInheritanceCheckOnSave(String tag) { if (tag.equals(DefaultFrameWriter.TYPE_AND_ID_STR)) { return false; } Item primary = getPrimary(); if (primary == null) return false; EncryptionDetail primaryItemTagEncryptionDetail = primary.primaryPropertyEncryption.get(tag); Type primaryItemTagEncryptionDetailType = primaryItemTagEncryptionDetail.getEncryptionDetailType(); return primaryItemTagEncryptionDetailType != EncryptionDetail.Type.UseUndecipheredValueOnSave; } public boolean acceptsKeyboardEnter() { return _acceptsKeyboardEnter; } public void setAcceptsEnter(boolean value) { if (this.getText() != null && this.getText().equals("Beep")) { System.err.println(); } _acceptsKeyboardEnter = value; } private void generateSurrogate(LabelInfo labelResult) { Item copy = this.copy(); if (copy.isAnnotation()) { if (ItemUtils.startsWithTag(copy, ItemUtils.TAG_IMAGE, true)) { String text = copy.getText(); String size = ""; // remove @i tag text = text.replaceFirst("@i:", ""); text = text.replaceAll("\n", ""); text = text.trim(); int dotPos = text.indexOf('.'); if (dotPos >= 0) { int endOfFileNamePos = text.indexOf(' ', dotPos); if (endOfFileNamePos >= 0) { size = text.substring(endOfFileNamePos).trim(); } } String copyText = ItemUtils.GetTag(ItemUtils.TAG_IMAGE) + ": " + Picture.REDACTED_IMAGE_NAME + " " + size; copy.setText(copyText.trim()); copy.setVisible(true); } } else if (copy instanceof Text) { copy.setText("Encrypted"); } // Encrypt XRayables representative files and update pointer. Collection xrayables = this.getEnclosures(); for (XRayable xray: xrayables) { if (xray instanceof Picture) { EncryptedImage.encryptImage((Picture) xray, labelResult.key); Text source = xray._source; String oldName = xray.getName(); String newName = oldName.substring(0, oldName.lastIndexOf('.')) + EncryptedImage.EXPEDITEE_ENCRYPTED_IMAGE_EXTENSION; source.setText(source.getText().replace(oldName, newName)); } } this.addToSurrogates(copy); } }