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

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

Frame::Parse has been updated to include a new boolean parameter. When true, widgets that are created as a result of the parse send not only notify the widget framework that they have been added, but are also visible. When false, they only notify they have been added.

The widget framework now distinguishes between added and visible widgets, this fixes a bug. Bug: when programmatically adding a widget to not the current frame, it never gets properly removed and therefore still catches click events from users. By distinguishing between adding and making visible this is avoided.


Another bug has been fixed. Bug: When setting a text item to have a right anchor, and then subsequently reducing the size of the window, this text item would get a width of zero assigned. This was caused by some issues with the logic of how right margins for items were calculated.

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