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

Last change on this file since 1430 was 1430, checked in by bln4, 5 years ago

Fixed bug for when there are no surrogates left for a primary.

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