source: trunk/src/org/expeditee/items/ItemUtils.java@ 121

Last change on this file since 121 was 121, checked in by bjn8, 16 years ago

Added invalidation for graphics... biiiig commit. LOts of effeciency improvements - now can animate

File size: 27.0 KB
Line 
1package org.expeditee.items;
2
3import java.awt.Color;
4import java.awt.Rectangle;
5import java.awt.image.ImageObserver;
6import java.io.File;
7import java.io.UnsupportedEncodingException;
8import java.net.URL;
9import java.net.URLDecoder;
10import java.util.ArrayList;
11import java.util.Collection;
12import java.util.HashMap;
13import java.util.LinkedHashSet;
14import java.util.LinkedList;
15import java.util.List;
16import java.util.Map;
17
18import org.expeditee.gui.DisplayIO;
19import org.expeditee.gui.Frame;
20import org.expeditee.gui.FreeItems;
21import org.expeditee.gui.Vector;
22import org.expeditee.items.Item.HighlightMode;
23
24
25//Static methods that provide functions for the objects\
26//mostly to transform values (string -> color etc).
27
28/**
29 * Static methods that provide functions for use in Items.
30 */
31public class ItemUtils {
32 // Tag constants
33 public static final int TAG_SORT = 0;
34
35 public static final int TAG_JOIN = 1;
36
37 public static final int TAG_INDENT = 2;
38
39 public static final int TAG_OVERLAY = 3;
40
41 public static final int TAG_ACTIVE_OVERLAY = 4;
42
43 public static final int TAG_IMAGE = 5;
44
45 public static final int TAG_ITEM_TEMPLATE = 6;
46
47 public static final int TAG_ANNOTATION_TEMPLATE = 7;
48
49 public static final int TAG_CODE_COMMENT_TEMPLATE = 8;
50
51 public static final int TAG_MENU = 9;
52
53 public static final int TAG_MENU_NEXT = 10;
54
55 public static final int TAG_PARENT = 11;
56
57 public static final int TAG_LITERAL = 12;
58
59 public static final int TAG_FRAME_IMAGE = 13;
60
61 public static final int TAG_BACKUP = 14;
62
63 public static final int TAG_POINTTYPE = 15;
64
65 // Brook: Im claiming this number!
66 public static final int TAG_IWIDGET = 16;
67
68 public static final int TAG_LINE_TEMPLATE = 17;
69
70 public static final int TAG_STAT_TEMPLATE = 18;
71
72 public static final int TAG_VECTOR = 19;
73
74 public static final int TAG_BITMAP_IMAGE = 20;
75
76 public static final int TAG_MIN = 0;
77
78 public static final int TAG_MAX = 20;
79
80 /**
81 * Determines if the given List of Items contains an Item that is one of the
82 * pre-defined tags.
83 *
84 * @param items
85 * The list of Items to search through
86 * @param tag
87 * The Tag to search for, this should correspond to one of the
88 * predefined constants in this class
89 * @return True if an Item was found that is the given Tag, False otherwise.
90 */
91 public static boolean ContainsTag(List<Item> items, int tag) {
92 return ContainsTag(items, GetTag(tag));
93 }
94
95 public static boolean ContainsTag(List<Item> items, String tag) {
96 return (FindTag(items, tag) != null);
97 }
98
99 public static boolean ContainsExactTag(List<Item> items, int tag) {
100 return ContainsExactTag(items, GetTag(tag));
101 }
102
103 public static boolean ContainsExactTag(List<Item> items, String tag) {
104 return (FindExactTag(items, tag) != null);
105 }
106
107 /**
108 * Searches the given List of Items for an Item that is one of the
109 * pre-defined tags.
110 *
111 * @param items
112 * The list of Items to search through
113 * @param tag
114 * The Tag to search for, this should correspond to one of the
115 * predefined constants in this class
116 * @return The Item that is the given tag if one is found, or False if none
117 * is found
118 */
119 public static Item FindTag(List<Item> items, int tag) {
120 return FindTag(items, GetTag(tag));
121 }
122
123 /**
124 * Searches the given List of Items for an Item that is the given tag
125 *
126 * @param items
127 * The list of Items to search through
128 * @param toFind
129 * The Tag to search for, this should include the at (@) symbol
130 * @return The Item that is the given tag if one is found, or False if none
131 * is found
132 */
133 public static Text FindTag(List<Item> items, String toFind) {
134 for (Item i : items) {
135 if (i instanceof Text && i.isAnnotation())
136 if (((Text) i).startsWith(toFind))
137 return (Text) i;
138 }
139 return null;
140 }
141
142 public static Item FindExactTag(List<Item> items, String toFind) {
143 for (Item i : items) {
144 if (i instanceof Text && i.isAnnotation())
145 if (((Text) i).getText().trim().equalsIgnoreCase(toFind))
146 return (Item) i;
147 }
148
149 return null;
150 }
151
152 public static Item FindExactTag(List<Item> items, int tag) {
153 return FindExactTag(items, GetTag(tag));
154 }
155
156 /**
157 * Determines if the given Item is one of the pre-defined tags in this class
158 *
159 * @param toCheck
160 * The Item to check
161 * @param tag
162 * The tag to check the Item against, this should correspond to
163 * one of the constants defined in this class
164 * @return True if the Item matches the given tag, false otherwise
165 */
166 public static boolean startsWithTag(Item toCheck, int tag) {
167 return startsWithTag(toCheck, GetTag(tag));
168 }
169
170 public static boolean startsWithTag(Item toCheck, int tag, boolean hasValue) {
171 return startsWithTag(toCheck, GetTag(tag), hasValue);
172 }
173
174 /**
175 * Checks if the given Item begins with the desired tag (case insensitive).
176 *
177 * @param toCheck
178 * The Item to check for the given tag
179 * @param tag
180 * The tag to check for in the given Item
181 * @param tagOnly
182 * True if the tag does not have a value
183 * @return True if the tag is found in the given Item, False otherwise.
184 */
185 public static boolean startsWithTag(Item toCheck, String tag,
186 boolean valueAllowed) {
187 if (!(toCheck instanceof Text))
188 return false;
189
190 Text txt = (Text) toCheck;
191 String value = ItemUtils.StripTag(txt.getText(), tag);
192
193 if (value == null)
194 return false;
195 return valueAllowed || value.equals("");
196 }
197
198 /**
199 * Checks if the item begins with the desired tag.
200 *
201 * @param toCheck
202 * @param tag
203 * @return
204 */
205 public static boolean startsWithTag(Item toCheck, String tag) {
206 return startsWithTag(toCheck, tag, true);
207 }
208
209 /**
210 * Strips off the given tag from the given String, and returns wathever is
211 * left. Dont put the colon after tags as it is not needed.
212 *
213 * @param toStrip
214 * The String to strip the Tag from
215 * @param tag
216 * The tag to remove from the String
217 * @return The String that results from removing the given Tag from the
218 * given String, or null if the given String is not the given Tag
219 */
220 public static String StripTag(String toStrip, String tag) {
221 if (toStrip == null)
222 return null;
223 toStrip = toStrip.trim();
224 if (!toStrip.toLowerCase().startsWith(tag.toLowerCase()))
225 return null;
226
227 if (toStrip.length() == tag.length())
228 return "";
229 // remove tag and ensure the char is the tag separator
230 char separator = toStrip.charAt(tag.length());
231 if (separator != ':')
232 return null;
233
234 if (toStrip.length() == tag.length() + 1)
235 return "";
236
237 return toStrip.substring(tag.length() + 1).trim();
238 }
239
240 /**
241 * Strips the first character from a string if it is the tag symbol and
242 * returns the remainder.
243 *
244 * @param toStrip
245 * the string to be stripped
246 * @return the stripped version of the string.
247 */
248 public static String StripTagSymbol(String toStrip) {
249 // there must be something left after stripping
250 if (toStrip != null) {
251 toStrip = toStrip.trim();
252 if (toStrip.length() > 0) {
253 if (toStrip.charAt(0) == '@') {
254 return toStrip.substring(1);
255 }
256 }
257 }
258 return toStrip;
259 }
260
261 /**
262 * Converts the given int to the String tag. The int should correspond to
263 * one of the constants in this class, if it does not this method will
264 * return null.
265 *
266 * @param tag
267 * The int corresponding to the constants in this class of which
268 * tag to return
269 * @return The String representation of the given Tag, or null if the given
270 * value does not have a tag associated
271 */
272 public static String GetTag(int tag) {
273 // TODO refactor so that this uses a map for INT to tags
274 switch (tag) {
275 case TAG_SORT:
276 return "@sort";
277 case TAG_JOIN:
278 return "@join";
279 case TAG_INDENT:
280 return "@indent";
281 case TAG_OVERLAY:
282 return "@o";
283 case TAG_VECTOR:
284 return "@v";
285 case TAG_ACTIVE_OVERLAY:
286 return "@ao";
287 case TAG_IMAGE:
288 return "@i";
289 case TAG_ITEM_TEMPLATE:
290 return "@itemtemplate";
291 case TAG_ANNOTATION_TEMPLATE:
292 return "@annotationtemplate";
293 case TAG_STAT_TEMPLATE:
294 return "@stattemplate";
295 case TAG_CODE_COMMENT_TEMPLATE:
296 return "@commenttemplate";
297 case TAG_MENU:
298 return "@menu";
299 case TAG_MENU_NEXT:
300 return "@nextmenu";
301 case TAG_PARENT:
302 return "@parent";
303 case TAG_LITERAL:
304 return "@lit";
305 case TAG_FRAME_IMAGE:
306 return "@f";
307 case TAG_BITMAP_IMAGE:
308 return "@b";
309 case TAG_BACKUP:
310 return "@old";
311 case TAG_POINTTYPE:
312 return "@pointtype";
313 case TAG_IWIDGET:
314 return "@iw";
315 case TAG_LINE_TEMPLATE:
316 return "@linetemplate";
317 default:
318 return null;
319 }
320 }
321
322 /**
323 * Creates a picture object from the information stored in the given Text
324 * object. <br>
325 * The paths searched are in the following order:<br>
326 * /images/<br>
327 * the source text as a relative path (from program root folder). <br>
328 * the source text as an absolute path <br>
329 * <br>
330 * If the Image file cannot be found on disk null is returned.
331 *
332 * @param source
333 * The Text file containing the Picture infomation
334 * @return The Picture object representing the file, or Null if the file is
335 * not found.
336 */
337 public static Picture CreatePicture(Text source, ImageObserver observer) {
338 String text = source.getText();
339 String path = "";
340 String fileName = "";
341 String size = "";
342
343 try {
344 // remove @i tag
345 text = text.replaceFirst("@i:", "");
346 text = text.replaceAll("\n", "");
347 text = text.trim();
348
349 int fileSuffixChar = text.indexOf('.');
350 if (fileSuffixChar < 0)
351 return null;
352 int endOfFileName = text.indexOf(' ', fileSuffixChar);
353 if (endOfFileName < 0) {
354 path = text;
355 size = "";
356 } else {
357 path = text.substring(0, endOfFileName);
358 size = text.substring(endOfFileName).trim();
359 }
360 fileName = path;
361
362 // try images subdirectory
363 File file = null;
364
365 for (String dir : org.expeditee.gui.UserSettings.ImageDirs) {
366 file = new File(dir + path);
367 if (file.exists() && !file.isDirectory())
368 break;
369 }
370
371 if (file == null || !file.exists() || file.isDirectory())
372 file = new File(path);
373
374 // try relative path
375 if (!file.exists() || file.isDirectory()) {
376 URL picture = new Object().getClass().getResource(path);
377
378 // decode to remove %20 in windows folder names
379 if (picture != null) {
380 try {
381 path = URLDecoder.decode(picture.getFile(), "UTF-8");
382 } catch (UnsupportedEncodingException e) {
383 // TODO Auto-generated catch block
384 e.printStackTrace();
385 }
386 }
387
388 } else
389 path = file.getPath();
390
391 // if the image isn't found by now, give up.
392 file = new File(path);
393 if (!file.exists() || file.isDirectory()) {
394 return null;
395 }
396
397 } catch (Exception e) {
398 return null;
399 }
400
401 try {
402 Picture pic = new Picture(source, fileName, path, size, observer);
403
404 return pic;
405 } catch (Exception e) {
406 e.printStackTrace();
407 return null;
408 }
409
410 }
411
412 /**
413 * Creates a deep copy of the given List of Items.
414 *
415 * @param toCopy
416 * The list of Items to copy
417 * @return A list containing a copy of all Items in the given List
418 */
419 public static List<Item> CopyItems(Collection<Item> toCopy) {
420 return CopyItems(toCopy, false, null);
421 }
422
423 public static List<Item> CopyItems(Collection<Item> toCopy, Vector v) {
424 return CopyItems(toCopy, false, v);
425 }
426
427 public static List<Item> CopyItems(Collection<Item> toCopy, boolean extrude) {
428 return CopyItems(toCopy, extrude, null);
429 }
430
431 public static List<Item> CopyItems(Collection<Item> toCopy,
432 boolean extrude, Vector v) {
433 // The copies to return
434 List<Item> copies = new ArrayList<Item>();
435
436 // list of dots at the end of lines
437 Collection<Item> lineEnds = new LinkedHashSet<Item>();
438 Collection<Line> lines = new LinkedHashSet<Line>();
439 Collection<XRayable> xrayables = new LinkedHashSet<XRayable>();
440 Collection<Constraint> constraints = new LinkedHashSet<Constraint>();
441
442 Collection<Item> singles = new LinkedHashSet<Item>();
443
444 Map<Item, Item> lineEndMap = new HashMap<Item, Item>();
445
446 // Widgets are super special
447 List<InteractiveWidget> widgets = new ArrayList<InteractiveWidget>();
448
449 for (Item i : toCopy) {
450
451 // BROOK
452 if (i instanceof WidgetCorner) { // dont add these
453 if (!widgets.contains(((WidgetCorner) i).getWidgetSource()))
454 widgets.add(((WidgetCorner) i).getWidgetSource());
455 // BROOK
456 } else if (i instanceof WidgetEdge) { // dont add these
457 // lines are recreated later
458 } else if (i instanceof Line) {
459 lines.add((Line) i);
460 } else if (i instanceof XRayable) {
461 xrayables.add((XRayable) i);
462 } else {
463 if (i.isLineEnd()) {
464 lineEnds.add(i);
465 constraints.addAll(i.getConstraints());
466 } else {
467 singles.add(i);
468 }
469 }
470 }
471
472 // Dont copy the other items that are part of the circle
473 for (XRayable x : xrayables) {
474 Collection<Item> connected = x.getConnected();
475 singles.removeAll(connected);
476 lineEnds.removeAll(connected);
477 lines.removeAll(connected);
478 Item xCopy = x.copy();
479 copies.addAll(xCopy.getConnected());
480 // Scale items that are from a vector frame
481 if (v != null) {
482 scaleItem(v, xCopy);
483 }
484 }
485
486 // copy all single items
487 for (Item i : singles) {
488 Item copy = i.copy();
489 Frame parent = i.getParent();
490 if (parent != null) {
491 // Items copied from overlay will be anchored onto the current
492 // frame
493 copy.setParent(parent);
494 // if this is the frame name, make sure the frame is saved (in
495 // case it is a TDFC frame)
496 if (i.isFrameName()) {
497 parent.setChanged(true);
498 }// check if the item is being copied from a vector
499 else if (v != null) {
500 // Find the vector this item is from
501 assert (v.Frame == parent);
502 scaleItem(v, copy);
503 }
504 }
505 copies.add(copy);
506 }
507
508 // replace line ends with their copies
509 // this is done here so that copied lines can still share end points
510 for (Item i : lineEnds) {
511 // create a copy of the line end
512 Item copy = i.copy();
513 copy.removeAllLines();
514 copy.removeAllConstraints();
515
516 if (extrude) {
517 Frame frame = i.getParentOrCurrentFrame();
518 Line newLine = new Line(i, copy, frame.getNextItemID());
519 // make sure overlay items are put back on the overlay
520 newLine.setParent(frame);
521 frame.addItem(newLine);
522 copies.add(newLine);
523 }
524 copies.add(copy);
525 lineEndMap.put(i, copy);
526 // Scale items that are from a vector frame
527 if (v != null) {
528 scaleItem(v, copy);
529 }
530 }
531
532 // recreate lines
533 for (Line line : lines) {
534 Line lineCopy = line.copy();
535 // get the lineEnd we copied above if it is in the MAPPING
536 Item originalLineEnd = line.getEndItem();
537 Item actualLineEnd = lineEndMap.get(originalLineEnd);
538 if (actualLineEnd == null)
539 lineCopy.setEndItem(originalLineEnd);
540 else
541 lineCopy.setEndItem(actualLineEnd);
542
543 Item originalLineStart = line.getStartItem();
544 Item actualLineStart = lineEndMap.get(originalLineStart);
545 if (actualLineStart == null)
546 lineCopy.setStartItem(originalLineStart);
547 else
548 lineCopy.setStartItem(actualLineStart);
549
550 copies.add(lineCopy);
551 }
552
553 // recreate constraints
554 for (Constraint c : constraints) {
555 Item start = lineEndMap.get(c.getStart());
556 Item end = lineEndMap.get(c.getEnd());
557 int id = DisplayIO.getCurrentFrame().getNextItemID();
558 if (start != null && end != null) {
559 new Constraint(start, end, id, c.getType());
560 }
561 }
562
563 // BROOK
564 for (InteractiveWidget iw : widgets) {
565 try {
566
567 InteractiveWidget icopy = iw.copy();
568 copies.addAll(icopy.getItems());
569
570 } catch (InteractiveWidgetNotAvailableException e) {
571 e.printStackTrace();
572 } catch (InteractiveWidgetInitialisationFailedException e) {
573 e.printStackTrace();
574 }
575
576 }
577
578 //Make sure filled rectangles are shown filled on vector overlays
579 if(v != null)
580 EnclosedCheck(copies);
581
582 return copies;
583 }
584
585 /**
586 * Attempts to create a new line that starts from the given Item
587 * ('unreeling'). The Item must already have at least one line, and not be a
588 * line itself to be unreeled from.
589 *
590 * @param toUnreelFrom
591 * The Item that will be one end point of the new line
592 * @return A List containing the newly created Item and Line that unreel
593 * from the given Item, or null if this Item cannot be unreeled
594 * from.
595 */
596 public static List<Item> UnreelLine(Item toUnreelFrom, boolean constrain) {
597 // the Item must already have one line to be unreeled from
598 if (toUnreelFrom == null || toUnreelFrom.getLines().size() < 1)
599 return null;
600
601 List<Item> unreel = new ArrayList<Item>(2);
602 unreel.add(toUnreelFrom);
603 unreel.addAll(toUnreelFrom.getLines());
604 return UnreelLine(unreel, constrain);
605 }
606
607 /**
608 * Attempts to create a new line that starts from the given list of Items
609 * ('unreeling'). The List must contain only one non-line Item. The non-line
610 * Item must already have at least one line to be unreeled from.
611 *
612 * @param toUnreel
613 * The List containing the Item that will be one end point of the
614 * new line
615 * @return A List of the newly created Item and Line that unreel from the
616 * Item in the given List, or null if this List cannot be unreeled
617 * from.
618 */
619 public static List<Item> UnreelLine(List<Item> toUnreel, boolean constrain) {
620 Item origEnd = null;
621 // find the end being unreeled from
622 for (Item item : toUnreel) {
623 // we dont want to unreel anything other than lines
624 if (item.hasEnclosures()
625 || !(item.isLineEnd() || item instanceof Line)) {
626 return null;
627 }
628 // find the dot to unreel from
629 if (item.isLineEnd()) {
630 // if there are multiple ends in the list, return
631 if (origEnd != null)
632 return null;
633
634 origEnd = item;
635 }
636 }
637
638 // copy the original endpoint
639 Item copy = origEnd.copy();
640 origEnd.setHighlightMode(HighlightMode.None);
641 copy.removeAllLines();
642 copy.removeAllConstraints();
643
644 // create a new line
645 Frame currentFrame = DisplayIO.getCurrentFrame();
646 Line line = new Line(origEnd, copy, currentFrame.getNextItemID());
647 // if the previous line was constrained then make the new line
648 // constrained if it was a single line
649 // TODO add later a diagonal constraint if getLines() == 3 or 4
650 Collection<Constraint> constraints = origEnd.getConstraints();
651 if (constrain && constraints.size() > 0
652 && origEnd.getLines().size() == 2) {
653 Integer type = null;
654 for (Constraint c : constraints) {
655 if (c.getType() == Constraint.HORIZONTAL) {
656 type = Constraint.VERTICAL;
657 } else if (c.getType() == Constraint.VERTICAL) {
658 type = Constraint.HORIZONTAL;
659 }
660 if (c.getType() == Constraint.DIAGONAL_NEG) {
661 type = Constraint.DIAGONAL_POS;
662 } else if (c.getType() == Constraint.DIAGONAL_POS) {
663 type = Constraint.DIAGONAL_NEG;
664 }
665 }
666 if (type != null) {
667 new Constraint(origEnd, copy, currentFrame.getNextItemID(),
668 type);
669 }
670 }
671
672 // copy.setFloating(true);
673 origEnd.setArrowheadLength(0);
674 // copy.setArrowheadLength(0);
675
676 List<Item> toReturn = new LinkedList<Item>();
677 toReturn.add(copy);
678 toReturn.add(line);
679 return toReturn;
680 }
681
682 public static void New() {
683 EnclosedCheck(DisplayIO.getCurrentFrame().getItems());
684 }
685
686 public static void Old() {
687 OldEnclosedCheck(DisplayIO.getCurrentFrame().getItems());
688 }
689
690 /**
691 * Updates the connectedToAnnotation flags for all items
692 */
693 public static void UpdateConnectedToAnnotations(Collection<Item> items) {
694 // get all lineEnds on the Frame
695 Collection<Item> lineEnds = new LinkedHashSet<Item>();
696 for (Item i : items) {
697 i.setConnectedToAnnotation(false);
698 if (i.isLineEnd()) {
699 lineEnds.add(i);
700 }
701 }
702
703 // if there are no line endpoints on the Frame, then there can't be an
704 // enclosure
705 if (lineEnds.size() == 0)
706 return;
707
708 // Now find go through line ends and see if any are annotation items
709 while (lineEnds.size() > 0) {
710 Item item = lineEnds.iterator().next();
711 // If its an annotation item then set the flag for all its connected
712 // items
713 if (item.isAnnotation()) {
714 Collection<Item> connected = item.getAllConnected();
715 for (Item i : connected)
716 i.setConnectedToAnnotation(true);
717 lineEnds.removeAll(connected);
718 }
719 lineEnds.remove(item);
720 }
721 }
722
723 /**
724 * Checks through all Lines and Dots on the current Frame to detect if any
725 * form an enclosure, which can then be used to manipulate items within the
726 * polygon. If an enclosure is found, then the dots will have their
727 * enclosure value set to true, and a List is created that contains all the
728 * Dots in the order they were processed. Actual calculation of the Polygon
729 * is done dynamically (to account for Dots being moved).
730 */
731 public static void EnclosedCheck(Collection<Item> items) {
732 // get all lineEnds on the Frame
733 List<Item> lineEnds = new LinkedList<Item>();
734 for (Item i : items) {
735 if (i.isLineEnd()) {
736 i.setEnclosedList(null);
737 // Add line ends joined to 2 other lines
738 if (i.getLines().size() == 2)
739 lineEnds.add(i);
740 }
741 }
742
743 // if there are no line endpoints on the Frame, then there can't be an
744 // enclosure
745 if (lineEnds.size() == 0)
746 return;
747
748 // New approach
749 while (lineEnds.size() > 0) {
750 Item item = lineEnds.get(0);
751 // Get the lineEnds connected to this item
752 Collection<Item> connected = item.getAllConnected();
753 Collection<Item> connectedLineEnds = new LinkedHashSet<Item>();
754 for (Item itemToCheck : connected) {
755 if (itemToCheck.isLineEnd())
756 connectedLineEnds.add(itemToCheck);
757 }
758 // Check that all the line ends are in our lineEnds list
759 int oldSize = lineEnds.size();
760 // Remove all the items from our line ends list
761 lineEnds.removeAll(connectedLineEnds);
762 int newSize = lineEnds.size();
763 int connectedSize = connectedLineEnds.size();
764 // Check if all the connectedItems were in the lineEnds collection
765 if (oldSize == newSize + connectedSize) {
766 // Set them to be the enclosed list for each of the items
767 for (Item enclosedLineEnd : connectedLineEnds) {
768 enclosedLineEnd.setEnclosedList(connectedLineEnds);
769 }
770 }
771
772 }
773 }
774
775 /**
776 * Checks through all Lines and Dots on the current Frame to detect if any
777 * form an enclosure, which can then be used to manipulate items within the
778 * polygon. If an enclosure is found, then the dots will have their
779 * enclosure value set to true, and a List is created that contains all the
780 * Dots in the order they were processed. Actual calculation of the Polygon
781 * is done dynamically (to account for Dots being moved).
782 */
783 public static void OldEnclosedCheck(Collection<Item> items) {
784 _seen.clear();
785
786 // get all lineEnds on the Frame
787 List<Item> lineEnds = new ArrayList<Item>(0);
788 for (Item i : items) {
789 if (i.isLineEnd()) {
790 i.setEnclosedList(null);
791
792 if (i.getLines().size() == 2)
793 lineEnds.add(i);
794 }
795 }
796
797 // if there are no line endpoints on the Frame, then there can't be an
798 // enclosure
799 if (lineEnds.size() == 0)
800 return;
801
802 // TODO optimise this code!!
803 // iterate through all the lineEnds
804 for (Item searchFor : lineEnds) {
805 _seen.clear();
806
807 for (Line l : searchFor.getLines()) {
808 _seen.add(l);
809 if (traverse(searchFor, l.getOppositeEnd(searchFor))) {
810 _path.add(l.getOppositeEnd(searchFor));
811
812 for (Item i : _path)
813 i.setEnclosedList(_path);
814
815 _path = new ArrayList<Item>(0);
816
817 break;
818 }
819 }
820 }
821
822 }
823
824 private static List<Line> _seen = new ArrayList<Line>();
825
826 private static List<Item> _path = new ArrayList<Item>();
827
828 private static boolean traverse(Item toFind, Item searchFrom) {
829 if (toFind == null || searchFrom == null || !searchFrom.isLineEnd())
830 return false;
831
832 if (searchFrom.getLines().size() != 2)
833 return false;
834
835 if (toFind == searchFrom)
836 return true;
837
838 for (Line l : searchFrom.getLines()) {
839 if (!(_seen.contains(l))) {
840 _seen.add(l);
841 if (traverse(toFind, l.getOppositeEnd(searchFrom))) {
842 _path.add(l.getOppositeEnd(searchFrom));
843 return true;
844 }
845 }
846
847 }
848
849 return false;
850 }
851
852 /**
853 * Determines if an item is visible from a the current frame(s).
854 * If the item is free then it is considered visible.
855 * @param i The item to check
856 * @return True if visible/free from given frame.
857 */
858 public static boolean isVisible(Item i) {
859 if (DisplayIO.isTwinFramesOn()) {
860 if (!isVisible(DisplayIO.getFrames()[0], i)) {
861 return isVisible(DisplayIO.getFrames()[1], i);
862 } else {
863 return true;
864 }
865 } else {
866 return isVisible(DisplayIO.getCurrentFrame(), i);
867 }
868 }
869
870 /**
871 * Determines if an item is visible from a given frame.
872 * If the item is free then it is considered visible.
873 *
874 * @param fromFrame The frame to check from.
875 * @param i The item to check
876 * @return True if visible/free from given frame.
877 */
878 public static boolean isVisible(Frame fromFrame, Item i) {
879 if (fromFrame == null) return false;
880
881 Frame parent = i.getParent();
882
883 if (parent == fromFrame) return true;
884
885 else if (parent == null) return FreeItems.getInstance().contains(i);
886
887 return fromFrame.getAllItems().contains(i) && i.isVisible();
888 }
889
890 public static Rectangle expandRectangle(Rectangle r, int n) {
891 return new Rectangle(r.x - (n >> 1), r.y - (n >> 1),
892 r.width + n, r.height + n);
893 }
894
895 /*
896 * FrameMouseActions while (!copies.isEmpty()) { Iterator<Item> iterator =
897 * copies.iterator(); Item item = iterator.next(); // Dont paint annotation
898 * items for @v if (!item.isVisible() || item.isAnnotation()) {
899 * iterator.remove(); continue; }
900 *
901 * if (!(item instanceof Line)) { item.setThickness(item.getThickness() *
902 * scale); if (item instanceof XRayable || item.hasEnclosures()) {
903 * scaleItem(scale, defaultForeground, defaultBackground, origin.x,
904 * origin.y, item); items.add(item); copies.remove(item); } else {
905 * Collection<Item> connected = item.getAllConnected(); // Get all the
906 * connected items because we can only set the // thickness ONCE for (Item i :
907 * connected) { scaleItem(scale, defaultForeground, defaultBackground,
908 * origin.x, origin.y, i); } items.addAll(connected);
909 * copies.removeAll(connected); } } else { iterator.remove(); } }
910 */
911
912 /**
913 * @param scale
914 * @param defaultForeground
915 * @param defaultBackground
916 * @param originX
917 * @param originY
918 * @param item
919 */
920 private static void scaleItem(Vector v, Item item) {
921 Float scale = v.Scale;
922 int originX = v.Origin.x;
923 int originY = v.Origin.y;
924 Color defaultForeground = v.Foreground;
925 Color defaultBackground = v.Background;
926 Permission permission = v.permission;
927 item.setPermission(permission);
928
929 //TODO encapsulate this somewhere inside of circle class!
930 if(item instanceof Circle){
931 scaleItem(v, ((Circle)item).getCenter());
932 }
933
934 if (!(item instanceof Line)) {
935 item.setXY(item.getX() * scale + originX, item.getY() * scale
936 + originY);
937 item.setArrowheadLength(item.getArrowheadLength() * scale);
938 if (item.getColor() == null) {
939 item.setColor(defaultForeground);
940 }
941 if (item.getBackgroundColor() == null) {
942 item.setBackgroundColor(defaultBackground);
943 }
944 if (item.getFillColor() == null) {
945 item.setFillColor(defaultBackground);
946 }
947
948 float thickness = item.getThickness();
949 if(thickness > 0)
950 item.setThickness(thickness * scale);
951
952 if (item instanceof Text)
953 item.setSize(item.getSize() * scale);
954 else if (item instanceof Picture) {
955 Picture p = (Picture) item;
956 p.setScale(p.getScale() * scale);
957 }
958 if (permission.equals(Permission.none)) {
959 item.setLinkMark(false);
960 item.setActionMark(false);
961 } else {
962 item.updatePolygon();
963 }
964 }
965
966 }
967}
Note: See TracBrowser for help on using the repository browser.