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

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

Added MailFrame agent

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