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

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

Enable per-item permission values, and tidy up DefaultFrameWriter a little

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