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

Last change on this file since 278 was 278, checked in by ra33, 16 years ago

Fixed some bugs...
AbstractCharts can not be copied, resized, etc

File size: 63.0 KB
Line 
1package org.expeditee.items;
2
3import java.awt.BasicStroke;
4import java.awt.Color;
5import java.awt.Cursor;
6import java.awt.GradientPaint;
7import java.awt.Graphics2D;
8import java.awt.Point;
9import java.awt.Polygon;
10import java.awt.Rectangle;
11import java.awt.Shape;
12import java.awt.Stroke;
13import java.awt.geom.AffineTransform;
14import java.awt.geom.Area;
15import java.awt.geom.Point2D;
16import java.awt.geom.Rectangle2D;
17import java.util.ArrayList;
18import java.util.Collection;
19import java.util.ConcurrentModificationException;
20import java.util.HashSet;
21import java.util.LinkedHashSet;
22import java.util.LinkedList;
23import java.util.List;
24
25import org.expeditee.actions.Actions;
26import org.expeditee.actions.Misc;
27import org.expeditee.actions.Simple;
28import org.expeditee.gui.DisplayIO;
29import org.expeditee.gui.Frame;
30import org.expeditee.gui.FrameGraphics;
31import org.expeditee.gui.FrameIO;
32import org.expeditee.gui.FrameKeyboardActions;
33import org.expeditee.gui.FrameUtils;
34import org.expeditee.gui.FreeItems;
35import org.expeditee.gui.MessageBay;
36import org.expeditee.gui.Overlay;
37import org.expeditee.gui.Vector;
38import org.expeditee.io.Conversion;
39import org.expeditee.io.Logger;
40import org.expeditee.simple.Context;
41import org.expeditee.stats.AgentStats;
42
43/**
44 * Represents everything that can be drawn on the screen (text, lines, dots,
45 * images). Each specific type is a subclass of Item.
46 *
47 * @author jdm18
48 *
49 */
50public abstract class Item implements Comparable<Item>, Runnable {
51
52 public static final Float DEFAULT_THICKNESS = 2f;
53
54 public static final Float MINIMUM_THICKNESS = 0f;
55
56 public static final Float MINIMUM_PAINT_THICKNESS = 1f;
57
58 protected final int JOIN = BasicStroke.JOIN_ROUND;
59
60 protected final int CAP = BasicStroke.CAP_BUTT;
61
62 protected final Stroke HIGHLIGHT_STROKE = new BasicStroke(
63 MINIMUM_THICKNESS, CAP, JOIN, 4.0F);
64
65 // contains all dots (including this one) that form an enclosure
66 // if this dot is part of an enclosing shape
67 private Collection<Item> _enclosure = null;
68
69 public static final int LEFT_MARGIN = 13;
70
71 // indicates which end the arrowhead should be drawn at
72 protected Polygon _poly = null;
73
74 protected boolean _connectedToAnnotation = false;
75
76 public static final int NEAR_DISTANCE = 15;
77
78 /**
79 * The default Color to draw highlighting in
80 */
81 public static final int DEFAULT_HIGHLIGHT_THICKNESS = 2;
82
83 public static final Color DEFAULT_HIGHLIGHT = Color.RED;
84
85 public static final Color DEPRESSED_HIGHLIGHT = Color.GREEN;
86
87 public static final Color ALTERNATE_HIGHLIGHT = Color.BLUE;
88
89 public static final Color LINK_COLOR = Color.BLACK;
90
91 public static final Color ACTION_COLOR = Color.BLACK;
92
93 public static final Color LINK_ACTION_COLOR = Color.RED;
94
95 public static final Color DEFAULT_FOREGROUND = Color.BLACK;
96
97 public static final Color DEFAULT_BACKGROUND = Color.white;
98
99 public static final Color TRANSPARENT = new Color(0, 0, 0, 0);
100
101 /**
102 * The number of pixels highlighting should extend around Items.
103 */
104 public static final int XGRAVITY = 3;
105
106 public static final int MARGIN_RIGHT = 2;
107
108 public static final int MARGIN_LEFT = 15;
109
110 protected static final double DEFAULT_ARROWHEAD_RATIO = 0.5;
111
112 public static final Color GREEN = Color.GREEN.darker();
113
114 /**
115 * The Colors cycled through when using function keys to set the Color of
116 * this Item.
117 */
118 public static Color[] COLOR_WHEEL = { Color.BLACK, Color.RED, Color.BLUE,
119 Item.GREEN, Color.MAGENTA, Color.YELLOW.darker(), Color.WHITE };
120
121 // TODO Have shift toggle through a black and white color wheel?
122 public static Color[] FILL_COLOR_WHEEL = { new Color(255, 150, 150),
123 new Color(150, 150, 255), new Color(150, 255, 150),
124 new Color(255, 150, 255), new Color(255, 255, 100), Color.WHITE,
125 Color.BLACK };
126
127 public static final int UNCHANGED_CURSOR = -100;
128
129 public static final int DEFAULT_CURSOR = Cursor.DEFAULT_CURSOR;
130
131 public static final int HIDDEN_CURSOR = Cursor.CUSTOM_CURSOR;
132
133 public static final int TEXT_CURSOR = Cursor.TEXT_CURSOR;
134
135 public static final int CROP_CURSOR = Cursor.CROSSHAIR_CURSOR;
136
137 // The default value for integer attributes
138 public static final int DEFAULT_INTEGER = -1;
139
140 public static final int POINTTYPE_SQUARE = -1;
141
142 public static final int POINTTYPE_CIRCLE = 0;
143
144 public static void DuplicateItem(Item source, Item dest) {
145 dest.setX(source.getX());
146 dest.setY(source.getY());
147
148 dest.setActions(source.getAction());
149 dest.setActionCursorEnter(source.getActionCursorEnter());
150 dest.setActionCursorLeave(source.getActionCursorLeave());
151 dest.setActionEnterFrame(source.getActionEnterFrame());
152 dest.setActionLeaveFrame(source.getActionLeaveFrame());
153 dest.setActionMark(source.getActionMark());
154
155 dest.setBackgroundColor(source.getBackgroundColor());
156 dest.setBottomShadowColor(source.getBottomShadowColor());
157 dest.setColor(source.getColor());
158 dest.setBorderColor(source.getBorderColor());
159
160 dest.setData(source.getData());
161 dest.setTag(source.getTag());
162 dest.setFillColor(source.getFillColor());
163 dest.setGradientColor(source.getGradientColor());
164 dest.setFillPattern(source.getFillPattern());
165
166 dest.setHighlight(source.getHighlight());
167 dest.setLink(source.getLink());
168 dest.setLinkFrameset(source.getLinkFrameset());
169 dest.setLinkMark(source.getLinkMark());
170 dest.setLinkTemplate(source.getLinkTemplate());
171
172 // dest.setMaxWidth(source.getMaxWidth());
173
174 dest.setOffset(source.getOffset());
175 dest.setOwner(source.getOwner());
176 dest.setThickness(source.getThickness());
177 dest.setSize(source.getSize());
178 dest.setTopShadowColor(source.getTopShadowColor());
179 dest.setLinePattern(source.getLinePattern());
180
181 dest.setFloating(source.isFloating());
182 dest.setArrow(source.getArrowheadLength(), source.getArrowheadRatio());
183
184 dest.setAnchorBottom(source.getAnchorBottom());
185 dest.setAnchorRight(source.getAnchorRight());
186
187 dest.setFormula(source.getFormula());
188 dest.setParent(source.getParent());
189 dest._overlay = source._overlay;
190 dest._mode = source._mode;// SelectedMode.None;
191 dest._visible = source._visible;
192 Frame parent = source.getParentOrCurrentFrame();
193 // TODO MIKE says maybe we could tighten up and only give items ID's if
194 // their
195 // current ID is negative?
196 if (parent != null) {
197 dest.setID(source.getParentOrCurrentFrame().getNextItemID());
198 }
199 // else {
200 // dest.setID(source.getID());
201 // }
202 }
203
204 public static int getGravity() {
205 return org.expeditee.gui.UserSettings.Gravity;
206 }
207
208 public static boolean showLineHighlight() {
209 return org.expeditee.gui.UserSettings.LineHighlight;
210 }
211
212 public enum HighlightMode {
213 None, Enclosed, Connected, Disconnect, Normal
214 }
215
216 public void setHighlightMode(HighlightMode mode) {
217 setHighlightMode(mode, DEFAULT_HIGHLIGHT);
218 }
219
220 protected Float _anchorRight = null;
221
222 protected Float _anchorBottom = null;
223
224 protected HighlightMode _mode = HighlightMode.None;
225
226 private Point _offset = new Point(0, 0);
227
228 protected float _x;
229
230 protected float _y;
231
232 private int _id;
233
234 private String _creationDate = null;
235
236 private boolean _linkMark = true;
237
238 private boolean _actionMark = true;
239
240 private boolean _highlight = true;
241
242 // private int _maxWidth = -1;
243
244 private String _owner = null;
245
246 private String _link = null;
247
248 private StringBuffer _tag = new StringBuffer();
249
250 private List<String> _actionCursorEnter = null;
251
252 private List<String> _actionCursorLeave = null;
253
254 private List<String> _actionEnterFrame = null;
255
256 private List<String> _actionLeaveFrame = null;
257
258 public Permission _permission = Permission.full;
259
260 public void setPermission(Permission permission) {
261 _permission = permission;
262 }
263
264 public boolean hasPermission(Permission permission) {
265 return _permission.ordinal() >= permission.ordinal();
266 }
267
268 // A fill color of null represents transparent
269 private Color _colorFill = null;
270
271 // A gradient color of null represents NO gradient
272 private Color _colorGradient = null;
273
274 // A fore color of null represents the default color
275 private Color _color = null;
276
277 protected Color _highlightColor = DEFAULT_HIGHLIGHT;
278
279 private Color _colorBackground = null;
280
281 private Color _colorBorder = null;
282
283 private Color _colorTopShadow = null;
284
285 private Color _colorBottomShadow = null;
286
287 // the link\action circle
288 private Polygon _circle = null;
289
290 // the invalid link cross
291 private Polygon _circleCross = null;
292
293 private Frame _parent = null;
294
295 protected int _highlightThickness = 2;
296
297 // arrowhead parameters
298 private float _arrowheadLength = 0;
299
300 private double _arrowheadRatio = DEFAULT_ARROWHEAD_RATIO;
301
302 private Polygon _arrowhead = null;
303
304 // the list of lines that this point is part of.
305 private List<Line> _lines = new ArrayList<Line>();
306
307 private int[] _linePattern = null;
308
309 private boolean _floating = false;
310
311 // list of points constrained with this point
312 private List<Constraint> _constraints = new ArrayList<Constraint>();
313
314 private List<String> _actions = null;
315
316 private List<String> _data = null;
317
318 private String _formula = null;
319
320 private String _link_frameset = null;
321
322 private String _link_template = null;
323
324 private String _fillPattern = null;
325
326 private boolean _visible = true;
327
328 private float _thickness = -1.0F;
329
330 protected Item() {
331 _creationDate = Logger.EasyDateFormat("ddMMMyyyy:HHmm");
332 }
333
334 /**
335 * Adds an action to this Item.
336 *
337 * @param action
338 * The action to add to this Item
339 */
340 public void addAction(String action) {
341 if (action == null || action.equals("")) {
342 return;
343 }
344
345 if (_actions == null) {
346 _actions = new LinkedList<String>();
347 }
348 _actions.add(action);
349 if (_actions.size() == 1) {
350 _poly = null;
351 invalidateCommonTrait(ItemAppearence.LinkChanged);
352 }
353 }
354
355 public void addAllConnected(Collection<Item> connected) {
356 if (!connected.contains(this))
357 connected.add(this);
358
359 for (Item item : getConnected()) {
360 if (!connected.contains(item))
361 item.addAllConnected(connected);
362 }
363 }
364
365 /**
366 * Adds the given Constraint to this Dot
367 *
368 * @param c
369 * The Constraint to set this Dot as a member of.
370 */
371 public void addConstraint(Constraint c) {
372 // do not add duplicate constraint
373 if (_constraints.contains(c))
374 return;
375
376 _constraints.add(c);
377 }
378
379 /**
380 * Adds a given line to the list of lines that this Point is an end for.
381 *
382 * @param line
383 * The Line that this Point is an end of.
384 */
385 public void addLine(Line line) {
386 if (_lines.contains(line)) {
387 return;
388 }
389
390 _lines.add(line);
391 }
392
393 /**
394 * Items are sorted by their Y coordinate on the screen.
395 *
396 * @param i
397 * The Item to compare this Item to
398 * @return a negative integer, zero, or a positive integer as this object is
399 * less than, equal to, or greater than the specified object.
400 */
401 public int compareTo(Item i) {
402 return getY() - i.getY();
403 }
404
405 /**
406 * Every Item has an area around it defined by a Shape (typically a
407 * rectangle), this method returns true if the given x,y pair lies within
408 * the area and false otherwise.
409 *
410 * @param x
411 * The x coordinate to check
412 * @param y
413 * The y coordinate to check
414 * @return True if the Shape around this Item contains the given x,y pair,
415 * false otherwise.
416 */
417 public boolean contains(int x, int y) {
418 return getPolygon().contains(x, y);
419 }
420
421 /**
422 * Returns a deep copy of this Item, note: it is up to the receiver to
423 * change the Item ID etc as necessary.
424 *
425 * @return A deep copy of this Item.
426 */
427 public abstract Item copy();
428
429 public void delete() {
430 _deleted = true;
431 }
432
433 @Override
434 public boolean equals(Object o) {
435 if (o == null)
436 return false;
437 if (getClass().equals(o.getClass())) {
438 Item i = (Item) o;
439 return i.getID() == getID()
440 && ((i.getParent() == _parent) || (i.getParent() != null && i
441 .getParent().equals(_parent)));
442 } else
443 return false;
444 }
445
446 /**
447 * Returns a list of any action code that is currently associated with this
448 * Item
449 *
450 * @return A List of action code associated with this Item, or null if none
451 * has been assigned.
452 */
453 public List<String> getAction() {
454 return _actions;
455 }
456
457 public List<String> getData() {
458 return _data;
459 }
460
461 public List<String> getActionCursorEnter() {
462 return _actionCursorEnter;
463 }
464
465 public List<String> getActionCursorLeave() {
466 return _actionCursorLeave;
467 }
468
469 public List<String> getActionEnterFrame() {
470 return _actionEnterFrame;
471 }
472
473 public List<String> getActionLeaveFrame() {
474 return _actionLeaveFrame;
475 };
476
477 public boolean getActionMark() {
478 return _actionMark;
479 }
480
481 /**
482 * Gets all the items connected to this item. Uses a recursive approach to
483 * search connected points.
484 *
485 * @return
486 */
487 public Collection<Item> getAllConnected() {
488 Collection<Item> list = new LinkedHashSet<Item>();
489 addAllConnected(list);
490 return list;
491 }
492
493 public Area getArea() {
494 return new Area(getPolygon());
495 }
496
497 public String getArrow() {
498 if (!hasVisibleArrow())
499 return null;
500
501 String ratio = "" + getArrowheadRatio();
502 if (ratio.length() - ratio.indexOf(".") > 2)
503 ratio = ratio.substring(0, ratio.indexOf(".") + 3);
504
505 return getArrowheadLength() + " " + ratio;
506 }
507
508 public Polygon getArrowhead() {
509 return _arrowhead;
510 }
511
512 public float getArrowheadLength() {
513 return _arrowheadLength;
514 }
515
516 public double getArrowheadRatio() {
517 return _arrowheadRatio;
518 }
519
520 public Color getBackgroundColor() {
521 return _colorBackground;
522 }
523
524 public Color getBorderColor() {
525 return _colorBorder;
526 }
527
528 /**
529 * Returns the Color being used to shade the bottom half of this Item's
530 * border. This can be NULL if no Color is being used
531 *
532 * @return The Color displayed on the bottom\right half of this Item's
533 * border.
534 */
535 public Color getBottomShadowColor() {
536 return _colorBottomShadow;
537 }
538
539 /**
540 * Returns the height (in pixels) of this Item's surrounding area.
541 *
542 * @return The height (in pixels) of this Item's surrounding area as
543 * returned by getArea().
544 */
545 public int getBoundsHeight() {
546 return getPolygon().getBounds().height;
547 }
548
549 /**
550 * Returns the width (in pixels) of this Item's surrounding area.
551 *
552 * @return The width (in pixels) of this Item's surrounding area as returned
553 * by getArea().
554 */
555 public int getBoundsWidth() {
556 return getPolygon().getBounds().width;
557 }
558
559 // TODO draw the link with a circle rather than a polygon!!
560 protected Polygon getLinkPoly() {
561 if (_circle == null) {
562 int points = 16;
563
564 double radians = 0.0;
565 int xPoints[] = new int[points];
566 int yPoints[] = new int[xPoints.length];
567
568 for (int i = 0; i < xPoints.length; i++) {
569 // circle looks best if these values are not related to gravity
570 xPoints[i] = (int) (3.5 * Math.cos(radians)) + 6;// (2 *
571 // GRAVITY);
572 yPoints[i] = (int) (3.5 * Math.sin(radians)) + 3;// GRAVITY;
573 radians += (2.0 * Math.PI) / xPoints.length;
574 }
575
576 _circle = new Polygon(xPoints, yPoints, xPoints.length);
577 }
578
579 return _circle;
580 }
581
582 protected Polygon getCircleCross() {
583
584 if (_circleCross == null) {
585 _circleCross = new Polygon();
586
587 Rectangle bounds = getLinkPoly().getBounds();
588 int x1 = (int) bounds.getMinX();
589 int x2 = (int) bounds.getMaxX();
590 int y1 = (int) bounds.getMinY();
591 int y2 = (int) bounds.getMaxY();
592 int midX = ((x2 - x1) / 2) + x1;
593 int midY = ((y2 - y1) / 2) + y1;
594
595 _circleCross.addPoint(x1, y1);
596 _circleCross.addPoint(x2, y2);
597 _circleCross.addPoint(midX, midY);
598 _circleCross.addPoint(x1, y2);
599 _circleCross.addPoint(x2, y1);
600 _circleCross.addPoint(midX, midY);
601 }
602
603 return _circleCross;
604 }
605
606 public Color getColor() {
607 return _color;
608 }
609
610 public Collection<Item> getConnected() {
611 List<Item> conn = new LinkedList<Item>();
612 conn.add(this);
613 conn.addAll(getEnclosures());
614 conn.addAll(getLines());
615 return conn;
616 }
617
618 public String getConstraintIDs() {
619 if (_constraints == null || _constraints.size() == 0)
620 return null;
621
622 String cons = "";
623
624 for (Constraint c : _constraints)
625 cons += c.getID() + " ";
626
627 return cons.trim();
628 }
629
630 /*
631 * public void setLinkValid(boolean val) { _isValidLink = val; }
632 */
633
634 /**
635 * Returns a List of any Constraints that this Dot is a memeber of.
636 *
637 * @return a List of Constraints that this Dot is a member of.
638 */
639 public List<Constraint> getConstraints() {
640 return _constraints;
641 }
642
643 public String getTag() {
644 if (_tag != null && _tag.length() > 0)
645 return _tag.toString();
646 return null;
647 }
648
649 public String getDateCreated() {
650 return _creationDate;
651 }
652
653 public Color getFillColor() {
654 return _colorFill;
655 }
656
657 public String getFillPattern() {
658 return _fillPattern;
659 }
660
661 public String getFirstAction() {
662 if (_actions == null || _actions.size() == 0)
663 return null;
664 return _actions.get(0);
665 }
666
667 public boolean getHighlight() {
668 return _highlight;
669 }
670
671 public Color getHighlightColor() {
672 if (_highlightColor.equals(getPaintColor()))
673 return ALTERNATE_HIGHLIGHT;
674 return _highlightColor;
675 }
676
677 /**
678 * Returns the ID of this Item, which must be unique for the Frame.
679 *
680 * @return The ID of this Item.
681 */
682 public int getID() {
683 return _id;
684 }
685
686 /**
687 * Returns the list of IDs of the Lines that this Dot is an end of.
688 *
689 * @return The list of Line IDs that this point is part of.
690 */
691 public String getLineIDs() {
692 String lineID = null;
693
694 if (_lines.size() > 0) {
695 lineID = "" + _lines.get(0).getID();
696
697 for (int i = 1; i < _lines.size(); i++)
698 lineID += " " + _lines.get(i).getID();
699 }
700
701 return lineID;
702 }
703
704 public int[] getLinePattern() {
705 return _linePattern;
706 }
707
708 /**
709 * Returns a list of Lines where this Dot is an end.
710 *
711 * @return A list of the Lines that this Dot is an end for or null if no
712 * Lines have been added.
713 */
714 public List<Line> getLines() {
715 return _lines;
716 }
717
718 /**
719 * Returns the name of a Frame that this Item links to, or null if this Item
720 * has no link.
721 *
722 * @return The name of a Frame that this Item links to (if any) or null if
723 * this Item does not link to anything.
724 */
725 public String getLink() {
726 return _link;
727 }
728
729 public String getFormula() {
730 return _formula;
731 }
732
733 public boolean hasFormula() {
734 return _formula != null;
735 }
736
737 public void setFormula(String formula) {
738 _formula = formula;
739 }
740
741 public void calculate(String formula) {
742 setFormula(formula);
743 }
744
745 public String getLinkFrameset() {
746 return _link_frameset;
747 }
748
749 public boolean getLinkMark() {
750 return _linkMark;
751 }
752
753 public String getLinkTemplate() {
754 return _link_template;
755 }
756
757 // public int getMaxWidth() {
758 // return _maxWidth;
759 // }
760
761 public Point getOffset() {
762 return _offset;
763 }
764
765 public String getOwner() {
766 return _owner;
767 }
768
769 public Color getPaintBackgroundColor() {
770 Color colorBackground = getBackgroundColor();
771 if (colorBackground == null) {
772 if (getParent() != null && getParent().getBackgroundColor() != null)
773 return getParent().getBackgroundColor();
774
775 return DEFAULT_BACKGROUND;
776 }
777
778 return colorBackground;
779 }
780
781 /**
782 * Returns the foreground Color of this Item.
783 *
784 * @return The Color of this item (foreground)
785 */
786 public final Color getPaintColor() {
787 // If color is null then get the paint foregroundColor for the frame the
788 // item is on which is a color adjusted to suit the background
789 Color color = getColor();
790
791 if (color == null) {
792 if (getParent() != null)
793 return getParent().getPaintForegroundColor();
794
795 Frame current = DisplayIO.getCurrentFrame();
796 if (current == null) {
797 return DEFAULT_FOREGROUND;
798 }
799 return current.getPaintForegroundColor();
800 }
801
802 return color;
803 }
804
805 public final Color getPaintBorderColor() {
806 // If color is null then get the paint foregroundColor for the frame the
807 // item is on which is a color adjusted to suit the background
808 Color color = getBorderColor();
809
810 if (color == null) {
811 if (getParent() != null)
812 return getParent().getPaintForegroundColor();
813
814 Frame current = DisplayIO.getCurrentFrame();
815 if (current == null) {
816 return DEFAULT_FOREGROUND;
817 }
818 return current.getPaintForegroundColor();
819 }
820
821 return color;
822 }
823
824 protected Color getPaintHighlightColor() {
825 Color highlightColor = _highlightColor;
826 if (hasVisibleBorder()) {
827 if (getPaintBorderColor().equals(highlightColor)) {
828 highlightColor = ALTERNATE_HIGHLIGHT;
829 }
830 } else if (getPaintBackgroundColor().equals(highlightColor)) {
831 highlightColor = ALTERNATE_HIGHLIGHT;
832 }
833 if (getParent() != null
834 && getParent().getPaintBackgroundColor().equals(highlightColor))
835 highlightColor = getParent().getPaintForegroundColor();
836
837 if (hasVisibleBorder()) {
838 if (highlightColor.equals(getBorderColor())
839 && getThickness() == _highlightThickness) {
840 highlightColor = new Color(highlightColor.getRed(),
841 highlightColor.getGreen(), highlightColor.getBlue(),
842 150);
843 }
844 }
845
846 return highlightColor;
847 }
848
849 public final Frame getParent() {
850 return _parent;
851 }
852
853 public final Point getPosition() {
854 return new Point(getX(), getY());
855 }
856
857 /**
858 * Returns the size of this Item. For Text this is the Font size, for Lines
859 * and Dots this is the thickness.
860 *
861 * @return The size of this Item.
862 */
863 public float getSize() {
864 return -1.0F;
865 }
866
867 /**
868 * Returns the Color being used to shade the top half of this Item's border.
869 * This can be NULL if no Color is being used
870 *
871 * @return The Color displayed on the top\left half of this Item's border.
872 */
873 public Color getTopShadowColor() {
874 return _colorTopShadow;
875 }
876
877 public String getTypeAndID() {
878 return "T " + getID();
879 }
880
881 public int getWidth() {
882 return 0;
883 }
884
885 /**
886 * Returns the X coordinate of this Item on the screen
887 *
888 * @return The X coordinate of this Item on the screen
889 */
890 public int getX() {
891 return Math.round(_x);
892 }
893
894 /**
895 * Returns the Y coordinate of this Item on the screen
896 *
897 * @return The Y coordinate of this Item on the screen
898 */
899 public int getY() {
900 return Math.round(_y);
901 }
902
903 protected boolean hasVisibleArrow() {
904 return isLineEnd() && getArrowheadRatio() != 0
905 && getArrowheadLength() != 0;
906 }
907
908 /**
909 * Checks if the given Shape intersects with the Shape around this Item.
910 *
911 * @param s
912 * The Shape to check.
913 * @return True if the two Shapes overlap, False otherwise.
914 */
915 public boolean intersects(Polygon p) {
916 if (p == null)
917 return false;
918
919 Area a = new Area(p);
920 Area thisArea = this.getArea();
921 // Need to do this check for circles
922 if (a.equals(thisArea))
923 return true;
924
925 a.intersect(thisArea);
926
927 // Need to check the second equality so that we dont pick up circles
928 // inside other circles
929 return !a.isEmpty() && !a.equals(new Area(p));
930 }
931
932 /**
933 * Note: Pictures always return False, as they should be drawn even when no
934 * other annotation Items are.
935 *
936 * @return True if this Item is an annotation, False otherwise.
937 */
938 public boolean isAnnotation() {
939 return false;
940 }
941
942 public boolean isFloating() {
943 return _floating;
944 }
945
946 public boolean isFrameName() {
947 if (this.getParent() == null || this.getParent().getNameItem() != this)
948 return false;
949 return true;
950 }
951
952 public boolean isFrameTitle() {
953 if (this.getParent() == null || this.getParent().getTitleItem() != this)
954 return false;
955 return true;
956 }
957
958 /**
959 * Returns True if this Item is currently highlighted.
960 *
961 * @return True if this Item is currently highlighted on the screen, False
962 * otherwise.
963 */
964 public boolean isHighlighted() {
965 if (isFloating())
966 return false;
967 return _mode != HighlightMode.None;
968 }
969
970 /**
971 * Tests if the item link is a valid framename, that is, the String must
972 * begin with a character, end with a number with 0 or more letters and
973 * numbers in between. If there is a dot in the framename all the chars
974 * after it must be digits.
975 *
976 * @return True if the given framename is proper, false otherwise.
977 */
978 public boolean isLinkValid() {
979 if (FrameIO.isPositiveInteger(getLink()))
980 return true;
981
982 if (FrameIO.isValidFrameName(getLink()))
983 return true;
984 return false;
985 }
986
987 public boolean isNear(int x, int y) {
988
989 int xLeft = getPolygon().getBounds().x;
990 int yTop = getPolygon().getBounds().y;
991
992 return (x > xLeft - NEAR_DISTANCE && y > yTop - NEAR_DISTANCE
993 && x < xLeft + getBoundsWidth() + NEAR_DISTANCE && y < yTop
994 + getBoundsHeight() + NEAR_DISTANCE);
995 }
996
997 public boolean isOldTag() {
998 if (this instanceof Text)
999 if (((Text) this).getTextList().get(0).toLowerCase().equals("@old"))
1000 return true;
1001 return false;
1002 }
1003
1004 /**
1005 * Merges this Item with the given Item. The merger Item should be left
1006 * unchanged after this method. The merger may or may not be the same class
1007 * as this Item, exact behaviour depends on the subclass, No-op is allowed.
1008 *
1009 * @param merger
1010 * The Item to merge with
1011 * @return any Item that should remain on the cursor
1012 */
1013 public abstract Item merge(Item merger, int mouseX, int mouseY);
1014
1015 /**
1016 * Displays this item directly on the screen. Note: All Items are
1017 * responsible for their own drawing, buffering, etc.
1018 *
1019 * @param g
1020 * The Graphics to draw this Item on.
1021 */
1022 public abstract void paint(Graphics2D g);
1023
1024 public void paintFill(Graphics2D g) {
1025 Color fillColor = getFillColor();
1026 if (fillColor != null && getEnclosingDots() != null) {
1027 setFillPaint(g);
1028 g.fillPolygon(getEnclosedShape());
1029 }
1030 }
1031
1032 protected void setFillPaint(Graphics2D g) {
1033 Color fillColor = getFillColor();
1034 if (isFloating()) {
1035 // TODO experiment with adding alpha when picking up filled
1036 // items... Slows things down quite alot!!
1037 fillColor = new Color(fillColor.getRed(), fillColor.getGreen(),
1038 fillColor.getBlue());
1039 }
1040 g.setColor(fillColor);
1041 Color gradientColor = getGradientColor();
1042 if (gradientColor != null) {
1043 // The painting is not efficient enough for gradients...
1044 Shape s = getEnclosedShape();
1045 if (s != null) {
1046 Rectangle b = s.getBounds();
1047 GradientPaint gp = new GradientPaint(
1048 (int) (b.x + b.width * 0.3), b.y, fillColor,
1049 (int) (b.x + b.width * 1.3), b.y, gradientColor);
1050 g.setPaint(gp);
1051 }
1052 }
1053 }
1054
1055 /**
1056 * This method performs all the actions in an items list. If it contains a
1057 * link as well the link is used as the source frame for all acitons.
1058 */
1059 public void performActions() {
1060 Frame sourceFrame = null;
1061 Item sourceItem = FreeItems.getItemAttachedToCursor();
1062
1063 if (sourceItem == null) {
1064 sourceItem = this;
1065 }else{
1066 for(Item i: sourceItem.getAllConnected()){
1067 if(i instanceof Text){
1068 sourceItem = i;
1069 break;
1070 }
1071 }
1072 }
1073
1074 // TODO decide whether to have items or
1075 // if a link exists make it the source frame for this action
1076 if (getLink() != null) {
1077 sourceFrame = FrameUtils.getFrame(getAbsoluteLink());
1078 }
1079 // if no link exists or the link is bad then use the
1080 // currently displayed frame as the source frame for the
1081 // action
1082 if (sourceFrame == null) {
1083 // For actions like format they rely on this being set to the
1084 // current frame incase the item being activated is on an overlay
1085 sourceFrame = DisplayIO.getCurrentFrame();
1086 }
1087
1088 for (String s : getAction()) {
1089 Object returnValue = Actions.PerformActionCatchErrors(sourceFrame,
1090 sourceItem, s);
1091 if (returnValue != null) {
1092 FreeItems.getInstance().clear();
1093 if (returnValue instanceof Item) {
1094 Misc.attachToCursor(((Item) returnValue).getAllConnected());
1095 } else {
1096 Misc.attachStatsToCursor(returnValue.toString());
1097 }
1098 }
1099 }
1100 }
1101
1102 /**
1103 * Removes all constraints that this item has.
1104 *
1105 */
1106 public void removeAllConstraints() {
1107 while (_constraints.size() > 0) {
1108 Constraint c = _constraints.get(0);
1109 c.getEnd().removeConstraint(c);
1110 c.getStart().removeConstraint(c);
1111 }
1112 }
1113
1114 /**
1115 * Clears the list of Lines that this Dot is an end of. Note: This only
1116 * clears this Dot's list and does not have any affect on the Lines or other
1117 * Dots.
1118 */
1119 public void removeAllLines() {
1120 for (Line l : _lines) {
1121 l.invalidateAll();
1122 }
1123 _lines.clear();
1124 }
1125
1126 /**
1127 * Removes the given Constraint from the list of constraintss that this Dot
1128 * is a part of.
1129 *
1130 * @param c
1131 * The Constraint that this Dot is no longer a part of.
1132 */
1133 public void removeConstraint(Constraint c) {
1134 _constraints.remove(c);
1135 }
1136
1137 /**
1138 * Removes the given Line from the list of lines that this Dot is an end
1139 * for.
1140 *
1141 * @param line
1142 * The Line that this Dot is no longer an end of.
1143 */
1144 public void removeLine(Line line) {
1145 if (_lines.remove(line))
1146 line.invalidateAll();
1147 }
1148
1149 public void run() {
1150 try {
1151 Simple.ProgramStarted();
1152 Simple.RunFrameAndReportError(this, new Context());
1153 Simple.ProgramFinished();
1154 MessageBay.displayMessage(AgentStats.getStats(), GREEN);
1155 } catch (ConcurrentModificationException ce) {
1156 Simple.ProgramFinished();
1157 ce.printStackTrace();
1158 } catch (Exception e) {
1159 MessageBay.linkedErrorMessage(e.getMessage());
1160 Simple.ProgramFinished();
1161 }
1162 // Need to repaint any highlights etc
1163 FrameGraphics.requestRefresh(true);
1164 }
1165
1166 /**
1167 * Check if it has a relative link if so make it absolute.
1168 *
1169 */
1170 public void setAbsoluteLink() {
1171 String link = getLink();
1172 if (link == null)
1173 return;
1174 // Check if all the characters are digits and hence it is a relative
1175 // link
1176 if (!FrameIO.isPositiveInteger(link))
1177 return;
1178
1179 // Make it an absolute link
1180 String framesetName;
1181
1182 if (_parent == null)
1183 framesetName = DisplayIO.getCurrentFrame().getFramesetName();
1184 else
1185 framesetName = _parent.getFramesetName();
1186
1187 setLink(framesetName + link);
1188 }
1189
1190 /**
1191 * Sets any action code that should be associated with this Item Each entry
1192 * in the list is one line of code
1193 *
1194 * @param actions
1195 * The lines of code to associate with this Item
1196 */
1197 public void setActions(List<String> actions) {
1198 if (actions == null || actions.size() == 0) {
1199 invalidateCommonTrait(ItemAppearence.LinkChanged);
1200 _actions = null;
1201 } else
1202 _actions = new LinkedList<String>(actions);
1203
1204 // Want to resize the highlight box for text items if actions have been
1205 // added
1206 _poly = null;
1207 invalidateCommonTrait(ItemAppearence.LinkChanged);
1208 }
1209
1210 public void setData(List<String> data) {
1211 if (data == null || data.size() == 0)
1212 _data = null;
1213 else
1214 _data = new LinkedList<String>(data);
1215 }
1216
1217 public void setData(String data) {
1218 if (data == null || data.length() == 0)
1219 _data = null;
1220 else {
1221 _data = new LinkedList<String>();
1222 _data.add(data);
1223 }
1224 }
1225
1226 public void addToData(String dataItem) {
1227 if (dataItem != null) {
1228 if (_data == null)
1229 _data = new LinkedList<String>();
1230 _data.add(dataItem);
1231 }
1232 }
1233
1234 public void setActionCursorEnter(List<String> enter) {
1235 _actionCursorEnter = enter;
1236 }
1237
1238 public void setActionCursorLeave(List<String> leave) {
1239 _actionCursorLeave = leave;
1240 }
1241
1242 public void setActionEnterFrame(List<String> enter) {
1243 _actionEnterFrame = enter;
1244 }
1245
1246 public void setActionLeaveFrame(List<String> leave) {
1247 _actionLeaveFrame = leave;
1248 }
1249
1250 public void setActionMark(boolean val) {
1251 if (!val)
1252 invalidateCommonTrait(ItemAppearence.LinkChanged);
1253 _poly = null;
1254 _actionMark = val;
1255 if (val)
1256 invalidateCommonTrait(ItemAppearence.LinkChanged);
1257 }
1258
1259 /**
1260 * Sets whether this Item is an Annotation.
1261 *
1262 * @param val
1263 * True if this Item is an Annotation, False otherwise.
1264 */
1265 public abstract void setAnnotation(boolean val);
1266
1267 /**
1268 * Used to set this Line as an Arrow. If length and ratio are 0, no arrow is
1269 * shown.
1270 *
1271 * @param length
1272 * The how far down the shaft of the line the arrowhead should
1273 * come.
1274 * @param ratio
1275 * The ratio of the arrow's length to its width.
1276 */
1277 public void setArrow(float length, double ratio) {
1278 _arrowheadLength = length;
1279 _arrowheadRatio = ratio;
1280 updateArrowPolygon();
1281 }
1282
1283 public void setArrowhead(Polygon arrow) {
1284 _arrowhead = arrow;
1285 }
1286
1287 public void setArrowheadLength(float length) {
1288 _arrowheadLength = length;
1289 updateArrowPolygon();
1290 }
1291
1292 public void setArrowheadRatio(double ratio) {
1293 _arrowheadRatio = ratio;
1294 updateArrowPolygon();
1295 }
1296
1297 public void setBackgroundColor(Color c) {
1298 if (c != _colorBackground) {
1299 _colorBackground = c;
1300 invalidateCommonTrait(ItemAppearence.BackgroundColorChanged);
1301 }
1302 }
1303
1304 public void setBorderColor(Color c) {
1305 if (c != _colorBorder) {
1306 _colorBorder = c;
1307 invalidateCommonTrait(ItemAppearence.BorderColorChanged);
1308 }
1309 }
1310
1311 /**
1312 * Sets the Color to use on the bottom and right sections of this Item's
1313 * border. If top is NULL, then the Item's background Color will be used.
1314 *
1315 * @param top
1316 * The Color to display in the bottom and right sections of this
1317 * Item's border.
1318 */
1319 public void setBottomShadowColor(Color bottom) {
1320 _colorBottomShadow = bottom;
1321 }
1322
1323 /**
1324 * Sets the foreground Color of this Item to the given Color.
1325 *
1326 * @param c
1327 */
1328 public void setColor(Color c) {
1329 if (c != _color) {
1330 _color = c;
1331 invalidateCommonTrait(ItemAppearence.ForegroundColorChanged);
1332 if (hasVector()) {
1333 // TODO make this more efficient so it only repaints the items
1334 // for this vector
1335 FrameKeyboardActions.Refresh();
1336 }
1337 }
1338 }
1339
1340 public void setConstraintIDs(String IDs) {
1341 }
1342
1343 public void setConstraints(List<Constraint> constraints) {
1344 _constraints = constraints;
1345 }
1346
1347 public void setTag(String newData) {
1348 if (newData != null)
1349 _tag = new StringBuffer(newData);
1350 else
1351 _tag = null;
1352 }
1353
1354 /**
1355 * Sets the created date of this Frame to the given String.
1356 *
1357 * @param date
1358 * The date to use for this Frame.
1359 */
1360 public void setDateCreated(String date) {
1361 _creationDate = date;
1362 }
1363
1364 public void setFillColor(Color c) {
1365
1366 _colorFill = c;
1367
1368 for (Line line : _lines) {
1369 Item other = line.getOppositeEnd(this);
1370 if (other.getFillColor() != c){
1371 other.setFillColor(c);
1372 }
1373 }
1374
1375 invalidateCommonTrait(ItemAppearence.FillColor);
1376 invalidateFill();
1377 }
1378
1379 public void setGradientColor(Color c) {
1380 _colorGradient = c;
1381
1382 for (Line line : _lines) {
1383 Item other = line.getOppositeEnd(this);
1384 if (other.getGradientColor() != c)
1385 other.setGradientColor(c);
1386 }
1387
1388 invalidateCommonTrait(ItemAppearence.GradientColor);
1389 invalidateFill();
1390 }
1391
1392 public Color getGradientColor() {
1393 return _colorGradient;
1394 }
1395
1396 public void setFillPattern(String patternLink) {
1397 _fillPattern = patternLink;
1398 invalidateCommonTrait(ItemAppearence.FillPattern);
1399 invalidateFill();
1400 }
1401
1402 public void setFloating(boolean val) {
1403 _floating = val;
1404 }
1405
1406 public void setHighlight(boolean val) {
1407 _highlight = val;
1408 }
1409
1410 /**
1411 * Sets the ID of this Item to the given Integer. Note: Items with ID's < 0
1412 * are not saved
1413 *
1414 * @param newID
1415 * The new ID to assign this Item.
1416 */
1417 public void setID(int newID) {
1418 _id = newID;
1419 }
1420
1421 /**
1422 * Sets the list of lines that this point is part of (may be set to null).
1423 *
1424 * @param lineID
1425 * A String of line ID numbers separated by spaces.
1426 */
1427 public void setLineIDs(String lineID) {
1428 }
1429
1430 public void setLinePattern(int[] pattern) {
1431 _linePattern = pattern;
1432
1433 for (Line line : getLines())
1434 line.setLinePattern(pattern);
1435 }
1436
1437 public void setLines(List<Line> lines) {
1438 _lines = lines;
1439
1440 for (Line line : lines)
1441 line.setLinePattern(getLinePattern());
1442
1443 }
1444
1445 /**
1446 * Links this item to the given Frame, this may be set to null to remove a
1447 * link.
1448 *
1449 * @param frameName
1450 * The name of the Frame to link this item to.
1451 */
1452 public void setLink(String frameName) {
1453 if (frameName == null) {
1454 invalidateCommonTrait(ItemAppearence.LinkChanged);
1455 }
1456
1457 // If a link is being removed or set then need to reset poly so the
1458 // highlighting is drawn with the correct width
1459 if (frameName == null || getLink() == null)
1460 _poly = null;
1461
1462 if (FrameIO.isValidLink(frameName))
1463 _link = frameName;
1464 else
1465 MessageBay.errorMessage("[" + frameName
1466 + "] is not a valid frame name");
1467 // TODO make this throw exceptions etc...
1468
1469 invalidateCommonTrait(ItemAppearence.LinkChanged);
1470 }
1471
1472 public void setLinkFrameset(String frameset) {
1473 if (frameset == null || FrameIO.isValidFramesetName(frameset))
1474 _link_frameset = frameset;
1475 else
1476 MessageBay.errorMessage("[" + frameset
1477 + "] is not a valid frameset name");
1478 // TODO make this throw exceptions etc...
1479 }
1480
1481 public void setLinkMark(boolean val) {
1482 if (!val)
1483 invalidateCommonTrait(ItemAppearence.LinkChanged);
1484 _poly = null;
1485 _linkMark = val;
1486 if (val)
1487 invalidateCommonTrait(ItemAppearence.LinkChanged);
1488 }
1489
1490 public void setLinkTemplate(String template) {
1491 if (FrameIO.isValidLink(template))
1492 _link_template = template;
1493 else
1494 MessageBay.errorMessage("[" + template
1495 + "] is not a valid frame name");
1496 // TODO make this throw exceptions etc...
1497 }
1498
1499 // /**
1500 // * Sets the maximum coordinates on the screen that this item may occupy.
1501 // * This is used by Text items to compute word-wrapping lengths.
1502 // *
1503 // * @param d
1504 // * The Maximum size of the Frame containing this Item.
1505 // */
1506 // public void setMaxWidth(int width) {
1507 // if (width > 0) {
1508 // _maxWidth = width;
1509 // updatePolygon();
1510 // }
1511 // }
1512
1513 public void setOffset(int x, int y) {
1514 _offset.setLocation(x, y);
1515 }
1516
1517 public void setOffset(Point p) {
1518 _offset.setLocation(p);
1519 }
1520
1521 public void setOwner(String own) {
1522 _owner = own;
1523 }
1524
1525 public void setParent(Frame frame) {
1526 _parent = frame;
1527 }
1528
1529 /**
1530 * Invalidates this, connected lines and fill
1531 *
1532 * @param trait
1533 */
1534 private void invalidateCommonTraitForAll(ItemAppearence trait) {
1535 invalidateCommonTrait(trait);
1536 for (Line line : getLines())
1537 line.invalidateCommonTrait(trait);
1538 if (_colorFill != null) {
1539 invalidateFill(); // only invalidates if has fill
1540 }
1541 for (XRayable x : getEnclosures()) {
1542 x.invalidateCommonTrait(trait);
1543 }
1544
1545 }
1546
1547 /**
1548 * Sets the position of this item on the screen
1549 *
1550 * @param x
1551 * The new X coordinate
1552 * @param y
1553 * The new Y coordinate
1554 */
1555 public void setPosition(float x, float y) {
1556 float deltaX = x - _x;
1557 float deltaY = y - _y;
1558
1559 if (deltaX == 0 && deltaY == 0)
1560 return;
1561
1562 invalidateCommonTraitForAll(ItemAppearence.PreMoved);
1563
1564 _x = x;
1565 _y = y;
1566
1567 for (Item i : getEnclosures()) {
1568 i.updatePolygon();
1569 }
1570 updatePolygon();
1571
1572 // update the position of any dots that are constrained by this one
1573 for (Constraint c : _constraints) {
1574 Item other = c.getOppositeEnd(this);
1575
1576 // only set position if the other dot is still fixed to the
1577 // frame
1578 if (/* this.isFloating() && */!other.isFloating()) {
1579 if (c.getType() == Constraint.HORIZONTAL) {
1580 if (other._y != y) {
1581 other.setY(y);
1582 }
1583 } else if (c.getType() == Constraint.VERTICAL) {
1584 if (other._x != x) {
1585 other.setX(x);
1586 }
1587 } else if (c.isDiagonal()) {
1588 if (Math.abs(other._x - x) != Math.abs(other._y - y)) {
1589
1590 float m1 = c.getGradient();
1591 float c1 = y - m1 * x;
1592 // Now work out the equation for the second line
1593 // Get the first line the other end is attached to that
1594 // is not the diagonal line
1595 List<Line> lines = other.getLines();
1596 // If there is only one line...
1597 if (lines.size() == 1) {
1598 if (m1 != 0) {
1599 if (Math.abs(deltaX) > Math.abs(deltaY)) {
1600 other.setX((other._y - c1) / m1);
1601 } else {
1602 other.setY(m1 * other._x + c1);
1603 }
1604 }
1605 } else if (lines.size() > 1) {
1606 Line otherLine = lines.get(0);
1607 Item end = otherLine.getOppositeEnd(other);
1608 if (end.equals(this)) {
1609 otherLine = lines.get(1);
1610 end = otherLine.getOppositeEnd(other);
1611 assert (!end.equals(this));
1612 }
1613
1614 float xDiff = end._x - other._x;
1615 float yDiff = end._y - other._y;
1616 if (xDiff == 0) {
1617 other.setY(m1 * other._x + c1);
1618 } else if (Math.abs(xDiff) == Math.abs(yDiff)
1619 && !this.isFloating() && deltaX == 0
1620 && deltaY == 0) {
1621 if (deltaX == 0) {
1622 _x = (_y - other._y) * m1 + other._x;
1623 } else {
1624 _y = (_x - other._x) * m1 + other._y;
1625 }
1626 } else {
1627 float m2 = yDiff / xDiff;
1628 float c2 = end._y - m2 * end._x;
1629 float mDiff = m1 - m2;
1630 if (Math.abs(mDiff) < 0.000001) {
1631 assert (false);
1632 // TODO how do I handle this case!!
1633 } else {
1634 float newX = (c2 - c1) / mDiff;
1635 float newY = m1 * newX + c1;
1636 if (other._x != newX
1637 /* && other._y != newY */) {
1638 other.setPosition(newX, newY);
1639 }
1640 }
1641 }
1642 }
1643 // Do simultaneous equations to get the new postion for
1644 // the other end of the diagonal line
1645 }
1646 }
1647 }
1648 }
1649
1650 for (Line line : getLines()) {
1651 line.updatePolygon();
1652 }
1653
1654 invalidateCommonTraitForAll(ItemAppearence.PostMoved);
1655
1656 }
1657
1658 public void setPosition(Point position) {
1659 setPosition(position.x, position.y);
1660 }
1661
1662 public void setRelativeLink() {
1663 String link = getLink();
1664 if (link == null)
1665 return;
1666 assert (_parent != null);
1667
1668 if (FrameIO.isPositiveInteger(link))
1669 return;
1670
1671 // Check if the link is for the current frameset
1672 if (_parent.getFramesetName().equalsIgnoreCase(
1673 Conversion.getFramesetName(link))) {
1674 setLink("" + Conversion.getFrameNumber(link));
1675 }
1676 }
1677
1678 /**
1679 * Sets the size of this Item. For Text this is the Font size. For Lines and
1680 * Dots this is the thickness.
1681 */
1682 public void setSize(float size) {
1683 }
1684
1685 /**
1686 * Sets the thickness of the item.
1687 *
1688 * @param thick
1689 */
1690 public void setThickness(float thick) {
1691 setThickness(thick, true);
1692 }
1693
1694 /**
1695 * Sets the thickness of this item.
1696 *
1697 * @param thick
1698 * the new thickness for the item
1699 * @param setConnectedThickness
1700 * true if all items connected to this item should also have
1701 * their thickness set
1702 */
1703 public void setThickness(float thick, boolean setConnectedThickness) {
1704 if (thick == _thickness)
1705 return;
1706 boolean bigger = thick > _thickness;
1707
1708 if (!bigger) {
1709 if (setConnectedThickness) {
1710 // TODO is there a more efficient way of doing this?
1711 for (Item i : getConnected())
1712 i.invalidateCommonTrait(ItemAppearence.Thickness);
1713 } else {
1714 invalidateCommonTrait(ItemAppearence.Thickness);
1715 }
1716 }
1717
1718 _thickness = thick;
1719 // update the size of any lines
1720 for (Line line : getLines())
1721 line.setThickness(thick, setConnectedThickness);
1722
1723 updatePolygon();
1724
1725 if (bigger) {
1726 if (setConnectedThickness) {
1727 for (Item i : getConnected())
1728 i.invalidateCommonTrait(ItemAppearence.Thickness);
1729 } else {
1730 invalidateCommonTrait(ItemAppearence.Thickness);
1731 }
1732 }
1733 }
1734
1735 /**
1736 * Returns the thickness (in pixels) of this Dot.
1737 *
1738 * @return The 'thickness' of this Dot. (returns -1 if the thickness is not
1739 * set).
1740 */
1741 public float getThickness() {
1742 return _thickness;
1743 }
1744
1745 /**
1746 * Sets the Color to use on the top and left sections of this Item's border.
1747 * If top is NULL, then the Item's background Color will be used.
1748 *
1749 * @param top
1750 * The Color to display in the top and left sections of this
1751 * Item's border.
1752 */
1753 public void setTopShadowColor(Color top) {
1754 _colorTopShadow = top;
1755 }
1756
1757 public void setWidth(int width) throws UnsupportedOperationException {
1758 throw new UnsupportedOperationException(
1759 "Item type does not support width attribute!");
1760 }
1761
1762 public void setRightMargin(int i) {
1763 setWidth(i - getX() - Item.MARGIN_LEFT);
1764 }
1765
1766 /**
1767 * Sets the position of this Item on the X axis
1768 *
1769 * @param newX
1770 * The position on the X axis to assign to this Item
1771 */
1772 public void setX(float newX) {
1773 setPosition(newX, getY());
1774 }
1775
1776 /**
1777 * Sets the position of this Item on the Y axis
1778 *
1779 * @param newY
1780 * The position on the Y axis to assign to this Item
1781 */
1782 public void setY(float newY) {
1783 setPosition(getX(), newY);
1784 }
1785
1786 /**
1787 * Paints any highlighting of this Item. This may include changing the
1788 * thickness (lines) or painting a box around the item (Text, Images). If
1789 * val is True then the Graphics Color is changed to the highlight Color, if
1790 * False then the Graphics Color is left unchanged (for clearing of
1791 * highlighting).
1792 *
1793 * @param val
1794 * True if this Item should be highlighted, false if the
1795 * highlighting is being cleared.
1796 * @return The desired mouse cursor when this Item is highlighted (negative
1797 * means no change)
1798 */
1799 public int setHighlightColor() {
1800 return setHighlightColor(DEFAULT_HIGHLIGHT);
1801 }
1802
1803 public int setHighlightColor(Color c) {
1804
1805 _highlightThickness = DEFAULT_HIGHLIGHT_THICKNESS;
1806
1807 Color selColor = (c != null) ? c : DEFAULT_HIGHLIGHT;
1808 if (_highlightColor != c) {
1809 _highlightColor = selColor;
1810 this.invalidateCommonTrait(ItemAppearence.HighlightColorChanged);
1811 }
1812
1813 return Item.UNCHANGED_CURSOR;
1814
1815 }
1816
1817 private void updateArrowPolygon() {
1818 if (getArrowheadLength() < 0 || getArrowheadRatio() < 0)
1819 _arrowhead = null;
1820 else {
1821 _arrowhead = new Polygon();
1822 _arrowhead.addPoint(Math.round(getX()), Math.round(getY()));
1823 _arrowhead.addPoint((Math.round(getX() - getArrowheadLength())),
1824 ((int) Math.round(getY()
1825 - (getArrowheadLength() * getArrowheadRatio()))));
1826 _arrowhead.addPoint(Math.round(getX()), (int) getY());
1827 _arrowhead
1828 .addPoint(
1829 (int) Math.round(getX() - getArrowheadLength()),
1830 (int) Math
1831 .round((getY() + (getArrowheadLength() * getArrowheadRatio()))));
1832 }
1833 }
1834
1835 public abstract void updatePolygon();
1836
1837 public void setHidden(boolean state) {
1838 this._visible = !state;
1839 }
1840
1841 public void setVisible(boolean state) {
1842 this._visible = state;
1843 }
1844
1845 public boolean isVisible() {
1846 return _visible && !_deleted;
1847 }
1848
1849 /**
1850 * Raised whenever the item is removed, added, no longer in view (That is,
1851 * when it is not on any of the current frames, of overlays of the current
1852 * frames) or has become visible. That is, when it is either on a current
1853 * frame, or an overlay of a current frame.
1854 *
1855 * @param e
1856 * The event
1857 */
1858 public void onParentStateChanged(ItemParentStateChangedEvent e) {
1859 }
1860
1861 public void setHighlightMode(HighlightMode mode, Color color) {
1862 setHighlightColor(color);
1863 if (hasPermission(Permission.followLinks)) {
1864 if (_mode != mode) {
1865 _mode = mode;
1866 this.invalidateCommonTrait(ItemAppearence.HighlightModeChanged);
1867 }
1868 }
1869 }
1870
1871 public HighlightMode getHighlightMode() {
1872 return _mode;
1873 }
1874
1875 public void anchor() {
1876 Frame current = getParentOrCurrentFrame();
1877 setID(current.getNextItemID());
1878 setOffset(0, 0);
1879 setParent(current);
1880
1881 current.addItem(this, false);
1882 current.setResort(true);
1883 setRelativeLink();
1884 setFloating(false);
1885
1886 // // If its an unconstrained line end check if we should add a
1887 // constraint
1888 // if (isLineEnd() && getLines().size() <= 2
1889 // && getConstraints().size() <= 1) {
1890 // Constraint existingConstraint = null;
1891 // List<Constraint> constraints = getConstraints();
1892 // // Get the existing constraint
1893 // if (constraints.size() > 0) {
1894 // existingConstraint = constraints.get(0);
1895 // }
1896 // for (Line line : getLines()) {
1897 // Integer constraintType = line.getPossibleConstraint();
1898 // if (constraintType != null) {
1899 // Item oppositeEnd = line.getOppositeEnd(this);
1900 // if (existingConstraint == null
1901 // || !existingConstraint.contains(oppositeEnd)) {
1902 // new Constraint(this, oppositeEnd,
1903 // getParentOrCurrentFrame().getNextItemID(),
1904 // constraintType);
1905 // }
1906 // }
1907 // }
1908 // }
1909 }
1910
1911 /**
1912 * Gets the parent frame if it is set or the current frame if this item does
1913 * not have a parent set.
1914 *
1915 * @return
1916 */
1917 public Frame getParentOrCurrentFrame() {
1918 // if the item is from an overlay the parent will NOT be null
1919 if (getParent() == null) {
1920 return DisplayIO.getCurrentFrame();
1921 }
1922 return getParent();
1923 }
1924
1925 /**
1926 * Sets the list of Dots (including this one) that form a closed shape.
1927 * Passing null sets this dot back to its normal (non-enclosed) state.
1928 *
1929 * @param enclosed
1930 * The List of Dots including this one that form a closed shape,
1931 * or null.
1932 */
1933 public void setEnclosedList(Collection<Item> enclosed) {
1934
1935 boolean changed = (_enclosure == null && enclosed != null);
1936
1937 if (_enclosure != null && enclosed == null) {
1938 invalidateFill();
1939 }
1940
1941 _enclosure = enclosed;
1942
1943 if (changed) {
1944 invalidateFill();
1945 ;
1946 }
1947 }
1948
1949 /**
1950 * Returns the polygon that represents the shape created by all the Dots in
1951 * this Dot's enclosed list. If the list is null, then null is returned.
1952 *
1953 * @return A Polygon the same shape and position as created by the Dots in
1954 * the enclosed list.
1955 */
1956 public Polygon getEnclosedShape() {
1957 if (_enclosure == null)
1958 return null;
1959
1960 Polygon poly = new Polygon();
1961 for (Item d : _enclosure) {
1962 poly.addPoint(d.getX(), d.getY());
1963 }
1964
1965 return poly;
1966 }
1967
1968 /**
1969 * Returns the list of Dots that, along with this Dot, form an enclosed
1970 * polygon. If this Dot is not part of an enclosure null may be returned.
1971 *
1972 * @return The List of Dots that form an enclosed shape with this Dot, or
1973 * null if this Dot is not part of an enclosure.
1974 */
1975 public Collection<Item> getEnclosingDots() {
1976 return _enclosure;
1977 }
1978
1979 /**
1980 * Returns whether this Dot has an assigned enclosure list of other Dots.
1981 * The result is the same as getEnclosedShape() != null.
1982 *
1983 * @return True if this Dot has an enclosure list of other Dots, false
1984 * otherwise.
1985 */
1986 public boolean isEnclosed() {
1987 return _enclosure != null;
1988 }
1989
1990 /**
1991 * True if this item is the end of a line.
1992 *
1993 * @return
1994 */
1995 public boolean isLineEnd() {
1996 // TODO this will need to be redone when enclosure class is added...
1997 // At the moment enclosures are only circles...we dont want circle
1998 // centers to be lineEnds
1999 return _lines.size() > 0;
2000 }
2001
2002 public boolean hasEnclosures() {
2003 return _enclosures.size() > 0;
2004 }
2005
2006 /**
2007 * Method that is called to notify an item that is on the end of a line that
2008 * its line has changed color.
2009 *
2010 * @param c
2011 * the new color for the line
2012 */
2013 protected void lineColorChanged(Color c) {
2014 for (Line l : getLines()) {
2015 if (l.getColor() != c)
2016 l.setColor(c);
2017 }
2018 }
2019
2020 /**
2021 * Checks if this item is off the left or top of the screen
2022 *
2023 * @return
2024 */
2025 public boolean offScreenTopOrLeft() {
2026 Rectangle itemRect = getArea().getBounds();
2027 // Check that the bottom right corner of this item is on the screen
2028 if (itemRect.x + itemRect.width >= 0
2029 && itemRect.y + itemRect.height >= 0)
2030 return false;
2031 // Check if all the items it is connected to are offscreen
2032 for (Item i : getAllConnected()) {
2033 Rectangle iRect = i.getArea().getBounds();
2034 // Check that the bottom right corner of this item is on the screen
2035 if (iRect.x + iRect.width >= 0 && iRect.y + iRect.height >= 0) {
2036 return false;
2037 }
2038 }
2039 return true;
2040 }
2041
2042 public void setConnectedToAnnotation(boolean val) {
2043 _connectedToAnnotation = val;
2044 }
2045
2046 public boolean isConnectedToAnnotation() {
2047 return _connectedToAnnotation;
2048 }
2049
2050 public boolean hasAction() {
2051 List<String> actions = getAction();
2052 return actions != null && actions.size() > 0;
2053 }
2054
2055 public void setAction(String action) {
2056 // Want to resize the highlight box for text items if actions are been
2057 // added
2058 if (action == null || action.length() == 0) {
2059 invalidateCommonTrait(ItemAppearence.LinkChanged);
2060 }
2061 if (_actions == null || _actions.size() == 0) {
2062 _poly = null;
2063 _actions = new LinkedList<String>();
2064 } else {
2065 _actions.clear();
2066 }
2067 if (action != null && action.length() > 0)
2068 _actions.add(action);
2069 invalidateCommonTrait(ItemAppearence.LinkChanged);
2070 }
2071
2072 protected int getLinkYOffset() {
2073 return 0;
2074 }
2075
2076 protected Rectangle getLinkDrawArea() {
2077 return getLinkDrawArea(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
2078 }
2079
2080 /**
2081 * TODO: Revise - it would be good to have a member that defines the link
2082 * dimensions.
2083 *
2084 * @param x
2085 * Left of graphic (i.e not centered)
2086 * @param y
2087 * Above graphic (i.e not centered)
2088 *
2089 * @return The drawing area of the link at the given coordinates.
2090 */
2091 public Rectangle getLinkDrawArea(int x, int y) {
2092 return new Rectangle(x + 2, y - 1, 8, 8);
2093 }
2094
2095 /**
2096 * Paint the link symbol for the item if it is a
2097 *
2098 * @param g
2099 */
2100 protected void paintLink(Graphics2D g) {
2101 paintLinkGraphic(g, getX() - LEFT_MARGIN, getY() + getLinkYOffset());
2102 }
2103
2104 /**
2105 * Paint the link symbol for the item at a given position.
2106 *
2107 * @see #paintLink
2108 *
2109 * @param g
2110 * The graphics to paint with
2111 *
2112 * @param x
2113 * The x position of the link. Left of graphic (i.e not centered)
2114 *
2115 * @param y
2116 * The y position of the link. Above of graphic (i.e not
2117 * centered)
2118 */
2119 public void paintLinkGraphic(Graphics2D g, int x, int y) {
2120
2121 boolean hasLink = getLink() != null;
2122 boolean hasAction = hasAction();
2123
2124 if (hasLink || hasAction) {
2125 g.setStroke(HIGHLIGHT_STROKE);
2126 if (hasLink && hasAction) {
2127 g.setColor(LINK_ACTION_COLOR);
2128 } else if (hasLink) {
2129 g.setColor(LINK_COLOR);
2130 } else if (hasAction) {
2131 g.setColor(ACTION_COLOR);
2132 }
2133
2134 AffineTransform at = new AffineTransform();
2135 AffineTransform orig = g.getTransform();
2136 at.translate(x, y);
2137 g.setTransform(at);
2138
2139 if (getLinkMark() && getLink() != null) {
2140 g.drawPolygon(getLinkPoly());
2141
2142 // if the link is not valid, cross out the circle
2143 if (!isLinkValid())
2144 g.drawPolygon(getCircleCross());
2145 }
2146
2147 if (getActionMark() && hasAction()) {
2148 g.drawPolygon(getLinkPoly());
2149 g.fillPolygon(getLinkPoly());
2150
2151 // if the link is not valid, cross out the circle
2152 if (!isLinkValid() && getLink() != null) {
2153 g.setColor(getParent().getPaintBackgroundColor());
2154 g.drawPolygon(getCircleCross());
2155 }
2156 }
2157
2158 // reset the graphics tranformation
2159 g.setTransform(orig);
2160 }
2161 }
2162
2163 /**
2164 * Gets the distance between the start of the text and the left border of
2165 * the item. This distance changes depending on whether or not the item is
2166 * linked or has an associated action.
2167 *
2168 * @return the gap size in pixels
2169 */
2170 protected int getLeftMargin() {
2171 return ((getLinkMark() && getLink() != null)
2172 || (getActionMark() && getAction() != null) ? MARGIN_LEFT
2173 - MARGIN_RIGHT : MARGIN_RIGHT);
2174 }
2175
2176 public String getName() {
2177 return getText();
2178 }
2179
2180 final public String getAbsoluteLinkTemplate() {
2181 return getAbsoluteLink(getLinkTemplate());
2182 }
2183
2184 final public String getAbsoluteLinkFrameset() {
2185 return getAbsoluteLink(getLinkFrameset());
2186 }
2187
2188 final public String getAbsoluteLink() {
2189 return getAbsoluteLink(getLink());
2190 }
2191
2192 /**
2193 * @param link
2194 * @return
2195 */
2196 private String getAbsoluteLink(String link) {
2197 if (link == null)
2198 return null;
2199 // assert (_parent!= null);
2200 Frame parent = getParentOrCurrentFrame();
2201 if (_parent == null) {
2202 // if parent is null it is an item on the message box
2203 // so it must already be absolute
2204 // assert (!FrameIO.isPositiveInteger(link));
2205 // return link;
2206
2207 }
2208
2209 // if its a relative link then return absolute
2210 if (FrameIO.isPositiveInteger(link)) {
2211 return parent.getFramesetName() + link;
2212 }
2213 return link;
2214 }
2215
2216 public static String convertToAbsoluteLink(String link) {
2217 if (link == null)
2218 return null;
2219 // assert (_parent!= null);
2220 Frame parent = DisplayIO.getCurrentFrame();
2221 assert (parent != null);
2222
2223 // if its a relative link then return absolute
2224 if (FrameIO.isPositiveInteger(link)) {
2225 return parent.getFramesetName() + link;
2226 }
2227 return link;
2228 }
2229
2230 /**
2231 * Sets the x and y values of this item ignoring constraints.
2232 *
2233 * @param x
2234 * new x position
2235 * @param y
2236 * new y position
2237 */
2238 public void setXY(float x, float y) {
2239 _x = x;
2240 _y = y;
2241 }
2242
2243 /**
2244 * Recursive function for getting the path around a shape. This is used to
2245 * get the path that is painted on the screen.
2246 *
2247 * @param visited
2248 * @param points
2249 * @param addToEnd
2250 * @param toExplore
2251 */
2252 public void appendPath(Collection<Line> visited, LinkedList<Point> points,
2253 boolean addToEnd, Collection<Line> toExplore) {
2254
2255 if (addToEnd) {
2256 // put the start item points into our list
2257 points.addLast(getPosition());
2258 } else {
2259 points.addFirst(getPosition());
2260 }
2261
2262 // Find the line that has not been added yet
2263 LinkedList<Line> lines = new LinkedList<Line>();
2264 lines.addAll(getLines());
2265
2266 while (!lines.isEmpty()) {
2267 Line l = lines.remove();
2268 // if we havnt visited the line yet visit it
2269 if (!visited.contains(l)) {
2270 visited.add(l);
2271 Item otherEnd = l.getOppositeEnd(this);
2272 // Add all the enexplored lines to our list
2273 while (!lines.isEmpty()) {
2274 l = lines.remove();
2275 // Get the paths for the rest of the lines to be explored
2276 // later
2277 if (!toExplore.contains(l) && !visited.contains(l)) {
2278 toExplore.add(l);
2279 }
2280 }
2281 otherEnd.appendPath(visited, points, addToEnd, toExplore);
2282 }
2283 }
2284 }
2285
2286 /**
2287 * Gets the size of the enclosure that this item is part of. Used to
2288 * determine the paint order of items, with smaller items being painted
2289 * first.
2290 *
2291 * @return the area of the box surrounding the enclosed shape that this item
2292 * is part of
2293 */
2294 public double getEnclosedArea() {
2295 if (_enclosure == null)
2296 return 0.0;
2297 Rectangle2D box = getEnclosedShape().getBounds2D();
2298 return box.getWidth() * box.getHeight();
2299 }
2300
2301 public Rectangle getEnclosedRectangle() {
2302 if (_enclosure == null)
2303 return null;
2304 return getEnclosedShape().getBounds();
2305 }
2306
2307 public int getEnclosureID() {
2308 return _enclosure == null ? 0 : _enclosure.hashCode();
2309 }
2310
2311 /**
2312 * Returns the Shape that surrounds this Item representing this Item's
2313 * 'gravity'.
2314 *
2315 * @return The Shape (rectangle) surrounding this Item, which represents
2316 * this Items 'gravity'.
2317 */
2318 public final Polygon getPolygon() {
2319 if (_poly == null)
2320 updatePolygon();
2321
2322 return new Polygon(_poly.xpoints, _poly.ypoints, _poly.npoints);
2323 }
2324
2325 /**
2326 * Shifts the position of the item along the line between this items
2327 * location and a specified point.
2328 *
2329 * @param origin
2330 * @param ratio
2331 */
2332 public void translate(Point2D origin, double ratio) {
2333
2334 invalidateCommonTraitForAll(ItemAppearence.PreMoved);
2335
2336 _x = (float) (origin.getX() + ratio * (_x - origin.getX()));
2337 _y = (float) (origin.getY() + ratio * (_y - origin.getY()));
2338 updatePolygon();
2339 for (Line line : getLines())
2340 line.updatePolygon();
2341
2342 invalidateCommonTraitForAll(ItemAppearence.PostMoved);
2343
2344 }
2345
2346 private static int[] LinePatterns = new int[] { 0, 10, 20 };
2347
2348 /**
2349 * The rotates through a wheel of dashed lines.
2350 *
2351 * @param amount
2352 * number of rotations around the wheel to toggle by.
2353 */
2354 public void toggleDashed(int amount) {
2355 // find the index of the current line pattern
2356 int[] currentPattern = getLinePattern();
2357
2358 // Find the current pattern and move to the next pattern in the wheel
2359 for (int i = 0; i < LinePatterns.length; i++) {
2360 if (currentPattern == null || currentPattern[0] == LinePatterns[i]) {
2361 i += LinePatterns.length + amount;
2362 i %= LinePatterns.length;
2363
2364 // if we are at the start of the wheel make it 'null' (solid
2365 // line)
2366 if (i == 0) {
2367 setLinePattern(null);
2368 } else {
2369 setLinePattern(new int[] { LinePatterns[i], LinePatterns[i] });
2370 }
2371
2372 invalidateCommonTrait(ItemAppearence.ToggleDashed);
2373 return;
2374 }
2375 }
2376
2377 }
2378
2379 Collection<XRayable> _enclosures = new HashSet<XRayable>();
2380
2381 private boolean _deleted = false;
2382
2383 private Overlay _overlay = null;
2384
2385 /**
2386 * For now there can only be one enclosure per item
2387 *
2388 * @param enclosure
2389 */
2390 public void addEnclosure(XRayable enclosure) {
2391 _enclosures.clear();
2392 _enclosures.add(enclosure);
2393 }
2394
2395 /**
2396 * Gets any XRayable items that have this item as a source.
2397 *
2398 * @return the collection of items that are linked to this item as source.
2399 * Guarenteed not to be null.
2400 */
2401 public Collection<? extends XRayable> getEnclosures() {
2402 return _enclosures;
2403 }
2404
2405 public void removeEnclosure(Item i) {
2406 _enclosures.remove(i);
2407
2408 }
2409
2410 public boolean isDeleted() {
2411 return _deleted;
2412 }
2413
2414 /**
2415 * @return The full canvas that this item draws to. Must include
2416 * highlighting bounds
2417 */
2418 public Rectangle[] getDrawingArea() {
2419
2420 return new Rectangle[] { ItemUtils.expandRectangle(getPolygon()
2421 .getBounds(), (int) Math.ceil(Math.max(_highlightThickness,
2422 getThickness()))) };
2423
2424 }
2425
2426 /**
2427 *
2428 * @param area
2429 * @return True if area intersects with this items drawing area.
2430 */
2431 public final boolean isInDrawingArea(Area area) {
2432 for (Rectangle r : getDrawingArea()) {
2433 if (area.intersects(r))
2434 return true;
2435 }
2436 return false;
2437 }
2438
2439 /**
2440 * Completetly invalidates the item - so that it should be redrawed. Note:
2441 * This is handled internally, it should be reare to invoke this externally
2442 */
2443 public final void invalidateAll() {
2444 invalidate(getDrawingArea());
2445 }
2446
2447 /**
2448 * Invalidates areas on the parent frame. Purpose: to be called on specific
2449 * areas of the item that needs redrawing.
2450 *
2451 * @param damagedAreas
2452 */
2453 protected final void invalidate(Rectangle[] damagedAreas) {
2454 for (Rectangle r : damagedAreas)
2455 invalidate(r);
2456 }
2457
2458 /**
2459 * Invalidates areas on the parent frame. Purpose: to be called on specific
2460 * areas of the item that needs redrawing.
2461 *
2462 * @param damagedAreas
2463 */
2464 protected final void invalidate(Rectangle damagedArea) {
2465 FrameGraphics.invalidateItem(this, damagedArea);
2466 }
2467
2468 /**
2469 * Used to invalidate visual traits commonly shared by all items.
2470 *
2471 * @param trait
2472 */
2473 public final void invalidateCommonTrait(ItemAppearence trait) {
2474 invalidate(getDamagedArea(trait));
2475
2476 if (_colorFill != null
2477 && (trait == ItemAppearence.Added || trait == ItemAppearence.Removed)) {
2478 invalidateFill();
2479 }
2480 }
2481
2482 /**
2483 * Invalidates fill if has one, even if no color is set.
2484 */
2485 public void invalidateFill() {
2486 if (isLineEnd() && _enclosure != null) {
2487 invalidate(getEnclosedShape().getBounds());
2488 }
2489 }
2490
2491 /**
2492 * Default implementation always uses drawing area except for links, where
2493 * the link drawing area is used. Override to make item drawing more
2494 * efficient - defining only parts of the item that needs redrawing.
2495 *
2496 * @see Item.getDrawingArea
2497 *
2498 * @param trait
2499 * The visual trait that has changed.
2500 *
2501 * @return The damaged area according to the visual trait that has changed.
2502 */
2503 protected Rectangle[] getDamagedArea(ItemAppearence trait) {
2504
2505 if (trait == ItemAppearence.LinkChanged)
2506 return new Rectangle[] { getLinkDrawArea() }; // Invalidate area
2507 // where link is
2508 // drawn
2509
2510 return getDrawingArea();
2511
2512 }
2513
2514 public boolean hasVector() {
2515 return _overlay instanceof Vector;
2516 }
2517
2518 public boolean hasOverlay() {
2519 return _overlay != null;
2520 }
2521
2522 public Vector getVector() {
2523 if (_overlay instanceof Vector)
2524 return (Vector) _overlay;
2525 return null;
2526 }
2527
2528 public void setOverlay(Overlay overlay) {
2529 _overlay = overlay;
2530 }
2531
2532 public boolean dontSave() {
2533 // TODO Mike says: checkout if the ID check is still needed- When
2534 // will ID still
2535 // be -1 when saving a frame?
2536 // assert (i != null);
2537 return !isVisible() || getID() < 0 || offScreenTopOrLeft();
2538 }
2539
2540 public void setAnchorRight(Float anchor) {
2541 this._anchorRight = anchor;
2542 if (anchor != null)
2543 setX(FrameGraphics.getMaxFrameSize().width - anchor - getBoundsWidth());
2544 }
2545
2546 public Float getAnchorRight() {
2547 return _anchorRight;
2548 }
2549
2550 public void setAnchorBottom(Float anchor) {
2551 this._anchorBottom = anchor;
2552 if (anchor != null)
2553 setY(FrameGraphics.getMaxFrameSize().height - anchor - getBoundsHeight());
2554 }
2555
2556 public Float getAnchorBottom() {
2557 return _anchorBottom;
2558 }
2559
2560 public String getText() {
2561 return toString();
2562 }
2563
2564 public void setText(String text) {
2565 }
2566
2567 public boolean recalculateWhenChanged() {
2568 return false;
2569 }
2570
2571 public void update() {
2572 calculate(getText());
2573 }
2574
2575 public Collection<Item> getEnclosedItems() {
2576 return FrameUtils.getItemsEnclosedBy(this.getParentOrCurrentFrame(),
2577 this.getEnclosedShape());
2578 }
2579
2580 public Collection<Text> getEnclosedNonAnnotationText() {
2581 Collection<Text> items = new LinkedHashSet<Text>();
2582 for (Item t : getEnclosedItems()) {
2583 if (t instanceof Text && !t.isAnnotation())
2584 items.add((Text) t);
2585 }
2586
2587 return items;
2588 }
2589
2590 public void dispose() {
2591 setParent(null);
2592 }
2593
2594 /**
2595 * @return
2596 */
2597 protected boolean hasVisibleBorder() {
2598 return getThickness() > 0 && !isLineEnd();
2599 }
2600
2601 public Frame getChild() {
2602 String childName = getAbsoluteLink();
2603 if (childName != null) {
2604 return FrameIO.LoadFrame(childName);
2605 }
2606 return null;
2607 }
2608}
Note: See TracBrowser for help on using the repository browser.