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

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