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

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

Recoding of the Labels class to improve surrogate mode functionality. Surrogate mode is now maintained when you navigate from one frame to another, even if that frame has a different set of labels. Completely different sets of labels cause Expeditee to exit surrogate mode with a message to the user.

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