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

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

Invert the behaviour of shift-delete (now the default is to delete a single item, and shift-delete deletes all the connected items too). Also update highlighting so connected items are highlighted in accordance with the deletion behaviour. Does not currently highlight items that are being carried (adding that would be as simple as disabling a few statements that explicitly disable highlighting on carried items, but it would look kind of ugly)

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