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

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

Changed surrogates to work the way discussed with David. EncryptedExpReader/Writer updated to work with this.

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