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

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

Implementation of the surrogate system.
When you set an item to have a encryption label, a surrogate for that item is generated.
The newly updated EncryptedExpReader/Writer has been updated to maintain the connection between the item and its surrogate.

Coming up next:
Surrogate mode. The ability to simulate viewing and editing an encrypted frame with a limited set of labels.

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