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

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

Added more import and mail stuff... including text importer

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