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

Last change on this file since 919 was 919, checked in by jts21, 10 years ago

Added license headers to all files, added full GPL3 license file, moved license header generator script to dev/bin/scripts

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