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

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