source: trunk/src/org/expeditee/gui/FrameUtils.java@ 242

Last change on this file since 242 was 242, checked in by ra33, 16 years ago
File size: 42.7 KB
Line 
1package org.expeditee.gui;
2
3import java.awt.Color;
4import java.awt.Point;
5import java.awt.Polygon;
6import java.io.File;
7import java.util.ArrayList;
8import java.util.Collection;
9import java.util.Collections;
10import java.util.Comparator;
11import java.util.LinkedHashSet;
12import java.util.LinkedList;
13import java.util.List;
14
15import org.expeditee.agents.mail.MailSession;
16import org.expeditee.io.Logger;
17import org.expeditee.items.Circle;
18import org.expeditee.items.Dot;
19import org.expeditee.items.FrameBitmap;
20import org.expeditee.items.FrameImage;
21import org.expeditee.items.Item;
22import org.expeditee.items.ItemUtils;
23import org.expeditee.items.Line;
24import org.expeditee.items.Permission;
25import org.expeditee.items.Picture;
26import org.expeditee.items.Text;
27import org.expeditee.items.XRayable;
28import org.expeditee.items.widgets.InteractiveWidget;
29import org.expeditee.items.widgets.InteractiveWidgetInitialisationFailedException;
30import org.expeditee.items.widgets.InteractiveWidgetNotAvailableException;
31import org.expeditee.items.widgets.WidgetCorner;
32import org.expeditee.items.widgets.WidgetEdge;
33import org.expeditee.stats.SessionStats;
34
35public class FrameUtils {
36
37 private static final int COLUMN_WIDTH = 50;
38
39 /**
40 * Provides a way to monitor the time elapsed between button-down and the
41 * finished painting.
42 */
43 public static TimeKeeper ResponseTimer = new TimeKeeper();
44
45 private static float _ResponseTimeSum = 0;
46
47 private static float _LastResponse = 0;
48
49 private static Text LastEdited = null;
50
51 public static int MINIMUM_INTERITEM_SPACING = -6;
52
53 public static float getResponseTimeTotal() {
54 return _ResponseTimeSum;
55 }
56
57 public static float getLastResponseTime() {
58 return _LastResponse;
59 }
60
61 /**
62 * Checks if the given top Item is above the given bottom Item, allowing for
63 * the X coordinates to be off by a certain width...
64 *
65 * @param item1
66 * The Item to check is above the other Item
67 * @param item2
68 * The Item to check is below the top Item
69 * @return True if top is above bottom, False otherwise.
70 */
71 public static boolean inSameColumn(Item item1, Item item2) {
72 if (!(item1 instanceof Text) || !(item2 instanceof Text))
73 return false;
74
75 if (item1.getID() < 0 || item2.getID() < 0)
76 return false;
77
78 int minX = item2.getX();
79 int maxX = item2.getX() + item2.getBoundsWidth();
80
81 int startX = item1.getX();
82 int endX = item1.getX() + item1.getBoundsWidth();
83
84 // Check that the two items left values are close
85 if (Math.abs(item1.getX() - item2.getX()) > COLUMN_WIDTH)
86 return false;
87
88 // Ensure the two items
89 if ((minX >= startX && minX <= endX)
90 || (maxX >= startX && maxX <= endX)
91 || (startX >= minX && startX <= maxX)
92 || (endX >= minX && endX <= maxX))
93 return true;
94
95 return false;
96 }
97
98 public static boolean sameBulletType(String bullet1, String bullet2) {
99 if (bullet1 == null || bullet2 == null)
100 return false;
101
102 if (bullet1.equals("") || bullet2.equals(""))
103 return false;
104
105 if (Character.isLetter(bullet1.charAt(0))
106 && Character.isLetter(bullet2.charAt(0)))
107 return true;
108
109 if (Character.isDigit(bullet1.charAt(0))
110 && Character.isDigit(bullet2.charAt(0)))
111 return true;
112
113 // TODO make this more sofisticated
114
115 return false;
116 }
117
118 private static boolean needsRenumbering(String s) {
119 if (s == null || s.equals(""))
120 return false;
121 if (!Character.isLetterOrDigit(s.charAt(0)))
122 return false;
123
124 s = s.trim();
125 // if its all letters then we dont want to auto adjust
126 if (s.length() > 2) {
127 for (int i = 0; i < s.length() - 1; i++) {
128 if (!Character.isLetter(s.charAt(i)))
129 return true;
130 }
131 } else
132 return true;
133
134 return false;
135 }
136
137 /**
138 *
139 * @param toAlign
140 * @param moveAll
141 * @param adjust
142 * @return
143 */
144 public static int Align(List<Text> toAlign, boolean moveAll, int adjust) {
145 Collections.sort(toAlign);
146
147 // Single items dont need alignment
148 if (toAlign.size() < 2)
149 return 0;
150
151 // get the first item
152 Text from = toAlign.get(0);
153 if (from.getParent() == null)
154 from = toAlign.get(1);
155 int x = from.getX();
156
157 Frame curr = from.getParent();
158 Text above = curr.getTextAbove(from);
159
160 String lastBullet = "";
161
162 if (above != null && curr.isNormalTextItem(above))
163 lastBullet = FrameKeyboardActions.getAutoBullet(above.getText());
164 else {
165 lastBullet = FrameKeyboardActions.getBullet(toAlign.get(0)
166 .getText());
167 }
168 if (needsRenumbering(lastBullet)) {
169 // renumber...
170 for (int i = 0; i < toAlign.size(); i++) {
171
172 Text currentText = toAlign.get(i);
173 String currentBullet = FrameKeyboardActions
174 .getAutoBullet(currentText.getText());
175
176 if (sameBulletType(lastBullet, currentBullet)) {
177 currentText.stripFirstWord();
178
179 currentText.setText(lastBullet + currentText.getText());
180 lastBullet = FrameKeyboardActions.getAutoBullet(currentText
181 .getText());
182 }
183 }
184 }
185
186 // work out the spacing between the first item and the one above it
187
188 int space = 10 + adjust;
189
190 // if we are dropping from the title make the space a little bigger
191 // than normal
192
193 // If there are only two items get the gap from the start item on the
194 // zero frame if there is one
195 if (above == curr.getTitleItem()) {
196 Frame zero = FrameIO.LoadFrame(curr.getFramesetName() + '0');
197 String strGap = zero.getAnnotationValue("start");
198 if (strGap != null) {
199 try {
200 int gap = Integer.parseInt(strGap);
201 space = gap;
202 } catch (NumberFormatException nfe) {
203
204 }
205 }
206 } else if (above != null) {
207 // Make the gap between all items the same as the gap between
208 // the first two
209 space = (int) (from.getPolygon().getBounds().getMinY() - above
210 .getPolygon().getBounds().getMaxY());
211
212 if (space < MINIMUM_INTERITEM_SPACING)
213 space = MINIMUM_INTERITEM_SPACING;
214
215 if (above != curr.getNameItem() && above != curr.getTitleItem())
216 x = above.getX();
217
218 space += adjust;
219
220 from.setY((int) above.getPolygon().getBounds().getMaxY()
221 + space
222 + ((int) (from.getY() - from.getPolygon().getBounds()
223 .getMinY())));
224
225 if (moveAll)
226 from.setX(x);
227 }
228
229 for (int i = 1; i < toAlign.size(); i++) {
230 Item current = toAlign.get(i);
231 Item top = toAlign.get(i - 1);
232
233 // The bottom of the previous item
234 int bottom = (int) top.getPolygon().getBounds().getMaxY();
235
236 // the difference between the current item's Y coordinate and
237 // the top of the highlight box
238 int diff = (int) (current.getY() - current.getPolygon().getBounds()
239 .getMinY());
240
241 int newPos = bottom + space + diff;
242
243 if (moveAll) {
244 current.setPosition(x, newPos);
245 } else if (newPos > current.getY()) {
246 current.setY(newPos);
247 }
248
249 }
250
251 // if (insert != null)
252 // return insert.getY();
253
254 // Michael thinks we return the y value for the next new item??
255 int y = from.getY() + from.getBoundsHeight() + space;
256 return y;
257 }
258
259 public static boolean LeavingFrame(Frame current) {
260 checkTDFCItemWaiting(current);
261 // active overlay frames may also require saving if they have been
262 // changed
263 for (Overlay o : current.getOverlays())
264 if (!SaveCheck(o.Frame))
265 return false;
266
267 // if the check fails there is no point continuing
268 if (!SaveCheck(current))
269 return false;
270
271 for (Item i : current.getItems())
272 i.setHighlightMode(Item.HighlightMode.None);
273 return true;
274 }
275
276 private static boolean SaveCheck(Frame toSave) {
277 // don't bother saving frames that haven't changed
278 if (!toSave.hasChanged())
279 return true;
280
281 // if the frame has been changed, then save it
282 if (DisplayIO.isTwinFramesOn()) {
283 Frame opposite = DisplayIO.getOppositeFrame();
284
285 String side = "left";
286 if (DisplayIO.getCurrentSide() == 0)
287 side = "right";
288
289 // if the two frames both have changes, prompt the user for the
290 // next move
291 if (opposite.hasChanged() && opposite.equals(toSave)) {
292 if (DisplayIO.DisplayConfirmDialog(
293 "Leaving this frame will discard changes made in the "
294 + side + " Frame. Continue?", "Changes",
295 DisplayIO.TYPE_WARNING, DisplayIO.OPTIONS_OK_CANCEL,
296 DisplayIO.RESULT_OK)) {
297 FrameIO.SaveFrame(toSave);
298 DisplayIO.Reload(DisplayIO.FrameOnSide(opposite));
299 return true;
300 } else
301 return false;
302 } else if (opposite.hasOverlay(toSave)) {
303 if (toSave.hasChanged())
304 if (DisplayIO.DisplayConfirmDialog(
305 "Leaving this frame will discard changes made in the "
306 + side + " Frame. Continue?", "Changes",
307 DisplayIO.TYPE_WARNING,
308 DisplayIO.OPTIONS_OK_CANCEL, DisplayIO.RESULT_OK)) {
309 FrameIO.SaveFrame(toSave);
310 DisplayIO.Reload(DisplayIO.FrameOnSide(opposite));
311 return true;
312 } else
313 return false;
314 }
315
316 // save the current frame and restore the other side
317 FrameIO.SaveFrame(toSave);
318 return true;
319 }
320
321 // single-frame mode can just save and return
322 FrameIO.SaveFrame(toSave);
323 return true;
324 }
325
326 /**
327 * Displays the given Frame on the display. If the current frame has changed
328 * since the last save then it will be saved before the switch is made. The
329 * caller can also dictate whether the current frame is added to the
330 * back-stack or not.
331 *
332 * @param toDisplay
333 * The Frame to display on the screen
334 * @param addToBack
335 * True if the current Frame should be added to the back-stack,
336 * False otherwise
337 */
338 public static void DisplayFrame(Frame toDisplay, boolean addToBack) {
339 if (toDisplay == null)
340 return;
341
342 Frame current = DisplayIO.getCurrentFrame();
343
344 // Dont need to do anything if the frame to display is already being
345 // displayed
346 if (current.equals(toDisplay))
347 return;
348
349 // move any anchored connected items
350 if (FreeItems.itemsAttachedToCursor()) {
351 List<Item> toAdd = new ArrayList<Item>();
352 List<Item> toCheck = new ArrayList<Item>(FreeItems.getInstance());
353
354 while (toCheck.size() > 0) {
355 Item i = toCheck.get(0);
356 Collection<Item> connected = i.getAllConnected();
357
358 // // Only move completely enclosed items
359 // if (!toCheck.containsAll(connected)) {
360 // connected.retainAll(FreeItems.getInstance());
361 // FreeItems.getInstance().removeAll(connected);
362 // toCheck.removeAll(connected);
363 // FrameMouseActions.anchor(connected);
364 // } else {
365 // toCheck.removeAll(connected);
366 // }
367
368 // Anchor overlay items where they belong
369 if (i.getParent() != null && i.getParent() != current) {
370 FreeItems.getInstance().removeAll(connected);
371 toCheck.removeAll(connected);
372 FrameMouseActions.anchor(connected);
373 } else {
374 // Add stuff that is partially enclosed
375 // remove all the connected items from our list to check
376 toCheck.removeAll(connected);
377 // Dont add the items that are free
378 connected.removeAll(FreeItems.getInstance());
379 toAdd.addAll(connected);
380 }
381 }
382
383 current.removeAllItems(toAdd);
384
385 boolean oldChange = toDisplay.hasChanged();
386 toDisplay.updateIDs(toAdd);
387 toDisplay.addAllItems(toAdd);
388 toDisplay.setChanged(oldChange);
389 }
390
391 if (addToBack && current != toDisplay) {
392 FrameIO.checkTDFC(current);
393 }
394
395 // if the saving happened properly, we can continue
396 if (!LeavingFrame(current)) {
397 MessageBay.displayMessage("Navigation cancelled");
398 return;
399 }
400
401 if (addToBack && current != toDisplay) {
402 DisplayIO.addToBack(current);
403 }
404
405 Parse(toDisplay);
406 DisplayIO.setCurrentFrame(toDisplay, addToBack);
407 FrameMouseActions.updateCursor();
408 // FrameMouseActions.getInstance().refreshHighlights();
409 // update response timer
410 _LastResponse = ResponseTimer.getElapsedSeconds();
411 _ResponseTimeSum += _LastResponse;
412 DisplayIO.UpdateTitle();
413 }
414
415 /**
416 * Loads and displays the Frame with the given framename, and adds the
417 * current frame to the back-stack if required.
418 *
419 * @param framename
420 * The name of the Frame to load and display
421 * @param addToBack
422 * True if the current Frame should be added to the back-stack,
423 * false otherwise
424 */
425 public static void DisplayFrame(String frameName, boolean addToBack) {
426 Frame newFrame = getFrame(frameName);
427
428 if (newFrame != null)
429 // display the frame
430 DisplayFrame(newFrame, addToBack);
431 }
432
433 /**
434 * Loads and displays the Frame with the given framename and adds the
435 * current frame to the back-stack. This is the same as calling
436 * DisplayFrame(framename, true)
437 *
438 * @param framename
439 * The name of the Frame to load and display
440 */
441 public static void DisplayFrame(String framename) {
442 DisplayFrame(framename, true);
443 }
444
445 public static void DisplayHomeFrame() {
446 DisplayFrame(UserSettings.FirstFrame);
447 }
448
449 public static void DisplayProfileFrame() {
450 DisplayFrame(UserSettings.Username + '1');
451 }
452
453 public static Frame getFrame(String frameName) {
454 // if the new frame does not exist then tell the user
455 Frame f = FrameIO.LoadFrame(frameName);
456
457 if (f == null) {
458 MessageBay.errorMessage("Frame '" + frameName
459 + "' could not be found.");
460 }
461
462 return f;
463 }
464
465 /**
466 * Creates a new Picture Item from the given Text source Item and adds it to
467 * the given Frame.
468 *
469 * @return True if the image was created successfully, false otherwise
470 */
471 private static boolean createPicture(Frame frame, Text txt) {
472 // attempt to create the picture
473 Picture pic = ItemUtils.CreatePicture(txt, frame);
474
475 // if the picture could not be created successfully
476 if (pic == null) {
477 String imagePath = txt.getText();
478 assert (imagePath != null);
479 imagePath = new AttributeValuePair(imagePath).getValue().trim();
480 if (imagePath.length() == 0) {
481 return false;
482 // MessageBay.errorMessage("Expected image path after @i:");
483 } else {
484 MessageBay.errorMessage("Image " + imagePath
485 + " could not be loaded");
486 }
487 return false;
488 }
489 frame.addItem(pic);
490
491 return true;
492 }
493
494 /**
495 * Creates an interactive widget and adds it to a frame. If txt has no
496 * parent the parent will be set to frame.
497 *
498 * @param frame
499 * Frame to add widget to. Must not be null.
500 *
501 * @param txt
502 * Text to create the widget from. Must not be null.
503 *
504 * @return True if created/added. False if coul not create.
505 *
506 * @author Brook Novak
507 */
508 private static boolean createWidget(Frame frame, Text txt) {
509
510 if (frame == null)
511 throw new NullPointerException("frame");
512 if (txt == null)
513 throw new NullPointerException("txt");
514
515 // Safety
516 if (txt.getParent() == null)
517 txt.setParent(frame);
518
519 InteractiveWidget iw = null;
520
521 try {
522
523 iw = InteractiveWidget.createWidget(txt);
524
525 } catch (InteractiveWidgetNotAvailableException e) {
526 e.printStackTrace();
527 MessageBay.errorMessage("Cannot create iWidget: " + e.getMessage());
528 } catch (InteractiveWidgetInitialisationFailedException e) {
529 e.printStackTrace();
530 MessageBay.errorMessage("Cannot create iWidget: " + e.getMessage());
531 } catch (IllegalArgumentException e) {
532 e.printStackTrace();
533 MessageBay.errorMessage("Cannot create iWidget: " + e.getMessage());
534 }
535
536 if (iw == null)
537 return false;
538
539 frame.removeItem(txt);
540
541 frame.addAllItems(iw.getItems());
542
543 return true;
544 }
545
546 public static Collection<String> ParseProfile(Frame profile) {
547 Collection<String> errors = new LinkedList<String>();
548 if (profile == null)
549 return errors;
550
551 UserSettings.TitleTemplate = profile.getTitleItem();
552
553 // check for all tags setting user values
554 for (Text item : profile.getBodyTextItems(false)) {
555
556 AttributeValuePair avp = new AttributeValuePair(item.getText());
557 String attributeFullCase = avp.getAttributeOrValue();
558
559 if (attributeFullCase == null)
560 continue;
561 String attribute = attributeFullCase.toLowerCase();
562
563 if (attribute.equals("homeframe")) {
564 String first = getLink(item, UserSettings.FirstFrame);
565 // do not use non-existant frames as the first frame
566 if (FrameIO.isValidFrameName(first)) {
567 UserSettings.FirstFrame = first;
568 }
569 // warn the user
570 else {
571 // MessageBay.warningMessage("Home frame: " + first
572 // + " is not a valid frame.");
573 UserSettings.FirstFrame = profile.getName();
574 }
575 } else if (attribute.equals("menuframe"))
576 UserSettings.MenuFrame = getLink(item, UserSettings.MenuFrame);
577 else if (attribute.equals("defaultframe"))
578 UserSettings.DefaultFrame = getLink(item,
579 UserSettings.DefaultFrame);
580 else if (attribute.equals("mailsettings"))
581 MailSession.init(item.getChild());
582 else if (attribute.equals("antialias"))
583 UserSettings.AntiAlias = avp.getBooleanValue();
584 else if (attribute.equals("gravity"))
585 UserSettings.Gravity = avp.getIntegerValue();
586 else if (attribute.equals("showlinehighlight"))
587 UserSettings.LineHighlight = avp.getBooleanValue();
588 else if (attribute.equals("linestraightenthreshold"))
589 UserSettings.LineStraightenThreshold = avp.getIntegerValue();
590 else if (attribute.equals("noopthreshold"))
591 UserSettings.NoOpThreshold = avp.getIntegerValue();
592 else if (attribute.equals("initialwidth")) {
593 UserSettings.InitialWidth = avp.getIntegerValue();
594 } else if (attribute.equals("initialheight")) {
595 UserSettings.InitialHeight = avp.getIntegerValue();
596 } else if (attribute.equals("titleposition")) {
597 UserSettings.TitlePosition = avp.getIntegerValue();
598 } else if (attribute.equals("logging")) {
599 UserSettings.Logging = avp.getBooleanValue();
600 } else if (attribute.equals("itemtemplate")) {
601 UserSettings.ItemTemplate = ((Text) item).getTemplateForm();
602 } else if (attribute.equals("annotationtemplate")) {
603 UserSettings.AnnotationTemplate = ((Text) item)
604 .getTemplateForm();
605 } else if (attribute.equals("statstemplate")) {
606 UserSettings.StatTemplate = ((Text) item).getTemplateForm();
607 } else if (attribute.equals("commenttemplate")) {
608 UserSettings.CodeCommentTemplate = ((Text) item)
609 .getTemplateForm();
610 } else if (attribute.equals("linetemplate")) {
611 UserSettings.LineTemplate = ((Text) item).getTemplateForm();
612 } else if (attribute.equals("framesetdir")) {
613 String dir = getDir(avp.getValue());
614 if (dir != null) {
615 UserSettings.FrameDirs.add(dir);
616 }
617 } else if (attribute.equals("logdir")) {
618 org.expeditee.gui.FrameIO.LOGS_DIR = getDir(avp.getValue());
619 } else if (attribute.equals("imagedir")) {
620 String dir = getDir(avp.getValue());
621 if (dir != null)
622 UserSettings.ImageDirs.add(0, dir);
623 } else if (attribute.equals("threading")) {
624 UserSettings.Threading = avp.getBooleanValue();
625 } else if (attribute.equals("colorwheel")) {
626 Item.COLOR_WHEEL = getColorWheel(item);
627 } else if (attribute.equals("fillcolorwheel")) {
628 Item.FILL_COLOR_WHEEL = getColorWheel(item);
629 } else if (attribute.equals("backgroundcolorwheel")) {
630 Frame.COLOR_WHEEL = getColorWheel(item);
631 } else if (attribute.equals("framesetdirs")) {
632 UserSettings.FrameDirs.addAll(getDirs(item));
633 } else {
634 errors.add(attributeFullCase + " is not a profile frame tag");
635 }
636 }
637 return errors;
638 }
639
640 public static void loadFirstFrame(Frame profile) {
641 if (UserSettings.FirstFrame == null)
642 UserSettings.FirstFrame = profile.getName();
643 // else {
644 Frame firstFrame = FrameIO.LoadFrame(UserSettings.FirstFrame);
645 if (firstFrame == null) {
646 MessageBay.warningMessage("Home frame not found: "
647 + UserSettings.FirstFrame);
648 UserSettings.FirstFrame = profile.getName();
649 DisplayIO.setCurrentFrame(profile, true);
650 } else {
651 DisplayIO.setCurrentFrame(firstFrame, true);
652 }
653 // }
654 }
655
656 private static Color[] getColorWheel(Item item) {
657 Frame child = item.getChild();
658 if (child != null) {
659 List<Text> textItems = child.getBodyTextItems(false);
660 Color[] colorList = new Color[textItems.size() + 1];
661 for (int i = 0; i < textItems.size(); i++) {
662 colorList[i] = textItems.get(i).getColor();
663 }
664 // Make the last item transparency or default for forecolor
665 colorList[colorList.length - 1] = null;
666
667 return colorList;
668 }
669 return new Color[] { Color.black, Color.white, null };
670 }
671
672 private static String getLink(Item item, String alt) {
673 if (item == null || !(item instanceof Text))
674 return alt;
675
676 String value = new AttributeValuePair(item.getText()).getValue().trim();
677 if (value.length() > 0) {
678 item.setLink(value);
679 return value;
680 } else if (item.getLink() != null)
681 return item.getLink();
682
683 return alt;
684 }
685
686 private static String getDir(String name) {
687 if (name != null) {
688 File tester = new File(name);
689 if (tester.exists() && tester.isDirectory()) {
690 if (name.endsWith(File.separator))
691 return name;
692 else
693 return name + File.separator;
694 } else {
695 MessageBay.errorMessage("Directory not found: " + name);
696 }
697 } else {
698 MessageBay.warningMessage("Missing value for profile attribute"
699 + name);
700 }
701 return null;
702 }
703
704 private static ArrayList<String> getDirs(Item item) {
705 ArrayList<String> dirsToAdd = new ArrayList<String>();
706 String dirListFrameName = item.getAbsoluteLink();
707 if (dirListFrameName != null) {
708 Frame dirListFrame = FrameIO.LoadFrame(dirListFrameName);
709 if (dirListFrame != null) {
710 for (Text t : dirListFrame.getBodyTextItems(false)) {
711 String dirName = t.getText().trim();
712 File tester = new File(dirName);
713 if (tester.exists() && tester.isDirectory()) {
714 if (dirName.endsWith(File.separator))
715 dirsToAdd.add(dirName);
716 else
717 dirsToAdd.add(dirName + File.separator);
718 }
719 }
720 }
721 }
722
723 return dirsToAdd;
724 }
725
726 public static void Parse(Frame toParse) {
727 Parse(toParse, false);
728 }
729
730 /**
731 * Checks for any special Annotation items and updates the display as
732 * necessary. Special Items: Images, overlays, sort.
733 *
734 */
735 public static void Parse(Frame toParse, boolean firstParse) {
736 // TODO check why we are getting toParse == null... when profile frame
737 // is being created and change the lines below
738 if (toParse == null)
739 return;
740 // System.out.println(firstParse);
741 if (firstParse)
742 ItemUtils.EnclosedCheck(toParse.getItems());
743 List<Item> items = toParse.getItems();
744
745 // if XRayMode is on, replace pictures with their underlying text
746 if (FrameGraphics.isXRayMode()) {
747
748 // BROOK: Must handle these a little different
749 List<InteractiveWidget> widgets = toParse.getInteractiveWidgets();
750
751 for (Item i : items) {
752 if (i instanceof XRayable) {
753 toParse.removeItem(i);
754 // Show the items
755 for (Item item : ((XRayable) i).getConnected()) {
756 item.setVisible(true);
757 item.removeEnclosure(i);
758 }
759 } else if (i instanceof WidgetCorner) {
760 toParse.removeItem(i);
761 } else if (i instanceof WidgetEdge) {
762 toParse.removeItem(i);
763 } else if (i.hasFormula()) {
764 i.setText(i.getFormula());
765 }
766 }
767
768 for (InteractiveWidget iw : widgets) {
769 toParse.addItem(iw.getSource());
770 }
771 }
772
773 // Text title = null;
774 // Text template = UserSettingsTemplate.copy();
775
776 List<Overlay> overlays = new ArrayList<Overlay>();
777 List<Vector> vectors = new ArrayList<Vector>();
778
779 // disable reading of cached overlays if in twinframes mode
780 if (DisplayIO.isTwinFramesOn())
781 FrameIO.SuspendCache();
782
783 int pointtype = Item.POINTTYPE_SQUARE;
784 boolean filledPoints = true;
785
786 Permission permission = toParse.getPermission();
787 toParse.clearAnnotations();
788
789 // check for any new overlay items
790 for (Item i : toParse.getItems()) {
791 try {
792 i.setPermission(permission);
793 if (i instanceof WidgetCorner) {
794 // TODO improve efficiency so it only updates once... using
795 // observer design pattern
796 i.update();
797 } else if (i instanceof Text) {
798 if (i.isAnnotation()) {
799 if (ItemUtils.startsWithTag(i, ItemUtils.TAG_POINTTYPE)) {
800 Text txt = (Text) i;
801 String line = txt.getFirstLine();
802 line = ItemUtils.StripTag(line, ItemUtils
803 .GetTag(ItemUtils.TAG_POINTTYPE));
804
805 if (line != null) {
806 line = line.toLowerCase();
807 if (line.indexOf(" ") > 0) {
808 String fill = line.substring(line
809 .indexOf(" ") + 1);
810 if (fill.startsWith("nofill"))
811 filledPoints = false;
812 else
813 filledPoints = true;
814 }
815
816 if (line.startsWith("circle"))
817 pointtype = Item.POINTTYPE_CIRCLE;
818 else
819 pointtype = Item.POINTTYPE_SQUARE;
820 }
821 }// check for new VECTOR items
822 else if (!FrameGraphics.isXRayMode()
823 && ItemUtils.startsWithTag(i,
824 ItemUtils.TAG_VECTOR)
825 && i.getLink() != null) {
826 addVector(vectors, Permission.none, permission, i);
827 } else if (!FrameGraphics.isXRayMode()
828 && ItemUtils.startsWithTag(i,
829 ItemUtils.TAG_ACTIVE_VECTOR)
830 && i.getLink() != null) {
831 addVector(vectors, Permission.followLinks,
832 permission, i);
833 }
834 // check for new OVERLAY items
835 else if (ItemUtils.startsWithTag(i,
836 ItemUtils.TAG_OVERLAY)
837 && i.getLink() != null) {
838 if (i.getAbsoluteLink().equalsIgnoreCase(
839 toParse.getName())) {
840 // This frame contains an active overlay which
841 // points to itself
842 MessageBay
843 .errorMessage(toParse.getName()
844 + " contains an @o which links to itself");
845 continue;
846 }
847
848 Frame overlayFrame = FrameIO.LoadFrame(i
849 .getAbsoluteLink());
850 // Parse(overlay);
851 if (overlayFrame != null
852 && Overlay.getOverlay(overlays,
853 overlayFrame) == null)
854 overlays.add(new Overlay(overlayFrame,
855 Permission.none));
856 }
857 // check for ACTIVE_OVERLAY items
858 else if (ItemUtils.startsWithTag(i,
859 ItemUtils.TAG_ACTIVE_OVERLAY)
860 && i.getLink() != null) {
861 String link = i.getAbsoluteLink();
862 if (link.equalsIgnoreCase(toParse.getName())) {
863 // This frame contains an active overlay which
864 // points to itself
865 MessageBay
866 .errorMessage(toParse.getName()
867 + " contains an @ao which links to itself");
868 continue;
869 }
870 Frame overlayFrame = FrameIO.LoadFrame(link);
871 // get level if specified
872 String level = new AttributeValuePair(i.getText())
873 .getValue();
874 // default permission (if none is specified)
875 Permission permissionLevel = Permission
876 .getPermission(level,
877 Permission.followLinks);
878
879 if (overlayFrame != null) {
880 Overlay existingOverlay = Overlay.getOverlay(
881 overlays, overlayFrame);
882 // If it wasnt in the list create it and add it.
883 if (existingOverlay == null) {
884 Overlay newOverlay = new Overlay(
885 overlayFrame, permissionLevel);
886 i.setOverlay(newOverlay);
887 overlays.add(newOverlay);
888 } else {
889 existingOverlay.Frame
890 .setPermission(permissionLevel);
891 }
892 }
893 }
894 // check for Images and widgets
895 else {
896 if (!FrameGraphics.isXRayMode()) {
897 if (ItemUtils.startsWithTag(i,
898 ItemUtils.TAG_IMAGE, true)) {
899 if (!i.hasEnclosures()) {
900 createPicture(toParse, (Text) i);
901 }
902 // check for frame images
903 } else if (ItemUtils.startsWithTag(i,
904 ItemUtils.TAG_FRAME_IMAGE)
905 && i.getLink() != null
906 && !i.getAbsoluteLink()
907 .equalsIgnoreCase(
908 toParse.getName())) {
909 XRayable image = null;
910 if (i.hasEnclosures()) {
911 // i.setHidden(true);
912 // image =
913 // i.getEnclosures().iterator().next();
914 // image.refresh();
915 } else {
916 image = new FrameImage((Text) i,
917 toParse, null);
918 }
919 // TODO Add the image when creating new
920 // FrameImage
921 toParse.addItem(image);
922 } else if (ItemUtils.startsWithTag(i,
923 ItemUtils.TAG_BITMAP_IMAGE)
924 && i.getLink() != null
925 && !i.getAbsoluteLink()
926 .equalsIgnoreCase(
927 toParse.getName())) {
928 XRayable image = null;
929 if (i.hasEnclosures()) {
930 // image =
931 // i.getEnclosures().iterator().next();
932 // image.refresh();
933 // i.setHidden(true);
934 } else {
935 // If a new bitmap is created for a
936 // frame which already has a bitmap dont
937 // recreate the bitmap
938 image = new FrameBitmap((Text) i,
939 toParse, null);
940 }
941 toParse.addItem(image);
942 } else if (ItemUtils.startsWithTag(i, "@c")) {
943 // Can only have a @c
944 if (!i.hasEnclosures()
945 && i.getLines().size() == 1) {
946 toParse.addItem(new Circle((Text) i));
947 }
948 // Check for interactive widgets
949 } else if (ItemUtils.startsWithTag(i,
950 ItemUtils.TAG_IWIDGET)) {
951 createWidget(toParse, (Text) i);
952 }
953 }
954 // TODO decide exactly what to do here!!
955 toParse.addAnnotation((Text) i);
956 }
957 } else if (!FrameGraphics.isXRayMode() && i.hasFormula()) {
958 i.calculate(i.getFormula());
959 }
960 }
961 } catch (Exception e) {
962 Logger.Log(e);
963 e.printStackTrace();
964 MessageBay.warningMessage("Exception occured when loading "
965 + i.getClass().getSimpleName() + "(ID: " + i.getID()
966 + ") " + e.getMessage());
967 }
968 }
969
970 for (Item i : items) {
971 if (i instanceof Dot) {
972 ((Dot) i).setPointType(pointtype);
973 ((Dot) i).useFilledPoints(filledPoints);
974 }
975 }
976
977 FrameIO.ResumeCache();
978
979 synchronized (toParse) { // BROOK: This does not appear to do
980 // anything! Their seems to be no
981 // thread-safe protocol for this project...
982 toParse.clearOverlays();
983 toParse.addAllOverlays(overlays);
984 toParse.clearVectors();
985 toParse.addAllVectors(vectors);
986 }
987 }
988
989 /**
990 * @param vectors
991 * @param permission
992 * @param i
993 */
994 private static void addVector(List<Vector> vectors,
995 Permission defaultPermission, Permission framePermission, Item i) {
996 // TODO It is possible to get into an infinate loop if a
997 // frame contains an @ao which leads to a frame with an
998 // @v which points back to the frame with the @ao
999 Frame vector = FrameIO.LoadFrame(i.getAbsoluteLink());
1000 // Get the permission from off the vector frame
1001 Permission vectorPermission = Permission.getPermission(vector
1002 .getAnnotationValue("permission"), defaultPermission);
1003 // If the frame permission is lower, use that
1004 vectorPermission = Permission.min(vectorPermission, framePermission);
1005 // Highest permissable permission for vectors is copy
1006 vectorPermission = Permission.min(vectorPermission, Permission.copy);
1007 if (vector != null) {
1008 String scaleString = new AttributeValuePair(i.getText()).getValue();
1009 Float scale = 1F;
1010 try {
1011 scale = Float.parseFloat(scaleString);
1012 } catch (Exception e) {
1013 }
1014 Vector newVector = new Vector(vector, vectorPermission, i
1015 .getPosition(), scale, i.getColor(), i.getBackgroundColor());
1016 i.setOverlay(newVector);
1017 vectors.add(newVector);
1018 }
1019 }
1020
1021 /**
1022 * Searches through the list of items on this frame to find one at the given
1023 * x,y coordinates.
1024 *
1025 * @param x
1026 * The x coordinate
1027 * @param y
1028 * The y coordinate
1029 * @return The Item at the given coordinates, or NULL if none is found.
1030 */
1031 public static Item onItem(Frame toCheck, float floatX, float floatY) {
1032 // System.out.println("MouseX: " + floatX + " MouseY: " + floatY);
1033 int x = Math.round(floatX);
1034 int y = Math.round(floatY);
1035 if (toCheck == null)
1036 return null;
1037
1038 List<Item> possibles = new ArrayList<Item>(0);
1039
1040 // if the mouse is in the message area
1041 if (y > FrameGraphics.getMaxFrameSize().getHeight()) {
1042 // check the individual message items
1043 for (Item message : MessageBay.getMessages()) {
1044 if (message != null) {
1045 if (message.contains(x, y)) {
1046 message.setPermission(Permission.copy);
1047 possibles.add(message);
1048 } else {
1049 // Not sure why but if the line below is removed then
1050 // several items can be highlighted at once
1051 message.setHighlightMode(Item.HighlightMode.None);
1052 }
1053 }
1054 }
1055
1056 // check the link to the message frame
1057 if (MessageBay.getMessageLink() != null) {
1058 if (MessageBay.getMessageLink().contains(x, y)) {
1059 MessageBay.getMessageLink().setPermission(Permission.copy);
1060 possibles.add(MessageBay.getMessageLink());
1061 }
1062 }
1063
1064 // this is taken into account in contains
1065 // y -= FrameGraphics.getMaxFrameSize().height;
1066 // otherwise, the mouse is on the frame
1067 } else {
1068 if (LastEdited != null && /*
1069 * LastEdited.isVisible() &&
1070 */LastEdited.contains(x, y)
1071 && !FreeItems.getInstance().contains(LastEdited)
1072 && LastEdited.getParent() == DisplayIO.getCurrentFrame()
1073 && LastEdited.getParent().getItems().contains(LastEdited)) {
1074 LastEdited.setPermission(Permission.full);
1075 return LastEdited;
1076 } else {
1077 setLastEdited(null);
1078 }
1079 ArrayList<Item> checkList = new ArrayList<Item>();
1080 checkList.addAll(toCheck.getAllItems());
1081 checkList.add(toCheck.getNameItem());
1082 for (Item i : checkList) {
1083 // do not check annotation items in audience mode
1084 if (i.isVisible()
1085 && !(FrameGraphics.isAudienceMode() && i.isAnnotation())) {
1086 if (i.contains(x, y)
1087 && !FreeItems.getInstance().contains(i)) {
1088 possibles.add(i);
1089 }
1090 }
1091 }
1092 }
1093
1094 // if there are no possible items, return null
1095 if (possibles.size() == 0)
1096 return null;
1097
1098 // if there is only one possibility, return it
1099 if (possibles.size() == 1)
1100 return possibles.get(0);
1101
1102 // return closest x,y pair to mouse
1103 Item closest = possibles.get(0);
1104 int distance = (int) Math.round(Math.sqrt(Math.pow(Math.abs(closest
1105 .getX()
1106 - x), 2)
1107 + Math.pow(Math.abs(closest.getY() - y), 2)));
1108
1109 for (Item i : possibles) {
1110 int d = (int) Math.round(Math.sqrt(Math.pow(Math.abs(i.getX() - x),
1111 2)
1112 + Math.pow(Math.abs(i.getY() - y), 2)));
1113
1114 // System.out.println(d);
1115 if (d <= distance) {
1116 distance = d;
1117
1118 // dots take precedence over lines
1119 if ((!(closest instanceof Dot && i instanceof Line))
1120 && (!(closest instanceof Text && i instanceof Line)))
1121 closest = i;
1122
1123 }
1124
1125 }
1126
1127 return closest;
1128 }
1129
1130 public synchronized static Item getCurrentItem() {
1131 return onItem(DisplayIO.getCurrentFrame(), DisplayIO.getMouseX(),
1132 FrameMouseActions.getY());
1133 }
1134
1135 public static Polygon getEnlosingPolygon() {
1136 Collection<Item> enclosure = getEnclosingLineEnds();
1137 if (enclosure == null || enclosure.size() == 0)
1138 return null;
1139
1140 return enclosure.iterator().next().getEnclosedShape();
1141 }
1142
1143 /**
1144 *
1145 * @param currentItem
1146 * @return
1147 */
1148 public static Collection<Item> getCurrentItems() {
1149 return getCurrentItems(getCurrentItem());
1150 }
1151
1152 public static Collection<Item> getCurrentItems(Item currentItem) {
1153
1154 Collection<Item> enclosure = getEnclosingLineEnds();
1155 if (enclosure == null || enclosure.size() == 0)
1156 return null;
1157
1158 Item firstItem = enclosure.iterator().next();
1159
1160 Collection<Item> enclosed = getItemsEnclosedBy(DisplayIO
1161 .getCurrentFrame(), firstItem.getEnclosedShape());
1162
1163 // Brook: enclosed widgets are to be fully enclosed, never partially
1164 List<InteractiveWidget> enclosedWidgets = new LinkedList<InteractiveWidget>();
1165 for (Item i : enclosed) {
1166 // Dont want to loose the highlighting from the current item
1167 if (i != currentItem && !enclosure.contains(i))
1168 i.setHighlightMode(Item.HighlightMode.None);
1169 if (i instanceof WidgetCorner) {
1170 if (!enclosedWidgets.contains(((WidgetCorner) i)
1171 .getWidgetSource()))
1172 enclosedWidgets.add(((WidgetCorner) i).getWidgetSource());
1173 }
1174 }
1175
1176 for (InteractiveWidget iw : enclosedWidgets) {
1177 for (Item i : iw.getItems()) {
1178 if (!enclosed.contains(i)) {
1179 enclosed.add(i);
1180 }
1181 }
1182 }
1183
1184 return enclosed;
1185 }
1186
1187 public static Collection<Item> getEnclosingLineEnds() {
1188 return getEnclosingLineEnds(new Point(DisplayIO.getMouseX(), FrameMouseActions.getY()));
1189 }
1190
1191 public static Collection<Item> getEnclosingLineEnds(Point position) {
1192 // update enclosed shapes
1193 Frame current = DisplayIO.getCurrentFrame();
1194 List<Item> items = current.getItems();
1195
1196 // Remove all items that are connected to freeItems
1197 List<Item> freeItems = new ArrayList<Item>(FreeItems.getInstance());
1198 while (freeItems.size() > 0) {
1199 Item item = freeItems.get(0);
1200 Collection<Item> connected = item.getAllConnected();
1201 items.removeAll(connected);
1202 freeItems.removeAll(connected);
1203 }
1204
1205 List<Item> used = new ArrayList<Item>(0);
1206
1207 while (items.size() > 0) {
1208 Item i = items.get(0);
1209 items.remove(i);
1210 if (i.isEnclosed()) {
1211 Polygon p = i.getEnclosedShape();
1212 if (p.contains(position.x, position.y)) {
1213 used.add(i);
1214 items.removeAll(i.getEnclosingDots());
1215 }
1216 }
1217 }
1218
1219 if (used.size() == 0)
1220 return null;
1221
1222 // if there is only one possibility, return it
1223 if (used.size() == 1) {
1224 return used.get(0).getEnclosingDots();
1225 // otherwise, determine which polygon is closest to the cursor
1226 } else {
1227 Collections.sort(used, new Comparator<Item>() {
1228 public int compare(Item d1, Item d2) {
1229 Polygon p1 = d1.getEnclosedShape();
1230 Polygon p2 = d2.getEnclosedShape();
1231
1232 int closest = Integer.MAX_VALUE;
1233 int close2 = Integer.MAX_VALUE;
1234
1235 int mouseX = DisplayIO.getMouseX();
1236 int mouseY = FrameMouseActions.getY();
1237
1238 for (int i = 0; i < p1.npoints; i++) {
1239 int diff = Math.abs(p1.xpoints[i] - mouseX)
1240 + Math.abs(p1.ypoints[i] - mouseY);
1241 int diff2 = Integer.MAX_VALUE;
1242
1243 if (i < p2.npoints)
1244 diff2 = Math.abs(p2.xpoints[i] - mouseX)
1245 + Math.abs(p2.ypoints[i] - mouseY);
1246
1247 if (diff < Math.abs(closest)) {
1248 close2 = closest;
1249 closest = diff;
1250 } else if (diff < Math.abs(close2))
1251 close2 = diff;
1252
1253 if (diff2 < Math.abs(closest)) {
1254 close2 = closest;
1255 closest = -diff2;
1256 } else if (diff2 < Math.abs(close2))
1257 close2 = diff2;
1258 }
1259
1260 if (closest > 0 && close2 > 0)
1261 return -10;
1262
1263 if (closest < 0 && close2 < 0)
1264 return 10;
1265
1266 if (closest > 0)
1267 return -10;
1268
1269 return 10;
1270 }
1271
1272 });
1273
1274 return used.get(0).getEnclosingDots();
1275 }
1276 }
1277
1278 // TODO Remove this method!!
1279 // Can just getItemsWithin be used?
1280 public static Collection<Item> getItemsEnclosedBy(Frame frame, Polygon poly) {
1281 Collection<Item> contained = frame.getItemsWithin(poly);
1282
1283 Collection<Item> results = new LinkedHashSet<Item>(contained.size());
1284
1285 // check for correct permissions
1286 for (Item item : contained) {
1287 // if the item is on the frame
1288 if (item.getParent() == frame || item.getParent() == null) {
1289 // item.Permission = Permission.full;
1290 results.add(item);
1291 // otherwise, it must be on an overlay frame
1292 } else {
1293 for (Overlay overlay : frame.getOverlays()) {
1294 if (overlay.Frame == item.getParent()) {
1295 item.setPermission(overlay.permission);
1296 results.add(item);
1297 break;
1298 }
1299 }
1300 }
1301 }
1302
1303 return results;
1304 }
1305
1306 /**
1307 * Fills the given Frame with default profile tags
1308 */
1309 public static void CreateDefaultProfile(Frame profile) {
1310 Text title = profile.getTitleItem();
1311 title.setText("Profile Frame");
1312 title.setSize(50);
1313 title.setFontStyle("Bold");
1314 title.setFamily("SansSerif");
1315 title.setColor(Color.BLUE);
1316 title.setPosition(25, 50);
1317
1318 int spacing = 50;
1319 final int intialYPos = 75;
1320 int xPos = 75;
1321 int yPos = intialYPos;
1322
1323 yPos += spacing;
1324 profile.addText(xPos, yPos, "HomeFrame: " + profile.getName(), null,
1325 profile.getName());
1326 yPos += spacing;
1327 String defaultFrameName = profile.getFramesetName() + "0";
1328 profile.addText(xPos, yPos, "DefaultFrame: " + defaultFrameName, null,
1329 defaultFrameName);
1330 yPos += spacing;
1331
1332 profile.addText(xPos, yPos, "InitialWidth: "
1333 + UserSettings.InitialWidth, null);
1334 yPos += spacing;
1335
1336 profile.addText(xPos, yPos, "InitialHeight: "
1337 + UserSettings.InitialHeight, null);
1338 yPos += spacing;
1339
1340 Text t = profile.addText(xPos, yPos, "ItemTemplate", null);
1341 t.setColor(null);
1342
1343 yPos += spacing;
1344 t = profile.addText(xPos, yPos, "AnnotationTemplate", null);
1345 t.setColor(Color.gray);
1346
1347 yPos += spacing;
1348 t = profile.addText(xPos, yPos, "CommentTemplate", null);
1349 t.setColor(Color.green.darker());
1350
1351 yPos += spacing;
1352 t = profile.addText(xPos, yPos, "StatsTemplate", null);
1353 t.setColor(Color.BLACK);
1354 t.setBackgroundColor(new Color(0.9F, 0.9F, 0.9F));
1355 t.setFamily(Text.MONOSPACED_FONT);
1356 t.setSize(14);
1357
1358 xPos = 600;
1359 yPos = intialYPos;
1360
1361 // Iterate through the help folder and add links
1362 File helpDirectory = new File(FrameIO.HELP_PATH);
1363 if (helpDirectory != null) {
1364 File[] helpFramesets = helpDirectory.listFiles();
1365 if (helpFramesets != null) {
1366
1367 // Add the title for the help index
1368 Text help = profile
1369 .addText(xPos, yPos, "@Expeditee Help", null);
1370 help.setSize(25);
1371 help.setFontStyle("Bold");
1372 help.setFamily("SansSerif");
1373 help.setColor(Item.COLOR_WHEEL[3]);
1374
1375 xPos = 625;
1376
1377 for (File helpFrameset : helpFramesets) {
1378 String framesetName = helpFrameset.getName();
1379 if (!FrameIO.isValidFramesetName(framesetName))
1380 continue;
1381 Frame indexFrame = FrameIO.LoadFrame(framesetName + '1');
1382 // Look through the folder for help index pages
1383 if (indexFrame != null
1384 && ItemUtils.FindTag(indexFrame.getItems(),
1385 "@HelpIndex") != null) {
1386 yPos += spacing;
1387 t = profile.addText(xPos, yPos, '@' + indexFrame
1388 .getFramesetName(), null);
1389 t.setLink(indexFrame.getName());
1390 }
1391 }
1392 }
1393 }
1394
1395 // FrameUtils.Parse(profile);
1396 FrameIO.SaveFrame(profile);
1397 }
1398
1399 private static void checkTDFCItemWaiting(Frame currentFrame) {
1400 Item tdfcItem = FrameUtils.getTdfcItem();
1401 // if there is a TDFC Item waiting
1402 if (tdfcItem != null) {
1403 boolean change = currentFrame.hasChanged();
1404 boolean saved = currentFrame.isSaved();
1405 // Save the parent of the item if it has not been saved
1406 if (!change && !saved) {
1407 tdfcItem.setLink(null);
1408 tdfcItem.getParent().setChanged(true);
1409 FrameIO.SaveFrame(tdfcItem.getParent());
1410 FrameGraphics.Repaint();
1411 } else {
1412 SessionStats.CreatedFrame();
1413 }
1414
1415 setTdfcItem(null);
1416 }
1417 }
1418
1419 public static void setTdfcItem(Item _tdfcItem) {
1420 FrameUtils._tdfcItem = _tdfcItem;
1421 }
1422
1423 public static Item getTdfcItem() {
1424 return FrameUtils._tdfcItem;
1425 }
1426
1427 private static Item _tdfcItem = null;
1428
1429 public static void setLastEdited(Text lastEdited) {
1430 // If the lastEdited is being changed then check if its @i
1431 Frame toReparse = null;
1432 Frame toRecalculate = null;
1433 if (LastEdited != null) {
1434 if (lastEdited != LastEdited) {
1435 if (LastEdited.startsWith("@i")) {
1436 toReparse = LastEdited.getParent();
1437 } else if (LastEdited.recalculateWhenChanged()) {
1438 toRecalculate = LastEdited.getParentOrCurrentFrame();
1439 }
1440 // Update the formula if in XRay mode
1441 if (FrameGraphics.isXRayMode() && LastEdited.hasFormula()) {
1442 LastEdited.setFormula(LastEdited.getText());
1443 }
1444 }
1445 if (lastEdited != LastEdited && LastEdited.getText().length() == 0) {
1446 LastEdited.getParentOrCurrentFrame().removeItem(LastEdited);
1447 }
1448 }
1449 LastEdited = lastEdited;
1450
1451 if (!FrameGraphics.isXRayMode()) {
1452 if (toReparse != null) {
1453 Parse(toReparse, false);
1454 } else if (toRecalculate != null) {
1455 toRecalculate.recalculate();
1456 }
1457 }
1458 }
1459
1460 public static Text getLastEdited() {
1461 return LastEdited;
1462 }
1463
1464 public static Collection<Text> getCurrentTextItems() {
1465 Collection<Text> currentTextItems = new LinkedHashSet<Text>();
1466 Collection<Item> currentItems = getCurrentItems(null);
1467 if (currentItems != null) {
1468 for (Item i : getCurrentItems(null)) {
1469 if (i instanceof Text && !i.isLineEnd()) {
1470 currentTextItems.add((Text) i);
1471 }
1472 }
1473 }
1474 return currentTextItems;
1475 }
1476}
Note: See TracBrowser for help on using the repository browser.