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

Last change on this file since 1102 was 1102, checked in by davidb, 6 years ago

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

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