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

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

You now have the ability to anchor Items to the center of the frame. AnchorCenterX: 0 will anchor a item directly to the vertical center of the frame. AnchorCenterY: 0 to the horizontal center of the frame. Negative numbers go left/up from the center, positive numbers right/down.

More work to come to deal with connected items such as rectangles made up on connected dots.

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