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

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

Set TitleTemplate in UserSettings, and decrease default TitleTemplate size

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