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

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

ItemEncryptionPermission is now respected.

File size: 124.6 KB
Line 
1/**
2 * Item.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.items;
20
21import java.util.ArrayList;
22import java.util.Collection;
23import java.util.ConcurrentModificationException;
24import java.util.HashMap;
25import java.util.HashSet;
26import java.util.LinkedHashSet;
27import java.util.LinkedList;
28import java.util.List;
29import java.util.Map;
30import java.util.Set;
31
32import org.expeditee.actions.Actions;
33import org.expeditee.actions.IncorrectUseOfStatementException;
34import org.expeditee.actions.Javascript;
35import org.expeditee.actions.Misc;
36import org.expeditee.actions.Simple;
37import org.expeditee.core.Anchoring;
38import org.expeditee.core.Colour;
39import org.expeditee.core.Cursor;
40import org.expeditee.core.Dimension;
41import org.expeditee.core.Fill;
42import org.expeditee.core.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 i, boolean fixWidth)
2743 {
2744 int newWidth = i - getX() - Item.MARGIN_LEFT;
2745 if (newWidth < 0) newWidth = 0;
2746
2747 if (!fixWidth) {
2748 newWidth *= -1;
2749 }
2750
2751 setWidth(newWidth);
2752 }
2753
2754 /**
2755 * Sets the position of this Item on the X axis
2756 *
2757 * @param newX
2758 * The position on the X axis to assign to this Item
2759 */
2760 public void setX(float newX) {
2761 setPosition(newX, getY());
2762
2763// if (isSurrogate()) {
2764// surrogatePropertyInheritance.put(DefaultFrameWriter.POSITION_STR, false);
2765// Item primary = getPrimary();
2766// if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.POSITION_STR)) {
2767// EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2768// primary.primaryPropertyEncryption.put(DefaultFrameWriter.POSITION_STR, inheritanceCheckOnSave);
2769// }
2770// }
2771 }
2772
2773 /**
2774 * Sets the position of this Item on the Y axis
2775 *
2776 * @param newY
2777 * The position on the Y axis to assign to this Item
2778 */
2779 public void setY(float newY) {
2780 setPosition(getX(), newY);
2781
2782// if (isSurrogate()) {
2783// surrogatePropertyInheritance.put(DefaultFrameWriter.POSITION_STR, false);
2784// Item primary = getPrimary();
2785// if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.POSITION_STR)) {
2786// EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
2787// primary.primaryPropertyEncryption.put(DefaultFrameWriter.POSITION_STR, inheritanceCheckOnSave);
2788// }
2789// }
2790 }
2791
2792 /**
2793 * Paints any highlighting of this Item. This may include changing the
2794 * thickness (lines) or painting a box around the item (Text, Images). If
2795 * val is True then the Graphics Color is changed to the highlight Color, if
2796 * False then the Graphics Color is left unchanged (for clearing of
2797 * highlighting).
2798 *
2799 * @param val
2800 * True if this Item should be highlighted, false if the
2801 * highlighting is being cleared.
2802 * @return The desired mouse cursor when this Item is highlighted (negative
2803 * means no change)
2804 */
2805
2806 /**
2807 *
2808 *
2809 * @return
2810 */
2811 public void setHighlightColorToDefault() {
2812 setHighlightColor(DEFAULT_HIGHLIGHT);
2813 }
2814
2815 public void setHighlightColor(Colour c) {
2816 if (c == null) return;
2817
2818 if (!this.isVisible() && this.hasVector()) {
2819 for (Item i : this.getParentOrCurrentFrame().getVectorItems()) {
2820 if (i.getEditTarget() == this) {
2821 i.setHighlightColor(c);
2822 }
2823 }
2824 }
2825
2826 _highlightThickness = DEFAULT_HIGHLIGHT_THICKNESS;
2827
2828 Colour selColor = (c != null) ? c : DEFAULT_HIGHLIGHT;
2829 if (_highlightColour != c) {
2830 _highlightColour = selColor;
2831 this.invalidateCommonTrait(ItemAppearence.HighlightColorChanged);
2832 }
2833
2834 }
2835
2836 private void updateArrowPolygon() {
2837 if (getArrowheadLength() < 0 || getArrowheadRatio() < 0 || getArrowheadNibPerc() < 0)
2838 _arrowhead = null;
2839 else {
2840 _arrowhead = Line.createArrowheadPolygon(getX(),getY(),getArrowheadLength(),getArrowheadRatio(),getArrowheadNibPerc());
2841 }
2842 }
2843
2844 /** Returns a Bounds which represents the area covered by the item (including its gravity). */
2845 public abstract Bounds updateBounds();
2846
2847 public void setHidden(boolean state) {
2848 this._visible = !state;
2849 }
2850
2851 public void setVisible(boolean state) {
2852 this._visible = state;
2853 }
2854
2855 public boolean isVisible() {
2856 return _visible && !_deleted;
2857 }
2858
2859 /**
2860 * Raised whenever the item is removed, added, no longer in view (That is,
2861 * when it is not on any of the current frames, of overlays of the current
2862 * frames) or has become visible. That is, when it is either on a current
2863 * frame, or an overlay of a current frame.
2864 *
2865 * @param e
2866 * The event
2867 */
2868 public void onParentStateChanged(ItemParentStateChangedEvent e) {
2869 }
2870
2871 /**
2872 * Sets the highlight mode and colour at the same time.
2873 *
2874 * @param mode The new highlight mode.
2875 * @param colour The new highlight colour.
2876 */
2877 public void setHighlightModeAndColour(HighlightMode mode, Colour colour)
2878 {
2879 setHighlightMode(mode);
2880 setHighlightColor(colour);
2881 }
2882
2883 public HighlightMode getHighlightMode() {
2884 return _highlightMode;
2885 }
2886
2887 public void anchor() {
2888 Frame current = getParentOrCurrentFrame();
2889 // only set the id if we've moved to a different frame, or if the frame already has an item with that id
2890 if(!current.equals(_oldParent) || current.getItemWithID(getID()) != null) {
2891 setID(current.getNextItemID());
2892 } else {
2893 // System.out.println(this + " - Kept old ID of " + _id);
2894 }
2895 setOffset(0, 0);
2896 setParent(current);
2897
2898 current.addItem(this, false);
2899 current.invalidateSorted();
2900 setRelativeLink();
2901 setFloating(false);
2902
2903 // // If its an unconstrained line end check if we should add a
2904 // constraint
2905 // if (isLineEnd() && getLines().size() <= 2
2906 // && getConstraints().size() <= 1) {
2907 // Constraint existingConstraint = null;
2908 // List<Constraint> constraints = getConstraints();
2909 // // Get the existing constraint
2910 // if (constraints.size() > 0) {
2911 // existingConstraint = constraints.get(0);
2912 // }
2913 // for (Line line : getLines()) {
2914 // Integer constraintType = line.getPossibleConstraint();
2915 // if (constraintType != null) {
2916 // Item oppositeEnd = line.getOppositeEnd(this);
2917 // if (existingConstraint == null
2918 // || !existingConstraint.contains(oppositeEnd)) {
2919 // new Constraint(this, oppositeEnd,
2920 // getParentOrCurrentFrame().getNextItemID(),
2921 // constraintType);
2922 // }
2923 // }
2924 // }
2925 // }
2926 }
2927
2928 /**
2929 * Gets the parent frame if it is set or the current frame if this item does
2930 * not have a parent set.
2931 *
2932 * @return
2933 */
2934 public Frame getParentOrCurrentFrame() {
2935 // if the item is from an overlay the parent will NOT be null
2936 if (getParent() == null) {
2937 return DisplayController.getCurrentFrame();
2938 }
2939 return getParent();
2940 }
2941
2942 /**
2943 * Sets the list of Dots (including this one) that form a closed shape.
2944 * Passing null sets this dot back to its normal (non-enclosed) state.
2945 *
2946 * @param enclosed
2947 * The List of Dots including this one that form a closed shape,
2948 * or null.
2949 */
2950 public void setEnclosedList(Collection<Item> enclosed) {
2951
2952 boolean changed = (_enclosure == null && enclosed != null);
2953
2954 if (_enclosure != null && enclosed == null) {
2955 invalidateFill();
2956 }
2957
2958 _enclosure = enclosed;
2959
2960 if (changed) {
2961 invalidateFill();
2962 ;
2963 }
2964 }
2965
2966 /**
2967 * Returns the polygon that represents the shape created by all the Dots in
2968 * this Dot's enclosed list. If the list is null, then null is returned.
2969 *
2970 * @return A Polygon the same shape and position as created by the Dots in
2971 * the enclosed list.
2972 */
2973 public PolygonBounds getEnclosedShape()
2974 {
2975 if (_enclosure == null) return null;
2976
2977 PolygonBounds poly = new PolygonBounds();
2978 for (Item d : _enclosure) {
2979 poly.addPoint(new Point(d.getX(), d.getY()));
2980 }
2981
2982 return poly;
2983 }
2984
2985 /**
2986 * Returns the list of Dots that, along with this Dot, form an enclosed
2987 * polygon. If this Dot is not part of an enclosure null may be returned.
2988 *
2989 * @return The List of Dots that form an enclosed shape with this Dot, or
2990 * null if this Dot is not part of an enclosure.
2991 */
2992 public Collection<Item> getEnclosingDots() {
2993 return _enclosure;
2994 }
2995
2996 /**
2997 * Returns whether this Dot has an assigned enclosure list of other Dots.
2998 * The result is the same as getEnclosedShape() != null.
2999 *
3000 * @return True if this Dot has an enclosure list of other Dots, false
3001 * otherwise.
3002 */
3003 public boolean isEnclosed() {
3004 return _enclosure != null;
3005 }
3006
3007 /**
3008 * True if this item is the end of a line.
3009 *
3010 * @return
3011 */
3012 public boolean isLineEnd() {
3013 // TODO this will need to be redone when enclosure class is added...
3014 // At the moment enclosures are only circles...we don't want circle
3015 // centres to be lineEnds
3016 return _lines.size() > 0;
3017 }
3018
3019 public boolean hasEnclosures() {
3020 return _enclosures.size() > 0;
3021 }
3022
3023 /**
3024 * Method that is called to notify an item that is on the end of a line that
3025 * its line has changed color.
3026 *
3027 * @param c
3028 * the new color for the line
3029 */
3030 protected void lineColorChanged(Colour c) {
3031 for (Line l : getLines()) {
3032 if (l.getColor() != c)
3033 l.setColor(c);
3034 }
3035 }
3036
3037 /**
3038 * Checks if this item is off the left or top of the screen
3039 *
3040 * @return
3041 */
3042 public boolean offScreenTopOrLeft() {
3043 Bounds bounds = getBoundingBox();
3044
3045 // Check that the bottom right corner of this item is on the screen
3046 if (bounds.getMaxX() >= 0 && bounds.getMaxY() >= 0) {
3047 return false;
3048 }
3049
3050 // Check if all the items it is connected to are offscreen
3051 for (Item i : getAllConnected()) {
3052 bounds = i.getBoundingBox();
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
3059 return true;
3060 }
3061
3062 public void setConnectedToAnnotation(boolean val) {
3063 _connectedToAnnotation = val;
3064 }
3065
3066 public boolean isConnectedToAnnotation() {
3067 return _connectedToAnnotation;
3068 }
3069
3070 public boolean hasAction() {
3071 List<String> actions = getAction();
3072 return actions != null && actions.size() > 0;
3073 }
3074
3075 public void setAction(String action)
3076 {
3077 // Want to resize the highlight box for text items if actions are been added
3078 if (action == null || action.length() == 0) {
3079 invalidateCommonTrait(ItemAppearence.LinkChanged);
3080 }
3081
3082 if (_actions == null || _actions.size() == 0) {
3083 invalidateBounds();
3084 _actions = new LinkedList<String>();
3085 } else {
3086 _actions.clear();
3087 }
3088
3089 if (action != null && action.length() > 0) _actions.add(action);
3090
3091 invalidateCommonTrait(ItemAppearence.LinkChanged);
3092 }
3093
3094 protected int getLinkYOffset() {
3095 return 0;
3096 }
3097
3098 protected AxisAlignedBoxBounds getLinkDrawArea() {
3099 return getLinkDrawArea(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
3100 }
3101
3102 /**
3103 * TODO: Revise - it would be good to have a member that defines the link
3104 * dimensions.
3105 *
3106 * @param x
3107 * Left of graphic (i.e not centered)
3108 * @param y
3109 * Above graphic (i.e not centered)
3110 *
3111 * @return The drawing area of the link at the given coordinates.
3112 */
3113 public AxisAlignedBoxBounds getLinkDrawArea(int x, int y) {
3114 return new AxisAlignedBoxBounds(x + 2, y - 1, 8, 8);
3115 }
3116
3117 /**
3118 * Paint the link symbol for the item if it is a
3119 *
3120 * @param g
3121 */
3122 protected void paintLink() {
3123 paintLinkGraphic(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
3124 paintKeyGraphic(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
3125 paintPadlockGraphic(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
3126 }
3127
3128 /**
3129 * Paint the link symbol for the item at a given position.
3130 *
3131 * @see #paintLink
3132 *
3133 * @param g
3134 * The graphics to paint with
3135 *
3136 * @param x
3137 * The x position of the link. Left of graphic (i.e not centered)
3138 *
3139 * @param y
3140 * The y position of the link. Above of graphic (i.e not
3141 * centered)
3142 */
3143 public void paintLinkGraphic(int x, int y) {
3144
3145 boolean hasLink = hasLink();
3146 boolean hasAction = hasAction();
3147
3148 if (hasLink || hasAction) {
3149 GraphicsManager g = EcosystemManager.getGraphicsManager();
3150 Fill fill = new Fill();
3151 Colour colour = null;
3152 Point offset = new Point(x, y);
3153
3154 if (hasLink && hasAction) {
3155 colour = LINK_ACTION_COLOR;
3156 } else if (hasLink) {
3157 colour = LINK_COLOR;
3158 } else if (hasAction) {
3159 colour = ACTION_COLOR;
3160 }
3161 fill.setColour(colour);
3162
3163 // Small circles look rubbish without AA. cts16
3164 g.setAntialiasing(true);
3165
3166 if (hasLink && getLinkMark()) {
3167 g.drawOval(offset, getLinkBounds().getDiameters(), 0.0f, null, colour, HIGHLIGHT_STROKE);
3168
3169 // if the link is not valid, cross out the circle
3170 if (!isLinkValid()) {
3171 g.drawPolygon(getCircleCross(), offset, null, 0.0f, null, colour, HIGHLIGHT_STROKE);
3172 }
3173 }
3174
3175 if (hasAction && getActionMark()) {
3176 g.drawOval(offset, getLinkBounds().getDiameters(), 0.0f, fill, colour, HIGHLIGHT_STROKE);
3177
3178 // if the link is not valid, cross out the circle
3179 if (!isLinkValid() && getLink() != null) {
3180 g.drawPolygon(getCircleCross(), offset, null, 0.0f, null, getParent().getPaintBackgroundColor(), HIGHLIGHT_STROKE);
3181 }
3182 }
3183
3184 g.setAntialiasing(false);
3185 }
3186 }
3187
3188 protected void paintKeyGraphic(int x, int y) {
3189 Colour fontColour = null;
3190 switch (this.keyType()) {
3191 case PartialKey:
3192 fontColour = Colour.LIGHT_GRAY;
3193 break;
3194 case FullKey:
3195 fontColour = Colour.BLACK;
3196 break;
3197 default:
3198 return;
3199 }
3200
3201 GraphicsManager g = EcosystemManager.getGraphicsManager();
3202 g.setAntialiasing(true);
3203 Font font = new Font();
3204 g.drawString("\uD83D\uDD11", new Point(x,y), font, fontColour);
3205 g.setAntialiasing(false);
3206 }
3207
3208 protected void paintPadlockGraphic(int x, int y) {
3209 String encryptionLabel = this.getEncryptionLabel();
3210 if (encryptionLabel != null && encryptionLabel.length() > 0) {
3211 GraphicsManager g = EcosystemManager.getGraphicsManager();
3212 g.setAntialiasing(true);
3213 Font font = new Font();
3214 g.drawString("\uD83D\uDD12", new Point(x,y), font, Colour.BLACK);
3215 g.setAntialiasing(false);
3216 }
3217 }
3218
3219 public KeyType keyType() {
3220 return keyType;
3221 }
3222
3223 public void setKeyType(String s) {
3224 try {
3225 keyType = KeyType.valueOf(s);
3226 } catch (IllegalArgumentException e) {
3227 keyType = KeyType.NotAKey;
3228 }
3229 }
3230
3231 /**
3232 * Gets the distance between the start of the text and the left border of
3233 * the item. This distance changes depending on whether or not the item is
3234 * linked or has an associated action.
3235 *
3236 * @return the gap size in pixels
3237 */
3238 protected int getLeftMargin() {
3239 return ((getLinkMark() && getLink() != null)
3240 || (getActionMark() && getAction() != null) ? MARGIN_LEFT
3241 - MARGIN_RIGHT : MARGIN_RIGHT);
3242 }
3243
3244 public String getName() {
3245 return getText();
3246 }
3247
3248 final public String getAbsoluteLinkTemplate() {
3249 return getAbsoluteLink(getLinkTemplate());
3250 }
3251
3252 final public String getAbsoluteLinkFrameset() {
3253 return getAbsoluteLink(getLinkFrameset());
3254 }
3255
3256 final public String getAbsoluteLink() {
3257 return getAbsoluteLink(getLink());
3258 }
3259
3260 /**
3261 * @param link
3262 * @return
3263 */
3264 private String getAbsoluteLink(String link) {
3265 if (link == null)
3266 return null;
3267 // assert (_parent!= null);
3268 Frame parent = getParentOrCurrentFrame();
3269 if (_parent == null) {
3270 // if parent is null it is an item on the message box
3271 // so it must already be absolute
3272 // assert (!FrameIO.isPositiveInteger(link));
3273 // return link;
3274
3275 }
3276
3277 // if its a relative link then return absolute
3278 if (FrameIO.isPositiveInteger(link)) {
3279 return parent.getFramesetName() + link;
3280 }
3281 return link;
3282 }
3283
3284 public static String convertToAbsoluteLink(String link) {
3285 if (link == null)
3286 return null;
3287 // assert (_parent!= null);
3288 Frame parent = DisplayController.getCurrentFrame();
3289 assert (parent != null);
3290
3291 // if its a relative link then return absolute
3292 if (FrameIO.isPositiveInteger(link)) {
3293 return parent.getFramesetName() + link;
3294 }
3295 return link;
3296 }
3297
3298 /**
3299 * Sets the x and y values of this item ignoring constraints.
3300 *
3301 * @param x
3302 * new x position
3303 * @param y
3304 * new y position
3305 */
3306 public void setXY(float x, float y) {
3307 _x = x;
3308 _y = y;
3309 }
3310
3311 /**
3312 * Recursive function for getting the path around a shape. This is used to
3313 * get the path that is painted on the screen.
3314 *
3315 * @param visited
3316 * @param points
3317 * @param addToEnd
3318 * @param toExplore
3319 */
3320 public void appendPath(Collection<Line> visited, LinkedList<Point> points,
3321 boolean addToEnd, Collection<Line> toExplore) {
3322
3323 if (addToEnd) {
3324 // put the start item points into our list
3325 points.addLast(getPosition());
3326 } else {
3327 points.addFirst(getPosition());
3328 }
3329
3330 // Find the line that has not been added yet
3331 LinkedList<Line> lines = new LinkedList<Line>();
3332 lines.addAll(getLines());
3333
3334 while (!lines.isEmpty()) {
3335 Line l = lines.remove();
3336 // if we haven't visited the line yet visit it
3337 if (!visited.contains(l)) {
3338 visited.add(l);
3339 Item otherEnd = l.getOppositeEnd(this);
3340 // Add all the unexplored lines to our list
3341 while (!lines.isEmpty()) {
3342 l = lines.remove();
3343 // Get the paths for the rest of the lines to be explored
3344 // later
3345 if (!toExplore.contains(l) && !visited.contains(l)) {
3346 toExplore.add(l);
3347 }
3348 }
3349 otherEnd.appendPath(visited, points, addToEnd, toExplore);
3350 }
3351 }
3352 }
3353
3354 /**
3355 * Gets the size of the enclosure that this item is part of. Used to
3356 * determine the paint order of items, with smaller items being painted
3357 * first.
3358 *
3359 * @return the area of the box surrounding the enclosed shape that this item
3360 * is part of
3361 */
3362 public double getEnclosedArea()
3363 {
3364 AxisAlignedBoxBounds box = getEnclosedBox();
3365 if (box == null) return 0.0;
3366 return box.getWidth() * box.getHeight();
3367 }
3368
3369 /**
3370 * Gets the box encompassing all points that form an enclosure with this item.
3371 *
3372 * @return An axis-aligned box around all enclosure points.
3373 */
3374 public AxisAlignedBoxBounds getEnclosedBox()
3375 {
3376 if (_enclosure == null) return null;
3377
3378 return AxisAlignedBoxBounds.getEnclosing(getEnclosedShape());
3379 }
3380
3381 public int getEnclosureID()
3382 {
3383 return _enclosure == null ? 0 : _enclosure.hashCode();
3384 }
3385
3386 /**
3387 * Returns the Bounds that surrounds this Item representing this Item's
3388 * 'gravity'.
3389 *
3390 * @return The Bounds surrounding this Item, which represents
3391 * this Items 'gravity'.
3392 */
3393 public final Bounds getBounds()
3394 {
3395 if (_bounds == null) _bounds = updateBounds();
3396
3397 // DEBUG
3398 if (_bounds == null) {
3399 //System.out.println("updateBounds failed!");
3400 }
3401
3402 return _bounds;
3403 }
3404
3405 public final Bounds getOldBounds()
3406 {
3407 return _oldBounds;
3408 }
3409
3410 public final void invalidateBounds()
3411 {
3412 if (_bounds != null) _oldBounds = _bounds;
3413 _bounds = null;
3414 for (Item surrogate: this.getSurrogates()) {
3415 surrogate.invalidateBounds();
3416 }
3417 }
3418
3419 public final AxisAlignedBoxBounds getBoundingBox()
3420 {
3421 return AxisAlignedBoxBounds.getEnclosing(getBounds());
3422 }
3423
3424 /**
3425 * Shifts the position of the item along the line between this items
3426 * location and a specified point.
3427 *
3428 * @param origin
3429 * @param ratio
3430 */
3431 public void translate(Point origin, double ratio) {
3432
3433 invalidateCommonTraitForAll(ItemAppearence.PreMoved);
3434
3435 _x = (float) (origin.getX() + ratio * (_x - origin.getX()));
3436 _y = (float) (origin.getY() + ratio * (_y - origin.getY()));
3437 invalidateBounds();
3438 for (Line line : getLines())
3439 line.invalidateBounds();
3440
3441 invalidateCommonTraitForAll(ItemAppearence.PostMoved);
3442
3443 }
3444
3445 private static int[] LinePatterns = new int[] { 0, 10, 20 };
3446
3447 /**
3448 * The rotates through a wheel of dashed lines.
3449 *
3450 * @param amount
3451 * number of rotations around the wheel to toggle by.
3452 */
3453 public void toggleDashed(int amount) {
3454 // find the index of the current line pattern
3455 int[] currentPattern = getLinePattern();
3456
3457 // Find the current pattern and move to the next pattern in the wheel
3458 for (int i = 0; i < LinePatterns.length; i++) {
3459 if (currentPattern == null || currentPattern[0] == LinePatterns[i]) {
3460 i += LinePatterns.length + amount;
3461 i %= LinePatterns.length;
3462
3463 // if we are at the start of the wheel make it 'null' (solid
3464 // line)
3465 if (i == 0) {
3466 setLinePattern(null);
3467 } else {
3468 setLinePattern(new int[] { LinePatterns[i], LinePatterns[i] });
3469 }
3470
3471 invalidateCommonTrait(ItemAppearence.ToggleDashed);
3472 return;
3473 }
3474 }
3475
3476 }
3477
3478 /**
3479 * For now there can only be one enclosure per item
3480 *
3481 * @param enclosure
3482 */
3483 public void addEnclosure(XRayable enclosure) {
3484 _enclosures.clear();
3485 _enclosures.add(enclosure);
3486 }
3487
3488 /**
3489 * Gets any XRayable items that have this item as a source.
3490 *
3491 * @return the collection of items that are linked to this item as source.
3492 * Guaranteed not to be null.
3493 */
3494 public Collection<? extends XRayable> getEnclosures() {
3495 return _enclosures;
3496 }
3497
3498 public void removeEnclosure(Item i) {
3499 _enclosures.remove(i);
3500
3501 }
3502
3503 public boolean isDeleted() {
3504 return _deleted;
3505 }
3506
3507 /**
3508 * @return The full canvas that this item draws to. Must include
3509 * highlighting bounds
3510 */
3511 public AxisAlignedBoxBounds getDrawingArea() {
3512
3513 final AxisAlignedBoxBounds boundingBox = getBoundingBox();
3514 return ItemUtils.expandRectangle(
3515 boundingBox,
3516 (int) Math.ceil(Math.max(_highlightThickness, getThickness())) + 1 // + 1 to make sure
3517 );
3518 }
3519
3520 /**
3521 *
3522 * @param area
3523 * @return True if area intersects with this items drawing area.
3524 */
3525 public final boolean isInDrawingArea(AxisAlignedBoxBounds area)
3526 {
3527 AxisAlignedBoxBounds drawingArea = getDrawingArea();
3528
3529 if (drawingArea == null) return false;
3530
3531 return drawingArea.intersects(area);
3532 }
3533
3534 /**
3535 * Completely invalidates the item - so that it should be redrawn. Note:
3536 * This is handled internally, it should be rare to invoke this externally
3537 */
3538 public final void invalidateAll()
3539 {
3540 invalidate(getDrawingArea());
3541 }
3542
3543 /**
3544 * Invalidates areas on the parent frame. Purpose: to be called on specific
3545 * areas of the item that needs redrawing.
3546 *
3547 * @param damagedAreas
3548 */
3549 protected final void invalidate(Bounds[] damagedAreas)
3550 {
3551 if (damagedAreas != null) for (Bounds b : damagedAreas) invalidate(b);
3552 }
3553
3554 /**
3555 * Invalidates areas on the parent frame. Purpose: to be called on specific
3556 * areas of the item that needs redrawing.
3557 *
3558 * @param damagedAreas
3559 */
3560 protected final void invalidate(Bounds damagedArea)
3561 {
3562 if (damagedArea != null) DisplayController.invalidateItem(this, damagedArea);
3563 }
3564
3565 /**
3566 * Used to invalidate visual traits commonly shared by all items.
3567 *
3568 * @param trait
3569 */
3570 public final void invalidateCommonTrait(ItemAppearence trait)
3571 {
3572 invalidate(getDamagedArea(trait));
3573
3574 if (_fillColour != null && (trait == ItemAppearence.Added || trait == ItemAppearence.Removed)) {
3575 invalidateFill();
3576 }
3577 }
3578
3579 /**
3580 * Invalidates fill if has one, even if no color is set.
3581 */
3582 public void invalidateFill()
3583 {
3584 if (isLineEnd() && _enclosure != null) {
3585 invalidate(getEnclosedBox());
3586 }
3587 }
3588
3589 /**
3590 * Default implementation always uses drawing area except for links, where
3591 * the link drawing area is used. Override to make item drawing more
3592 * efficient - defining only parts of the item that needs redrawing.
3593 *
3594 * @see Item.getDrawingArea
3595 *
3596 * @param trait
3597 * The visual trait that has changed.
3598 *
3599 * @return The damaged area according to the visual trait that has changed.
3600 */
3601 protected AxisAlignedBoxBounds getDamagedArea(ItemAppearence trait)
3602 {
3603 if (trait == ItemAppearence.LinkChanged)
3604 return getLinkDrawArea(); // Invalidate area where link is drawn
3605
3606 return getDrawingArea();
3607 }
3608
3609 public boolean hasVector() {
3610 return _overlay instanceof Vector;
3611 }
3612
3613 public boolean hasOverlay() {
3614 return _overlay != null;
3615 }
3616
3617 public Vector getVector() {
3618 if (_overlay instanceof Vector)
3619 return (Vector) _overlay;
3620 return null;
3621 }
3622
3623 public void setOverlay(Overlay overlay) {
3624 _overlay = overlay;
3625 }
3626
3627 public boolean dontSave() {
3628 /*
3629 * TODO Mike says: checkout if the ID check is still needed- When will
3630 * ID still be -1 when saving a frame? assert (i != null);
3631 */
3632 // make it save stuff that's off the screen so stuff isn't deleted by panning - jts21
3633 return !_save || !isVisible() || getID() < 0; // || offScreenTopOrLeft();
3634 }
3635
3636 public void setAnchorLeft(Integer anchor) {
3637 this._anchoring.setLeftAnchor(anchor);
3638 if (anchor != null) {
3639 anchorConstraints();
3640 setX(anchor);
3641 }
3642
3643 if (isSurrogate()) {
3644 surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_LEFT_STR, false);
3645 Item primary = getPrimary();
3646 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_LEFT_STR)) {
3647 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
3648 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_LEFT_STR, inheritanceCheckOnSave);
3649 }
3650 }
3651 }
3652
3653 public void setAnchorRight(Integer anchor) {
3654 this._anchoring.setRightAnchor(anchor);
3655 if (anchor != null) {
3656 anchorConstraints();
3657 setX(DisplayController.getFramePaintArea().getMaxX() - anchor - getBoundsWidth());
3658 }
3659
3660 if (isSurrogate()) {
3661 surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_RIGHT_STR, false);
3662 Item primary = getPrimary();
3663 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_RIGHT_STR)) {
3664 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
3665 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_RIGHT_STR, inheritanceCheckOnSave);
3666 }
3667 }
3668 }
3669
3670 public void setAnchorTop(Integer anchor) {
3671 this._anchoring.setTopAnchor(anchor);
3672 if (anchor != null) {
3673 anchorConstraints();
3674 setY(anchor);
3675 }
3676
3677 if (isSurrogate()) {
3678 surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_TOP_STR, false);
3679 Item primary = getPrimary();
3680 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_TOP_STR)) {
3681 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
3682 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_TOP_STR, inheritanceCheckOnSave);
3683 }
3684 }
3685 }
3686
3687
3688 public void setAnchorBottom(Integer anchor) {
3689 this._anchoring.setBottomAnchor(anchor);
3690 if (anchor != null) {
3691 anchorConstraints();
3692 setY(DisplayController.getFramePaintArea().getMaxY() - anchor);
3693 }
3694
3695 if (isSurrogate()) {
3696 surrogatePropertyInheritance.put(DefaultFrameWriter.ANCHOR_BOTTOM_STR, false);
3697 Item primary = getPrimary();
3698 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.ANCHOR_BOTTOM_STR)) {
3699 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
3700 primary.primaryPropertyEncryption.put(DefaultFrameWriter.ANCHOR_BOTTOM_STR, inheritanceCheckOnSave);
3701 }
3702 }
3703 }
3704
3705 public boolean isAnchored()
3706 {
3707 return _anchoring.isAnchored();
3708 }
3709
3710 public boolean isAnchoredX() {
3711 return _anchoring.isXAnchored();
3712 }
3713
3714 public boolean isAnchoredY() {
3715 return _anchoring.isYAnchored();
3716 }
3717
3718 public Integer getAnchorLeft() {
3719 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_LEFT_STR)) {
3720 return this.getPrimary().getAnchorLeft();
3721 } else {
3722 return _anchoring.getLeftAnchor();
3723 }
3724 }
3725
3726 public Integer getAnchorRight() {
3727 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_RIGHT_STR)) {
3728 return this.getPrimary().getAnchorRight();
3729 } else {
3730 return _anchoring.getRightAnchor();
3731 }
3732 }
3733
3734 public Integer getAnchorTop() {
3735 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_TOP_STR)) {
3736 return this.getPrimary().getAnchorTop();
3737 } else {
3738 return _anchoring.getTopAnchor();
3739 }
3740 }
3741
3742 public Integer getAnchorBottom() {
3743 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ANCHOR_BOTTOM_STR)) {
3744 return this.getPrimary().getAnchorBottom();
3745 } else {
3746 return _anchoring.getBottomAnchor();
3747 }
3748 }
3749
3750 public String getText() {
3751 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.TEXT_STR)) {
3752 return this.getPrimary().getText();
3753 } else {
3754 return "@" + getClass().getSimpleName() + ":" + getID();
3755 }
3756 }
3757
3758 public void setText(String text) {
3759 }
3760
3761 public boolean recalculateWhenChanged() {
3762 return false;
3763 }
3764
3765 public boolean update() {
3766 return calculate(getText());
3767 }
3768
3769 public Collection<Item> getEnclosedItems() {
3770 return FrameUtils.getItemsEnclosedBy(this.getParentOrCurrentFrame(),
3771 this.getEnclosedShape());
3772 }
3773
3774 public Collection<Text> getEnclosedNonAnnotationText() {
3775 Collection<Text> items = new LinkedHashSet<Text>();
3776 for (Item t : getEnclosedItems()) {
3777 if (t instanceof Text && !t.isAnnotation())
3778 items.add((Text) t);
3779 }
3780
3781 return items;
3782 }
3783
3784 public void dispose() {
3785 setParent(null);
3786 }
3787
3788 /**
3789 * @return
3790 */
3791 protected boolean hasVisibleBorder() {
3792 return getThickness() > 0 && !isLineEnd() && getBorderColor() != null;
3793 }
3794
3795 public Frame getChild() {
3796 String childName = getAbsoluteLink();
3797 if (childName != null) {
3798 return FrameIO.LoadFrame(childName);
3799 }
3800 return null;
3801 }
3802
3803 public boolean hasLink() {
3804 return _link != null;
3805 }
3806
3807 protected void anchorConnectedOLD(AnchorEdgeType anchorEdgeType, Float delta) {
3808 // Check for a more efficient way to do this!!
3809 // Invalidate all the items
3810 for (Item i : this.getAllConnected()) {
3811 i.invalidateAll();
3812 }
3813 // Move the items
3814 for (Item i : this.getAllConnected()) {
3815 if (i.isLineEnd()) {
3816 if (delta != null) {
3817 if ((anchorEdgeType == AnchorEdgeType.Left) || (anchorEdgeType == AnchorEdgeType.Right)) {
3818 // 'delta' encodes a horizontal (x) move
3819 if (anchorEdgeType == AnchorEdgeType.Left) {
3820 i.setAnchorLeft(null);
3821 }
3822 else {
3823 // must be Right
3824 i.setAnchorRight(null);
3825 }
3826
3827 i.setXY(i.getX() + delta, i.getY());
3828 }
3829 if ((anchorEdgeType == AnchorEdgeType.Top) || (anchorEdgeType == AnchorEdgeType.Bottom)) {
3830 // 'delta; encodes a vertical (y) move
3831 if (anchorEdgeType == AnchorEdgeType.Top) {
3832 i.setAnchorTop(null);
3833 }
3834 else {
3835 // must be Bottom
3836 i.setAnchorBottom(null);
3837 }
3838 i.setXY(i.getX(), i.getY() + delta);
3839 }
3840
3841 }
3842 }
3843 }
3844 // Invalidate them again!!
3845 for (Item i : this.getAllConnected()) {
3846 i.invalidateBounds();
3847 i.invalidateAll();
3848 }
3849 }
3850
3851 protected void anchorConnected(AnchorEdgeType anchorEdgeType, Float delta) {
3852
3853 // Check for a more efficient way to do this!!
3854 // Invalidate all the items
3855 for (Item i : this.getAllConnected()) {
3856 i.invalidateAll();
3857 }
3858
3859 // Move the items
3860 for (Item i : this.getAllConnected()) {
3861 if (i.isLineEnd()) {
3862 if (delta != null) {
3863 if ((anchorEdgeType == AnchorEdgeType.Left) || (anchorEdgeType == AnchorEdgeType.Right)) {
3864 // 'delta' encodes a horizontal (x) move
3865 if (anchorEdgeType == AnchorEdgeType.Left) {
3866 // Processing a Left anchor
3867 // => Anything connected that is *not* anchored to the right should be moved by 'delta'
3868 if (i.getAnchorRight()==null) {
3869 i.setXY(i.getX() + delta, i.getY());
3870 }
3871 }
3872 else {
3873 // Processing a Right anchor
3874 // => Anything connected that is *not* anchored to the left should be moved by 'delta'
3875 if (i.getAnchorLeft()==null) {
3876 i.setXY(i.getX() + delta, i.getY());
3877 }
3878 }
3879
3880 }
3881 if ((anchorEdgeType == AnchorEdgeType.Top) || (anchorEdgeType == AnchorEdgeType.Bottom)) {
3882 // 'delta; encodes a vertical (y) move
3883 if (anchorEdgeType == AnchorEdgeType.Top) {
3884 // Processing a Top anchor
3885 // => Anything connected that is *not* anchored to the bottom should be moved by 'delta'
3886 if (i.getAnchorBottom()==null) {
3887 i.setXY(i.getX(), i.getY() + delta);
3888 }
3889 }
3890 else {
3891 // Processing a Bottom anchor
3892 // => Anything connected that is *not* anchored to the top should be moved by 'delta'
3893 if (i.getAnchorTop()==null) {
3894 // must be Bottom
3895 //i.setAnchorBottom(null);
3896 i.setXY(i.getX(), i.getY() + delta);
3897 }
3898 }
3899 }
3900 }
3901 }
3902 }
3903
3904 anchorConstraints();
3905
3906 // Invalidate them again!!
3907 for (Item i : this.getAllConnected()) {
3908 i.invalidateBounds();
3909 i.invalidateAll();
3910 }
3911 }
3912 /**
3913 * Sets the item to pickup when the user attempts to pick this item up.
3914 * EditTarget has a value of 'this' by default but may be set to other
3915 * values if this item is on a vector.
3916 *
3917 * @param target
3918 * the item to be copied or picked up when the user attempts to
3919 * edit this item.
3920 */
3921 public void setEditTarget(Item target) {
3922 _editTarget = target;
3923 }
3924
3925 /**
3926 * Gets the item to pickup when the user attempts to pick this item up.
3927 * EditTarget has a value of 'this' by default but may be set to other
3928 * values if this item is on a vector.
3929 */
3930 public Item getEditTarget() {
3931 return _editTarget;
3932 }
3933
3934 public void scale(Float scale, int originX, int originY) {
3935 setXY((getX() - originX) * scale + originX, (getY() - originY) * scale + originY);
3936 setArrowheadLength(getArrowheadLength() * scale);
3937
3938 float thickness = getThickness();
3939 if (thickness > 0)
3940 setThickness(thickness * scale, false);
3941
3942 // DONT PUT SIZE IN HERE CAUSE IT STUFFS UP CIRCLES
3943
3944 invalidateBounds();
3945 }
3946
3947 protected boolean isVectorItem() {
3948 return _editTarget != this;
3949 }
3950
3951 public AttributeValuePair getAttributeValuePair() {
3952 if (_attributeValuePair == null) {
3953 _attributeValuePair = new AttributeValuePair(getText());
3954 }
3955 return _attributeValuePair;
3956 }
3957
3958 /*
3959 * private static Set<Object> _locks = new HashSet<Object>();
3960 *
3961 * public static void lock(Object itemToLock) { _locks.add(itemToLock); }
3962 *
3963 * public static void unlock(Object itemToUnlock) {
3964 * _locks.remove(itemToUnlock); }
3965 *
3966 * public static boolean isLocked(Object item) { return
3967 * _locks.contains(item); }
3968 */
3969
3970 public void setSave(boolean state) {
3971 _save = state;
3972 }
3973
3974 public boolean getSave() {
3975 return _save;
3976 }
3977
3978 public void setAutoStamp(Float rate) {
3979 _autoStamp = rate;
3980 }
3981
3982 public Float getAutoStamp() {
3983 return _autoStamp;
3984 }
3985
3986 public boolean isAutoStamp() {
3987 return _autoStamp != null && _autoStamp >= 0.0;
3988 }
3989
3990 public int getMagnetizedItemLeft() {
3991 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR)) {
3992 return this.getPrimary().getMagnetizedItemLeft();
3993 } else {
3994 if(_magnetizedItemLeft != null) return _magnetizedItemLeft.getID();
3995 else return -1;
3996 }
3997 }
3998
3999 public void setMagnetizedItemLeft(final Item item) {
4000 _magnetizedItemLeft = item;
4001 }
4002
4003 public void setMagnetizedItemLeft(final int id) {
4004 setMagnetizedItemLeft(this.getParent().getItemWithID(id));
4005
4006 if (isSurrogate()) {
4007 surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR, false);
4008 Item primary = getPrimary();
4009 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR)) {
4010 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
4011 primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_LEFT_STR, inheritanceCheckOnSave);
4012 }
4013 }
4014 }
4015
4016 public int getMagnetizedItemRight() {
4017 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR)) {
4018 return this.getPrimary().getMagnetizedItemRight();
4019 } else {
4020 if(_magnetizedItemRight != null) return _magnetizedItemRight.getID();
4021 else return -1;
4022 }
4023 }
4024
4025 public void setMagnetizedItemRight(final Item item) {
4026 _magnetizedItemRight = item;
4027 }
4028
4029 public void setMagnetizedItemRight(final int id) {
4030 setMagnetizedItemRight(this.getParent().getItemWithID(id));
4031
4032 if (isSurrogate()) {
4033 surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR, false);
4034 Item primary = getPrimary();
4035 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR)) {
4036 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
4037 primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_RIGHT_STR, inheritanceCheckOnSave);
4038 }
4039 }
4040 }
4041
4042 public int getMagnetizedItemTop() {
4043 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR)) {
4044 return this.getPrimary().getMagnetizedItemTop();
4045 } else {
4046 if(_magnetizedItemTop != null) return _magnetizedItemTop.getID();
4047 else return -1;
4048 }
4049 }
4050
4051 public void setMagnetizedItemTop(final Item item) {
4052 _magnetizedItemTop = item;
4053 }
4054
4055 public void setMagnetizedItemTop(final int id) {
4056 setMagnetizedItemTop(this.getParent().getItemWithID(id));
4057
4058 if (isSurrogate()) {
4059 surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR, false);
4060 Item primary = getPrimary();
4061 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR)) {
4062 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
4063 primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_TOP_STR, inheritanceCheckOnSave);
4064 }
4065 }
4066 }
4067
4068 public int getMagnetizedItemBottom() {
4069 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR)) {
4070 return this.getPrimary().getMagnetizedItemBottom();
4071 } else {
4072 if(_magnetizedItemBottom != null) return _magnetizedItemBottom.getID();
4073 else return -1;
4074 }
4075 }
4076
4077 public void setMagnetizedItemBottom(final Item item) {
4078 _magnetizedItemBottom = item;
4079 }
4080
4081 public void setMagnetizedItemBottom(final int id) {
4082 setMagnetizedItemBottom(this.getParent().getItemWithID(id));
4083
4084 if (isSurrogate()) {
4085 surrogatePropertyInheritance.put(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR, false);
4086 Item primary = getPrimary();
4087 if (subjectToInheritanceCheckOnSave(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR)) {
4088 EncryptionDetail inheritanceCheckOnSave = new EncryptionDetail(EncryptionDetail.Type.InheritanceCheckOnSave);
4089 primary.primaryPropertyEncryption.put(DefaultFrameWriter.MAGNETIZED_ITEM_BOTTOM_STR, inheritanceCheckOnSave);
4090 }
4091 }
4092 }
4093
4094 public String getEncryptionLabel() {
4095 if (isSurrogate() && surrogatePropertyInheritance.get(DefaultFrameWriter.ENCRYPTION_LABEL_STR)) {
4096 return this.getPrimary().getEncryptionLabel();
4097 } else {
4098 return _encryptionLabel;
4099 }
4100 }
4101
4102 public void setEncryptionLabel(String label) {
4103 if (label == null) {
4104 _encryptionLabel = null;
4105 return;
4106 }
4107
4108 if (this.getParent().getFrameEncryptionLabel() == null) {
4109 MessageBay.displayMessage("Items can only be entrypted if the frame they are on is.");
4110 return;
4111 }
4112
4113 LabelInfo labelResult = Label.getLabel(label);
4114 if (!labelResult.is(LabelResult.SuccessResolveLabelToKey)) {
4115 MessageBay.displayMessage(labelResult.toString());
4116 return;
4117 }
4118
4119 String errorMessage = "You do not have sufficient permissions to set the encryption label to " + label;
4120 UserAppliedEncryptionPermission p = getParent().getEncryptionPermission().getPermission(getParent().getOwner(), getParent().getGroupMembers());
4121 String homogeneousEncryptionLabel = getParent().getHomogeneousEncryptionLabel();
4122 if (homogeneousEncryptionLabel == null) { homogeneousEncryptionLabel = getParent().getFrameEncryptionLabel(); }
4123 if (homogeneousEncryptionLabel == null) { homogeneousEncryptionLabel = EncryptedExpWriter.getLabelNone(); }
4124 List<String> hetrogeneousFrameOwnerLabels = getParent().getHetrogeneousFrameOwnerLabels();
4125
4126 switch(p) {
4127 case none:
4128 MessageBay.errorMessage(errorMessage);
4129 return;
4130 case homogeneous:
4131 if (!homogeneousEncryptionLabel.equals(label)) {
4132 MessageBay.errorMessage(errorMessage);
4133 return;
4134 }
4135 break;
4136 case hetrogeneous_owner:
4137 if (!homogeneousEncryptionLabel.equals(label) && !hetrogeneousFrameOwnerLabels.contains(label)) {
4138 MessageBay.errorMessage(errorMessage);
4139 return;
4140 }
4141 break;
4142 case hetrogeneous: break;
4143 }
4144
4145 this.getSurrogates().clear();
4146 this._encryptionLabel = label;
4147
4148 //Setup surrogate items.
4149 generateSurrogate(labelResult);
4150 }
4151
4152 public void setEncryptionLabelOnLoad(String label) {
4153 this._encryptionLabel = label;
4154 }
4155
4156 /**
4157 * Replaces the given dot item with a text item displaying the given character.
4158 *
4159 * @param dot
4160 * The Dot item to replace.
4161 *
4162 * @param ch
4163 * The character to display as the text for the created Text item.
4164 *
4165 * @return
4166 * The created Text item.
4167 */
4168 public static Text replaceDot(Item dot, char ch) {
4169 // TODO: Should this make sure 'dot' is actually a Dot and not some other item? cts16
4170 Text text = Text.createText(ch);
4171 Item.DuplicateItem(dot, text);
4172 FrameUtils.setLastEdited(text);
4173
4174 // Copy the lines list so it can be modified
4175 List<Line> lines = new LinkedList<Line>(dot.getLines());
4176 for (Line line : lines)
4177 line.replaceLineEnd(dot, text);
4178 Frame current = dot.getParentOrCurrentFrame();
4179 current.removeItem(dot);
4180 ItemUtils.EnclosedCheck(current.getSortedItems());
4181 return text;
4182 // TODO: Should this add the newly-created Text item to the frame? cts16
4183 }
4184
4185 /**
4186 * Replaces the given text item with a dot
4187 */
4188 public static Item replaceText(Item text) {
4189 Item dot = new Dot(text.getX(), text.getY(), text.getID());
4190 Item.DuplicateItem(text, dot);
4191
4192 List<Line> lines = new LinkedList<Line>();
4193 lines.addAll(text.getLines());
4194 if (lines.size() > 0)
4195 dot.setColor(lines.get(0).getColor());
4196 for (Line line : lines) {
4197 line.replaceLineEnd(text, dot);
4198 }
4199 text.delete();
4200 Frame current = text.getParentOrCurrentFrame();
4201 current.addItem(dot);
4202 DisplayController.setCursor(Item.DEFAULT_CURSOR);
4203 ItemUtils.EnclosedCheck(current.getSortedItems());
4204 return dot;
4205 }
4206
4207 public Set<Item> getSurrogates() {
4208 return surrogateItems;
4209 }
4210
4211 private void setAsSurrogateFor(Item primary) {
4212 this.surrogateFor = primary;
4213 }
4214
4215 public void addToSurrogates(Item surrogate) {
4216 if (this.getEncryptionLabel() == null) {
4217 MessageBay.displayMessage("Only Items with encryption labels can have surrogates.");
4218 return;
4219 }
4220
4221 this.getParent().removeItem(surrogate);
4222 this.surrogateItems.add(surrogate);
4223 surrogate.setAsSurrogateFor(this);
4224 this.getParent().addItem(surrogate);
4225
4226 EncryptionDetail reencryptOnSave = new EncryptionDetail(EncryptionDetail.Type.ReencryptOnSave);
4227 EncryptionDetail unencryptedOnSave = new EncryptionDetail(EncryptionDetail.Type.UnencryptedOnSave);
4228
4229 for (Character tag: DefaultFrameWriter.getItemCharTags().keySet()) {
4230 if (tag == 'T') {
4231 primaryPropertyEncryption.put(tag + "", reencryptOnSave.clone());
4232 } else {
4233 primaryPropertyEncryption.put(tag + "", unencryptedOnSave.clone());
4234 }
4235
4236 if (tag == 'T' || tag == 'S') {
4237 surrogate.surrogatePropertyInheritance.put(tag + "", false);
4238 } else {
4239 surrogate.surrogatePropertyInheritance.put(tag + "", true);
4240 }
4241 }
4242
4243 for (String tag: DefaultFrameWriter.getItemStrTags().keySet()) {
4244 primaryPropertyEncryption.put(tag, unencryptedOnSave.clone());
4245 surrogate.surrogatePropertyInheritance.put(tag + "", true);
4246 }
4247 }
4248
4249 public boolean isSurrogate() {
4250 return this.surrogateFor != null;
4251 }
4252
4253 public Item getPrimary() {
4254 return this.surrogateFor;
4255 }
4256
4257 public EncryptionDetail getEncryptionDetailForTag(String tag) {
4258 EncryptionDetail encryptionDetail = primaryPropertyEncryption.get(tag);
4259
4260 if (encryptionDetail == null) {
4261 EncryptionDetail unencryptedOnSave = new EncryptionDetail(EncryptionDetail.Type.UnencryptedOnSave);
4262 return unencryptedOnSave;
4263 } else {
4264 return encryptionDetail;
4265 }
4266 }
4267
4268 public void setEncryptionDetailForTag(String tag, EncryptionDetail encryptionDetail) {
4269 primaryPropertyEncryption.put(tag, encryptionDetail);
4270 }
4271
4272 public boolean isTagInherited(String tag) {
4273 return surrogatePropertyInheritance.get(tag);
4274 }
4275
4276 public void setTagNotInherited(String tag) {
4277 surrogatePropertyInheritance.put(tag, false);
4278 }
4279
4280 public boolean hasAccessToItemAsPrimary() {
4281 String label = this.getEncryptionLabel();
4282 if (this.isSurrogate() || label == null || label.length() == 0) {
4283 return true;
4284 }
4285
4286 return Label.getLabel(label).is(LabelResult.SuccessResolveLabelToKey);
4287 }
4288
4289
4290 /**
4291 * If when setting a property, we find that the primary has a undeciphered value, when we must continue using that undeciphered value
4292 * when eventually saving.
4293 * @return
4294 */
4295 protected boolean subjectToInheritanceCheckOnSave(String tag) {
4296 if (tag.equals(DefaultFrameWriter.TYPE_AND_ID_STR)) {
4297 return false;
4298 }
4299 Item primary = getPrimary();
4300 if (primary == null) return false;
4301 EncryptionDetail primaryItemTagEncryptionDetail = primary.primaryPropertyEncryption.get(tag);
4302 Type primaryItemTagEncryptionDetailType = primaryItemTagEncryptionDetail.getEncryptionDetailType();
4303 return primaryItemTagEncryptionDetailType != EncryptionDetail.Type.UseUndecipheredValueOnSave;
4304 }
4305
4306 public boolean acceptsKeyboardEnter() {
4307 return _acceptsKeyboardEnter;
4308 }
4309
4310 public void setAcceptsEnter(boolean value) {
4311 if (this.getText() != null && this.getText().equals("Beep")) {
4312 System.err.println();
4313 }
4314 _acceptsKeyboardEnter = value;
4315 }
4316
4317 private void generateSurrogate(LabelInfo labelResult) {
4318 Item copy = this.copy();
4319 if (copy.isAnnotation()) {
4320 if (ItemUtils.startsWithTag(copy, ItemUtils.TAG_IMAGE, true)) {
4321 String text = copy.getText();
4322 String size = "";
4323
4324 // remove @i tag
4325 text = text.replaceFirst("@i:", "");
4326 text = text.replaceAll("\n", "");
4327 text = text.trim();
4328
4329 int dotPos = text.indexOf('.');
4330 if (dotPos >= 0) {
4331 int endOfFileNamePos = text.indexOf(' ', dotPos);
4332 if (endOfFileNamePos >= 0) {
4333 size = text.substring(endOfFileNamePos).trim();
4334 }
4335 }
4336
4337 String copyText = ItemUtils.GetTag(ItemUtils.TAG_IMAGE) + ": " + Picture.REDACTED_IMAGE_NAME + " " + size;
4338 copy.setText(copyText.trim());
4339 copy.setVisible(true);
4340 }
4341 } else if (copy instanceof Text) {
4342 copy.setText("Encrypted");
4343 }
4344
4345 // Encrypt XRayables representative files and update pointer.
4346 Collection<? extends XRayable> xrayables = this.getEnclosures();
4347 for (XRayable xray: xrayables) {
4348 if (xray instanceof Picture) {
4349 EncryptedImage.encryptImage((Picture) xray, labelResult.key);
4350 Text source = xray._source;
4351 String oldName = xray.getName();
4352 String newName = oldName.substring(0, oldName.lastIndexOf('.')) + EncryptedImage.EXPEDITEE_ENCRYPTED_IMAGE_EXTENSION;
4353 source.setText(source.getText().replace(oldName, newName));
4354 }
4355 }
4356
4357 this.addToSurrogates(copy);
4358 }
4359}
Note: See TracBrowser for help on using the repository browser.