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

Last change on this file since 592 was 592, checked in by jts21, 11 years ago

Fix loading images from Text source items

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