source: trunk/src/org/expeditee/items/Item.java@ 1505

Last change on this file since 1505 was 1505, checked in by bnemhaus, 4 years ago

New Attributes (and repurposed old ones) to be used for encryption of frames:

  • FrameEncryptionLabel. Used to be EncryptionLabel, which is still the case for items. When applied to a frame, it determines the label used to encrypt the entire frame.
  • HomogeneousEncryptionLabel. Does not yet actually do anything. The future point of this attribute is to provide the label that must be used to encrypt items on the frame when the user has only homogeneous encryption permissions.
  • EncryptionFramePermission. Does not yet actually do anything. The future point of this attribute isto determine if a user is able to change the FrameEncryptionLabel on a frame. Level 0 (none), no they cannot. Level 1 (homogeneous), they can only change it to HomogeneousEncryptionLabel. Level 2 (Hetrogeneous Owner), they can change it to any label as long as the owner of the Frame has that label. Level 3 (Hetrogeneous), they can change it to anything.
  • EncryptionPermission. Does not yet actually do anything. The future point of this attribute is to determine what encryption labels can be applied to items on the frame. Level 0 (none), cannot apply an encryption label. Level 1 (homogeneous), they can only used the label specified in HomogeneousEncryptionLabel. Level 2 (Hetrogeneous Owner), they can only use encryption labels that the owner of the frame has. Level 3 (Hetrogeneous) they can use any labels to encrypt an item.
File size: 123.2 KB
Line 
1/**
2 * Item.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.items;
20
21import java.util.ArrayList;
22import java.util.Collection;
23import java.util.ConcurrentModificationException;
24import java.util.HashMap;
25import java.util.HashSet;
26import java.util.LinkedHashSet;
27import java.util.LinkedList;
28import java.util.List;
29import java.util.Map;
30import java.util.Set;
31
32import org.expeditee.actions.Actions;
33import org.expeditee.actions.IncorrectUseOfStatementException;
34import org.expeditee.actions.Javascript;
35import org.expeditee.actions.Misc;
36import org.expeditee.actions.Simple;
37import org.expeditee.core.Anchoring;
38import org.expeditee.core.Colour;
39import org.expeditee.core.Cursor;
40import org.expeditee.core.Dimension;
41import org.expeditee.core.Fill;
42import org.expeditee.core.Font;
43import org.expeditee.core.GradientFill;
44import org.expeditee.core.Point;
45import org.expeditee.core.Stroke;
46import org.expeditee.core.bounds.AxisAlignedBoxBounds;
47import org.expeditee.core.bounds.Bounds;
48import org.expeditee.core.bounds.EllipticalBounds;
49import org.expeditee.core.bounds.PolygonBounds;
50import org.expeditee.encryption.core.EncryptedImage;
51import org.expeditee.encryption.items.KeyType;
52import org.expeditee.encryption.items.surrogates.EncryptionDetail;
53import org.expeditee.encryption.items.surrogates.EncryptionDetail.Type;
54import org.expeditee.encryption.items.surrogates.Label.LabelInfo;
55import org.expeditee.encryption.items.surrogates.Label.LabelResult;
56import org.expeditee.encryption.items.surrogates.Label;
57import org.expeditee.gio.EcosystemManager;
58import org.expeditee.gio.GraphicsManager;
59import org.expeditee.gio.gesture.StandardGestureActions;
60import org.expeditee.gui.AttributeValuePair;
61import org.expeditee.gui.DisplayController;
62import org.expeditee.gui.Frame;
63import org.expeditee.gui.FrameIO;
64import org.expeditee.gui.FrameUtils;
65import org.expeditee.gui.FreeItems;
66import org.expeditee.gui.MessageBay;
67import org.expeditee.gui.Overlay;
68import org.expeditee.gui.Vector;
69import org.expeditee.io.Conversion;
70import org.expeditee.io.DefaultFrameWriter;
71import org.expeditee.settings.UserSettings;
72import org.expeditee.settings.legacy.LegacyFeatures;
73import org.expeditee.simple.Context;
74import org.expeditee.stats.AgentStats;
75import org.expeditee.stats.Formatter;
76import org.mozilla.javascript.Scriptable;
77import org.mozilla.javascript.ScriptableObject;
78
79/**
80 * Represents everything that can be drawn on the screen (text, lines, dots,
81 * images). Each specific type is a subclass of Item.
82 *
83 * @author jdm18
84 *
85 */
86public abstract class Item implements Comparable<Item>, Runnable {
87
88 public enum HighlightMode {
89 None, // The item has no highlighting
90 Enclosed, // The item is part of the current enclosure
91 Connected, // The item is connected to the current item
92 Disconnect, // The item is a free item
93 Normal // The item is the current item
94 }
95
96 /** Which edge of the window things are anchored to. */
97 public enum AnchorEdgeType {
98 None, Left, Right, Top, Bottom
99 }
100
101 public static final float SIZE_NOT_APPLICABLE = Float.NaN;
102
103 public static final Float DEFAULT_THICKNESS = 2f;
104
105 public static final Float MINIMUM_THICKNESS = 0f;
106
107 public static final Float MINIMUM_PAINT_THICKNESS = 1f;
108
109 protected static final Stroke.JOIN DEFAULT_JOIN = Stroke.JOIN.ROUND;
110
111 protected static final Stroke.CAP DEFAULT_CAP = Stroke.CAP.BUTT;
112
113 protected static final Stroke DOT_STROKE = new Stroke(DEFAULT_THICKNESS, DEFAULT_CAP, DEFAULT_JOIN);
114
115 protected static final Stroke HIGHLIGHT_STROKE = new Stroke(MINIMUM_THICKNESS, DEFAULT_CAP, DEFAULT_JOIN);
116
117 public static final int LEFT_MARGIN = 13;
118
119 public static final int NEAR_DISTANCE = 15;
120
121 public static final int DEFAULT_HIGHLIGHT_THICKNESS = 2;
122
123 /** The default colour to draw highlighting in */
124 public static final Colour DEFAULT_HIGHLIGHT = Colour.RED;
125
126 public static final Colour DEPRESSED_HIGHLIGHT = Colour.GREEN;
127
128 public static final Colour ALTERNATE_HIGHLIGHT = Colour.BLUE;
129
130 public static final Colour LINK_COLOR = Colour.BLACK;
131
132 public static final Colour ACTION_COLOR = Colour.BLACK;
133
134 public static final Colour LINK_ACTION_COLOR = Colour.RED;
135
136 public static final Colour DEFAULT_FOREGROUND = Colour.BLACK;
137
138 public static final Colour DEFAULT_BACKGROUND = Colour.WHITE;
139
140 public static final Colour TRANSPARENT = new Colour(0, 0, 0, 0);
141
142 /** The number of pixels highlighting should extend around Items. */
143 public static final int XGRAVITY = 3;
144
145 public static final int MARGIN_RIGHT = 2;
146
147 public static final int MARGIN_LEFT = 15;
148
149 protected static final double DEFAULT_ARROWHEAD_RATIO = 0.3; // used to be 0.5
150
151 public static final double DEFAULT_ARROWHEAD_NIB_PERC = 0.75;
152
153 public static final Colour GREEN = Colour.GREEN.darker();
154
155 //public static final int UNCHANGED_CURSOR = -100;
156
157 public static final Cursor.CursorType DEFAULT_CURSOR = Cursor.CursorType.DEFAULT;
158
159 public static final Cursor.CursorType HIDDEN_CURSOR = Cursor.CursorType.CUSTOM;
160
161 public static final Cursor.CursorType TEXT_CURSOR = Cursor.CursorType.TEXT;
162
163 public static final Cursor.CursorType CROP_CURSOR = Cursor.CursorType.CROSSHAIR;
164
165 /** The default value for integer attributes */
166 public static final int DEFAULT_INTEGER = -1;
167
168 private static final int BRIGHTNESS = 185;
169
170 /** Contains all dots (including this one) that form an enclosure if this dot is part of an enclosing shape. */
171 private Collection<Item> _enclosure = null;
172
173 /** The area which this item covers (including its gravity). */
174 private Bounds _bounds = null;
175
176 /** The area this item covered before it was invalidated. */
177 private Bounds _oldBounds = null;
178
179 protected boolean _connectedToAnnotation = false;
180
181 protected boolean _save = true;
182
183 /** The angle of change for gradient colour fills (in radians). */
184 private double _gradientAngle = 0.0;
185
186 private Tooltip _tooltip = new Tooltip();
187
188 protected Anchoring _anchoring = new Anchoring();
189
190 /** The highlight mode for this item. */
191 protected HighlightMode _highlightMode = HighlightMode.None;
192
193 private Point _offset = new Point(0, 0);
194
195 protected float _x;
196 protected float _y;
197
198 private int _id;
199
200 private Item _editTarget = this;
201
202 private String _creationDate = null;
203
204 /** Whether or not this item should display a mark indicating it has a link. */
205 private boolean _linkMark = true;
206
207 /** Whether or not this item should display a mark indicating it has an action. */
208 private boolean _actionMark = true;
209
210 /** TODO: Appears unused? cts16 */
211 private boolean _highlight = true;
212
213 // private int _maxWidth = -1;
214
215 private String _owner = null;
216
217 private String _link = null;
218
219 private boolean _linkHistory = true;
220
221 private StringBuffer _tag = new StringBuffer();
222
223 private List<String> _actionCursorEnter = null;
224
225 private List<String> _actionCursorLeave = null;
226
227 private List<String> _actionEnterFrame = null;
228
229 private List<String> _actionLeaveFrame = null;
230
231 private PermissionTriple _permissionTriple = null;
232
233 private UserAppliedPermission _overlayPermission = null;
234
235 /** The primary fill colour of this item. A fill colour of null represents transparent. */
236 private Colour _fillColour = null;
237
238 /** The secondary fill colour if this item has a gradient fill. Null represents no gradient. */
239 private Colour _gradientColour = null;
240
241 /** The primary draw colour of this item. Null represents the default colour. */
242 private Colour _foregroundColour = null;
243
244 /** The colour to draw highlights on this item. */
245 protected Colour _highlightColour = DEFAULT_HIGHLIGHT;
246
247 /** The background colour for this item. */
248 private Colour _backgroundColour = null;
249
250 private Colour _colorBorder = null;
251
252 private Colour _colorTopShadow = null;
253
254 private Colour _colorBottomShadow = null;
255
256 /** The shape representing the circle drawn next to link/action items. */
257 private static EllipticalBounds _linkCircle = null;
258
259 /** The shape representing the cross drawn next to invalid links. */
260 private static PolygonBounds _linkCircleCross = null;
261
262 private Frame _parent = null;
263 private Frame _oldParent = null;
264
265 protected int _highlightThickness = 2;
266
267 protected int _vectorHighlightThickness = 1;
268
269 // arrowhead parameters
270 private float _arrowheadLength = 0;
271 private double _arrowheadRatio = DEFAULT_ARROWHEAD_RATIO;
272 private double _arrowheadNibPerc = DEFAULT_ARROWHEAD_NIB_PERC;
273
274 private PolygonBounds _arrowhead = null;
275
276 // the list of lines that this point is part of.
277 private List<Line> _lines = new ArrayList<Line>();
278
279 private int[] _linePattern = null;
280
281 private boolean _floating = false;
282
283 // list of points constrained with this point
284 private List<Constraint> _constraints = new ArrayList<Constraint>();
285
286 private List<String> _actions = null;
287
288 private String _formula = null;
289
290 private String _link_frameset = null;
291
292 private String _link_template = null;
293
294 private String _fillPattern = null;
295
296 private boolean _visible = true;
297
298 private float _thickness = -1.0F;
299
300 protected Collection<XRayable> _enclosures = new HashSet<XRayable>();
301
302 private boolean _deleted = false;
303
304 private Overlay _overlay = null;
305
306 protected AttributeValuePair _attributeValuePair = null;
307
308 private Float _autoStamp = null;
309
310 private Item _magnetizedItemLeft = null;
311
312 private Item _magnetizedItemRight = null;
313
314 private Item _magnetizedItemTop = null;
315
316 private Item _magnetizedItemBottom = null;
317
318 private String _encryptionLabel = null;
319
320 protected DotType _type = DotType.square;
321
322 protected boolean _filled = true;
323
324 private Data _data = new Data();
325
326 // Used via reflection by AttributeUtils to determine if the boolean value is different from default.
327 public static final boolean acceptsKeyboardEnterDefault = false;
328 private boolean _acceptsKeyboardEnter = acceptsKeyboardEnterDefault;
329
330 private Item surrogateFor = null;
331 private Set<Item> surrogateItems = new HashSet<Item>();
332 private static Map<String, EncryptionDetail> primaryPropertyEncryptionDefault = new HashMap<String, EncryptionDetail>();
333 private static Map<String, Boolean> surrogatePropertyInheritanceDefault = new HashMap<String, Boolean>();
334 protected Map<String, EncryptionDetail> primaryPropertyEncryption = new HashMap<String, EncryptionDetail>(primaryPropertyEncryptionDefault);
335 protected Map<String, Boolean> surrogatePropertyInheritance = new HashMap<String, Boolean>(surrogatePropertyInheritanceDefault);
336
337 private KeyType keyType = KeyType.NotAKey;
338
339 {
340 EncryptionDetail unencryptedOnSave = new EncryptionDetail(EncryptionDetail.Type.UnencryptedOnSave);
341 for (String tag: DefaultFrameWriter.getItemTags().keySet()) {
342 if (tag == "T" || tag == "S") {
343 surrogatePropertyInheritanceDefault.put(tag, false);
344 } else {
345 surrogatePropertyInheritanceDefault.put(tag, true);
346 }
347 primaryPropertyEncryptionDefault.put(tag, unencryptedOnSave);
348 }
349 }
350
351 /** Just calls source.duplicateOnto(dest). */
352 public static void DuplicateItem(Item source, Item dest)
353 {
354 if (source == null) return;
355
356 source.duplicateOnto(dest);
357 }
358
359 /** Sets the properties of dest so that they match this item's properties. */
360 public void duplicateOnto(Item dest)
361 {
362 if (dest == null) return;
363
364 dest.setX(this.getX());
365 dest.setY(this.getY());
366
367 dest.setActions(this.getAction());
368 dest.setActionCursorEnter(this.getActionCursorEnter());
369 dest.setActionCursorLeave(this.getActionCursorLeave());
370 dest.setActionEnterFrame(this.getActionEnterFrame());
371 dest.setActionLeaveFrame(this.getActionLeaveFrame());
372 dest.setActionMark(this.getActionMark());
373
374 dest.setBackgroundColor(this.getBackgroundColor());
375 dest.setBottomShadowColor(this.getBottomShadowColor());
376 dest.setColor(this.getColor());
377 dest.setBorderColor(this.getBorderColor());
378
379 dest.setTooltips(this.getTooltip());
380 dest.setData(this.getData());
381 dest.setTag(this.getTag());
382 dest.setFillColor(this.getFillColor());
383 dest.setGradientColor(this.getGradientColor());
384 dest.setGradientAngle(this.getGradientAngle());
385 dest.setFillPattern(this.getFillPattern());
386
387 dest.setHighlight(this.getHighlight());
388 dest.setLink(this.getLink());
389 dest.setLinkFrameset(this.getLinkFrameset());
390 dest.setLinkMark(this.getLinkMark());
391 dest.setLinkTemplate(this.getLinkTemplate());
392
393 // dest.setWidth(this.getWidth());
394
395 dest.setOffset(this.getOffset());
396 // dest.setOwner(this.getOwner());
397 dest.setThickness(this.getThickness());
398 dest.setSize(this.getSize());
399 dest.setTopShadowColor(this.getTopShadowColor());
400 dest.setLinePattern(this.getLinePattern());
401
402 dest.setFloating(this.isFloating());
403 dest.setArrow(this.getArrowheadLength(), this.getArrowheadRatio(), this.getArrowheadNibPerc());
404 dest.setDotType(this.getDotType());
405 dest.setFilled(this.getFilled());
406 /*
407 * Calling the methods will move the item... This messes things up when
408 * the user uses backspace to delete a text line end
409 */
410 // dest._anchorLeft = this._anchorLeft;
411 // dest._anchorRight = this._anchorRight;
412 // dest._anchorTop = this._anchorTop;
413 // dest._anchorBottom = this._anchorBottom;
414 dest.setFormula(this.getFormula());
415 dest._overlay = this._overlay;
416 dest._highlightMode = this._highlightMode;// SelectedMode.None;
417 // dest._highlightColor = this._highlightColor;
418 // dest.setHighlight(this.getHighlight());
419
420 dest._visible = this._visible;
421
422 Frame parent = DisplayController.getCurrentFrame();
423 if (parent == null) parent = this.getParentOrCurrentFrame();
424 dest.setParent(parent);
425
426 /*
427 * TODO MIKE says maybe we could tighten up and only give items ID's if
428 * their current ID is negative?
429 */
430 if (parent != null) {
431 dest.setID(parent.getNextItemID());
432 }
433
434 String currentUser = UserSettings.UserName.get();
435// if (parent != null && !currentUser.equals(parent.getOwner())) {
436// //dest.setOwner(currentUser);
437// } else {
438// System.err.println("I have duplicated a item and made it owned by "
439// + "current user, whereas the old code would not have "
440// + "changed ownership at this time.");
441// System.err.println("Item: " + dest + ", Class: " + dest.getClass());
442// System.err.println("Current owner: " + dest.getOwner());
443// System.err.println("Current user: " + currentUser);
444// }
445 dest.setOwner(currentUser);
446 }
447
448 public void setDotType(DotType type) {
449 invalidateAll();
450 _type = type;
451 invalidateAll();
452 if (isSurrogate()) {
453 surrogatePropertyInheritance.put(DefaultFrameWriter.DOT_TYPE_STR, false);
454 Item primary = getPrimary();
455 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DOT_TYPE_STR)) {
456 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
457 primary.primaryPropertyEncryption.put(DefaultFrameWriter.DOT_TYPE_STR, inheritanceCheckOnSave);
458 }
459 }
460 }
461
462 public DotType getDotType() {
463 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.DOT_TYPE_STR)) {
464 return this.getPrimary().getDotType();
465 } else {
466 return _type;
467 }
468 }
469
470
471 public void setFilled(boolean filled) {
472 invalidateAll();
473 _filled = filled;
474 invalidateAll();
475
476 if (isSurrogate()) {
477 surrogatePropertyInheritance.put(DefaultFrameWriter.FILLED_STR, false);
478 Item primary = getPrimary();
479 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DOT_TYPE_STR)) {
480 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
481 primary.primaryPropertyEncryption.put(DefaultFrameWriter.FILLED_STR, inheritanceCheckOnSave);
482 }
483 }
484 }
485
486 public boolean getFilled() {
487 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.FILLED_STR)) {
488 return this.getPrimary().getFilled();
489 } else {
490 return _filled;
491 }
492 }
493
494 /**
495 * Sets the angle of colour change for gradient colour fills.
496 *
497 * @param gradientAngle The new angle of colour change.
498 */
499 public void setGradientAngle(double gradientAngle) {
500 _gradientAngle = gradientAngle;
501
502 for (Line line : _lines) {
503 Item other = line.getOppositeEnd(this);
504 if (other.getGradientAngle() != gradientAngle) other.setGradientAngle(gradientAngle);
505 }
506
507 invalidateCommonTrait(ItemAppearence.GradientColor);
508 invalidateFill();
509
510 if (isSurrogate()) {
511 surrogatePropertyInheritance.put(DefaultFrameWriter.GRADIENT_ANGLE_STR, false);
512 Item primary = getPrimary();
513 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DOT_TYPE_STR)) {
514 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
515 primary.primaryPropertyEncryption.put(DefaultFrameWriter.GRADIENT_ANGLE_STR, inheritanceCheckOnSave);
516 }
517 }
518 }
519
520 /**
521 * Gets the angle of colour change for gradient fills.
522 *
523 * @return The angle of colour change.
524 */
525 public double getGradientAngle() {
526 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.GRADIENT_ANGLE_STR)) {
527 return this.getPrimary().getGradientAngle();
528 } else {
529 return _gradientAngle;
530 }
531 }
532
533 /**
534 * Gets the gravity for this item. Gravity is the distance from the item at which mouse interaction
535 * applies to the item (like a small buffer zone so you don't need to click exactly on the item).
536 *
537 * @return The gravity distance for this item.
538 */
539 public int getGravity()
540 {
541 if (isVectorItem()) return 2;
542
543 return UserSettings.Gravity.get();
544 }
545
546 /**
547 * Whether or not line highlights should be shown.
548 * TODO: Not really an item method is it? Goes straight to user settings. Refactor. cts16
549 *
550 * @return <code>true</code> if line highlighting should be shown, <code>false</code> otherwise.
551 */
552 public static boolean shouldShowLineHighlight()
553 {
554 return UserSettings.LineHighlight.get();
555 }
556
557 /**
558 * Sets the highlight mode for this item.
559 *
560 * @param mode The new highlight mode.
561 */
562 public void setHighlightMode(HighlightMode mode)
563 {
564 if (hasPermission(UserAppliedPermission.followLinks) || getEditTarget().hasPermission(UserAppliedPermission.followLinks)) {
565 if (_highlightMode != mode) {
566 _highlightMode = mode;
567 this.invalidateCommonTrait(ItemAppearence.HighlightModeChanged);
568 }
569 }
570 }
571
572 public void setOverlayPermission(UserAppliedPermission overlayPermission)
573 {
574 _overlayPermission = overlayPermission;
575 }
576
577 public void setPermission(PermissionTriple permissionPair) {
578 List<String> groupMembers = getParent() != null ? getParent().getGroupMembers() : new ArrayList<String>();
579 _permissionTriple = permissionPair;
580 if (_permissionTriple.getPermission(_owner, groupMembers) == UserAppliedPermission.denied) {
581 this.getParent().moveItemToBodyHiddenDueToPermission(this);
582 }
583
584 if (isSurrogate()) {
585 surrogatePropertyInheritance.put(DefaultFrameWriter.PERMISSION_STR, false);
586 Item primary = getPrimary();
587 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DOT_TYPE_STR)) {
588 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
589 primary.primaryPropertyEncryption.put(DefaultFrameWriter.PERMISSION_STR, inheritanceCheckOnSave);
590 }
591 }
592 }
593
594 public PermissionTriple getPermission() {
595 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.PERMISSION_STR)) {
596 return this.getPrimary().getPermission();
597 } else {
598 return _permissionTriple;
599 }
600 }
601
602 public UserAppliedPermission getUserAppliedPermission() {
603 List<String> groupMembers = getParent() != null ? getParent().getGroupMembers() : new ArrayList<String>();
604 String owner = _owner != null ? _owner : _parent != null ? _parent.getOwner() : null;
605 if(_permissionTriple != null) return _permissionTriple.getPermission(owner, groupMembers);
606 if(_overlayPermission != null) return _overlayPermission;
607 if(_parent != null) return _parent.getUserAppliedPermission();
608 return UserAppliedPermission.full;
609 }
610
611 public boolean hasPermission(UserAppliedPermission permission) {
612 return getUserAppliedPermission().ordinal() >= permission.ordinal();
613 }
614
615 protected Item() {
616 _creationDate = Formatter.getLongDateTime();
617 }
618
619 /**
620 * Adds an action to this Item.
621 *
622 * @param action
623 * The name of the action to add to this Item.
624 */
625 public void addAction(String action)
626 {
627 if (action == null || action.equals("")) return;
628
629 if (_actions == null) {
630 _actions = new LinkedList<String>();
631 }
632
633 _actions.add(action);
634
635 if (_actions.size() == 1) {
636 invalidateBounds();
637 invalidateCommonTrait(ItemAppearence.LinkChanged);
638 }
639 }
640
641 public void addAllConnected(Collection<Item> connected)
642 {
643 if (!connected.contains(this)) connected.add(this);
644
645 for (Item item : getConnected()) {
646 if (!connected.contains(item)) {
647 item.addAllConnected(connected);
648 }
649 }
650 }
651
652 /**
653 * Adds the given Constraint to this Dot
654 *
655 * @param c
656 * The Constraint to set this Dot as a member of.
657 */
658 public void addConstraint(Constraint c)
659 {
660 // do not add duplicate constraint
661 if (_constraints.contains(c))
662 return;
663
664 _constraints.add(c);
665 }
666
667 /**
668 * Adds a given line to the list of lines that this Point is an end for.
669 *
670 * @param line
671 * The Line that this Point is an end of.
672 */
673 public void addLine(Line line)
674 {
675 if (_lines.contains(line)) {
676 return;
677 }
678
679 _lines.add(line);
680 }
681
682 /**
683 * Items are sorted by their Y coordinate on the screen.
684 *
685 * @param i
686 * The Item to compare this Item to
687 * @return a negative integer, zero, or a positive integer as this object is
688 * less than, equal to, or greater than the specified object.
689 */
690 public int compareTo(Item i)
691 {
692 return getY() - i.getY();
693 }
694
695 /**
696 * Every Item has an area around it defined by a Shape (typically a
697 * rectangle), this method returns true if the given x,y pair lies within
698 * the area and false otherwise.
699 *
700 * @param p
701 * The coordinate to check
702 * @return True if the Shape around this Item contains the given x,y pair,
703 * false otherwise.
704 */
705 public boolean contains(Point p)
706 {
707 return getBounds().contains(p);
708 }
709
710 /**
711 * Returns a deep copy of this Item, note: it is up to the receiver to
712 * change the Item ID etc as necessary.
713 *
714 * @return A deep copy of this Item.
715 */
716 public abstract Item copy();
717
718 public void delete()
719 {
720 _deleted = true;
721 }
722
723 @Override
724 public boolean equals(Object o)
725 {
726 if (o == null)
727 return false;
728 if (getClass().equals(o.getClass())) {
729 Item i = (Item) o;
730 return i.getID() == getID()
731 && ((i.getParent() == _parent) || (i.getParent() != null && i
732 .getParent().equals(_parent)));
733 } else
734 return false;
735 }
736
737 /**
738 * Returns a list of any action code that is currently associated with this
739 * Item
740 *
741 * @return A List of action code associated with this Item, or null if none
742 * has been assigned.
743 */
744 public List<String> getAction() {
745 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_STR)) {
746 return this.getPrimary().getAction();
747 } else {
748 return _actions;
749 }
750 }
751
752 public List<String> getData() {
753 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.DATA_STR)) {
754 return this.getPrimary().getData();
755 } else {
756 return _data.getData();
757 }
758 }
759
760 public List<String> getActionCursorEnter() {
761 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_CURSOR_ENTER_STR)) {
762 return this.getPrimary().getActionCursorEnter();
763 } else {
764 return _actionCursorEnter;
765 }
766 }
767
768 public List<String> getActionCursorLeave() {
769 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_CURSOR_LEAVE_STR)) {
770 return this.getPrimary().getActionCursorLeave();
771 } else {
772 return _actionCursorLeave;
773 }
774 }
775
776 public List<String> getActionEnterFrame() {
777 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_ENTER_FRAME_STR)) {
778 return this.getPrimary().getActionEnterFrame();
779 } else {
780 return _actionEnterFrame;
781 }
782 }
783
784 public List<String> getActionLeaveFrame() {
785 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_LEAVE_FRAME_STR)) {
786 return this.getPrimary().getActionLeaveFrame();
787 } else {
788 return _actionLeaveFrame;
789 }
790 }
791
792 public boolean getActionMark() {
793 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ACTION_MARK_STR)) {
794 return this.getPrimary().getActionMark();
795 } else {
796 return _actionMark;
797 }
798 }
799
800 /**
801 * Gets all the items connected to this item. Uses a recursive approach to
802 * search connected points.
803 *
804 * @return
805 */
806 public Collection<Item> getAllConnected()
807 {
808 Collection<Item> list = new LinkedHashSet<Item>();
809 addAllConnected(list);
810 return list;
811 }
812
813/* public Area getArea() {
814 return new Area(getPolygon());
815 }*/
816
817 public String getArrow() {
818 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ARROW_STR)) {
819 return this.getPrimary().getArrow();
820 } else {
821 if (!hasVisibleArrow())
822 return null;
823
824 String ratio = "" + getArrowheadRatio();
825 if (ratio.length() - ratio.indexOf(".") > 2)
826 ratio = ratio.substring(0, ratio.indexOf(".") + 3);
827
828 return getArrowheadLength() + " " + ratio + " " + getArrowheadNibPerc();
829 }
830 }
831
832 public PolygonBounds getArrowhead()
833 {
834 return _arrowhead;
835 }
836
837 public float getArrowheadLength()
838 {
839 return _arrowheadLength;
840 }
841
842 public double getArrowheadRatio()
843 {
844 return _arrowheadRatio;
845 }
846
847 public double getArrowheadNibPerc()
848 {
849 return _arrowheadNibPerc;
850 }
851
852 public Colour getBackgroundColor() {
853 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.BACKGROUND_COLOR_STR)) {
854 return this.getPrimary().getBackgroundColor();
855 } else {
856 return _backgroundColour;
857 }
858 }
859
860 public Colour getBorderColor() {
861 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.BORDER_COLOR_STR)) {
862 return this.getPrimary().getBorderColor();
863 } else {
864 return _colorBorder;
865 }
866 }
867
868 /**
869 * Returns the Color being used to shade the bottom half of this Item's
870 * border. This can be NULL if no Color is being used
871 *
872 * @return The Color displayed on the bottom\right half of this Item's
873 * border.
874 */
875 public Colour getBottomShadowColor()
876 {
877 return _colorBottomShadow;
878 }
879
880 /**
881 * Returns the height (in pixels) of this Item's surrounding area.
882 *
883 * @return The height (in pixels) of this Item's surrounding area as
884 * returned by getArea().
885 */
886 public int getBoundsHeight()
887 {
888 return AxisAlignedBoxBounds.getEnclosing(getBounds()).getHeight();
889 }
890
891 /**
892 * Returns the width (in pixels) of this Item's surrounding area.
893 *
894 * @return The width (in pixels) of this Item's surrounding area as returned
895 * by getArea().
896 */
897 public int getBoundsWidth()
898 {
899 return AxisAlignedBoxBounds.getEnclosing(getBounds()).getWidth();
900 }
901
902 // TODO: Remove magic constants. cts16
903 public EllipticalBounds getLinkBounds()
904 {
905 if (_linkCircle == null) {
906 _linkCircle = new EllipticalBounds(new Point(6, 3), 7);
907 }
908
909 return _linkCircle;
910 }
911
912 protected PolygonBounds getCircleCross()
913 {
914
915 if (_linkCircleCross == null) {
916 _linkCircleCross = new PolygonBounds();
917
918 EllipticalBounds poly = getLinkBounds();
919 int x1 = poly.getMinX();
920 int x2 = poly.getMaxX();
921 int y1 = poly.getMinY();
922 int y2 = poly.getMaxY();
923 int midX = (x2 + x1) / 2;
924 int midY = (y2 + y1) / 2;
925
926 _linkCircleCross.addPoint(new Point(x1, y1));
927 _linkCircleCross.addPoint(new Point(x2, y2));
928 _linkCircleCross.addPoint(new Point(midX, midY));
929 _linkCircleCross.addPoint(new Point(x1, y2));
930 _linkCircleCross.addPoint(new Point(x2, y1));
931 _linkCircleCross.addPoint(new Point(midX, midY));
932 }
933
934 return _linkCircleCross;
935 }
936
937 public Colour getColor() {
938 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.COLOR_STR)) {
939 return this.getPrimary().getColor();
940 } else {
941 return _foregroundColour;
942 }
943 }
944
945 public Collection<Item> getConnected()
946 {
947 List<Item> conn = new LinkedList<Item>();
948 conn.add(this);
949 conn.addAll(getEnclosures());
950 conn.addAll(getLines());
951 return conn;
952 }
953
954 public String getConstraintIDs() {
955 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.CONSTRAINT_IDS_STR)) {
956 return this.getPrimary().getConstraintIDs();
957 } else {
958 if (_constraints == null || _constraints.size() == 0)
959 return null;
960
961 String cons = "";
962
963 for (Constraint c : _constraints)
964 cons += c.getID() + " ";
965
966 return cons.trim();
967 }
968 }
969
970 /*
971 * public void setLinkValid(boolean val) { _isValidLink = val; }
972 */
973
974 /**
975 * Returns a List of any Constraints that this Dot is a memeber of.
976 *
977 * @return a List of Constraints that this Dot is a member of.
978 */
979 public List<Constraint> getConstraints()
980 {
981 return _constraints;
982 }
983
984 public String getTag()
985 {
986 if (_tag != null && _tag.length() > 0)
987 return _tag.toString();
988 return null;
989 }
990
991 public String getDateCreated() {
992 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.DATE_CREATED_STR)) {
993 return this.getPrimary().getDateCreated();
994 } else {
995 return _creationDate;
996 }
997 }
998
999 public Colour getFillColor() {
1000 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.FILL_COLOR_STR)) {
1001 return this.getPrimary().getFillColor();
1002 } else {
1003 return _fillColour;
1004 }
1005 }
1006
1007 public String getFillPattern() {
1008 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.FILL_PATTERN_STR)) {
1009 return this.getPrimary().getFillPattern();
1010 } else {
1011 return _fillPattern;
1012 }
1013 }
1014
1015 public String getFirstAction()
1016 {
1017 if (_actions == null || _actions.size() == 0)
1018 return null;
1019 return _actions.get(0);
1020 }
1021
1022 /**
1023 * Gets the value of <code>_highlight</code> for this item.
1024 * TODO: Appears unused? cts16.
1025 *
1026 * @return The value of <code>_highlight</code>.
1027 */
1028 public boolean getHighlight() {
1029 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.HIGHLIGHT_STR)) {
1030 return this.getPrimary().getHighlight();
1031 } else {
1032 return _highlight;
1033 }
1034 }
1035
1036 public Colour getHighlightColor()
1037 {
1038 if (_highlightColour.equals(getPaintColor())) return getAlternateHighlightColor();
1039
1040 return getDefaultHighlightColor();
1041 }
1042
1043 /**
1044 * Returns the ID of this Item, which must be unique for the Frame.
1045 *
1046 * @return The ID of this Item.
1047 *
1048 * TODO: What does it mean to have a negative ID# (as used in TDFC)? cts16
1049 */
1050 public int getID() {
1051 return _id;
1052 }
1053
1054 /**
1055 * Returns the list of IDs of the Lines that this Dot is an end of.
1056 *
1057 * @return The list of Line IDs that this point is part of.
1058 */
1059 public String getLineIDs() {
1060 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINE_IDS_STR)) {
1061 return this.getPrimary().getLineIDs();
1062 } else {
1063 String lineID = null;
1064
1065 if (_lines.size() > 0) {
1066 lineID = "" + _lines.get(0).getID();
1067
1068 for (int i = 1; i < _lines.size(); i++)
1069 lineID += " " + _lines.get(i).getID();
1070 }
1071
1072 return lineID;
1073 }
1074 }
1075
1076 public int[] getLinePattern() {
1077 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINE_PATTERN_STR)) {
1078 return this.getPrimary().getLinePattern();
1079 } else {
1080 return _linePattern;
1081 }
1082 }
1083
1084 /**
1085 * Returns a list of Lines where this Dot is an end.
1086 *
1087 * @return A list of the Lines that this Dot is an end for or null if no
1088 * Lines have been added.
1089 */
1090 public List<Line> getLines()
1091 {
1092 return _lines;
1093 }
1094
1095 /**
1096 * Returns the name of a Frame that this Item links to, or null if this Item
1097 * has no link.
1098 *
1099 * @return The name of a Frame that this Item links to (if any) or null if
1100 * this Item does not link to anything.
1101 */
1102 public String getLink() {
1103 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINK_STR)) {
1104 return this.getPrimary().getLink();
1105 } else {
1106 return _link;
1107 }
1108 }
1109
1110 public String getFormula() {
1111 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.FORMULA_STR)) {
1112 return this.getPrimary().getFormula();
1113 } else {
1114 return _formula;
1115 }
1116 }
1117
1118 public boolean hasFormula()
1119 {
1120 return _formula != null;
1121 }
1122
1123 public boolean hasAttributeValuePair()
1124 {
1125 return _attributeValuePair != null && _attributeValuePair.hasPair();
1126 }
1127
1128 public void setFormula(String formula) {
1129 _formula = formula;
1130
1131 if (isSurrogate()) {
1132 surrogatePropertyInheritance.put(DefaultFrameWriter.FORMULA_STR, false);
1133 Item primary = getPrimary();
1134 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.FORMULA_STR)) {
1135 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
1136 primary.primaryPropertyEncryption.put(DefaultFrameWriter.FORMULA_STR, inheritanceCheckOnSave);
1137 }
1138 }
1139 }
1140
1141 public boolean calculate(String formula)
1142 {
1143 setFormula(formula);
1144 return true;
1145 }
1146
1147 public String getLinkFrameset() {
1148 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINK_FRAMESET_STR)) {
1149 return this.getPrimary().getLinkFrameset();
1150 } else {
1151 return _link_frameset;
1152 }
1153 }
1154
1155 public boolean getLinkMark() {
1156 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINK_MARK_STR)) {
1157 return this.getPrimary().getLinkMark();
1158 } else {
1159 return _linkMark;
1160 }
1161 }
1162
1163 public String getLinkTemplate() {
1164 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINK_TEMPLATE_STR)) {
1165 return this.getPrimary().getLinkTemplate();
1166 } else {
1167 return _link_template;
1168 }
1169 }
1170
1171 public Point getOffset()
1172 {
1173 return _offset;
1174 }
1175
1176 public String getOwner() {
1177 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.OWNER_STR)) {
1178 return this.getPrimary().getOwner();
1179 } else {
1180 return _owner;
1181 }
1182 }
1183
1184 public Colour getPaintBackgroundColor()
1185 {
1186 Colour colorBackground = getBackgroundColor();
1187 if (colorBackground == null) {
1188 if (getParent() != null && getParent().getBackgroundColor() != null)
1189 return getParent().getBackgroundColor();
1190
1191 return DEFAULT_BACKGROUND;
1192 }
1193
1194 return colorBackground;
1195 }
1196
1197 /**
1198 * Returns the foreground Color of this Item.
1199 *
1200 * @return The Color of this item (foreground)
1201 */
1202 public final Colour getPaintColor()
1203 {
1204 // If color is null then get the paint foregroundColor for the frame the
1205 // item is on which is a color adjusted to suit the background
1206 Colour color = getColor();
1207
1208 if (color == null) {
1209 if (getParent() != null)
1210 return getParent().getPaintForegroundColor();
1211
1212 Frame current = DisplayController.getCurrentFrame();
1213 if (current == null) {
1214 return DEFAULT_FOREGROUND;
1215 }
1216 return current.getPaintForegroundColor();
1217 }
1218
1219 return color;
1220 }
1221
1222 public final Colour getPaintBorderColor()
1223 {
1224 // If color is null then get the paint foregroundColor for the frame the
1225 // item is on which is a color adjusted to suit the background
1226 Colour color = getBorderColor();
1227
1228 if (color == null) {
1229 if (getParent() != null)
1230 return getParent().getPaintForegroundColor();
1231
1232 Frame current = DisplayController.getCurrentFrame();
1233 if (current == null) {
1234 return DEFAULT_FOREGROUND;
1235 }
1236 return current.getPaintForegroundColor();
1237 }
1238
1239 return color;
1240 }
1241
1242 protected Colour getPaintHighlightColor()
1243 {
1244 Colour highlightColor = getDefaultHighlightColor();
1245 if (hasVisibleBorder()) {
1246 if (getPaintBorderColor().equals(highlightColor)) {
1247 highlightColor = getDefaultHighlightColor();
1248 }
1249 } else if (getPaintBackgroundColor().equals(highlightColor)) {
1250 highlightColor = getDefaultHighlightColor();
1251 }
1252
1253 if (getParent() != null && getParent().getPaintBackgroundColor().equals(highlightColor)) {
1254 highlightColor = getParent().getPaintForegroundColor();
1255 }
1256
1257 if (hasVisibleBorder()) {
1258 if (highlightColor.equals(getBorderColor()) && getThickness() == getHighlightThickness()) {
1259 highlightColor = highlightColor.clone();
1260 highlightColor.setAlpha(Colour.FromComponent255(150));
1261 }
1262 }
1263
1264 return highlightColor;
1265 }
1266
1267 protected Colour getDefaultHighlightColor()
1268 {
1269 if (isVectorItem() && !this.contains(EcosystemManager.getInputManager().getCursorPosition())) {
1270 return Colour.FromRGB255(255, BRIGHTNESS, BRIGHTNESS);
1271 }
1272 return _highlightColour;
1273 }
1274
1275 protected Colour getAlternateHighlightColor()
1276 {
1277 if (isVectorItem() && !this.contains(EcosystemManager.getInputManager().getCursorPosition())) {
1278 return Colour.FromRGB255(BRIGHTNESS, BRIGHTNESS, 255);
1279 }
1280 return ALTERNATE_HIGHLIGHT;
1281 }
1282
1283 protected int getHighlightThickness()
1284 {
1285 if (isVectorItem()) return _vectorHighlightThickness;
1286
1287 return _highlightThickness;
1288 }
1289
1290 public final Frame getParent()
1291 {
1292 return _parent;
1293 }
1294
1295 /** Gets the position of this item. */
1296 public final Point getPosition() {
1297 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.POSITION_STR)) {
1298 return this.getPrimary().getPosition();
1299 } else {
1300 return new Point(getX(), getY());
1301 }
1302 }
1303
1304 /**
1305 * Returns the size of this Item. For Text this is the Font size, for Lines
1306 * and Dots this is the thickness.
1307 *
1308 * @return The size of this Item.
1309 */
1310 public float getSize()
1311 {
1312 return SIZE_NOT_APPLICABLE;
1313 }
1314
1315 /**
1316 * Returns the Color being used to shade the top half of this Item's border.
1317 * This can be NULL if no Color is being used
1318 *
1319 * @return The Color displayed on the top\left half of this Item's border.
1320 */
1321 public Colour getTopShadowColor()
1322 {
1323 return _colorTopShadow;
1324 }
1325
1326 public String getTypeAndID() {
1327 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.TYPE_AND_ID_STR)) {
1328 return this.getPrimary().getTypeAndID();
1329 } else {
1330 return "T " + getID();
1331 }
1332 }
1333
1334 public Integer getWidthToSave() {
1335 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.WIDTH_TO_SAVE_STR)) {
1336 return this.getPrimary().getWidthToSave();
1337 } else {
1338 return getWidth();
1339 }
1340 }
1341
1342 public Integer getMinWidthToSave() {
1343 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MIN_WIDTH_TO_SAVE_STR)) {
1344 return this.getPrimary().getMinWidthToSave();
1345 } else {
1346 return getMinWidth();
1347 }
1348 }
1349
1350 public Integer getWidth()
1351 {
1352 return null;
1353 }
1354
1355 public Integer getMinWidth() {
1356 return null;
1357 }
1358
1359 public int getHeight()
1360 {
1361 return 0;
1362 }
1363
1364 /**
1365 * Returns the X coordinate of this Item on the screen
1366 *
1367 * @return The X coordinate of this Item on the screen
1368 */
1369 public int getX() {
1370 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.POSITION_STR)) {
1371 return this.getPrimary().getX();
1372 } else {
1373 return Math.round(_x);
1374 }
1375 }
1376
1377 /**
1378 * Returns the Y coordinate of this Item on the screen
1379 *
1380 * @return The Y coordinate of this Item on the screen
1381 */
1382 public int getY() {
1383 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.POSITION_STR)) {
1384 return this.getPrimary().getY();
1385 } else {
1386 return Math.round(_y);
1387 }
1388 }
1389
1390 public boolean hasVisibleArrow()
1391 {
1392 return isLineEnd() && getArrowheadRatio() != 0 && getArrowheadLength() != 0;
1393 }
1394
1395 /**
1396 * Checks if the given Shape intersects with the Shape around this Item.
1397 *
1398 * @param s
1399 * The Shape to check.
1400 * @return True if the two Shapes overlap, False otherwise.
1401 */
1402 public boolean intersects(PolygonBounds otherBounds)
1403 {
1404 if (otherBounds == null) return false;
1405
1406 Bounds thisBounds = getBounds();
1407
1408 // Need to do this check for circles
1409 if (otherBounds.equals(thisBounds)) return true;
1410
1411 boolean intersects = otherBounds.intersects(thisBounds);
1412
1413 /*if (intersects) {
1414 System.err.println("Found intersection between this item (" + this + ") with bounds: " + thisBounds + "...and...");
1415 System.err.println("item with bounds: " + otherBounds.toString());
1416 }*/
1417 return intersects;
1418
1419 // Need to check the second equality so that we dont pick up circles
1420 // inside other circles
1421 //return !a.isEmpty() && !a.equals(new Area(p));
1422 }
1423
1424 /**
1425 * Note: Pictures always return False, as they should be drawn even when no
1426 * other annotation Items are.
1427 *
1428 * @return True if this Item is an annotation, False otherwise.
1429 */
1430 public boolean isAnnotation()
1431 {
1432 return false;
1433 }
1434
1435 public boolean isFloating()
1436 {
1437 return _floating;
1438 }
1439
1440 public boolean isFrameName()
1441 {
1442 if (this.getParent() == null || this.getParent().getNameItem() != this)
1443 return false;
1444 return true;
1445 }
1446
1447 public boolean isFrameTitle()
1448 {
1449 if (this.getParent() == null || this.getParent().getTitleItem() != this)
1450 return false;
1451 return true;
1452 }
1453
1454 /**
1455 * Returns True if this Item is currently highlighted.
1456 *
1457 * @return True if this Item is currently highlighted on the screen, False
1458 * otherwise.
1459 */
1460 public boolean isHighlighted()
1461 {
1462 if (isFloating())
1463 return false;
1464 return _highlightMode != HighlightMode.None;
1465 }
1466
1467 /**
1468 * Tests if the item link is a valid framename, that is, the String must
1469 * begin with a character, end with a number with 0 or more letters and
1470 * numbers in between. If there is a dot in the framename all the chars
1471 * after it must be digits.
1472 *
1473 * @return True if the given framename is proper, false otherwise.
1474 */
1475 public boolean isLinkValid()
1476 {
1477 if (FrameIO.isPositiveInteger(getLink()))
1478 return true;
1479
1480 if (FrameIO.isValidFrameName(getLink()))
1481 return true;
1482 return false;
1483 }
1484
1485 /**
1486 * Checks if the given point is 'near' to the item. Here 'near' means within a certain distance
1487 * of the axis-aligned box bounding the item's polygon.
1488 *
1489 * @param x
1490 * The x-coordinate of the point to check.
1491 *
1492 * @param y
1493 * The y-coordinate of the point to check.
1494 *
1495 * @return
1496 * True if the given point is 'near' to the item, false otherwise.
1497 */
1498 public boolean isNear(int x, int y)
1499 {
1500 AxisAlignedBoxBounds box = ItemUtils.expandRectangle(getBoundingBox(), NEAR_DISTANCE * 2);
1501
1502 return box.contains(x, y);
1503 }
1504
1505 public boolean isOldTag()
1506 {
1507 if (this instanceof Text)
1508 if (((Text) this).getTextList().get(0).toLowerCase().equals("@old"))
1509 return true;
1510 return false;
1511 }
1512
1513 /**
1514 * Merges this Item with the given Item. The merger Item should be left
1515 * unchanged after this method. The merger may or may not be the same class
1516 * as this Item, exact behaviour depends on the subclass, No-op is allowed.
1517 *
1518 * @param merger
1519 * The Item to merge with
1520 * @return any Item that should remain on the cursor
1521 */
1522 public abstract Item merge(Item merger, int mouseX, int mouseY);
1523
1524 /**
1525 * Displays this item directly on the screen. Note: All Items are
1526 * responsible for their own drawing, buffering, etc.
1527 *
1528 * @param g
1529 * The Graphics to draw this Item on.
1530 */
1531 public abstract void paint();
1532
1533 public void setTooltips(final List<String> tooltips)
1534 {
1535 if (tooltips == null || tooltips.size() == 0) {
1536 _tooltip = new Tooltip();
1537 } else {
1538 for (final String content: tooltips) _tooltip.addTooltip(content, this);
1539 }
1540 }
1541
1542 public void setTooltip(final String tooltip) {
1543 if(tooltip != null && tooltip.trim().length() > 0) {
1544 _tooltip.addTooltip(tooltip, this);
1545 }
1546
1547 if (isSurrogate()) {
1548 surrogatePropertyInheritance.put(DefaultFrameWriter.TOOLTIP_STR, false);
1549 Item primary = getPrimary();
1550 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.TOOLTIP_STR)) {
1551 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
1552 primary.primaryPropertyEncryption.put(DefaultFrameWriter.TOOLTIP_STR, inheritanceCheckOnSave);
1553 }
1554 }
1555 }
1556
1557 public List<String> getTooltip() {
1558 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.TOOLTIP_STR)) {
1559 return this.getPrimary().getTooltip();
1560 } else {
1561 return _tooltip.asStringList();
1562 }
1563 }
1564
1565 public Collection<Text> getTooltipItems()
1566 {
1567 return _tooltip.getTooltips();
1568 }
1569
1570 public void clearTooltips()
1571 {
1572 final Frame frame = this.getParent();
1573 if(_tooltip != null) {
1574 for(final Text tooltip: _tooltip.getTooltips()) frame.removeItem(tooltip);
1575 }
1576 }
1577
1578 public void paintTooltip()
1579 {
1580 final Bounds bounds = AxisAlignedBoxBounds.getEnclosing(this.getBoundingBox());
1581 Dimension frameSize = DisplayController.getFramePaintAreaSize();
1582
1583 int x = bounds.getMaxX();
1584
1585 // If the tooltip goes off the right side of the window, move it left so it's completely on
1586 if(x + _tooltip.getWidth() > frameSize.getWidth()) {
1587 x = frameSize.getWidth() - _tooltip.getWidth();
1588 }
1589
1590 int y = bounds.getMaxY();
1591
1592 if(y + _tooltip.getCollectiveHeight() > frameSize.getHeight()) {
1593 y = (bounds.getMinY() + bounds.getMaxY()) / 2 - _tooltip.getCollectiveHeight();
1594 }
1595
1596 for(final Text tooltip : _tooltip.getTooltips()) {
1597 this.getParent().addItem(tooltip);
1598 tooltip.setPosition(x, y);
1599 tooltip.paint();
1600 y += tooltip.getHeight();
1601 }
1602 }
1603
1604 public void paintFill() {
1605 Colour fillColor = getFillColor();
1606 if (fillColor != null && getEnclosingDots() != null) {
1607 Fill fill = getFill();
1608 EcosystemManager.getGraphicsManager().drawPolygon(getEnclosedShape(), null, null, 0.0f, fill, null, null);
1609 }
1610 }
1611
1612 protected Fill getFill() {
1613 Fill fill;
1614 Colour fillColour = getFillColor();
1615 if (isFloating()) {
1616 // TODO experiment with adding alpha when picking up filled
1617 // items... Slows things down quite alot!!
1618 // TODO: Does nothing as it stands... cts16
1619 fillColour = new Colour(fillColour.getRed(), fillColour.getGreen(),
1620 fillColour.getBlue(), fillColour.getAlpha());
1621 }
1622 Colour gradientColor = getGradientColor();
1623 PolygonBounds poly = getEnclosedShape();
1624 if (gradientColor != null && poly != null) {
1625 /*
1626 * It is slow when painting gradients... modify so this is only done
1627 * once unless it is resized...
1628 */
1629 AxisAlignedBoxBounds b = AxisAlignedBoxBounds.getEnclosing(poly);
1630 double rads = getGradientAngle();
1631 double cos = Math.cos(rads);
1632 double sin = Math.sin(rads);
1633
1634 Point fromPoint = new Point((int) (b.getMinX() + b.getWidth() * (0.2 * cos + 0.5)), (int) (b.getMinY() + b.getHeight() * (0.2 * sin + 0.5)));
1635 Point toPoint = new Point((int) (b.getMinX() + b.getWidth() * (-0.8 * cos + 0.5)), (int) (b.getMinY() + b.getHeight() * (-0.8 * sin + 0.5)));
1636
1637 fill = new GradientFill(fillColour, fromPoint, gradientColor, toPoint);
1638 } else {
1639 fill = new Fill(fillColour);
1640 }
1641
1642 return fill;
1643 }
1644
1645 /**
1646 * This method performs all the actions in an items list. If it contains a
1647 * link as well the link is used as the source frame for all actions.
1648 */
1649 public void performActions() {
1650 Frame sourceFrame = null;
1651 Item sourceItem = FreeItems.getItemAttachedToCursor();
1652
1653 if (sourceItem == null) {
1654 sourceItem = this;
1655 } else {
1656 for (Item i : sourceItem.getAllConnected()) {
1657 if (i instanceof Text) {
1658 sourceItem = i;
1659 break;
1660 }
1661 }
1662 }
1663
1664 // TODO decide whether to have items or
1665 // if a link exists make it the source frame for this action
1666 if (getLink() != null) {
1667 sourceFrame = FrameUtils.getFrame(getAbsoluteLink());
1668 }
1669 // if no link exists or the link is bad then use the
1670 // currently displayed frame as the source frame for the
1671 // action
1672 if (sourceFrame == null) {
1673 // For actions like format they rely on this being set to the
1674 // current frame incase the item being activated is on an overlay
1675 sourceFrame = DisplayController.getCurrentFrame();
1676 }
1677
1678 for (String s : getAction()) {
1679 Object returnValue;
1680 if (LegacyFeatures.UseLegacyActionArgumentMapping.get()) {
1681 returnValue = Actions.LegacyPerformActionCatchErrors(sourceFrame, sourceItem, s);
1682 } else {
1683 returnValue = Actions.PerformActionCatchErrors(sourceFrame, sourceItem, s, this);
1684 }
1685
1686 if (returnValue != null) {
1687 FreeItems.getInstance().clear();
1688 if (returnValue instanceof Item) {
1689 Misc.attachToCursor(((Item) returnValue).getAllConnected());
1690 } else if (returnValue instanceof Collection) {
1691 try {
1692 Misc.attachToCursor((Collection) returnValue);
1693 } catch (Exception e) {
1694 e.printStackTrace();
1695 }
1696 } else {
1697 Misc.attachStatsToCursor(returnValue.toString());
1698 }
1699 }
1700 }
1701 }
1702
1703 /**
1704 * Removes all constraints that this item has.
1705 *
1706 */
1707 public void removeAllConstraints() {
1708 while (_constraints.size() > 0) {
1709 Constraint c = _constraints.get(0);
1710 c.getEnd().removeConstraint(c);
1711 c.getStart().removeConstraint(c);
1712 }
1713 }
1714
1715 /**
1716 * Clears the list of Lines that this Dot is an end of. Note: This only
1717 * clears this Dot's list and does not have any affect on the Lines or other
1718 * Dots.
1719 */
1720 public void removeAllLines() {
1721 for (Line l : _lines) {
1722 l.invalidateAll();
1723 }
1724 _lines.clear();
1725 }
1726
1727 /**
1728 * Removes the given Constraint from the list of constraints that this Dot
1729 * is a part of.
1730 *
1731 * @param c
1732 * The Constraint that this Dot is no longer a part of.
1733 */
1734 public void removeConstraint(Constraint c) {
1735 _constraints.remove(c);
1736 }
1737
1738 /**
1739 * Removes the given Line from the list of lines that this Dot is an end
1740 * for.
1741 *
1742 * @param line
1743 * The Line that this Dot is no longer an end of.
1744 */
1745 public void removeLine(Line line) {
1746 if (_lines.remove(line))
1747 line.invalidateAll();
1748 }
1749
1750 public void run() {
1751 try {
1752
1753 List<String> action = this.getAction();
1754 if (action != null) {
1755 String action_name = action.get(0);
1756 if (action_name.equalsIgnoreCase("RunJavascriptFrame")){
1757 // Associate a new Context with this thread
1758 org.mozilla.javascript.Context javascript_context = org.mozilla.javascript.Context.enter();
1759 try {
1760 Scriptable javascript_scope = javascript_context.initStandardObjects();
1761 Context simple_context = new Context();
1762
1763
1764 //Object jsDisplayIO = org.mozilla.javascript.Context.javaToJS(org.expeditee.gui.DisplayIO, javascript_scope);
1765 //ScriptableObject.putProperty(javascript_scope, "displayIO", jsDisplayIO);
1766
1767
1768 Object jsSimpleContext = org.mozilla.javascript.Context.javaToJS(simple_context, javascript_scope);
1769 ScriptableObject.putProperty(javascript_scope, "simpleContext", jsSimpleContext);
1770
1771 Object jsErr = org.mozilla.javascript.Context.javaToJS(System.err, javascript_scope);
1772 ScriptableObject.putProperty(javascript_scope, "err", jsErr);
1773
1774 Object jsOut = org.mozilla.javascript.Context.javaToJS(System.out, javascript_scope);
1775 ScriptableObject.putProperty(javascript_scope, "out", jsOut);
1776
1777 Javascript.ProgramStarted();
1778 Javascript.RunFrameAndReportError(this, javascript_context,javascript_scope);
1779 MessageBay.displayMessage(AgentStats.getStats(), GREEN);
1780 }
1781 finally {
1782 org.mozilla.javascript.Context.exit();
1783 }
1784 }
1785 }
1786 else {
1787
1788 // assume it is a simple program that is to be run
1789 Simple.ProgramStarted();
1790 Context simple_context = new Context();
1791 Simple.RunFrameAndReportError(this, simple_context);
1792 MessageBay.displayMessage(AgentStats.getStats(), GREEN);
1793 }
1794 } catch (ConcurrentModificationException ce) {
1795 ce.printStackTrace();
1796 } catch (IncorrectUseOfStatementException ise) {
1797 MessageBay.linkedErrorMessage(ise.getMessage());
1798 MessageBay.displayMessage("See SIMPLE doc for ["
1799 + ise.getStatement() + "] statement", ise.getStatement()
1800 + "1", Colour.CYAN.darker(), true, null);
1801 } catch (Exception e) {
1802 MessageBay.linkedErrorMessage(e.getMessage());
1803 }
1804 Simple.ProgramFinished();
1805 // Need to repaint any highlights etc
1806 DisplayController.requestRefresh(true);
1807 }
1808
1809 /**
1810 * Check if it has a relative link if so make it absolute.
1811 *
1812 */
1813 public void setAbsoluteLink() {
1814 String link = getLink();
1815 if (link == null)
1816 return;
1817 // Check if all the characters are digits and hence it is a relative
1818 // link
1819 if (!FrameIO.isPositiveInteger(link))
1820 return;
1821
1822 // Make it an absolute link
1823 String framesetName;
1824
1825 if (_parent == null)
1826 framesetName = DisplayController.getCurrentFrame().getFramesetName();
1827 else
1828 framesetName = _parent.getFramesetName();
1829
1830 setLink(framesetName + link);
1831 }
1832
1833 /**
1834 * Sets any action code that should be associated with this Item Each entry
1835 * in the list is one line of code
1836 *
1837 * @param actions
1838 * The lines of code to associate with this Item
1839 */
1840 public void setActions(List<String> actions) {
1841 if (actions == null || actions.size() == 0) {
1842 invalidateCommonTrait(ItemAppearence.LinkChanged);
1843 _actions = null;
1844 } else {
1845 _actions = new LinkedList<String>(actions);
1846 }
1847
1848 // Want to resize the highlight box for text items if actions have been added
1849 invalidateBounds();
1850 invalidateCommonTrait(ItemAppearence.LinkChanged);
1851
1852 if (isSurrogate()) {
1853 surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_STR, false);
1854 Item primary = getPrimary();
1855 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_STR)) {
1856 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
1857 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_STR, inheritanceCheckOnSave);
1858 }
1859 }
1860 }
1861
1862 public void setData(List<String> data) {
1863 _data.setData(data);
1864 }
1865
1866 public void setData(String data) {
1867 _data.setData(data);
1868 }
1869
1870 public void addToData(String dataItem) {
1871 _data.addToData(dataItem);
1872
1873 if (isSurrogate()) {
1874 surrogatePropertyInheritance.put(DefaultFrameWriter.DATA_STR, false);
1875 Item primary = getPrimary();
1876 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DATA_STR)) {
1877 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
1878 primary.primaryPropertyEncryption.put(DefaultFrameWriter.DATA_STR, inheritanceCheckOnSave);
1879 }
1880 }
1881 }
1882
1883 public boolean hasData(String dataItem) {
1884 return _data.hasData(dataItem);
1885 }
1886
1887 public void setActionCursorEnter(List<String> enter) {
1888 _actionCursorEnter = enter;
1889
1890 if (isSurrogate()) {
1891 surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_CURSOR_ENTER_STR, false);
1892 Item primary = getPrimary();
1893 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_CURSOR_ENTER_STR)) {
1894 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
1895 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_CURSOR_ENTER_STR, inheritanceCheckOnSave);
1896 }
1897 }
1898 }
1899
1900 public void setActionCursorLeave(List<String> leave) {
1901 _actionCursorLeave = leave;
1902
1903 if (isSurrogate()) {
1904 surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_CURSOR_LEAVE_STR, false);
1905 Item primary = getPrimary();
1906 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_CURSOR_LEAVE_STR)) {
1907 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
1908 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_CURSOR_LEAVE_STR, inheritanceCheckOnSave);
1909 }
1910 }
1911 }
1912
1913 public void setActionEnterFrame(List<String> enter) {
1914 _actionEnterFrame = enter;
1915
1916 if (isSurrogate()) {
1917 surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_ENTER_FRAME_STR, false);
1918 Item primary = getPrimary();
1919 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_ENTER_FRAME_STR)) {
1920 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
1921 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_ENTER_FRAME_STR, inheritanceCheckOnSave);
1922 }
1923 }
1924 }
1925
1926 public void setActionLeaveFrame(List<String> leave) {
1927 _actionLeaveFrame = leave;
1928
1929 if (isSurrogate()) {
1930 surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_LEAVE_FRAME_STR, false);
1931 Item primary = getPrimary();
1932 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_LEAVE_FRAME_STR)) {
1933 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
1934 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_LEAVE_FRAME_STR, inheritanceCheckOnSave);
1935 }
1936 }
1937 }
1938
1939 public void setActionMark(boolean val) {
1940 if (!val) invalidateCommonTrait(ItemAppearence.LinkChanged);
1941 invalidateBounds();
1942 _actionMark = val;
1943 if (val) invalidateCommonTrait(ItemAppearence.LinkChanged);
1944
1945 if (isSurrogate()) {
1946 surrogatePropertyInheritance.put(DefaultFrameWriter.ACTION_MARK_STR, false);
1947 Item primary = getPrimary();
1948 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ACTION_MARK_STR)) {
1949 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
1950 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ACTION_MARK_STR, inheritanceCheckOnSave);
1951 }
1952 }
1953 }
1954
1955 /**
1956 * Sets whether this Item is an Annotation.
1957 *
1958 * @param val
1959 * True if this Item is an Annotation, False otherwise.
1960 */
1961 public abstract void setAnnotation(boolean val);
1962
1963 /**
1964 * Used to set this Line as an Arrow. If length and ratio are 0, no arrow is
1965 * shown.
1966 *
1967 * @param length
1968 * The how far down the shaft of the line the arrowhead should
1969 * come.
1970 * @param ratio
1971 * The ratio of the arrow's length to its width.
1972 */
1973 public void setArrow(float length, double ratio, double nib_perc) {
1974 _arrowheadLength = length;
1975 _arrowheadRatio = ratio;
1976 _arrowheadNibPerc = nib_perc;
1977 updateArrowPolygon();
1978
1979 if (isSurrogate()) {
1980 surrogatePropertyInheritance.put(DefaultFrameWriter.ARROW_STR, false);
1981 Item primary = getPrimary();
1982 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ARROW_STR)) {
1983 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
1984 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ARROW_STR, inheritanceCheckOnSave);
1985 }
1986 }
1987 }
1988
1989 public void setArrow(float length, double ratio) {
1990 setArrow(length,ratio,DEFAULT_ARROWHEAD_NIB_PERC);
1991 }
1992
1993 public void setArrowhead(PolygonBounds arrow) {
1994 _arrowhead = arrow;
1995 }
1996
1997 public void setArrowheadLength(float length) {
1998 _arrowheadLength = length;
1999 updateArrowPolygon();
2000 }
2001
2002 public void setArrowheadRatio(double ratio) {
2003 _arrowheadRatio = ratio;
2004 updateArrowPolygon();
2005 }
2006
2007 public void setArrowheadNibPerc(double perc) {
2008 _arrowheadNibPerc = perc;
2009 updateArrowPolygon();
2010 }
2011
2012 public void setBackgroundColor(Colour c) {
2013 if (c != _backgroundColour) {
2014 _backgroundColour = c;
2015 invalidateCommonTrait(ItemAppearence.BackgroundColorChanged);
2016 }
2017
2018 if (isSurrogate()) {
2019 surrogatePropertyInheritance.put(DefaultFrameWriter.BACKGROUND_COLOR_STR, false);
2020 Item primary = getPrimary();
2021 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.BACKGROUND_COLOR_STR)) {
2022 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2023 primary.primaryPropertyEncryption.put(DefaultFrameWriter.BACKGROUND_COLOR_STR, inheritanceCheckOnSave);
2024 }
2025 }
2026 }
2027
2028 public void setBorderColor(Colour c) {
2029 if (c != _colorBorder) {
2030 _colorBorder = c;
2031 invalidateCommonTrait(ItemAppearence.BorderColorChanged);
2032 }
2033
2034 if (isSurrogate()) {
2035 surrogatePropertyInheritance.put(DefaultFrameWriter.BORDER_COLOR_STR, false);
2036 Item primary = getPrimary();
2037 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.BORDER_COLOR_STR)) {
2038 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2039 primary.primaryPropertyEncryption.put(DefaultFrameWriter.BORDER_COLOR_STR, inheritanceCheckOnSave);
2040 }
2041 }
2042 }
2043
2044 /**
2045 * Sets the Color to use on the bottom and right sections of this Item's
2046 * border. If top is NULL, then the Item's background Color will be used.
2047 *
2048 * @param top
2049 * The Color to display in the bottom and right sections of this
2050 * Item's border.
2051 */
2052 public void setBottomShadowColor(Colour bottom) {
2053 _colorBottomShadow = bottom;
2054 }
2055
2056 /**
2057 * Sets the foreground Color of this Item to the given Color.
2058 *
2059 * @param c
2060 */
2061 public void setColor(Colour c) {
2062 if (c != _foregroundColour) {
2063 _foregroundColour = c;
2064 invalidateCommonTrait(ItemAppearence.ForegroundColorChanged);
2065 if (hasVector()) {
2066 // TODO make this more efficient so it only repaints the items
2067 // for this vector
2068 StandardGestureActions.Refresh();
2069 }
2070 }
2071 }
2072
2073 public void setConstraintIDs(String IDs) {
2074 if (isSurrogate()) {
2075 surrogatePropertyInheritance.put(DefaultFrameWriter.CONSTRAINT_IDS_STR, false);
2076 Item primary = getPrimary();
2077 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.CONSTRAINT_IDS_STR)) {
2078 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2079 primary.primaryPropertyEncryption.put(DefaultFrameWriter.CONSTRAINT_IDS_STR, inheritanceCheckOnSave);
2080 }
2081 }
2082 }
2083
2084 public void setConstraints(List<Constraint> constraints) {
2085 _constraints = constraints;
2086 }
2087
2088 public void setTag(String newData) {
2089 if (newData != null)
2090 _tag = new StringBuffer(newData);
2091 else
2092 _tag = null;
2093 }
2094
2095 /**
2096 * Sets the created date of this Frame to the given String.
2097 *
2098 * @param date
2099 * The date to use for this Frame.
2100 */
2101 public void setDateCreated(String date) {
2102 _creationDate = date;
2103
2104 if (isSurrogate()) {
2105 surrogatePropertyInheritance.put(DefaultFrameWriter.DATE_CREATED_STR, false);
2106 Item primary = getPrimary();
2107 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.DATE_CREATED_STR)) {
2108 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2109 primary.primaryPropertyEncryption.put(DefaultFrameWriter.DATE_CREATED_STR, inheritanceCheckOnSave);
2110 }
2111 }
2112 }
2113
2114 public void setFillColor(Colour c) {
2115
2116 _fillColour = c;
2117
2118 for (Line line : _lines) {
2119 Item other = line.getOppositeEnd(this);
2120 if (other.getFillColor() != c) {
2121 other.setFillColor(c);
2122 }
2123 }
2124
2125 invalidateCommonTrait(ItemAppearence.FillColor);
2126 invalidateFill();
2127
2128 if (isSurrogate()) {
2129 surrogatePropertyInheritance.put(DefaultFrameWriter.FILL_COLOR_STR, false);
2130 Item primary = getPrimary();
2131 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.FILL_COLOR_STR)) {
2132 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2133 primary.primaryPropertyEncryption.put(DefaultFrameWriter.FILL_COLOR_STR, inheritanceCheckOnSave);
2134 }
2135 }
2136 }
2137
2138 public void setGradientColor(Colour c) {
2139 _gradientColour = c;
2140
2141 for (Line line : _lines) {
2142 Item other = line.getOppositeEnd(this);
2143 if (other.getGradientColor() != c)
2144 other.setGradientColor(c);
2145 }
2146
2147 invalidateCommonTrait(ItemAppearence.GradientColor);
2148 invalidateFill();
2149
2150 if (isSurrogate()) {
2151 surrogatePropertyInheritance.put(DefaultFrameWriter.GRADIENT_COLOR_STR, false);
2152 Item primary = getPrimary();
2153 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.GRADIENT_COLOR_STR)) {
2154 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2155 primary.primaryPropertyEncryption.put(DefaultFrameWriter.GRADIENT_COLOR_STR, inheritanceCheckOnSave);
2156 }
2157 }
2158 }
2159
2160 public Colour getGradientColor() {
2161 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.GRADIENT_COLOR_STR)) {
2162 return this.getPrimary().getGradientColor();
2163 } else {
2164 return _gradientColour;
2165 }
2166 }
2167
2168 public void setFillPattern(String patternLink) {
2169 _fillPattern = patternLink;
2170 invalidateCommonTrait(ItemAppearence.FillPattern);
2171 invalidateFill();
2172
2173 if (isSurrogate()) {
2174 surrogatePropertyInheritance.put(DefaultFrameWriter.FILL_PATTERN_STR, false);
2175 Item primary = getPrimary();
2176 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.FILL_PATTERN_STR)) {
2177 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2178 primary.primaryPropertyEncryption.put(DefaultFrameWriter.FILL_PATTERN_STR, inheritanceCheckOnSave);
2179 }
2180 }
2181 }
2182
2183 public void setFloating(boolean val) {
2184 _floating = val;
2185 }
2186
2187 /**
2188 * Sets the value <code>_highlight</code> for this item.
2189 * TODO: Appears unused? cts16
2190 *
2191 * @param val The new value for <code>_highlight</code>.
2192 */
2193 public void setHighlight(boolean val) {
2194 _highlight = val;
2195
2196 if (isSurrogate()) {
2197 surrogatePropertyInheritance.put(DefaultFrameWriter.HIGHLIGHT_STR, false);
2198 Item primary = getPrimary();
2199 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.HIGHLIGHT_STR)) {
2200 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2201 primary.primaryPropertyEncryption.put(DefaultFrameWriter.HIGHLIGHT_STR, inheritanceCheckOnSave);
2202 }
2203 }
2204 }
2205
2206 /**
2207 * Sets the ID of this Item to the given Integer. Note: Items with ID's < 0
2208 * are not saved
2209 *
2210 * @param newID
2211 * The new ID to assign this Item.
2212 */
2213 public void setID(int newID) {
2214 _id = newID;
2215
2216 if (isSurrogate()) {
2217 surrogatePropertyInheritance.put(DefaultFrameWriter.TYPE_AND_ID_STR, false);
2218 Item primary = getPrimary();
2219 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.TYPE_AND_ID_STR)) {
2220 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2221 primary.primaryPropertyEncryption.put(DefaultFrameWriter.TYPE_AND_ID_STR, inheritanceCheckOnSave);
2222 }
2223 }
2224 }
2225
2226 /**
2227 * Function called when a user attempts to set the ID of a Item. Simply provides
2228 * feedback to the user telling them that they are not allowed to do this. This
2229 * function is provided so that users are able to get the ID of a item when
2230 * extracting properties. See {@link org.expeditee.gui.AttributeUtils}.
2231 *
2232 * @param newID The requested new ID that will be ignored.
2233 */
2234 public void setIDFail(int newID) {
2235 MessageBay.displayMessage("A user cannot change the ID of an item.");
2236 }
2237
2238 /**
2239 * Sets the list of lines that this point is part of (may be set to null).
2240 *
2241 * @param lineID
2242 * A String of line ID numbers separated by spaces.
2243 */
2244 public void setLineIDs(String lineID) {
2245 if (isSurrogate()) {
2246 surrogatePropertyInheritance.put(DefaultFrameWriter.LINE_IDS_STR, false);
2247 Item primary = getPrimary();
2248 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINE_IDS_STR)) {
2249 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2250 primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINE_IDS_STR, inheritanceCheckOnSave);
2251 }
2252 }
2253 }
2254
2255 public void setLinePattern(int[] pattern) {
2256 _linePattern = pattern;
2257
2258 for (Line line : getLines())
2259 line.setLinePattern(pattern);
2260
2261 if (isSurrogate()) {
2262 surrogatePropertyInheritance.put(DefaultFrameWriter.LINE_PATTERN_STR, false);
2263 Item primary = getPrimary();
2264 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINE_PATTERN_STR)) {
2265 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2266 primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINE_PATTERN_STR, inheritanceCheckOnSave);
2267 }
2268 }
2269 }
2270
2271 public void setLines(List<Line> lines) {
2272 _lines = lines;
2273
2274 for (Line line : lines)
2275 line.setLinePattern(getLinePattern());
2276
2277 }
2278
2279 /**
2280 * Links this item to the given Frame, this may be set to null to remove a
2281 * link.
2282 *
2283 * @param frameName
2284 * The name of the Frame to link this item to.
2285 */
2286 public void setLink(String frameName) {
2287 if (frameName == null) invalidateCommonTrait(ItemAppearence.LinkChanged);
2288
2289 // If a link is being removed or set then need to reset _bounds so the
2290 // highlighting is drawn with the correct width
2291 if (frameName == null || getLink() == null) invalidateBounds();
2292
2293 if (FrameIO.isValidLink(frameName)) {
2294 _link = frameName;
2295 } else {
2296 MessageBay.errorMessage("[" + frameName + "] is not a valid frame name");
2297 }
2298 // TODO make this throw exceptions etc...
2299
2300 invalidateCommonTrait(ItemAppearence.LinkChanged);
2301
2302 if (isSurrogate()) {
2303 surrogatePropertyInheritance.put(DefaultFrameWriter.LINK_STR, false);
2304 Item primary = getPrimary();
2305 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINK_STR)) {
2306 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2307 primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINK_STR, inheritanceCheckOnSave);
2308 }
2309 }
2310 }
2311
2312 public void setLinkHistory(boolean value) {
2313 _linkHistory = value;
2314
2315 if (isSurrogate()) {
2316 surrogatePropertyInheritance.put(DefaultFrameWriter.LINK_HISTORY_STR, false);
2317 Item primary = getPrimary();
2318 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINK_HISTORY_STR)) {
2319 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2320 primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINK_HISTORY_STR, inheritanceCheckOnSave);
2321 }
2322 }
2323 }
2324
2325 public boolean getLinkHistory() {
2326 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.LINK_HISTORY_STR)) {
2327 return this.getPrimary().getLinkHistory();
2328 } else {
2329 return _linkHistory;
2330 }
2331 }
2332
2333 public void setLinkFrameset(String frameset)
2334 {
2335 if (frameset == null || FrameIO.isValidFramesetName(frameset)) {
2336 _link_frameset = frameset;
2337 } else {
2338 MessageBay.errorMessage("[" + frameset + "] is not a valid frameset name");
2339 }
2340 // TODO make this throw exceptions etc...
2341
2342 if (isSurrogate()) {
2343 surrogatePropertyInheritance.put(DefaultFrameWriter.LINK_FRAMESET_STR, false);
2344 Item primary = getPrimary();
2345 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINK_FRAMESET_STR)) {
2346 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2347 primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINK_FRAMESET_STR, inheritanceCheckOnSave);
2348 }
2349 }
2350 }
2351
2352 public void setLinkMark(boolean val) {
2353 if (!val) invalidateCommonTrait(ItemAppearence.LinkChanged);
2354 invalidateBounds();
2355 _linkMark = val;
2356 if (val) invalidateCommonTrait(ItemAppearence.LinkChanged);
2357
2358 if (isSurrogate()) {
2359 surrogatePropertyInheritance.put(DefaultFrameWriter.LINK_MARK_STR, false);
2360 Item primary = getPrimary();
2361 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINK_MARK_STR)) {
2362 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2363 primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINK_MARK_STR, inheritanceCheckOnSave);
2364 }
2365 }
2366 }
2367
2368 public void setLinkTemplate(String template) {
2369 if (FrameIO.isValidLink(template)) {
2370 _link_template = template;
2371 } else {
2372 MessageBay.errorMessage("[" + template + "] is not a valid frame name");
2373 }
2374 // TODO make this throw exceptions etc...
2375
2376 if (isSurrogate()) {
2377 surrogatePropertyInheritance.put(DefaultFrameWriter.LINK_TEMPLATE_STR, false);
2378 Item primary = getPrimary();
2379 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.LINK_TEMPLATE_STR)) {
2380 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2381 primary.primaryPropertyEncryption.put(DefaultFrameWriter.LINK_TEMPLATE_STR, inheritanceCheckOnSave);
2382 }
2383 }
2384 }
2385
2386 // /**
2387 // * Sets the maximum coordinates on the screen that this item may occupy.
2388 // * This is used by Text items to compute word-wrapping lengths.
2389 // *
2390 // * @param d
2391 // * The Maximum size of the Frame containing this Item.
2392 // */
2393 // public void setMaxWidth(int width) {
2394 // if (width > 0) {
2395 // _maxWidth = width;
2396 // updatePolygon();
2397 // }
2398 // }
2399
2400 public void setOffset(int x, int y) {
2401 _offset.set(x, y);
2402 }
2403
2404 public void setOffset(Point p) {
2405 _offset.set(p);
2406 }
2407
2408 public void setOwner(String own) {
2409 _owner = own;
2410
2411 if (isSurrogate()) {
2412 surrogatePropertyInheritance.put(DefaultFrameWriter.OWNER_STR, false);
2413 Item primary = getPrimary();
2414 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.OWNER_STR)) {
2415 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2416 primary.primaryPropertyEncryption.put(DefaultFrameWriter.OWNER_STR, inheritanceCheckOnSave);
2417 }
2418 }
2419 }
2420
2421 public void setParent(Frame frame) {
2422 _oldParent = _parent;
2423 _parent = frame;
2424
2425 if (_parent == null) { return; }
2426
2427 final String currentUser = UserSettings.UserName.get();
2428 final String existingOwner = _parent.getOwner();
2429 if (currentUser != null && (existingOwner == null || currentUser.compareTo(existingOwner) != 0)) {
2430 setOwner(currentUser);
2431 }
2432 }
2433
2434 /**
2435 * Invalidates this, connected lines and fill
2436 *
2437 * @param trait
2438 */
2439 private void invalidateCommonTraitForAll(ItemAppearence trait) {
2440 invalidateCommonTrait(trait);
2441 if (isLineEnd()) {
2442 boolean hasLinePattern = getLines().get(0).getLinePattern() != null;
2443 if (hasLinePattern) {
2444 for (Item i : getAllConnected()) {
2445 if (i instanceof Line) {
2446 ((Line) i).invalidateCommonTrait(trait);
2447 }
2448 }
2449 } else {
2450 for (Line line : getLines()) {
2451 line.invalidateCommonTrait(trait);
2452 }
2453 }
2454 }
2455 if (_fillColour != null) {
2456 invalidateFill(); // only invalidates if has fill
2457 }
2458 for (XRayable x : getEnclosures()) {
2459 x.invalidateCommonTrait(trait);
2460 }
2461
2462 }
2463
2464 protected void anchorConstraints()
2465 {
2466 // update the position of any dots that are constrained by this one
2467 for (Constraint c : _constraints) {
2468 Item other = c.getOppositeEnd(this);
2469
2470 // only set position if the other dot is still fixed to the
2471 // frame
2472 if (/* this.isFloating() && */!other.isFloating()) {
2473 if (c.getType() == Constraint.HORIZONTAL) {
2474 if (isAnchoredY()) {
2475 // Make the 'other' item have the same anchor top/bottom values as this
2476 other._anchoring.setYAnchor(this._anchoring);
2477 }
2478 } else if (c.getType() == Constraint.VERTICAL) {
2479 if (isAnchoredX()) {
2480 // Make the 'other' item have the same anchor left/right values as this
2481 other._anchoring.setXAnchor(this._anchoring);
2482 }
2483 } else if (c.isDiagonal()) {
2484
2485 System.err.println("Warning: anchorConstraints() not implement for Diagonal setting");
2486 }
2487 }
2488 }
2489 }
2490
2491 /**
2492 * Sets the position of this item on the screen
2493 *
2494 * @param x
2495 * The new X coordinate
2496 * @param y
2497 * The new Y coordinate
2498 */
2499 public void setPosition(float x, float y) {
2500 float deltaX = x - _x;
2501 float deltaY = y - _y;
2502
2503 if (deltaX == 0 && deltaY == 0) return;
2504
2505 invalidateCommonTraitForAll(ItemAppearence.PreMoved);
2506
2507 _x = x;
2508 _y = y;
2509
2510 for (Item i : getEnclosures()) {
2511 i.invalidateBounds();
2512 }
2513 invalidateBounds();
2514
2515 // update the position of any dots that are constrained by this one
2516 for (Constraint c : _constraints) {
2517 Item other = c.getOppositeEnd(this);
2518
2519 // only set position if the other dot is still fixed to the
2520 // frame
2521 if (/* this.isFloating() && */!other.isFloating()) {
2522 if (c.getType() == Constraint.HORIZONTAL) {
2523 if (other._y != y) {
2524 other.setY(y);
2525 }
2526 } else if (c.getType() == Constraint.VERTICAL) {
2527 if (other._x != x) {
2528 other.setX(x);
2529 }
2530 } else if (c.isDiagonal()) {
2531 if (Math.abs(other._x - x) != Math.abs(other._y - y)) {
2532
2533 float m1 = c.getGradient();
2534 float c1 = y - m1 * x;
2535 // Now work out the equation for the second line
2536 // Get the first line the other end is attached to that
2537 // is not the diagonal line
2538 List<Line> lines = other.getLines();
2539 // If there is only one line...
2540 if (lines.size() == 1) {
2541 if (m1 != 0) {
2542 if (Math.abs(deltaX) > Math.abs(deltaY)) {
2543 other.setX((other._y - c1) / m1);
2544 } else {
2545 other.setY(m1 * other._x + c1);
2546 }
2547 }
2548 } else if (lines.size() > 1) {
2549 Line otherLine = lines.get(0);
2550 Item end = otherLine.getOppositeEnd(other);
2551 if (end.equals(this)) {
2552 otherLine = lines.get(1);
2553 end = otherLine.getOppositeEnd(other);
2554 assert (!end.equals(this));
2555 }
2556
2557 float xDiff = end._x - other._x;
2558 float yDiff = end._y - other._y;
2559 if (xDiff == 0) {
2560 other.setY(m1 * other._x + c1);
2561 } else if (Math.abs(xDiff) == Math.abs(yDiff)
2562 && !this.isFloating() && deltaX == 0
2563 && deltaY == 0) {
2564 if (deltaX == 0) {
2565 _x = (_y - other._y) * m1 + other._x;
2566 } else {
2567 _y = (_x - other._x) * m1 + other._y;
2568 }
2569 } else {
2570 float m2 = yDiff / xDiff;
2571 float c2 = end._y - m2 * end._x;
2572 float mDiff = m1 - m2;
2573 if (Math.abs(mDiff) < 0.000001) {
2574 assert (false);
2575 // TODO how do I handle this case!!
2576 } else {
2577 float newX = (c2 - c1) / mDiff;
2578 float newY = m1 * newX + c1;
2579 if (other._x != newX
2580 /* && other._y != newY */) {
2581 other.setPosition(newX, newY);
2582 }
2583 }
2584 }
2585 }
2586 // Do simultaneous equations to get the new postion for
2587 // the other end of the diagonal line
2588 }
2589 }
2590 }
2591 }
2592
2593 for (Line line : getLines()) {
2594 line.invalidateBounds();
2595 }
2596
2597 // for (Item item : getAllConnected()) {
2598 // item.updatePolygon();
2599 // }
2600
2601 invalidateCommonTraitForAll(ItemAppearence.PostMoved);
2602
2603 if (isSurrogate()) {
2604 surrogatePropertyInheritance.put(DefaultFrameWriter.POSITION_STR, false);
2605 Item primary = getPrimary();
2606 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.POSITION_STR)) {
2607 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2608 primary.primaryPropertyEncryption.put(DefaultFrameWriter.POSITION_STR, inheritanceCheckOnSave);
2609 }
2610 }
2611 }
2612
2613 public void setPosition(Point position) {
2614 setPosition(position.getX(), position.getY());
2615 }
2616
2617 public void setRelativeLink() {
2618 String link = getLink();
2619 if (link == null)
2620 return;
2621 assert (_parent != null);
2622
2623 if (FrameIO.isPositiveInteger(link))
2624 return;
2625
2626 // Check if the link is for the current frameset
2627 if (_parent.getFramesetName().equalsIgnoreCase(
2628 Conversion.getFramesetName(link))) {
2629 setLink("" + Conversion.getFrameNumber(link));
2630 }
2631 }
2632
2633 /**
2634 * Sets the size of this Item. For Text this is the Font size. For Lines and
2635 * Dots this is the thickness.
2636 */
2637 public void setSize(float size) {
2638 }
2639
2640 /**
2641 * Sets the thickness of the item.
2642 *
2643 * @param thick
2644 */
2645 public final void setThickness(float thick) {
2646 setThickness(thick, true);
2647
2648 if (isSurrogate()) {
2649 surrogatePropertyInheritance.put(DefaultFrameWriter.THICKNESS_STR, false);
2650 Item primary = getPrimary();
2651 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.THICKNESS_STR)) {
2652 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2653 primary.primaryPropertyEncryption.put(DefaultFrameWriter.THICKNESS_STR, inheritanceCheckOnSave);
2654 }
2655 }
2656 }
2657
2658 /**
2659 * Sets the thickness of this item.
2660 *
2661 * @param thick
2662 * the new thickness for the item
2663 * @param setConnectedThickness
2664 * true if all items connected to this item should also have
2665 * their thickness set
2666 */
2667 public void setThickness(float thick, boolean setConnectedThickness)
2668 {
2669 if (thick == _thickness) return;
2670
2671 boolean bigger = thick > _thickness;
2672
2673 if (!bigger) {
2674 if (setConnectedThickness) {
2675 // TODO is there a more efficient way of doing this?
2676 for (Item i : getConnected()) i.invalidateCommonTrait(ItemAppearence.Thickness);
2677 } else {
2678 invalidateCommonTrait(ItemAppearence.Thickness);
2679 }
2680 }
2681
2682 _thickness = thick;
2683 // update the size of any lines
2684 /*
2685 * TODO: Revise the way line thickness is set to make it more efficient
2686 * etc...
2687 */
2688 for (Line line : getLines()) line.setThickness(thick, setConnectedThickness);
2689
2690 if (setConnectedThickness) invalidateBounds();
2691
2692 if (bigger) {
2693 if (setConnectedThickness) {
2694 for (Item i : getConnected()) i.invalidateCommonTrait(ItemAppearence.Thickness);
2695 } else {
2696 invalidateCommonTrait(ItemAppearence.Thickness);
2697 }
2698 }
2699 }
2700
2701 /**
2702 * Returns the thickness (in pixels) of this Dot.
2703 *
2704 * @return The 'thickness' of this Dot. (returns -1 if the thickness is not
2705 * set).
2706 */
2707 public float getThickness() {
2708 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.THICKNESS_STR)) {
2709 return this.getPrimary().getThickness();
2710 } else {
2711 return _thickness;
2712 }
2713 }
2714
2715 /**
2716 * Sets the Color to use on the top and left sections of this Item's border.
2717 * If top is NULL, then the Item's background Color will be used.
2718 *
2719 * @param top
2720 * The Color to display in the top and left sections of this
2721 * Item's border.
2722 */
2723 public void setTopShadowColor(Colour top) {
2724 _colorTopShadow = top;
2725 }
2726
2727 public void setWidth(Integer width) throws UnsupportedOperationException
2728 {
2729 throw new UnsupportedOperationException("Item type does not support width attribute!");
2730 }
2731
2732 public void setMinWidth(final Integer width) throws UnsupportedOperationException {
2733 throw new UnsupportedOperationException("Item type does not support minwidth attribute.");
2734 }
2735
2736 public void setMaxWidth(Integer width) throws UnsupportedOperationException {
2737 throw new UnsupportedOperationException("Item type does not support maxwidth attribute");
2738 }
2739
2740 public void setRightMargin(int i, boolean fixWidth)
2741 {
2742 int newWidth = i - getX() - Item.MARGIN_LEFT;
2743 if (newWidth < 0) newWidth = 0;
2744
2745 if (!fixWidth) {
2746 newWidth *= -1;
2747 }
2748
2749 setWidth(newWidth);
2750 }
2751
2752 /**
2753 * Sets the position of this Item on the X axis
2754 *
2755 * @param newX
2756 * The position on the X axis to assign to this Item
2757 */
2758 public void setX(float newX) {
2759 setPosition(newX, getY());
2760
2761// if (isSurrogate()) {
2762// surrogatePropertyInheritance.put(DefaultFrameWriter.POSITION_STR, false);
2763// Item primary = getPrimary();
2764// if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.POSITION_STR)) {
2765// EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2766// primary.primaryPropertyEncryption.put(DefaultFrameWriter.POSITION_STR, inheritanceCheckOnSave);
2767// }
2768// }
2769 }
2770
2771 /**
2772 * Sets the position of this Item on the Y axis
2773 *
2774 * @param newY
2775 * The position on the Y axis to assign to this Item
2776 */
2777 public void setY(float newY) {
2778 setPosition(getX(), newY);
2779
2780// if (isSurrogate()) {
2781// surrogatePropertyInheritance.put(DefaultFrameWriter.POSITION_STR, false);
2782// Item primary = getPrimary();
2783// if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.POSITION_STR)) {
2784// EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2785// primary.primaryPropertyEncryption.put(DefaultFrameWriter.POSITION_STR, inheritanceCheckOnSave);
2786// }
2787// }
2788 }
2789
2790 /**
2791 * Paints any highlighting of this Item. This may include changing the
2792 * thickness (lines) or painting a box around the item (Text, Images). If
2793 * val is True then the Graphics Color is changed to the highlight Color, if
2794 * False then the Graphics Color is left unchanged (for clearing of
2795 * highlighting).
2796 *
2797 * @param val
2798 * True if this Item should be highlighted, false if the
2799 * highlighting is being cleared.
2800 * @return The desired mouse cursor when this Item is highlighted (negative
2801 * means no change)
2802 */
2803
2804 /**
2805 *
2806 *
2807 * @return
2808 */
2809 public void setHighlightColorToDefault() {
2810 setHighlightColor(DEFAULT_HIGHLIGHT);
2811 }
2812
2813 public void setHighlightColor(Colour c) {
2814 if (c == null) return;
2815
2816 if (!this.isVisible() && this.hasVector()) {
2817 for (Item i : this.getParentOrCurrentFrame().getVectorItems()) {
2818 if (i.getEditTarget() == this) {
2819 i.setHighlightColor(c);
2820 }
2821 }
2822 }
2823
2824 _highlightThickness = DEFAULT_HIGHLIGHT_THICKNESS;
2825
2826 Colour selColor = (c != null) ? c : DEFAULT_HIGHLIGHT;
2827 if (_highlightColour != c) {
2828 _highlightColour = selColor;
2829 this.invalidateCommonTrait(ItemAppearence.HighlightColorChanged);
2830 }
2831
2832 }
2833
2834 private void updateArrowPolygon() {
2835 if (getArrowheadLength() < 0 || getArrowheadRatio() < 0 || getArrowheadNibPerc() < 0)
2836 _arrowhead = null;
2837 else {
2838 _arrowhead = Line.createArrowheadPolygon(getX(),getY(),getArrowheadLength(),getArrowheadRatio(),getArrowheadNibPerc());
2839 }
2840 }
2841
2842 /** Returns a Bounds which represents the area covered by the item (including its gravity). */
2843 public abstract Bounds updateBounds();
2844
2845 public void setHidden(boolean state) {
2846 this._visible = !state;
2847 }
2848
2849 public void setVisible(boolean state) {
2850 this._visible = state;
2851 }
2852
2853 public boolean isVisible() {
2854 return _visible && !_deleted;
2855 }
2856
2857 /**
2858 * Raised whenever the item is removed, added, no longer in view (That is,
2859 * when it is not on any of the current frames, of overlays of the current
2860 * frames) or has become visible. That is, when it is either on a current
2861 * frame, or an overlay of a current frame.
2862 *
2863 * @param e
2864 * The event
2865 */
2866 public void onParentStateChanged(ItemParentStateChangedEvent e) {
2867 }
2868
2869 /**
2870 * Sets the highlight mode and colour at the same time.
2871 *
2872 * @param mode The new highlight mode.
2873 * @param colour The new highlight colour.
2874 */
2875 public void setHighlightModeAndColour(HighlightMode mode, Colour colour)
2876 {
2877 setHighlightMode(mode);
2878 setHighlightColor(colour);
2879 }
2880
2881 public HighlightMode getHighlightMode() {
2882 return _highlightMode;
2883 }
2884
2885 public void anchor() {
2886 Frame current = getParentOrCurrentFrame();
2887 // only set the id if we've moved to a different frame, or if the frame already has an item with that id
2888 if(!current.equals(_oldParent) || current.getItemWithID(getID()) != null) {
2889 setID(current.getNextItemID());
2890 } else {
2891 // System.out.println(this + " - Kept old ID of " + _id);
2892 }
2893 setOffset(0, 0);
2894 setParent(current);
2895
2896 current.addItem(this, false);
2897 current.invalidateSorted();
2898 setRelativeLink();
2899 setFloating(false);
2900
2901 // // If its an unconstrained line end check if we should add a
2902 // constraint
2903 // if (isLineEnd() && getLines().size() <= 2
2904 // && getConstraints().size() <= 1) {
2905 // Constraint existingConstraint = null;
2906 // List<Constraint> constraints = getConstraints();
2907 // // Get the existing constraint
2908 // if (constraints.size() > 0) {
2909 // existingConstraint = constraints.get(0);
2910 // }
2911 // for (Line line : getLines()) {
2912 // Integer constraintType = line.getPossibleConstraint();
2913 // if (constraintType != null) {
2914 // Item oppositeEnd = line.getOppositeEnd(this);
2915 // if (existingConstraint == null
2916 // || !existingConstraint.contains(oppositeEnd)) {
2917 // new Constraint(this, oppositeEnd,
2918 // getParentOrCurrentFrame().getNextItemID(),
2919 // constraintType);
2920 // }
2921 // }
2922 // }
2923 // }
2924 }
2925
2926 /**
2927 * Gets the parent frame if it is set or the current frame if this item does
2928 * not have a parent set.
2929 *
2930 * @return
2931 */
2932 public Frame getParentOrCurrentFrame() {
2933 // if the item is from an overlay the parent will NOT be null
2934 if (getParent() == null) {
2935 return DisplayController.getCurrentFrame();
2936 }
2937 return getParent();
2938 }
2939
2940 /**
2941 * Sets the list of Dots (including this one) that form a closed shape.
2942 * Passing null sets this dot back to its normal (non-enclosed) state.
2943 *
2944 * @param enclosed
2945 * The List of Dots including this one that form a closed shape,
2946 * or null.
2947 */
2948 public void setEnclosedList(Collection<Item> enclosed) {
2949
2950 boolean changed = (_enclosure == null && enclosed != null);
2951
2952 if (_enclosure != null && enclosed == null) {
2953 invalidateFill();
2954 }
2955
2956 _enclosure = enclosed;
2957
2958 if (changed) {
2959 invalidateFill();
2960 ;
2961 }
2962 }
2963
2964 /**
2965 * Returns the polygon that represents the shape created by all the Dots in
2966 * this Dot's enclosed list. If the list is null, then null is returned.
2967 *
2968 * @return A Polygon the same shape and position as created by the Dots in
2969 * the enclosed list.
2970 */
2971 public PolygonBounds getEnclosedShape()
2972 {
2973 if (_enclosure == null) return null;
2974
2975 PolygonBounds poly = new PolygonBounds();
2976 for (Item d : _enclosure) {
2977 poly.addPoint(new Point(d.getX(), d.getY()));
2978 }
2979
2980 return poly;
2981 }
2982
2983 /**
2984 * Returns the list of Dots that, along with this Dot, form an enclosed
2985 * polygon. If this Dot is not part of an enclosure null may be returned.
2986 *
2987 * @return The List of Dots that form an enclosed shape with this Dot, or
2988 * null if this Dot is not part of an enclosure.
2989 */
2990 public Collection<Item> getEnclosingDots() {
2991 return _enclosure;
2992 }
2993
2994 /**
2995 * Returns whether this Dot has an assigned enclosure list of other Dots.
2996 * The result is the same as getEnclosedShape() != null.
2997 *
2998 * @return True if this Dot has an enclosure list of other Dots, false
2999 * otherwise.
3000 */
3001 public boolean isEnclosed() {
3002 return _enclosure != null;
3003 }
3004
3005 /**
3006 * True if this item is the end of a line.
3007 *
3008 * @return
3009 */
3010 public boolean isLineEnd() {
3011 // TODO this will need to be redone when enclosure class is added...
3012 // At the moment enclosures are only circles...we don't want circle
3013 // centres to be lineEnds
3014 return _lines.size() > 0;
3015 }
3016
3017 public boolean hasEnclosures() {
3018 return _enclosures.size() > 0;
3019 }
3020
3021 /**
3022 * Method that is called to notify an item that is on the end of a line that
3023 * its line has changed color.
3024 *
3025 * @param c
3026 * the new color for the line
3027 */
3028 protected void lineColorChanged(Colour c) {
3029 for (Line l : getLines()) {
3030 if (l.getColor() != c)
3031 l.setColor(c);
3032 }
3033 }
3034
3035 /**
3036 * Checks if this item is off the left or top of the screen
3037 *
3038 * @return
3039 */
3040 public boolean offScreenTopOrLeft() {
3041 Bounds bounds = getBoundingBox();
3042
3043 // Check that the bottom right corner of this item is on the screen
3044 if (bounds.getMaxX() >= 0 && bounds.getMaxY() >= 0) {
3045 return false;
3046 }
3047
3048 // Check if all the items it is connected to are offscreen
3049 for (Item i : getAllConnected()) {
3050 bounds = i.getBoundingBox();
3051 // Check that the bottom right corner of this item is on the screen
3052 if (bounds.getMaxX() >= 0 && bounds.getMaxY() >= 0) {
3053 return false;
3054 }
3055 }
3056
3057 return true;
3058 }
3059
3060 public void setConnectedToAnnotation(boolean val) {
3061 _connectedToAnnotation = val;
3062 }
3063
3064 public boolean isConnectedToAnnotation() {
3065 return _connectedToAnnotation;
3066 }
3067
3068 public boolean hasAction() {
3069 List<String> actions = getAction();
3070 return actions != null && actions.size() > 0;
3071 }
3072
3073 public void setAction(String action)
3074 {
3075 // Want to resize the highlight box for text items if actions are been added
3076 if (action == null || action.length() == 0) {
3077 invalidateCommonTrait(ItemAppearence.LinkChanged);
3078 }
3079
3080 if (_actions == null || _actions.size() == 0) {
3081 invalidateBounds();
3082 _actions = new LinkedList<String>();
3083 } else {
3084 _actions.clear();
3085 }
3086
3087 if (action != null && action.length() > 0) _actions.add(action);
3088
3089 invalidateCommonTrait(ItemAppearence.LinkChanged);
3090 }
3091
3092 protected int getLinkYOffset() {
3093 return 0;
3094 }
3095
3096 protected AxisAlignedBoxBounds getLinkDrawArea() {
3097 return getLinkDrawArea(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
3098 }
3099
3100 /**
3101 * TODO: Revise - it would be good to have a member that defines the link
3102 * dimensions.
3103 *
3104 * @param x
3105 * Left of graphic (i.e not centered)
3106 * @param y
3107 * Above graphic (i.e not centered)
3108 *
3109 * @return The drawing area of the link at the given coordinates.
3110 */
3111 public AxisAlignedBoxBounds getLinkDrawArea(int x, int y) {
3112 return new AxisAlignedBoxBounds(x + 2, y - 1, 8, 8);
3113 }
3114
3115 /**
3116 * Paint the link symbol for the item if it is a
3117 *
3118 * @param g
3119 */
3120 protected void paintLink() {
3121 paintLinkGraphic(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
3122 paintKeyGraphic(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
3123 paintPadlockGraphic(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
3124 }
3125
3126 /**
3127 * Paint the link symbol for the item at a given position.
3128 *
3129 * @see #paintLink
3130 *
3131 * @param g
3132 * The graphics to paint with
3133 *
3134 * @param x
3135 * The x position of the link. Left of graphic (i.e not centered)
3136 *
3137 * @param y
3138 * The y position of the link. Above of graphic (i.e not
3139 * centered)
3140 */
3141 public void paintLinkGraphic(int x, int y) {
3142
3143 boolean hasLink = hasLink();
3144 boolean hasAction = hasAction();
3145
3146 if (hasLink || hasAction) {
3147 GraphicsManager g = EcosystemManager.getGraphicsManager();
3148 Fill fill = new Fill();
3149 Colour colour = null;
3150 Point offset = new Point(x, y);
3151
3152 if (hasLink && hasAction) {
3153 colour = LINK_ACTION_COLOR;
3154 } else if (hasLink) {
3155 colour = LINK_COLOR;
3156 } else if (hasAction) {
3157 colour = ACTION_COLOR;
3158 }
3159 fill.setColour(colour);
3160
3161 // Small circles look rubbish without AA. cts16
3162 g.setAntialiasing(true);
3163
3164 if (hasLink && getLinkMark()) {
3165 g.drawOval(offset, getLinkBounds().getDiameters(), 0.0f, null, colour, HIGHLIGHT_STROKE);
3166
3167 // if the link is not valid, cross out the circle
3168 if (!isLinkValid()) {
3169 g.drawPolygon(getCircleCross(), offset, null, 0.0f, null, colour, HIGHLIGHT_STROKE);
3170 }
3171 }
3172
3173 if (hasAction && getActionMark()) {
3174 g.drawOval(offset, getLinkBounds().getDiameters(), 0.0f, fill, colour, HIGHLIGHT_STROKE);
3175
3176 // if the link is not valid, cross out the circle
3177 if (!isLinkValid() && getLink() != null) {
3178 g.drawPolygon(getCircleCross(), offset, null, 0.0f, null, getParent().getPaintBackgroundColor(), HIGHLIGHT_STROKE);
3179 }
3180 }
3181
3182 g.setAntialiasing(false);
3183 }
3184 }
3185
3186 protected void paintKeyGraphic(int x, int y) {
3187 Colour fontColour = null;
3188 switch (this.keyType()) {
3189 case PartialKey:
3190 fontColour = Colour.LIGHT_GRAY;
3191 break;
3192 case FullKey:
3193 fontColour = Colour.BLACK;
3194 break;
3195 default:
3196 return;
3197 }
3198
3199 GraphicsManager g = EcosystemManager.getGraphicsManager();
3200 g.setAntialiasing(true);
3201 Font font = new Font();
3202 g.drawString("\uD83D\uDD11", new Point(x,y), font, fontColour);
3203 g.setAntialiasing(false);
3204 }
3205
3206 protected void paintPadlockGraphic(int x, int y) {
3207 String encryptionLabel = this.getEncryptionLabel();
3208 if (encryptionLabel != null && encryptionLabel.length() > 0) {
3209 GraphicsManager g = EcosystemManager.getGraphicsManager();
3210 g.setAntialiasing(true);
3211 Font font = new Font();
3212 g.drawString("\uD83D\uDD12", new Point(x,y), font, Colour.BLACK);
3213 g.setAntialiasing(false);
3214 }
3215 }
3216
3217 public KeyType keyType() {
3218 return keyType;
3219 }
3220
3221 public void setKeyType(String s) {
3222 try {
3223 keyType = KeyType.valueOf(s);
3224 } catch (IllegalArgumentException e) {
3225 keyType = KeyType.NotAKey;
3226 }
3227 }
3228
3229 /**
3230 * Gets the distance between the start of the text and the left border of
3231 * the item. This distance changes depending on whether or not the item is
3232 * linked or has an associated action.
3233 *
3234 * @return the gap size in pixels
3235 */
3236 protected int getLeftMargin() {
3237 return ((getLinkMark() && getLink() != null)
3238 || (getActionMark() && getAction() != null) ? MARGIN_LEFT
3239 - MARGIN_RIGHT : MARGIN_RIGHT);
3240 }
3241
3242 public String getName() {
3243 return getText();
3244 }
3245
3246 final public String getAbsoluteLinkTemplate() {
3247 return getAbsoluteLink(getLinkTemplate());
3248 }
3249
3250 final public String getAbsoluteLinkFrameset() {
3251 return getAbsoluteLink(getLinkFrameset());
3252 }
3253
3254 final public String getAbsoluteLink() {
3255 return getAbsoluteLink(getLink());
3256 }
3257
3258 /**
3259 * @param link
3260 * @return
3261 */
3262 private String getAbsoluteLink(String link) {
3263 if (link == null)
3264 return null;
3265 // assert (_parent!= null);
3266 Frame parent = getParentOrCurrentFrame();
3267 if (_parent == null) {
3268 // if parent is null it is an item on the message box
3269 // so it must already be absolute
3270 // assert (!FrameIO.isPositiveInteger(link));
3271 // return link;
3272
3273 }
3274
3275 // if its a relative link then return absolute
3276 if (FrameIO.isPositiveInteger(link)) {
3277 return parent.getFramesetName() + link;
3278 }
3279 return link;
3280 }
3281
3282 public static String convertToAbsoluteLink(String link) {
3283 if (link == null)
3284 return null;
3285 // assert (_parent!= null);
3286 Frame parent = DisplayController.getCurrentFrame();
3287 assert (parent != null);
3288
3289 // if its a relative link then return absolute
3290 if (FrameIO.isPositiveInteger(link)) {
3291 return parent.getFramesetName() + link;
3292 }
3293 return link;
3294 }
3295
3296 /**
3297 * Sets the x and y values of this item ignoring constraints.
3298 *
3299 * @param x
3300 * new x position
3301 * @param y
3302 * new y position
3303 */
3304 public void setXY(float x, float y) {
3305 _x = x;
3306 _y = y;
3307 }
3308
3309 /**
3310 * Recursive function for getting the path around a shape. This is used to
3311 * get the path that is painted on the screen.
3312 *
3313 * @param visited
3314 * @param points
3315 * @param addToEnd
3316 * @param toExplore
3317 */
3318 public void appendPath(Collection<Line> visited, LinkedList<Point> points,
3319 boolean addToEnd, Collection<Line> toExplore) {
3320
3321 if (addToEnd) {
3322 // put the start item points into our list
3323 points.addLast(getPosition());
3324 } else {
3325 points.addFirst(getPosition());
3326 }
3327
3328 // Find the line that has not been added yet
3329 LinkedList<Line> lines = new LinkedList<Line>();
3330 lines.addAll(getLines());
3331
3332 while (!lines.isEmpty()) {
3333 Line l = lines.remove();
3334 // if we haven't visited the line yet visit it
3335 if (!visited.contains(l)) {
3336 visited.add(l);
3337 Item otherEnd = l.getOppositeEnd(this);
3338 // Add all the unexplored lines to our list
3339 while (!lines.isEmpty()) {
3340 l = lines.remove();
3341 // Get the paths for the rest of the lines to be explored
3342 // later
3343 if (!toExplore.contains(l) && !visited.contains(l)) {
3344 toExplore.add(l);
3345 }
3346 }
3347 otherEnd.appendPath(visited, points, addToEnd, toExplore);
3348 }
3349 }
3350 }
3351
3352 /**
3353 * Gets the size of the enclosure that this item is part of. Used to
3354 * determine the paint order of items, with smaller items being painted
3355 * first.
3356 *
3357 * @return the area of the box surrounding the enclosed shape that this item
3358 * is part of
3359 */
3360 public double getEnclosedArea()
3361 {
3362 AxisAlignedBoxBounds box = getEnclosedBox();
3363 if (box == null) return 0.0;
3364 return box.getWidth() * box.getHeight();
3365 }
3366
3367 /**
3368 * Gets the box encompassing all points that form an enclosure with this item.
3369 *
3370 * @return An axis-aligned box around all enclosure points.
3371 */
3372 public AxisAlignedBoxBounds getEnclosedBox()
3373 {
3374 if (_enclosure == null) return null;
3375
3376 return AxisAlignedBoxBounds.getEnclosing(getEnclosedShape());
3377 }
3378
3379 public int getEnclosureID()
3380 {
3381 return _enclosure == null ? 0 : _enclosure.hashCode();
3382 }
3383
3384 /**
3385 * Returns the Bounds that surrounds this Item representing this Item's
3386 * 'gravity'.
3387 *
3388 * @return The Bounds surrounding this Item, which represents
3389 * this Items 'gravity'.
3390 */
3391 public final Bounds getBounds()
3392 {
3393 if (_bounds == null) _bounds = updateBounds();
3394
3395 // DEBUG
3396 if (_bounds == null) {
3397 //System.out.println("updateBounds failed!");
3398 }
3399
3400 return _bounds;
3401 }
3402
3403 public final Bounds getOldBounds()
3404 {
3405 return _oldBounds;
3406 }
3407
3408 public final void invalidateBounds()
3409 {
3410 if (_bounds != null) _oldBounds = _bounds;
3411 _bounds = null;
3412 for (Item surrogate: this.getSurrogates()) {
3413 surrogate.invalidateBounds();
3414 }
3415 }
3416
3417 public final AxisAlignedBoxBounds getBoundingBox()
3418 {
3419 return AxisAlignedBoxBounds.getEnclosing(getBounds());
3420 }
3421
3422 /**
3423 * Shifts the position of the item along the line between this items
3424 * location and a specified point.
3425 *
3426 * @param origin
3427 * @param ratio
3428 */
3429 public void translate(Point origin, double ratio) {
3430
3431 invalidateCommonTraitForAll(ItemAppearence.PreMoved);
3432
3433 _x = (float) (origin.getX() + ratio * (_x - origin.getX()));
3434 _y = (float) (origin.getY() + ratio * (_y - origin.getY()));
3435 invalidateBounds();
3436 for (Line line : getLines())
3437 line.invalidateBounds();
3438
3439 invalidateCommonTraitForAll(ItemAppearence.PostMoved);
3440
3441 }
3442
3443 private static int[] LinePatterns = new int[] { 0, 10, 20 };
3444
3445 /**
3446 * The rotates through a wheel of dashed lines.
3447 *
3448 * @param amount
3449 * number of rotations around the wheel to toggle by.
3450 */
3451 public void toggleDashed(int amount) {
3452 // find the index of the current line pattern
3453 int[] currentPattern = getLinePattern();
3454
3455 // Find the current pattern and move to the next pattern in the wheel
3456 for (int i = 0; i < LinePatterns.length; i++) {
3457 if (currentPattern == null || currentPattern[0] == LinePatterns[i]) {
3458 i += LinePatterns.length + amount;
3459 i %= LinePatterns.length;
3460
3461 // if we are at the start of the wheel make it 'null' (solid
3462 // line)
3463 if (i == 0) {
3464 setLinePattern(null);
3465 } else {
3466 setLinePattern(new int[] { LinePatterns[i], LinePatterns[i] });
3467 }
3468
3469 invalidateCommonTrait(ItemAppearence.ToggleDashed);
3470 return;
3471 }
3472 }
3473
3474 }
3475
3476 /**
3477 * For now there can only be one enclosure per item
3478 *
3479 * @param enclosure
3480 */
3481 public void addEnclosure(XRayable enclosure) {
3482 _enclosures.clear();
3483 _enclosures.add(enclosure);
3484 }
3485
3486 /**
3487 * Gets any XRayable items that have this item as a source.
3488 *
3489 * @return the collection of items that are linked to this item as source.
3490 * Guaranteed not to be null.
3491 */
3492 public Collection<? extends XRayable> getEnclosures() {
3493 return _enclosures;
3494 }
3495
3496 public void removeEnclosure(Item i) {
3497 _enclosures.remove(i);
3498
3499 }
3500
3501 public boolean isDeleted() {
3502 return _deleted;
3503 }
3504
3505 /**
3506 * @return The full canvas that this item draws to. Must include
3507 * highlighting bounds
3508 */
3509 public AxisAlignedBoxBounds getDrawingArea() {
3510
3511 final AxisAlignedBoxBounds boundingBox = getBoundingBox();
3512 return ItemUtils.expandRectangle(
3513 boundingBox,
3514 (int) Math.ceil(Math.max(_highlightThickness, getThickness())) + 1 // + 1 to make sure
3515 );
3516 }
3517
3518 /**
3519 *
3520 * @param area
3521 * @return True if area intersects with this items drawing area.
3522 */
3523 public final boolean isInDrawingArea(AxisAlignedBoxBounds area)
3524 {
3525 AxisAlignedBoxBounds drawingArea = getDrawingArea();
3526
3527 if (drawingArea == null) return false;
3528
3529 return drawingArea.intersects(area);
3530 }
3531
3532 /**
3533 * Completely invalidates the item - so that it should be redrawn. Note:
3534 * This is handled internally, it should be rare to invoke this externally
3535 */
3536 public final void invalidateAll()
3537 {
3538 invalidate(getDrawingArea());
3539 }
3540
3541 /**
3542 * Invalidates areas on the parent frame. Purpose: to be called on specific
3543 * areas of the item that needs redrawing.
3544 *
3545 * @param damagedAreas
3546 */
3547 protected final void invalidate(Bounds[] damagedAreas)
3548 {
3549 if (damagedAreas != null) for (Bounds b : damagedAreas) invalidate(b);
3550 }
3551
3552 /**
3553 * Invalidates areas on the parent frame. Purpose: to be called on specific
3554 * areas of the item that needs redrawing.
3555 *
3556 * @param damagedAreas
3557 */
3558 protected final void invalidate(Bounds damagedArea)
3559 {
3560 if (damagedArea != null) DisplayController.invalidateItem(this, damagedArea);
3561 }
3562
3563 /**
3564 * Used to invalidate visual traits commonly shared by all items.
3565 *
3566 * @param trait
3567 */
3568 public final void invalidateCommonTrait(ItemAppearence trait)
3569 {
3570 invalidate(getDamagedArea(trait));
3571
3572 if (_fillColour != null && (trait == ItemAppearence.Added || trait == ItemAppearence.Removed)) {
3573 invalidateFill();
3574 }
3575 }
3576
3577 /**
3578 * Invalidates fill if has one, even if no color is set.
3579 */
3580 public void invalidateFill()
3581 {
3582 if (isLineEnd() && _enclosure != null) {
3583 invalidate(getEnclosedBox());
3584 }
3585 }
3586
3587 /**
3588 * Default implementation always uses drawing area except for links, where
3589 * the link drawing area is used. Override to make item drawing more
3590 * efficient - defining only parts of the item that needs redrawing.
3591 *
3592 * @see Item.getDrawingArea
3593 *
3594 * @param trait
3595 * The visual trait that has changed.
3596 *
3597 * @return The damaged area according to the visual trait that has changed.
3598 */
3599 protected AxisAlignedBoxBounds getDamagedArea(ItemAppearence trait)
3600 {
3601 if (trait == ItemAppearence.LinkChanged)
3602 return getLinkDrawArea(); // Invalidate area where link is drawn
3603
3604 return getDrawingArea();
3605 }
3606
3607 public boolean hasVector() {
3608 return _overlay instanceof Vector;
3609 }
3610
3611 public boolean hasOverlay() {
3612 return _overlay != null;
3613 }
3614
3615 public Vector getVector() {
3616 if (_overlay instanceof Vector)
3617 return (Vector) _overlay;
3618 return null;
3619 }
3620
3621 public void setOverlay(Overlay overlay) {
3622 _overlay = overlay;
3623 }
3624
3625 public boolean dontSave() {
3626 /*
3627 * TODO Mike says: checkout if the ID check is still needed- When will
3628 * ID still be -1 when saving a frame? assert (i != null);
3629 */
3630 // make it save stuff that's off the screen so stuff isn't deleted by panning - jts21
3631 return !_save || !isVisible() || getID() < 0; // || offScreenTopOrLeft();
3632 }
3633
3634 public void setAnchorLeft(Integer anchor) {
3635 this._anchoring.setLeftAnchor(anchor);
3636 if (anchor != null) {
3637 anchorConstraints();
3638 setX(anchor);
3639 }
3640
3641 if (isSurrogate()) {
3642 surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_LEFT_STR, false);
3643 Item primary = getPrimary();
3644 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_LEFT_STR)) {
3645 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
3646 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_LEFT_STR, inheritanceCheckOnSave);
3647 }
3648 }
3649 }
3650
3651 public void setAnchorRight(Integer anchor) {
3652 this._anchoring.setRightAnchor(anchor);
3653 if (anchor != null) {
3654 anchorConstraints();
3655 setX(DisplayController.getFramePaintArea().getMaxX() - anchor - getBoundsWidth());
3656 }
3657
3658 if (isSurrogate()) {
3659 surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_RIGHT_STR, false);
3660 Item primary = getPrimary();
3661 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_RIGHT_STR)) {
3662 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
3663 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_RIGHT_STR, inheritanceCheckOnSave);
3664 }
3665 }
3666 }
3667
3668 public void setAnchorTop(Integer anchor) {
3669 this._anchoring.setTopAnchor(anchor);
3670 if (anchor != null) {
3671 anchorConstraints();
3672 setY(anchor);
3673 }
3674
3675 if (isSurrogate()) {
3676 surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_TOP_STR, false);
3677 Item primary = getPrimary();
3678 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_TOP_STR)) {
3679 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
3680 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_TOP_STR, inheritanceCheckOnSave);
3681 }
3682 }
3683 }
3684
3685
3686 public void setAnchorBottom(Integer anchor) {
3687 this._anchoring.setBottomAnchor(anchor);
3688 if (anchor != null) {
3689 anchorConstraints();
3690 setY(DisplayController.getFramePaintArea().getMaxY() - anchor);
3691 }
3692
3693 if (isSurrogate()) {
3694 surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_BOTTOM_STR, false);
3695 Item primary = getPrimary();
3696 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_BOTTOM_STR)) {
3697 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
3698 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_BOTTOM_STR, inheritanceCheckOnSave);
3699 }
3700 }
3701 }
3702
3703 public boolean isAnchored()
3704 {
3705 return _anchoring.isAnchored();
3706 }
3707
3708 public boolean isAnchoredX() {
3709 return _anchoring.isXAnchored();
3710 }
3711
3712 public boolean isAnchoredY() {
3713 return _anchoring.isYAnchored();
3714 }
3715
3716 public Integer getAnchorLeft() {
3717 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_LEFT_STR)) {
3718 return this.getPrimary().getAnchorLeft();
3719 } else {
3720 return _anchoring.getLeftAnchor();
3721 }
3722 }
3723
3724 public Integer getAnchorRight() {
3725 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_RIGHT_STR)) {
3726 return this.getPrimary().getAnchorRight();
3727 } else {
3728 return _anchoring.getRightAnchor();
3729 }
3730 }
3731
3732 public Integer getAnchorTop() {
3733 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_TOP_STR)) {
3734 return this.getPrimary().getAnchorTop();
3735 } else {
3736 return _anchoring.getTopAnchor();
3737 }
3738 }
3739
3740 public Integer getAnchorBottom() {
3741 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_BOTTOM_STR)) {
3742 return this.getPrimary().getAnchorBottom();
3743 } else {
3744 return _anchoring.getBottomAnchor();
3745 }
3746 }
3747
3748 public String getText() {
3749 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.TEXT_STR)) {
3750 return this.getPrimary().getText();
3751 } else {
3752 return "@" + getClass().getSimpleName() + ":" + getID();
3753 }
3754 }
3755
3756 public void setText(String text) {
3757 }
3758
3759 public boolean recalculateWhenChanged() {
3760 return false;
3761 }
3762
3763 public boolean update() {
3764 return calculate(getText());
3765 }
3766
3767 public Collection<Item> getEnclosedItems() {
3768 return FrameUtils.getItemsEnclosedBy(this.getParentOrCurrentFrame(),
3769 this.getEnclosedShape());
3770 }
3771
3772 public Collection<Text> getEnclosedNonAnnotationText() {
3773 Collection<Text> items = new LinkedHashSet<Text>();
3774 for (Item t : getEnclosedItems()) {
3775 if (t instanceof Text && !t.isAnnotation())
3776 items.add((Text) t);
3777 }
3778
3779 return items;
3780 }
3781
3782 public void dispose() {
3783 setParent(null);
3784 }
3785
3786 /**
3787 * @return
3788 */
3789 protected boolean hasVisibleBorder() {
3790 return getThickness() > 0 && !isLineEnd() && getBorderColor() != null;
3791 }
3792
3793 public Frame getChild() {
3794 String childName = getAbsoluteLink();
3795 if (childName != null) {
3796 return FrameIO.LoadFrame(childName);
3797 }
3798 return null;
3799 }
3800
3801 public boolean hasLink() {
3802 return _link != null;
3803 }
3804
3805 protected void anchorConnectedOLD(AnchorEdgeType anchorEdgeType, Float delta) {
3806 // Check for a more efficient way to do this!!
3807 // Invalidate all the items
3808 for (Item i : this.getAllConnected()) {
3809 i.invalidateAll();
3810 }
3811 // Move the items
3812 for (Item i : this.getAllConnected()) {
3813 if (i.isLineEnd()) {
3814 if (delta != null) {
3815 if ((anchorEdgeType == AnchorEdgeType.Left) || (anchorEdgeType == AnchorEdgeType.Right)) {
3816 // 'delta' encodes a horizontal (x) move
3817 if (anchorEdgeType == AnchorEdgeType.Left) {
3818 i.setAnchorLeft(null);
3819 }
3820 else {
3821 // must be Right
3822 i.setAnchorRight(null);
3823 }
3824
3825 i.setXY(i.getX() + delta, i.getY());
3826 }
3827 if ((anchorEdgeType == AnchorEdgeType.Top) || (anchorEdgeType == AnchorEdgeType.Bottom)) {
3828 // 'delta; encodes a vertical (y) move
3829 if (anchorEdgeType == AnchorEdgeType.Top) {
3830 i.setAnchorTop(null);
3831 }
3832 else {
3833 // must be Bottom
3834 i.setAnchorBottom(null);
3835 }
3836 i.setXY(i.getX(), i.getY() + delta);
3837 }
3838
3839 }
3840 }
3841 }
3842 // Invalidate them again!!
3843 for (Item i : this.getAllConnected()) {
3844 i.invalidateBounds();
3845 i.invalidateAll();
3846 }
3847 }
3848
3849 protected void anchorConnected(AnchorEdgeType anchorEdgeType, Float delta) {
3850
3851 // Check for a more efficient way to do this!!
3852 // Invalidate all the items
3853 for (Item i : this.getAllConnected()) {
3854 i.invalidateAll();
3855 }
3856
3857 // Move the items
3858 for (Item i : this.getAllConnected()) {
3859 if (i.isLineEnd()) {
3860 if (delta != null) {
3861 if ((anchorEdgeType == AnchorEdgeType.Left) || (anchorEdgeType == AnchorEdgeType.Right)) {
3862 // 'delta' encodes a horizontal (x) move
3863 if (anchorEdgeType == AnchorEdgeType.Left) {
3864 // Processing a Left anchor
3865 // => Anything connected that is *not* anchored to the right should be moved by 'delta'
3866 if (i.getAnchorRight()==null) {
3867 i.setXY(i.getX() + delta, i.getY());
3868 }
3869 }
3870 else {
3871 // Processing a Right anchor
3872 // => Anything connected that is *not* anchored to the left should be moved by 'delta'
3873 if (i.getAnchorLeft()==null) {
3874 i.setXY(i.getX() + delta, i.getY());
3875 }
3876 }
3877
3878 }
3879 if ((anchorEdgeType == AnchorEdgeType.Top) || (anchorEdgeType == AnchorEdgeType.Bottom)) {
3880 // 'delta; encodes a vertical (y) move
3881 if (anchorEdgeType == AnchorEdgeType.Top) {
3882 // Processing a Top anchor
3883 // => Anything connected that is *not* anchored to the bottom should be moved by 'delta'
3884 if (i.getAnchorBottom()==null) {
3885 i.setXY(i.getX(), i.getY() + delta);
3886 }
3887 }
3888 else {
3889 // Processing a Bottom anchor
3890 // => Anything connected that is *not* anchored to the top should be moved by 'delta'
3891 if (i.getAnchorTop()==null) {
3892 // must be Bottom
3893 //i.setAnchorBottom(null);
3894 i.setXY(i.getX(), i.getY() + delta);
3895 }
3896 }
3897 }
3898 }
3899 }
3900 }
3901
3902 anchorConstraints();
3903
3904 // Invalidate them again!!
3905 for (Item i : this.getAllConnected()) {
3906 i.invalidateBounds();
3907 i.invalidateAll();
3908 }
3909 }
3910 /**
3911 * Sets the item to pickup when the user attempts to pick this item up.
3912 * EditTarget has a value of 'this' by default but may be set to other
3913 * values if this item is on a vector.
3914 *
3915 * @param target
3916 * the item to be copied or picked up when the user attempts to
3917 * edit this item.
3918 */
3919 public void setEditTarget(Item target) {
3920 _editTarget = target;
3921 }
3922
3923 /**
3924 * Gets the item to pickup when the user attempts to pick this item up.
3925 * EditTarget has a value of 'this' by default but may be set to other
3926 * values if this item is on a vector.
3927 */
3928 public Item getEditTarget() {
3929 return _editTarget;
3930 }
3931
3932 public void scale(Float scale, int originX, int originY) {
3933 setXY((getX() - originX) * scale + originX, (getY() - originY) * scale + originY);
3934 setArrowheadLength(getArrowheadLength() * scale);
3935
3936 float thickness = getThickness();
3937 if (thickness > 0)
3938 setThickness(thickness * scale, false);
3939
3940 // DONT PUT SIZE IN HERE CAUSE IT STUFFS UP CIRCLES
3941
3942 invalidateBounds();
3943 }
3944
3945 protected boolean isVectorItem() {
3946 return _editTarget != this;
3947 }
3948
3949 public AttributeValuePair getAttributeValuePair() {
3950 if (_attributeValuePair == null) {
3951 _attributeValuePair = new AttributeValuePair(getText());
3952 }
3953 return _attributeValuePair;
3954 }
3955
3956 /*
3957 * private static Set<Object> _locks = new HashSet<Object>();
3958 *
3959 * public static void lock(Object itemToLock) { _locks.add(itemToLock); }
3960 *
3961 * public static void unlock(Object itemToUnlock) {
3962 * _locks.remove(itemToUnlock); }
3963 *
3964 * public static boolean isLocked(Object item) { return
3965 * _locks.contains(item); }
3966 */
3967
3968 public void setSave(boolean state) {
3969 _save = state;
3970 }
3971
3972 public boolean getSave() {
3973 return _save;
3974 }
3975
3976 public void setAutoStamp(Float rate) {
3977 _autoStamp = rate;
3978 }
3979
3980 public Float getAutoStamp() {
3981 return _autoStamp;
3982 }
3983
3984 public boolean isAutoStamp() {
3985 return _autoStamp != null && _autoStamp >= 0.0;
3986 }
3987
3988 public int getMagnetizedItemLeft() {
3989 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR)) {
3990 return this.getPrimary().getMagnetizedItemLeft();
3991 } else {
3992 if(_magnetizedItemLeft != null) return _magnetizedItemLeft.getID();
3993 else return -1;
3994 }
3995 }
3996
3997 public void setMagnetizedItemLeft(final Item item) {
3998 _magnetizedItemLeft = item;
3999 }
4000
4001 public void setMagnetizedItemLeft(final int id) {
4002 setMagnetizedItemLeft(this.getParent().getItemWithID(id));
4003
4004 if (isSurrogate()) {
4005 surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR, false);
4006 Item primary = getPrimary();
4007 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR)) {
4008 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
4009 primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR, inheritanceCheckOnSave);
4010 }
4011 }
4012 }
4013
4014 public int getMagnetizedItemRight() {
4015 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR)) {
4016 return this.getPrimary().getMagnetizedItemRight();
4017 } else {
4018 if(_magnetizedItemRight != null) return _magnetizedItemRight.getID();
4019 else return -1;
4020 }
4021 }
4022
4023 public void setMagnetizedItemRight(final Item item) {
4024 _magnetizedItemRight = item;
4025 }
4026
4027 public void setMagnetizedItemRight(final int id) {
4028 setMagnetizedItemRight(this.getParent().getItemWithID(id));
4029
4030 if (isSurrogate()) {
4031 surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR, false);
4032 Item primary = getPrimary();
4033 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR)) {
4034 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
4035 primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR, inheritanceCheckOnSave);
4036 }
4037 }
4038 }
4039
4040 public int getMagnetizedItemTop() {
4041 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR)) {
4042 return this.getPrimary().getMagnetizedItemTop();
4043 } else {
4044 if(_magnetizedItemTop != null) return _magnetizedItemTop.getID();
4045 else return -1;
4046 }
4047 }
4048
4049 public void setMagnetizedItemTop(final Item item) {
4050 _magnetizedItemTop = item;
4051 }
4052
4053 public void setMagnetizedItemTop(final int id) {
4054 setMagnetizedItemTop(this.getParent().getItemWithID(id));
4055
4056 if (isSurrogate()) {
4057 surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR, false);
4058 Item primary = getPrimary();
4059 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR)) {
4060 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
4061 primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR, inheritanceCheckOnSave);
4062 }
4063 }
4064 }
4065
4066 public int getMagnetizedItemBottom() {
4067 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR)) {
4068 return this.getPrimary().getMagnetizedItemBottom();
4069 } else {
4070 if(_magnetizedItemBottom != null) return _magnetizedItemBottom.getID();
4071 else return -1;
4072 }
4073 }
4074
4075 public void setMagnetizedItemBottom(final Item item) {
4076 _magnetizedItemBottom = item;
4077 }
4078
4079 public void setMagnetizedItemBottom(final int id) {
4080 setMagnetizedItemBottom(this.getParent().getItemWithID(id));
4081
4082 if (isSurrogate()) {
4083 surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR, false);
4084 Item primary = getPrimary();
4085 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR)) {
4086 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
4087 primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR, inheritanceCheckOnSave);
4088 }
4089 }
4090 }
4091
4092 public String getEncryptionLabel() {
4093 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ENCRYPTION_LABEL_STR)) {
4094 return this.getPrimary().getEncryptionLabel();
4095 } else {
4096 return _encryptionLabel;
4097 }
4098 }
4099
4100 public void setEncryptionLabel(String label) {
4101 this.getSurrogates().clear();
4102 this._encryptionLabel = label;
4103
4104 if (this.getParent().getFrameEncryptionLabel() == null) {
4105 MessageBay.displayMessage("Items can only be entrypted if the frame they are on is.");
4106 return;
4107 }
4108 LabelInfo labelResult = Label.getLabel(label);
4109 if (!labelResult.is(LabelResult.SuccessResolveLabelToKey)) {
4110 MessageBay.displayMessage(labelResult.toString());
4111 this._encryptionLabel = null;
4112 return;
4113 }
4114
4115 //Setup surrogate items.
4116 Item copy = this.copy();
4117 if (copy.isAnnotation()) {
4118 if (ItemUtils.startsWithTag(copy, ItemUtils.TAG_IMAGE, true)) {
4119 String text = copy.getText();
4120 String size = "";
4121
4122 // remove @i tag
4123 text = text.replaceFirst("@i:", "");
4124 text = text.replaceAll("\n", "");
4125 text = text.trim();
4126
4127 int dotPos = text.indexOf('.');
4128 if (dotPos >= 0) {
4129 int endOfFileNamePos = text.indexOf(' ', dotPos);
4130 if (endOfFileNamePos >= 0) {
4131 size = text.substring(endOfFileNamePos).trim();
4132 }
4133 }
4134
4135 String copyText = ItemUtils.GetTag(ItemUtils.TAG_IMAGE) + ": " + Picture.REDACTED_IMAGE_NAME + " " + size;
4136 copy.setText(copyText.trim());
4137 copy.setVisible(true);
4138 }
4139 } else if (copy instanceof Text) {
4140 copy.setText("Encrypted");
4141 }
4142
4143 // Encrypt XRayables representative files and update pointer.
4144 Collection<? extends XRayable> xrayables = this.getEnclosures();
4145 for (XRayable xray: xrayables) {
4146 if (xray instanceof Picture) {
4147 EncryptedImage.encryptImage((Picture) xray, labelResult.key);
4148 Text source = xray._source;
4149 String oldName = xray.getName();
4150 String newName = oldName.substring(0, oldName.lastIndexOf('.')) + EncryptedImage.EXPEDITEE_ENCRYPTED_IMAGE_EXTENSION;
4151 source.setText(source.getText().replace(oldName, newName));
4152 }
4153 }
4154
4155 this.addToSurrogates(copy);
4156 }
4157
4158 public void setEncryptionLabelOnLoad(String label) {
4159 this._encryptionLabel = label;
4160 }
4161
4162 /**
4163 * Replaces the given dot item with a text item displaying the given character.
4164 *
4165 * @param dot
4166 * The Dot item to replace.
4167 *
4168 * @param ch
4169 * The character to display as the text for the created Text item.
4170 *
4171 * @return
4172 * The created Text item.
4173 */
4174 public static Text replaceDot(Item dot, char ch) {
4175 // TODO: Should this make sure 'dot' is actually a Dot and not some other item? cts16
4176 Text text = Text.createText(ch);
4177 Item.DuplicateItem(dot, text);
4178 FrameUtils.setLastEdited(text);
4179
4180 // Copy the lines list so it can be modified
4181 List<Line> lines = new LinkedList<Line>(dot.getLines());
4182 for (Line line : lines)
4183 line.replaceLineEnd(dot, text);
4184 Frame current = dot.getParentOrCurrentFrame();
4185 current.removeItem(dot);
4186 ItemUtils.EnclosedCheck(current.getSortedItems());
4187 return text;
4188 // TODO: Should this add the newly-created Text item to the frame? cts16
4189 }
4190
4191 /**
4192 * Replaces the given text item with a dot
4193 */
4194 public static Item replaceText(Item text) {
4195 Item dot = new Dot(text.getX(), text.getY(), text.getID());
4196 Item.DuplicateItem(text, dot);
4197
4198 List<Line> lines = new LinkedList<Line>();
4199 lines.addAll(text.getLines());
4200 if (lines.size() > 0)
4201 dot.setColor(lines.get(0).getColor());
4202 for (Line line : lines) {
4203 line.replaceLineEnd(text, dot);
4204 }
4205 text.delete();
4206 Frame current = text.getParentOrCurrentFrame();
4207 current.addItem(dot);
4208 DisplayController.setCursor(Item.DEFAULT_CURSOR);
4209 ItemUtils.EnclosedCheck(current.getSortedItems());
4210 return dot;
4211 }
4212
4213 public Set<Item> getSurrogates() {
4214 return surrogateItems;
4215 }
4216
4217 private void setAsSurrogateFor(Item primary) {
4218 this.surrogateFor = primary;
4219 }
4220
4221 public void addToSurrogates(Item surrogate) {
4222 if (this.getEncryptionLabel() == null) {
4223 MessageBay.displayMessage("Only Items with encryption labels can have surrogates.");
4224 return;
4225 }
4226
4227 this.getParent().removeItem(surrogate);
4228 this.surrogateItems.add(surrogate);
4229 surrogate.setAsSurrogateFor(this);
4230 this.getParent().addItem(surrogate);
4231
4232 EncryptionDetail reencryptOnSave = new EncryptionDetail(EncryptionDetail.Type.ReencryptOnSave);
4233 EncryptionDetail unencryptedOnSave = new EncryptionDetail(EncryptionDetail.Type.UnencryptedOnSave);
4234
4235 for (Character tag: DefaultFrameWriter.getItemCharTags().keySet()) {
4236 if (tag == 'T') {
4237 primaryPropertyEncryption.put(tag + "", reencryptOnSave.clone());
4238 } else {
4239 primaryPropertyEncryption.put(tag + "", unencryptedOnSave.clone());
4240 }
4241
4242 if (tag == 'T' || tag == 'S') {
4243 surrogate.surrogatePropertyInheritance.put(tag + "", false);
4244 } else {
4245 surrogate.surrogatePropertyInheritance.put(tag + "", true);
4246 }
4247 }
4248
4249 for (String tag: DefaultFrameWriter.getItemStrTags().keySet()) {
4250 primaryPropertyEncryption.put(tag, unencryptedOnSave.clone());
4251 surrogate.surrogatePropertyInheritance.put(tag + "", true);
4252 }
4253 }
4254
4255 public boolean isSurrogate() {
4256 return this.surrogateFor != null;
4257 }
4258
4259 public Item getPrimary() {
4260 return this.surrogateFor;
4261 }
4262
4263 public EncryptionDetail getEncryptionDetailForTag(String tag) {
4264 EncryptionDetail encryptionDetail = primaryPropertyEncryption.get(tag);
4265
4266 if (encryptionDetail == null) {
4267 EncryptionDetail unencryptedOnSave = new EncryptionDetail(EncryptionDetail.Type.UnencryptedOnSave);
4268 return unencryptedOnSave;
4269 } else {
4270 return encryptionDetail;
4271 }
4272 }
4273
4274 public void setEncryptionDetailForTag(String tag, EncryptionDetail encryptionDetail) {
4275 primaryPropertyEncryption.put(tag, encryptionDetail);
4276 }
4277
4278 public boolean isTagInherited(String tag) {
4279 return surrogatePropertyInheritance.get(tag);
4280 }
4281
4282 public void setTagNotInherited(String tag) {
4283 surrogatePropertyInheritance.put(tag, false);
4284 }
4285
4286 public boolean hasAccessToItemAsPrimary() {
4287 String label = this.getEncryptionLabel();
4288 if (this.isSurrogate() || label == null || label.length() == 0) {
4289 return true;
4290 }
4291
4292 return Label.getLabel(label).is(LabelResult.SuccessResolveLabelToKey);
4293 }
4294
4295
4296 /**
4297 * If when setting a property, we find that the primary has a undeciphered value, when we must continue using that undeciphered value
4298 * when eventually saving.
4299 * @return
4300 */
4301 protected boolean subjectToInheritanceCheckOnSave(String tag) {
4302 if (tag.equals(DefaultFrameWriter.TYPE_AND_ID_STR)) {
4303 return false;
4304 }
4305 Item primary = getPrimary();
4306 if (primary == null) return false;
4307 EncryptionDetail primaryItemTagEncryptionDetail = primary.primaryPropertyEncryption.get(tag);
4308 Type primaryItemTagEncryptionDetailType = primaryItemTagEncryptionDetail.getEncryptionDetailType();
4309 return primaryItemTagEncryptionDetailType != EncryptionDetail.Type.UseUndecipheredValueOnSave;
4310 }
4311
4312 public boolean acceptsKeyboardEnter() {
4313 return _acceptsKeyboardEnter;
4314 }
4315
4316 public void setAcceptsEnter(boolean value) {
4317 if (this.getText() != null && this.getText().equals("Beep")) {
4318 System.err.println();
4319 }
4320 _acceptsKeyboardEnter = value;
4321 }
4322}
Note: See TracBrowser for help on using the repository browser.