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

Last change on this file since 778 was 778, checked in by jts21, 10 years ago

Move some settings into subpackages to tidy up the main settings page a bit, and make settings parser look for settings in subpages of the current settings page if it finds a setting it doesn't know what to do with

File size: 28.2 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;
28import org.expeditee.settings.folders.FolderSettings;
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 : FolderSettings.ImageDirs.get()) {
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 // Dont copy parts of a vector
460 if (!i.hasPermission(UserAppliedPermission.copy))
461 continue;
462
463 // BROOK
464 if (i instanceof WidgetCorner) { // dont add these
465 if (!widgets.contains(((WidgetCorner) i).getWidgetSource()))
466 widgets.add(((WidgetCorner) i).getWidgetSource());
467 // BROOK
468 } else if (i instanceof WidgetEdge) { // dont add these
469 // lines are recreated later
470 } else if (i instanceof Line) {
471 lines.add((Line) i);
472 } else if (i instanceof XRayable) {
473 xrayables.add((XRayable) i);
474 } else {
475 if (i.isLineEnd()) {
476 lineEnds.add(i);
477 constraints.addAll(i.getConstraints());
478 } else {
479 singles.add(i);
480 }
481 }
482 }
483
484 // Dont copy the other items that are part of the circle
485 for (XRayable x : xrayables) {
486 Collection<Item> connected = x.getConnected();
487 singles.removeAll(connected);
488 lineEnds.removeAll(connected);
489 lines.removeAll(connected);
490 Item xCopy = x.copy();
491 copies.addAll(xCopy.getConnected());
492 // Scale items that are from a vector frame
493 if (v != null) {
494 scaleItem(v, xCopy);
495 }
496 }
497
498 // copy all single items
499 for (Item i : singles) {
500 Item copy = i.copy();
501 Frame parent = i.getParent();
502 if (parent != null) {
503 // Items copied from overlay will be anchored onto the current
504 // frame
505 copy.setParent(parent);
506 // if this is the frame name, make sure the frame is saved (in
507 // case it is a TDFC frame)
508 if (i.isFrameName()) {
509 parent.setChanged(true);
510 }// check if the item is being copied from a vector
511 else if (v != null) {
512 // Find the vector this item is from
513 assert (v.Frame == parent);
514 scaleItem(v, copy);
515 }
516 }
517 copies.add(copy);
518 }
519
520 // replace line ends with their copies
521 // this is done here so that copied lines can still share end points
522 for (Item i : lineEnds) {
523 // create a copy of the line end
524 Item copy = i.copy();
525 copy.removeAllLines();
526 copy.removeAllConstraints();
527
528 if (extrude) {
529 Frame frame = i.getParentOrCurrentFrame();
530 Line newLine = new Line(i, copy, frame.getNextItemID());
531 // make sure overlay items are put back on the overlay
532 newLine.setParent(frame);
533 frame.addItem(newLine);
534 copies.add(newLine);
535 }
536 copies.add(copy);
537 lineEndMap.put(i, copy);
538 // Scale items that are from a vector frame
539 if (v != null) {
540 scaleItem(v, copy);
541 }
542 }
543
544 // recreate lines
545 for (Line line : lines) {
546 Line lineCopy = line.copy();
547 // get the lineEnd we copied above if it is in the MAPPING
548 Item originalLineEnd = line.getEndItem();
549 Item actualLineEnd = lineEndMap.get(originalLineEnd);
550 if (actualLineEnd == null)
551 lineCopy.setEndItem(originalLineEnd);
552 else
553 lineCopy.setEndItem(actualLineEnd);
554
555 Item originalLineStart = line.getStartItem();
556 Item actualLineStart = lineEndMap.get(originalLineStart);
557 if (actualLineStart == null)
558 lineCopy.setStartItem(originalLineStart);
559 else
560 lineCopy.setStartItem(actualLineStart);
561
562 copies.add(lineCopy);
563 }
564
565 // recreate constraints
566 for (Constraint c : constraints) {
567 Item start = lineEndMap.get(c.getStart());
568 Item end = lineEndMap.get(c.getEnd());
569 int id = DisplayIO.getCurrentFrame().getNextItemID();
570 if (start != null && end != null) {
571 new Constraint(start, end, id, c.getType());
572 }
573 }
574
575 // BROOK
576 for (InteractiveWidget iw : widgets) {
577 try {
578
579 InteractiveWidget icopy = iw.copy();
580 copies.addAll(icopy.getItems());
581
582 } catch (InteractiveWidgetNotAvailableException e) {
583 e.printStackTrace();
584 } catch (InteractiveWidgetInitialisationFailedException e) {
585 e.printStackTrace();
586 }
587
588 }
589
590 // Make sure filled rectangles are shown filled on vector overlays
591 if (v != null)
592 EnclosedCheck(copies);
593
594 return copies;
595 }
596
597 /**
598 * Attempts to create a new line that starts from the given Item
599 * ('unreeling'). The Item must already have at least one line, and not be a
600 * line itself to be unreeled from.
601 *
602 * @param toUnreelFrom
603 * The Item that will be one end point of the new line
604 * @return A List containing the newly created Item and Line that unreel
605 * from the given Item, or null if this Item cannot be unreeled
606 * from.
607 */
608 public static List<Item> UnreelLine(Item toUnreelFrom, boolean constrain) {
609 // the Item must already have one line to be unreeled from
610 if (toUnreelFrom == null || toUnreelFrom.getLines().size() < 1)
611 return null;
612
613 List<Item> unreel = new ArrayList<Item>(2);
614 unreel.add(toUnreelFrom);
615 unreel.addAll(toUnreelFrom.getLines());
616 return UnreelLine(unreel, constrain);
617 }
618
619 /**
620 * Attempts to create a new line that starts from the given list of Items
621 * ('unreeling'). The List must contain only one non-line Item. The non-line
622 * Item must already have at least one line to be unreeled from.
623 *
624 * @param toUnreel
625 * The List containing the Item that will be one end point of the
626 * new line
627 * @return A List of the newly created Item and Line that unreel from the
628 * Item in the given List, or null if this List cannot be unreeled
629 * from.
630 */
631 public static List<Item> UnreelLine(List<Item> toUnreel, boolean constrain) {
632 Item origEnd = null;
633 // find the end being unreeled from
634 for (Item item : toUnreel) {
635 // we dont want to unreel anything other than lines
636 if (item.hasEnclosures()
637 || !(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 origEnd.setHighlightMode(HighlightMode.None);
653 copy.removeAllLines();
654 copy.removeAllConstraints();
655
656 for (Line l : origEnd.getLines()) {
657 l.invalidateAll();
658 }
659
660 // create a new line
661 Frame currentFrame = DisplayIO.getCurrentFrame();
662 Line line = new Line(origEnd, copy, currentFrame.getNextItemID());
663 // if the previous line was constrained then make the new line
664 // constrained if it was a single line
665 // TODO add later a diagonal constraint if getLines() == 3 or 4
666 Collection<Constraint> constraints = origEnd.getConstraints();
667 if (constrain && constraints.size() > 0
668 && origEnd.getLines().size() == 2) {
669 Integer type = null;
670 for (Constraint c : constraints) {
671 if (c.getType() == Constraint.HORIZONTAL) {
672 type = Constraint.VERTICAL;
673 } else if (c.getType() == Constraint.VERTICAL) {
674 type = Constraint.HORIZONTAL;
675 }
676 if (c.getType() == Constraint.DIAGONAL_NEG) {
677 type = Constraint.DIAGONAL_POS;
678 } else if (c.getType() == Constraint.DIAGONAL_POS) {
679 type = Constraint.DIAGONAL_NEG;
680 }
681 }
682 if (type != null) {
683 new Constraint(origEnd, copy, currentFrame.getNextItemID(),
684 type);
685 }
686 }
687
688 // copy.setFloating(true);
689 origEnd.setArrowheadLength(0);
690 // copy.setArrowheadLength(0);
691
692 List<Item> toReturn = new LinkedList<Item>();
693 toReturn.add(copy);
694 toReturn.add(line);
695 return toReturn;
696 }
697
698 public static void New() {
699 EnclosedCheck(DisplayIO.getCurrentFrame().getItems());
700 }
701
702 public static void Old() {
703 OldEnclosedCheck(DisplayIO.getCurrentFrame().getItems());
704 }
705
706 /**
707 * Updates the connectedToAnnotation flags for all items
708 */
709 public static void UpdateConnectedToAnnotations(Collection<Item> items) {
710 // get all lineEnds on the Frame
711 Collection<Item> lineEnds = new LinkedHashSet<Item>();
712 for (Item i : items) {
713 i.setConnectedToAnnotation(false);
714 if (i.isLineEnd()) {
715 lineEnds.add(i);
716 }
717 }
718
719 // if there are no line endpoints on the Frame, then there can't be an
720 // enclosure
721 if (lineEnds.size() == 0)
722 return;
723
724 // Now find go through line ends and see if any are annotation items
725 while (lineEnds.size() > 0) {
726 Item item = lineEnds.iterator().next();
727 // If its an annotation item then set the flag for all its connected
728 // items
729 if (item.isAnnotation()) {
730 Collection<Item> connected = item.getAllConnected();
731 for (Item i : connected)
732 i.setConnectedToAnnotation(true);
733 lineEnds.removeAll(connected);
734 }
735 lineEnds.remove(item);
736 }
737 }
738
739 /**
740 * Checks through all Lines and Dots on the current Frame to detect if any
741 * form an enclosure, which can then be used to manipulate items within the
742 * polygon. If an enclosure is found, then the dots will have their
743 * enclosure value set to true, and a List is created that contains all the
744 * Dots in the order they were processed. Actual calculation of the Polygon
745 * is done dynamically (to account for Dots being moved).
746 */
747 public static void EnclosedCheck(Collection<Item> items) {
748 // get all lineEnds on the Frame
749 List<Item> lineEnds = new LinkedList<Item>();
750 for (Item i : items) {
751 if (i.isLineEnd()) {
752 i.setEnclosedList(null);
753 // Add line ends joined to 2 other lines
754 if (i.getLines().size() == 2)
755 lineEnds.add(i);
756 }
757 }
758
759 // if there are no line endpoints on the Frame, then there can't be an
760 // enclosure
761 if (lineEnds.size() == 0)
762 return;
763
764 // New approach
765 while (lineEnds.size() > 0) {
766 Item item = lineEnds.get(0);
767 // Get the lineEnds connected to this item
768 Collection<Item> connected = item.getAllConnected();
769 Collection<Item> connectedLineEnds = new LinkedHashSet<Item>();
770 for (Item itemToCheck : connected) {
771 if (itemToCheck.isLineEnd())
772 connectedLineEnds.add(itemToCheck);
773 }
774 // Check that all the line ends are in our lineEnds list
775 int oldSize = lineEnds.size();
776 // Remove all the items from our line ends list
777 lineEnds.removeAll(connectedLineEnds);
778 int newSize = lineEnds.size();
779 int connectedSize = connectedLineEnds.size();
780 // Check if all the connectedItems were in the lineEnds collection
781 if (oldSize == newSize + connectedSize) {
782 // Set them to be the enclosed list for each of the items
783 for (Item enclosedLineEnd : connectedLineEnds) {
784 enclosedLineEnd.setEnclosedList(connectedLineEnds);
785 }
786 }
787 }
788 }
789
790 /**
791 * Checks through all Lines and Dots on the current Frame to detect if any
792 * form an enclosure, which can then be used to manipulate items within the
793 * polygon. If an enclosure is found, then the dots will have their
794 * enclosure value set to true, and a List is created that contains all the
795 * Dots in the order they were processed. Actual calculation of the Polygon
796 * is done dynamically (to account for Dots being moved).
797 */
798 public static void OldEnclosedCheck(Collection<Item> items) {
799 _seen.clear();
800
801 // get all lineEnds on the Frame
802 List<Item> lineEnds = new ArrayList<Item>(0);
803 for (Item i : items) {
804 if (i.isLineEnd()) {
805 i.setEnclosedList(null);
806
807 if (i.getLines().size() == 2)
808 lineEnds.add(i);
809 }
810 }
811
812 // if there are no line endpoints on the Frame, then there can't be an
813 // enclosure
814 if (lineEnds.size() == 0)
815 return;
816
817 // TODO optimise this code!!
818 // iterate through all the lineEnds
819 for (Item searchFor : lineEnds) {
820 _seen.clear();
821
822 for (Line l : searchFor.getLines()) {
823 _seen.add(l);
824 if (traverse(searchFor, l.getOppositeEnd(searchFor))) {
825 _path.add(l.getOppositeEnd(searchFor));
826
827 for (Item i : _path)
828 i.setEnclosedList(_path);
829
830 _path = new ArrayList<Item>(0);
831
832 break;
833 }
834 }
835 }
836 }
837
838 private static List<Line> _seen = new ArrayList<Line>();
839
840 private static List<Item> _path = new ArrayList<Item>();
841
842 private static boolean traverse(Item toFind, Item searchFrom) {
843 if (toFind == null || searchFrom == null || !searchFrom.isLineEnd())
844 return false;
845
846 if (searchFrom.getLines().size() != 2)
847 return false;
848
849 if (toFind == searchFrom)
850 return true;
851
852 for (Line l : searchFrom.getLines()) {
853 if (!(_seen.contains(l))) {
854 _seen.add(l);
855 if (traverse(toFind, l.getOppositeEnd(searchFrom))) {
856 _path.add(l.getOppositeEnd(searchFrom));
857 return true;
858 }
859 }
860
861 }
862
863 return false;
864 }
865
866 /**
867 * Determines if an item is visible from a the current frame(s). If the item
868 * is free then it is considered visible.
869 *
870 * @param i
871 * The item to check
872 * @return True if visible/free from given frame.
873 */
874 public static boolean isVisible(Item i) {
875 if (DisplayIO.isTwinFramesOn()) {
876 if (!isVisible(DisplayIO.getFrames()[0], i)) {
877 return isVisible(DisplayIO.getFrames()[1], i);
878 } else {
879 return true;
880 }
881 } else {
882 return isVisible(DisplayIO.getCurrentFrame(), i);
883 }
884 }
885
886 /**
887 * Determines if an item is visible from a given frame. If the item is free
888 * then it is considered visible.
889 *
890 * @param fromFrame
891 * The frame to check from.
892 * @param i
893 * The item to check
894 * @return True if visible/free from given frame.
895 */
896 public static boolean isVisible(Frame fromFrame, Item i) {
897 if (fromFrame == null)
898 return false;
899
900 Frame parent = i.getParent();
901
902 if (parent == fromFrame)
903 return true;
904
905 else if (parent == null)
906 return FreeItems.getInstance().contains(i)
907 || FreeItems.getCursor().contains(i);
908
909 return fromFrame.getAllItems().contains(i) && i.isVisible();
910 }
911
912 public static Rectangle expandRectangle(Rectangle r, int n) {
913 return new Rectangle(r.x - (n >> 1), r.y - (n >> 1), r.width + n,
914 r.height + n);
915 }
916
917 /*
918 * FrameMouseActions while (!copies.isEmpty()) { Iterator<Item> iterator =
919 * copies.iterator(); Item item = iterator.next(); // Dont paint annotation
920 * items for @v if (!item.isVisible() || item.isAnnotation()) {
921 * iterator.remove(); continue; }
922 *
923 * if (!(item instanceof Line)) { item.setThickness(item.getThickness() *
924 * scale); if (item instanceof XRayable || item.hasEnclosures()) {
925 * scaleItem(scale, defaultForeground, defaultBackground, origin.x,
926 * origin.y, item); items.add(item); copies.remove(item); } else {
927 * Collection<Item> connected = item.getAllConnected(); // Get all the
928 * connected items because we can only set the // thickness ONCE for (Item i :
929 * connected) { scaleItem(scale, defaultForeground, defaultBackground,
930 * origin.x, origin.y, i); } items.addAll(connected);
931 * copies.removeAll(connected); } } else { iterator.remove(); } }
932 */
933
934 /**
935 * @param scale
936 * @param defaultForeground
937 * @param defaultBackground
938 * @param originX
939 * @param originY
940 * @param item
941 */
942 private static void scaleItem(Vector v, Item item) {
943 Float scale = v.Scale;
944 int originX = v.Origin.x;
945 int originY = v.Origin.y;
946 Color defaultForeground = v.Foreground;
947 Color defaultBackground = v.Background;
948 UserAppliedPermission permission = v.permission;
949 // TODO should this be checking if the frame has the
950 // same permissions as the vector
951 // and if so don't set the item's permissions?
952 item.setOverlayPermission(permission);
953
954 // TODO encapsulate this somewhere inside of circle class!
955 // if(item instanceof Circle){
956 // scaleItem(v, ((Circle)item).getCenter());
957 // }
958
959 if (!(item instanceof Line)) {
960 if (item.getColor() == null) {
961 item.setColor(defaultForeground);
962 }
963 if (item.getBackgroundColor() == null) {
964 item.setBackgroundColor(defaultBackground);
965 }
966 if (item.getFillColor() == null) {
967 item.setFillColor(defaultBackground);
968 }
969
970 if (permission.equals(UserAppliedPermission.none)) {
971 item.setLinkMark(false);
972 item.setActionMark(false);
973 }
974
975 item.scale(scale, originX, originY);
976 }
977 }
978
979 /**
980 * Extracts widgets from an item list.
981 *
982 * @param items
983 * Items to extract from. Must not be null.
984 *
985 * @return List of (unique)widgets in items. Never null.
986 */
987 public static List<InteractiveWidget> extractWidgets(List<Item> items) {
988 assert (items != null);
989
990 List<InteractiveWidget> iWidgets = new LinkedList<InteractiveWidget>();
991
992 for (Item i : items) {
993 if (i instanceof WidgetEdge) {
994 WidgetEdge we = (WidgetEdge) i;
995 if (!iWidgets.contains(we.getWidgetSource()))
996 iWidgets.add(we.getWidgetSource());
997 } else if (i instanceof WidgetCorner) {
998 WidgetCorner wc = (WidgetCorner) i;
999 if (!iWidgets.contains(wc.getWidgetSource()))
1000 iWidgets.add(wc.getWidgetSource());
1001 }
1002 }
1003
1004 return iWidgets;
1005 }
1006}
Note: See TracBrowser for help on using the repository browser.