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

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

Fixed up search stuff... to adjust to getting params off the cursor

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