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

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

Added Frame and Box variables to the Math calculations

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