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

Last change on this file since 511 was 511, checked in by csl14, 11 years ago

Fixed documentation extraction for Windows compatability

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