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

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

Added getTreeStats

File size: 22.3 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 copies.add(copy);
519 }
520
521 // replace line ends with their copies
522 // this is done here so that copied lines can still share end points
523 for (Item i : lineEnds) {
524 // create a copy of the line end
525 Item copy = i.copy();
526 copy.removeAllLines();
527 copy.removeAllConstraints();
528
529 if (extrude) {
530 Frame frame = i.getParentOrCurrentFrame();
531 Line newLine = new Line(i, copy, frame.getNextItemID());
532 // make sure overlay items are put back on the overlay
533 newLine.setParent(frame);
534 frame.addItem(newLine);
535 copies.add(newLine);
536 }
537 copies.add(copy);
538 lineEndMap.put(i, copy);
539 }
540
541 // recreate lines
542 for (Line line : lines) {
543 Line lineCopy = line.copy();
544 // get the lineEnd we copied above if it is in the MAPPING
545 Item originalLineEnd = line.getEndItem();
546 Item actualLineEnd = lineEndMap.get(originalLineEnd);
547 if (actualLineEnd == null)
548 lineCopy.setEndItem(originalLineEnd);
549 else
550 lineCopy.setEndItem(actualLineEnd);
551
552 Item originalLineStart = line.getStartItem();
553 Item actualLineStart = lineEndMap.get(originalLineStart);
554 if (actualLineStart == null)
555 lineCopy.setStartItem(originalLineStart);
556 else
557 lineCopy.setStartItem(actualLineStart);
558
559 copies.add(lineCopy);
560 }
561
562 // recreate constraints
563 for (Constraint c : constraints) {
564 Item start = lineEndMap.get(c.getStart());
565 Item end = lineEndMap.get(c.getEnd());
566 int id = DisplayIO.getCurrentFrame().getNextItemID();
567 if (start != null && end != null) {
568 new Constraint(start, end, id, c.getType());
569 }
570 }
571
572 // BROOK
573 for (InteractiveWidget iw : widgets) {
574 try {
575
576 InteractiveWidget icopy = iw.copy();
577 copies.addAll(icopy.getItems());
578
579 } catch (InteractiveWidgetNotAvailableException e) {
580 e.printStackTrace();
581 } catch (InteractiveWidgetInitialisationFailedException e) {
582 e.printStackTrace();
583 }
584
585 }
586
587 return copies;
588 }
589
590 /**
591 * Attempts to create a new line that starts from the given Item
592 * ('unreeling'). The Item must already have at least one line, and not be a
593 * line itself to be unreeled from.
594 *
595 * @param toUnreelFrom
596 * The Item that will be one end point of the new line
597 * @return A List containing the newly created Item and Line that unreel
598 * from the given Item, or null if this Item cannot be unreeled
599 * from.
600 */
601 public static List<Item> UnreelLine(Item toUnreelFrom) {
602 // the Item must already have one line to be unreeled from
603 if (toUnreelFrom == null || toUnreelFrom.getLines().size() < 1)
604 return null;
605
606 List<Item> unreel = new ArrayList<Item>(2);
607 unreel.add(toUnreelFrom);
608 unreel.addAll(toUnreelFrom.getLines());
609 return UnreelLine(unreel);
610 }
611
612 /**
613 * Attempts to create a new line that starts from the given list of Items
614 * ('unreeling'). The List must contain only one non-line Item. The non-line
615 * Item must already have at least one line to be unreeled from.
616 *
617 * @param toUnreel
618 * The List containing the Item that will be one end point of the
619 * new line
620 * @return A List of the newly created Item and Line that unreel from the
621 * Item in the given List, or null if this List cannot be unreeled
622 * from.
623 */
624 public static List<Item> UnreelLine(List<Item> toUnreel) {
625 Item origEnd = null;
626 // find the end being unreeled from
627 for (Item item : toUnreel) {
628 // we dont want to unreel anything other than lines
629 if (!(item.isLineEnd() || item instanceof Line)) {
630 return null;
631 }
632 // find the dot to unreel from
633 if (item.isLineEnd()) {
634 // if there are multiple ends in the list, return
635 if (origEnd != null)
636 return null;
637
638 origEnd = item;
639 }
640 }
641
642 // copy the original endpoint
643 Item copy = origEnd.copy();
644 copy.removeAllLines();
645 copy.removeAllConstraints();
646
647 // create a new line
648 Line line = new Line(origEnd, copy, DisplayIO.getCurrentFrame()
649 .getNextItemID());
650 // copy.setFloating(true);
651 origEnd.setArrowheadLength(0);
652 // copy.setArrowheadLength(0);
653
654 List<Item> toReturn = new LinkedList<Item>();
655 toReturn.add(copy);
656 toReturn.add(line);
657 return toReturn;
658 }
659
660 public static void New() {
661 EnclosedCheck(DisplayIO.getCurrentFrame().getItems());
662 }
663
664 public static void Old() {
665 OldEnclosedCheck(DisplayIO.getCurrentFrame().getItems());
666 }
667
668 /**
669 * Updates the connectedToAnnotation flags for all items
670 */
671 public static void UpdateConnectedToAnnotations(Collection<Item> items) {
672 // get all lineEnds on the Frame
673 Collection<Item> lineEnds = new LinkedHashSet<Item>();
674 for (Item i : items) {
675 i.setConnectedToAnnotation(false);
676 if (i.isLineEnd()) {
677 lineEnds.add(i);
678 }
679 }
680
681 // if there are no line endpoints on the Frame, then there can't be an
682 // enclosure
683 if (lineEnds.size() == 0)
684 return;
685
686 // Now find go through line ends and see if any are annotation items
687 while (lineEnds.size() > 0) {
688 Item item = lineEnds.iterator().next();
689 // If its an annotation item then set the flag for all its connected
690 // items
691 if (item.isAnnotation()) {
692 Collection<Item> connected = item.getAllConnected();
693 for (Item i : connected)
694 i.setConnectedToAnnotation(true);
695 lineEnds.removeAll(connected);
696 }
697 lineEnds.remove(item);
698 }
699 }
700
701 /**
702 * Checks through all Lines and Dots on the current Frame to detect if any
703 * form an enclosure, which can then be used to manipulate items within the
704 * polygon. If an enclosure is found, then the dots will have their
705 * enclosure value set to true, and a List is created that contains all the
706 * Dots in the order they were processed. Actual calculation of the Polygon
707 * is done dynamically (to account for Dots being moved).
708 */
709 public static void EnclosedCheck(Collection<Item> items) {
710 // get all lineEnds on the Frame
711 List<Item> lineEnds = new LinkedList<Item>();
712 for (Item i : items) {
713 if (i.isLineEnd()) {
714 i.setEnclosedList(null);
715 // Add line ends joined to 2 other lines
716 if (i.getLines().size() == 2)
717 lineEnds.add(i);
718 }
719 }
720
721 // if there are no line endpoints on the Frame, then there can't be an
722 // enclosure
723 if (lineEnds.size() == 0)
724 return;
725
726 // New approach
727 while (lineEnds.size() > 0) {
728 Item item = lineEnds.get(0);
729 // Get the lineEnds connected to this item
730 Collection<Item> connected = item.getAllConnected();
731 Collection<Item> connectedLineEnds = new LinkedHashSet<Item>();
732 for (Item itemToCheck : connected) {
733 if (itemToCheck.isLineEnd())
734 connectedLineEnds.add(itemToCheck);
735 }
736 // Check that all the line ends are in our lineEnds list
737 int oldSize = lineEnds.size();
738 // Remove all the items from our line ends list
739 lineEnds.removeAll(connectedLineEnds);
740 int newSize = lineEnds.size();
741 int connectedSize = connectedLineEnds.size();
742 // Check if all the connectedItems were in the lineEnds collection
743 if (oldSize == newSize + connectedSize) {
744 // Set them to be the enclosed list for each of the items
745 for (Item enclosedLineEnd : connectedLineEnds) {
746 enclosedLineEnd.setEnclosedList(connectedLineEnds);
747 }
748 }
749
750 }
751 }
752
753 /**
754 * Checks through all Lines and Dots on the current Frame to detect if any
755 * form an enclosure, which can then be used to manipulate items within the
756 * polygon. If an enclosure is found, then the dots will have their
757 * enclosure value set to true, and a List is created that contains all the
758 * Dots in the order they were processed. Actual calculation of the Polygon
759 * is done dynamically (to account for Dots being moved).
760 */
761 public static void OldEnclosedCheck(Collection<Item> items) {
762 _seen.clear();
763
764 // get all lineEnds on the Frame
765 List<Item> lineEnds = new ArrayList<Item>(0);
766 for (Item i : items) {
767 if (i.isLineEnd()) {
768 i.setEnclosedList(null);
769
770 if (i.getLines().size() == 2)
771 lineEnds.add(i);
772 }
773 }
774
775 // if there are no line endpoints on the Frame, then there can't be an
776 // enclosure
777 if (lineEnds.size() == 0)
778 return;
779
780 // TODO optimise this code!!
781 // iterate through all the lineEnds
782 for (Item searchFor : lineEnds) {
783 _seen.clear();
784
785 for (Line l : searchFor.getLines()) {
786 _seen.add(l);
787 if (traverse(searchFor, l.getOppositeEnd(searchFor))) {
788 _path.add(l.getOppositeEnd(searchFor));
789
790 for (Item i : _path)
791 i.setEnclosedList(_path);
792
793 _path = new ArrayList<Item>(0);
794
795 break;
796 }
797 }
798 }
799
800 }
801
802 private static List<Line> _seen = new ArrayList<Line>();
803
804 private static List<Item> _path = new ArrayList<Item>();
805
806 private static boolean traverse(Item toFind, Item searchFrom) {
807 if (toFind == null || searchFrom == null || !searchFrom.isLineEnd())
808 return false;
809
810 if (searchFrom.getLines().size() != 2)
811 return false;
812
813 if (toFind == searchFrom)
814 return true;
815
816 for (Line l : searchFrom.getLines()) {
817 if (!(_seen.contains(l))) {
818 _seen.add(l);
819 if (traverse(toFind, l.getOppositeEnd(searchFrom))) {
820 _path.add(l.getOppositeEnd(searchFrom));
821 return true;
822 }
823 }
824
825 }
826
827 return false;
828 }
829}
Note: See TracBrowser for help on using the repository browser.