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

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

Added DebugFrame action
Added GetCometStats
Lots of bug fixes

File size: 22.6 KB
Line 
1package org.expeditee.items;
2
3import java.awt.Font;
4import java.awt.FontMetrics;
5import java.awt.Image;
6import java.awt.image.ImageObserver;
7import java.io.File;
8import java.io.UnsupportedEncodingException;
9import java.net.URL;
10import java.net.URLDecoder;
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.HashMap;
14import java.util.LinkedHashSet;
15import java.util.LinkedList;
16import java.util.List;
17import java.util.Map;
18
19import javax.swing.JFrame;
20
21import org.expeditee.gui.AttributeUtils;
22import org.expeditee.gui.DisplayIO;
23import org.expeditee.gui.Frame;
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 private static JFrame _jf = new JFrame();
33
34 // Tag constants
35 public static final int TAG_SORT = 0;
36
37 public static final int TAG_JOIN = 1;
38
39 public static final int TAG_INDENT = 2;
40
41 public static final int TAG_OVERLAY = 3;
42
43 public static final int TAG_ACTIVE_OVERLAY = 4;
44
45 public static final int TAG_IMAGE = 5;
46
47 public static final int TAG_ITEM_TEMPLATE = 6;
48
49 public static final int TAG_ANNOTATION_TEMPLATE = 7;
50
51 public static final int TAG_CODE_COMMENT_TEMPLATE = 8;
52
53 public static final int TAG_MENU = 9;
54
55 public static final int TAG_MENU_NEXT = 10;
56
57 public static final int TAG_PARENT = 11;
58
59 public static final int TAG_LITERAL = 12;
60
61 public static final int TAG_FRAME_IMAGE = 13;
62
63 public static final int TAG_BACKUP = 14;
64
65 public static final int TAG_POINTTYPE = 15;
66
67 // Brook: Im claiming this number!
68 public static final int TAG_IWIDGET = 16;
69
70 public static final int TAG_LINE_TEMPLATE = 17;
71
72 public static final int TAG_STAT_TEMPLATE = 18;
73
74 public static final int TAG_VECTOR = 19;
75
76 public static final int TAG_BITMAP_IMAGE = 20;
77
78 public static final int TAG_MIN = 0;
79
80 public static final int TAG_MAX = 20;
81
82 /**
83 * Determines if the given List of Items contains an Item that is one of the
84 * pre-defined tags.
85 *
86 * @param items
87 * The list of Items to search through
88 * @param tag
89 * The Tag to search for, this should correspond to one of the
90 * predefined constants in this class
91 * @return True if an Item was found that is the given Tag, False otherwise.
92 */
93 public static boolean ContainsTag(List<Item> items, int tag) {
94 return ContainsTag(items, GetTag(tag));
95 }
96
97 public static boolean ContainsTag(List<Item> items, String tag) {
98 return (FindTag(items, tag) != null);
99 }
100
101 public static boolean ContainsExactTag(List<Item> items, int tag) {
102 return ContainsExactTag(items, GetTag(tag));
103 }
104
105 public static boolean ContainsExactTag(List<Item> items, String tag) {
106 return (FindExactTag(items, tag) != null);
107 }
108
109 /**
110 * Searches the given List of Items for an Item that is one of the
111 * pre-defined tags.
112 *
113 * @param items
114 * The list of Items to search through
115 * @param tag
116 * The Tag to search for, this should correspond to one of the
117 * predefined constants in this class
118 * @return The Item that is the given tag if one is found, or False if none
119 * is found
120 */
121 public static Item FindTag(List<Item> items, int tag) {
122 return FindTag(items, GetTag(tag));
123 }
124
125 /**
126 * Searches the given List of Items for an Item that is the given tag
127 *
128 * @param items
129 * The list of Items to search through
130 * @param toFind
131 * The Tag to search for, this should include the at (@) symbol
132 * @return The Item that is the given tag if one is found, or False if none
133 * is found
134 */
135 public static Text FindTag(List<Item> items, String toFind) {
136 for (Item i : items) {
137 if (i instanceof Text && i.isAnnotation())
138 if (((Text) i).startsWith(toFind))
139 return (Text) i;
140 }
141
142 return null;
143 }
144
145 public static Item FindExactTag(List<Item> items, String toFind) {
146 for (Item i : items) {
147 if (i instanceof Text && i.isAnnotation())
148 if (((Text) i).getText().trim().equalsIgnoreCase(toFind))
149 return (Item) i;
150 }
151
152 return null;
153 }
154
155 public static Item FindExactTag(List<Item> items, int tag) {
156 return FindExactTag(items, GetTag(tag));
157 }
158
159 /**
160 * Determines if the given Item is one of the pre-defined tags in this class
161 *
162 * @param toCheck
163 * The Item to check
164 * @param tag
165 * The tag to check the Item against, this should correspond to
166 * one of the constants defined in this class
167 * @return True if the Item matches the given tag, false otherwise
168 */
169 public static boolean startsWithTag(Item toCheck, int tag) {
170 return startsWithTag(toCheck, GetTag(tag));
171 }
172
173 public static boolean startsWithTag(Item toCheck, int tag, boolean hasValue) {
174 return startsWithTag(toCheck, GetTag(tag), hasValue);
175 }
176
177 /**
178 * Checks if the given Item begins with the desired tag (case insensitive).
179 *
180 * @param toCheck
181 * The Item to check for the given tag
182 * @param tag
183 * The tag to check for in the given Item
184 * @param tagOnly
185 * True if the tag does not have a value
186 * @return True if the tag is found in the given Item, False otherwise.
187 */
188 public static boolean startsWithTag(Item toCheck, String tag, boolean valueAllowed) {
189 if (!(toCheck instanceof Text))
190 return false;
191
192 Text txt = (Text) toCheck;
193 String value = ItemUtils.StripTag(txt.getText(), tag);
194
195 if (value == null)
196 return false;
197 return valueAllowed || value.equals("");
198 }
199
200 /**
201 * Checks if the item begins with the desired tag.
202 * @param toCheck
203 * @param tag
204 * @return
205 */
206 public static boolean startsWithTag(Item toCheck, String tag) {
207 return startsWithTag(toCheck, tag, true);
208 }
209
210 /**
211 * Strips off the given tag from the given String, and returns wathever is
212 * left. Dont put the colon after tags as it is not needed.
213 *
214 * @param toStrip
215 * The String to strip the Tag from
216 * @param tag
217 * The tag to remove from the String
218 * @return The String that results from removing the given Tag from the
219 * given String, or null if the given String is not the given Tag
220 */
221 public static String StripTag(String toStrip, String tag) {
222 if (toStrip == null)
223 return null;
224 toStrip = toStrip.trim();
225 if (!toStrip.toLowerCase().startsWith(tag.toLowerCase()))
226 return null;
227
228 if (toStrip.length() == tag.length())
229 return "";
230 // remove tag and ensure the char is the tag separator
231 char separator = toStrip.charAt(tag.length());
232 if (separator != ':')
233 return null;
234
235 if (toStrip.length() == tag.length() + 1)
236 return "";
237
238 return toStrip.substring(tag.length() + 1).trim();
239 }
240
241 /**
242 * Strips the first character from a string if it is the tag symbol and
243 * returns the remainder.
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 * Returns a FontMetrics object that corresponds to the given Font.
324 *
325 * @param font
326 * The Font to derive the FontMetrics from
327 * @return FontMetrics that correspond to the given Font
328 */
329 public static FontMetrics getFontMetrics(Font font) {
330 return _jf.getFontMetrics(font);
331 }
332
333 public static Image CreateImage(int x, int y) {
334 return _jf.createImage(x, y);
335 }
336
337 /**
338 * Creates a picture object from the information stored in the given Text
339 * object. <br>
340 * The paths searched are in the following order:<br>
341 * /images/<br>
342 * the source text as a relative path (from program root folder). <br>
343 * the source text as an absolute path <br>
344 * <br>
345 * If the Image file cannot be found on disk null is returned.
346 *
347 * @param source
348 * The Text file containing the Picture infomation
349 * @return The Picture object representing the file, or Null if the file is
350 * not found.
351 */
352 public static Picture CreatePicture(Text source, ImageObserver observer) {
353 String text = source.getText();
354 String path = "";
355 String fileName = "";
356 String size = "";
357
358 try {
359 // remove @i tag
360 text = text.replaceFirst("@i:", "");
361 text = text.replaceAll("\n", "");
362 text = text.trim();
363
364 int fileSuffixChar = text.indexOf('.');
365 if (fileSuffixChar < 0)
366 return null;
367 int endOfFileName = text.indexOf(' ', fileSuffixChar);
368 if (endOfFileName < 0) {
369 path = text;
370 size = "";
371 } else {
372 path = text.substring(0, endOfFileName);
373 size = text.substring(endOfFileName).trim();
374 }
375 fileName = path;
376
377 // try images subdirectory
378 File file = null;
379
380 for (String dir : org.expeditee.gui.UserSettings.ImageDirs) {
381 file = new File(dir + path);
382 if (file.exists() && !file.isDirectory())
383 break;
384 }
385
386 if (file == null || !file.exists() || file.isDirectory())
387 file = new File(path);
388
389 // try relative path
390 if (!file.exists() || file.isDirectory()) {
391 URL picture = new Object().getClass().getResource(path);
392
393 // decode to remove %20 in windows folder names
394 if (picture != null) {
395 try {
396 path = URLDecoder.decode(picture.getFile(), "UTF-8");
397 } catch (UnsupportedEncodingException e) {
398 // TODO Auto-generated catch block
399 e.printStackTrace();
400 }
401 }
402
403 } else
404 path = file.getPath();
405
406 // if the image isn't found by now, give up.
407 file = new File(path);
408 if (!file.exists() || file.isDirectory()) {
409 return null;
410 }
411
412 } catch (Exception e) {
413 return null;
414 }
415
416 try {
417 Picture pic = new Picture(source, fileName, path, size, observer);
418
419 return pic;
420 } catch (Exception e) {
421 e.printStackTrace();
422 return null;
423 }
424
425 }
426
427 public static Picture CreateFrameImage(Text source, ImageObserver observer) {
428 String size = source.getFirstLine();
429
430 // remove @f tag
431 size = AttributeUtils.getValue(size);
432
433 try {
434 Picture pic = new FrameImage(source, size, observer);
435 return pic;
436 } catch (Exception e) {
437 // e.printStackTrace();
438 return null;
439 }
440 }
441
442 public static Picture CreateFrameBitmap(Text source, ImageObserver observer) {
443 String size = source.getFirstLine();
444
445 // remove @b tag
446 size = AttributeUtils.getValue(size);
447
448 try {
449 Picture pic = new FrameBitmap(source, size, observer);
450 return pic;
451 } catch (Exception e) {
452 // e.printStackTrace();
453 return null;
454 }
455 }
456
457 /**
458 * Creates a deep copy of the given List of Items.
459 *
460 * @param toCopy
461 * The list of Items to copy
462 * @return A list containing a copy of all Items in the given List
463 */
464 public static List<Item> CopyItems(Collection<Item> toCopy) {
465 return CopyItems(toCopy, false);
466 }
467
468 public static List<Item> CopyItems(Collection<Item> toCopy, boolean extrude) {
469 // The copies to return
470 List<Item> copies = new ArrayList<Item>();
471
472 // list of dots at the end of lines
473 Collection<Item> lineEnds = new LinkedHashSet<Item>();
474 Collection<Line> lines = new LinkedHashSet<Line>();
475 Collection<Constraint> constraints = new LinkedHashSet<Constraint>();
476
477 Collection<Item> singles = new LinkedHashSet<Item>();
478
479 Map<Item, Item> lineEndMap = new HashMap<Item, Item>();
480
481 // Widgets are super special
482 List<InteractiveWidget> widgets = new ArrayList<InteractiveWidget>();
483
484 for (Item i : toCopy) {
485
486 // BROOK
487 if (i instanceof WidgetCorner) { // dont add these
488
489 if (!widgets.contains(((WidgetCorner) i).getWidgetSource()))
490 widgets.add(((WidgetCorner) i).getWidgetSource());
491
492 // BROOK
493 } else if (i instanceof WidgetEdge) { // dont add these
494
495 // lines are recreated later
496 } else if (i instanceof Line) {
497 lines.add((Line) i);
498 } else {
499 if (i.isLineEnd()) {
500 lineEnds.add(i);
501 constraints.addAll(i.getConstraints());
502 } else {
503 singles.add(i);
504 }
505 }
506 }
507
508 // copy all single items
509 for (Item i : singles) {
510 Item copy = i.copy();
511
512 if (i.getParent() != null) {
513 // if this is the frame name, make sure the frame is saved (in
514 // case it is a TDFC frame)
515 if (i == i.getParent().getNameItem())
516 i.getParent().setChanged(true);
517
518 // if this is the title of the frame, link it to the frame
519 if (i.getLink() == null && i == i.getParent().getTitleItem()
520 && toCopy.size() == 1) {
521 // save the frame after copying
522 i.getParent().setChanged(true);
523 copy.setLink(i.getParent().getName());
524 }
525 }
526 copies.add(copy);
527 }
528
529 // replace line ends with their copies
530 // this is done here so that copied lines can still share end points
531 for (Item i : lineEnds) {
532 // create a copy of the line end
533 Item copy = i.copy();
534 copy.removeAllLines();
535 copy.removeAllConstraints();
536
537 if (extrude) {
538 Frame frame = i.getParentOrCurrentFrame();
539 Line newLine = new Line(i, copy, frame.getNextItemID());
540 // make sure overlay items are put back on the overlay
541 newLine.setParent(frame);
542 frame.addItem(newLine);
543 copies.add(newLine);
544 }
545 copies.add(copy);
546 lineEndMap.put(i, copy);
547 }
548
549 // recreate lines
550 for (Line line : lines) {
551 Line lineCopy = line.copy();
552 // get the lineEnd we copied above if it is in the MAPPING
553 Item originalLineEnd = line.getEndItem();
554 Item actualLineEnd = lineEndMap.get(originalLineEnd);
555 if (actualLineEnd == null)
556 lineCopy.setEndItem(originalLineEnd);
557 else
558 lineCopy.setEndItem(actualLineEnd);
559
560 Item originalLineStart = line.getStartItem();
561 Item actualLineStart = lineEndMap.get(originalLineStart);
562 if (actualLineStart == null)
563 lineCopy.setStartItem(originalLineStart);
564 else
565 lineCopy.setStartItem(actualLineStart);
566
567 copies.add(lineCopy);
568 }
569
570 // recreate constraints
571 for (Constraint c : constraints) {
572 Item start = lineEndMap.get(c.getStart());
573 Item end = lineEndMap.get(c.getEnd());
574 int id = DisplayIO.getCurrentFrame().getNextItemID();
575 if (start != null && end != null) {
576 new Constraint(start, end, id, c.getType());
577 }
578 }
579
580 // BROOK
581 for (InteractiveWidget iw : widgets) {
582 try {
583
584 InteractiveWidget icopy = iw.copy();
585 copies.addAll(icopy.getItems());
586
587 } catch (InteractiveWidgetNotAvailableException e) {
588 e.printStackTrace();
589 } catch (InteractiveWidgetInitialisationFailedException e) {
590 e.printStackTrace();
591 }
592
593 }
594
595 return copies;
596 }
597
598 /**
599 * Attempts to create a new line that starts from the given Item
600 * ('unreeling'). The Item must already have at least one line, and not be a
601 * line itself to be unreeled from.
602 *
603 * @param toUnreelFrom
604 * The Item that will be one end point of the new line
605 * @return A List containing the newly created Item and Line that unreel
606 * from the given Item, or null if this Item cannot be unreeled
607 * from.
608 */
609 public static List<Item> UnreelLine(Item toUnreelFrom) {
610 // the Item must already have one line to be unreeled from
611 if (toUnreelFrom == null || toUnreelFrom.getLines().size() < 1)
612 return null;
613
614 List<Item> unreel = new ArrayList<Item>(2);
615 unreel.add(toUnreelFrom);
616 unreel.addAll(toUnreelFrom.getLines());
617 return UnreelLine(unreel);
618 }
619
620 /**
621 * Attempts to create a new line that starts from the given list of Items
622 * ('unreeling'). The List must contain only one non-line Item. The non-line
623 * Item must already have at least one line to be unreeled from.
624 *
625 * @param toUnreel
626 * The List containing the Item that will be one end point of the
627 * new line
628 * @return A List of the newly created Item and Line that unreel from the
629 * Item in the given List, or null if this List cannot be unreeled
630 * from.
631 */
632 public static List<Item> UnreelLine(List<Item> toUnreel) {
633 Item origEnd = null;
634 // find the end being unreeled from
635 for (Item item : toUnreel) {
636 // we dont want to unreel anything other than lines
637 if (!(item.isLineEnd() || item instanceof Line)) {
638 return null;
639 }
640 // find the dot to unreel from
641 if (item.isLineEnd()) {
642 // if there are multiple ends in the list, return
643 if (origEnd != null)
644 return null;
645
646 origEnd = item;
647 }
648 }
649
650 // copy the original endpoint
651 Item copy = origEnd.copy();
652 copy.removeAllLines();
653 copy.removeAllConstraints();
654
655 // create a new line
656 Line line = new Line(origEnd, copy, DisplayIO.getCurrentFrame()
657 .getNextItemID());
658 // copy.setFloating(true);
659 origEnd.setArrowheadLength(0);
660 // copy.setArrowheadLength(0);
661
662 List<Item> toReturn = new LinkedList<Item>();
663 toReturn.add(copy);
664 toReturn.add(line);
665 return toReturn;
666 }
667
668 public static void New() {
669 EnclosedCheck(DisplayIO.getCurrentFrame().getItems());
670 }
671
672 public static void Old() {
673 OldEnclosedCheck(DisplayIO.getCurrentFrame().getItems());
674 }
675
676 /**
677 * Updates the connectedToAnnotation flags for all items
678 */
679 public static void UpdateConnectedToAnnotations(Collection<Item> items) {
680 // get all lineEnds on the Frame
681 Collection<Item> lineEnds = new LinkedHashSet<Item>();
682 for (Item i : items) {
683 i.setConnectedToAnnotation(false);
684 if (i.isLineEnd()) {
685 lineEnds.add(i);
686 }
687 }
688
689 // if there are no line endpoints on the Frame, then there can't be an
690 // enclosure
691 if (lineEnds.size() == 0)
692 return;
693
694 // Now find go through line ends and see if any are annotation items
695 while (lineEnds.size() > 0) {
696 Item item = lineEnds.iterator().next();
697 // If its an annotation item then set the flag for all its connected
698 // items
699 if (item.isAnnotation()) {
700 Collection<Item> connected = item.getAllConnected();
701 for (Item i : connected)
702 i.setConnectedToAnnotation(true);
703 lineEnds.removeAll(connected);
704 }
705 lineEnds.remove(item);
706 }
707 }
708
709 /**
710 * Checks through all Lines and Dots on the current Frame to detect if any
711 * form an enclosure, which can then be used to manipulate items within the
712 * polygon. If an enclosure is found, then the dots will have their
713 * enclosure value set to true, and a List is created that contains all the
714 * Dots in the order they were processed. Actual calculation of the Polygon
715 * is done dynamically (to account for Dots being moved).
716 */
717 public static void EnclosedCheck(Collection<Item> items) {
718 // get all lineEnds on the Frame
719 List<Item> lineEnds = new LinkedList<Item>();
720 for (Item i : items) {
721 if (i.isLineEnd()) {
722 i.setEnclosedList(null);
723 // Add line ends joined to 2 other lines
724 if (i.getLines().size() == 2)
725 lineEnds.add(i);
726 }
727 }
728
729 // if there are no line endpoints on the Frame, then there can't be an
730 // enclosure
731 if (lineEnds.size() == 0)
732 return;
733
734 // New approach
735 while (lineEnds.size() > 0) {
736 Item item = lineEnds.get(0);
737 // Get the lineEnds connected to this item
738 Collection<Item> connected = item.getAllConnected();
739 Collection<Item> connectedLineEnds = new LinkedHashSet<Item>();
740 for (Item itemToCheck : connected) {
741 if (itemToCheck.isLineEnd())
742 connectedLineEnds.add(itemToCheck);
743 }
744 // Check that all the line ends are in our lineEnds list
745 int oldSize = lineEnds.size();
746 // Remove all the items from our line ends list
747 lineEnds.removeAll(connectedLineEnds);
748 int newSize = lineEnds.size();
749 int connectedSize = connectedLineEnds.size();
750 // Check if all the connectedItems were in the lineEnds collection
751 if (oldSize == newSize + connectedSize) {
752 // Set them to be the enclosed list for each of the items
753 for (Item enclosedLineEnd : connectedLineEnds) {
754 enclosedLineEnd.setEnclosedList(connectedLineEnds);
755 }
756 }
757
758 }
759 }
760
761 /**
762 * Checks through all Lines and Dots on the current Frame to detect if any
763 * form an enclosure, which can then be used to manipulate items within the
764 * polygon. If an enclosure is found, then the dots will have their
765 * enclosure value set to true, and a List is created that contains all the
766 * Dots in the order they were processed. Actual calculation of the Polygon
767 * is done dynamically (to account for Dots being moved).
768 */
769 public static void OldEnclosedCheck(Collection<Item> items) {
770 _seen.clear();
771
772 // get all lineEnds on the Frame
773 List<Item> lineEnds = new ArrayList<Item>(0);
774 for (Item i : items) {
775 if (i.isLineEnd()) {
776 i.setEnclosedList(null);
777
778 if (i.getLines().size() == 2)
779 lineEnds.add(i);
780 }
781 }
782
783 // if there are no line endpoints on the Frame, then there can't be an
784 // enclosure
785 if (lineEnds.size() == 0)
786 return;
787
788 // TODO optimise this code!!
789 // iterate through all the lineEnds
790 for (Item searchFor : lineEnds) {
791 _seen.clear();
792
793 for (Line l : searchFor.getLines()) {
794 _seen.add(l);
795 if (traverse(searchFor, l.getOppositeEnd(searchFor))) {
796 _path.add(l.getOppositeEnd(searchFor));
797
798 for (Item i : _path)
799 i.setEnclosedList(_path);
800
801 _path = new ArrayList<Item>(0);
802
803 break;
804 }
805 }
806 }
807
808 }
809
810 private static List<Line> _seen = new ArrayList<Line>();
811
812 private static List<Item> _path = new ArrayList<Item>();
813
814 private static boolean traverse(Item toFind, Item searchFrom) {
815 if (toFind == null || searchFrom == null || !searchFrom.isLineEnd())
816 return false;
817
818 if (searchFrom.getLines().size() != 2)
819 return false;
820
821 if (toFind == searchFrom)
822 return true;
823
824 for (Line l : searchFrom.getLines()) {
825 if (!(_seen.contains(l))) {
826 _seen.add(l);
827 if (traverse(toFind, l.getOppositeEnd(searchFrom))) {
828 _path.add(l.getOppositeEnd(searchFrom));
829 return true;
830 }
831 }
832
833 }
834
835 return false;
836 }
837}
Note: See TracBrowser for help on using the repository browser.