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

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