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

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

A whole day of big changes.
Adding the ability to have Text at the end of Lines.
Also a lot of refactoring to improve the quality of code relating to constraints and lines

File size: 34.8 KB
Line 
1package org.expeditee.gui;
2
3import java.awt.Color;
4import java.awt.Polygon;
5import java.io.File;
6import java.util.ArrayList;
7import java.util.Collections;
8import java.util.Comparator;
9import java.util.List;
10
11import org.expeditee.io.Logger;
12import org.expeditee.items.Dot;
13import org.expeditee.items.InteractiveWidget;
14import org.expeditee.items.InteractiveWidgetNotAvailableException;
15import org.expeditee.items.Item;
16import org.expeditee.items.ItemUtils;
17import org.expeditee.items.Line;
18import org.expeditee.items.Picture;
19import org.expeditee.items.Text;
20import org.expeditee.items.WidgetCorner;
21import org.expeditee.items.WidgetEdge;
22
23public class FrameUtils {
24
25 private static final int COLUMN_WIDTH = 50;
26
27 /**
28 * Provides a way to monitor the time elapsed between button-down and the
29 * finished painting.
30 */
31 public static TimeKeeper ResponseTimer = new TimeKeeper();
32
33 private static float _ResponseTimeSum = 0;
34
35 private static float _LastResponse = 0;
36
37 public static Item LastEdited = null;
38
39 public static int MINIMUM_INTERITEM_SPACING = -6;
40
41 public static float getResponseTimeTotal() {
42 return _ResponseTimeSum;
43 }
44
45 public static float getLastResponseTime() {
46 return _LastResponse;
47 }
48
49 /**
50 * Checks if the given top Item is above the given bottom Item, allowing for
51 * the X coordinates to be off by a certain width...
52 *
53 * @param item1
54 * The Item to check is above the other Item
55 * @param item2
56 * The Item to check is below the top Item
57 * @return True if top is above bottom, False otherwise.
58 */
59 public static boolean inSameColumn(Item item1, Item item2) {
60 if (!(item1 instanceof Text) || !(item2 instanceof Text))
61 return false;
62
63 if (item1.getID() < 0 || item2.getID() < 0)
64 return false;
65
66 int minX = item2.getX();
67 int maxX = item2.getX() + item2.getBoundsWidth();
68
69 int startX = item1.getX();
70 int endX = item1.getX() + item1.getBoundsWidth();
71
72 // Check that the two items left values are close
73 if (Math.abs(item1.getX() - item2.getX()) > COLUMN_WIDTH)
74 return false;
75
76 // Ensure the two items
77 if ((minX >= startX && minX <= endX)
78 || (maxX >= startX && maxX <= endX)
79 || (startX >= minX && startX <= maxX)
80 || (endX >= minX && endX <= maxX))
81 return true;
82
83 return false;
84 }
85
86 public static boolean sameBulletType(String bullet1, String bullet2) {
87 if (bullet1 == null || bullet2 == null)
88 return false;
89
90 if (bullet1 == "" || bullet2 == "")
91 return false;
92
93 if (Character.isLetter(bullet1.charAt(0))
94 && Character.isLetter(bullet2.charAt(0)))
95 return true;
96
97 if (Character.isDigit(bullet1.charAt(0))
98 && Character.isDigit(bullet2.charAt(0)))
99 return true;
100
101 // TODO make this more sofisticated
102
103 return false;
104 }
105
106 private static boolean needsRenumbering(String s) {
107 if (s == null || s == "")
108 return false;
109 if (!Character.isLetterOrDigit(s.charAt(0)))
110 return false;
111
112 s = s.trim();
113 // if its all letters then we dont want to auto adjust
114 if (s.length() > 2) {
115 for (int i = 0; i < s.length() - 1; i++) {
116 if (!Character.isLetter(s.charAt(i)))
117 return true;
118 }
119 } else
120 return true;
121
122 return false;
123 }
124
125 /**
126 *
127 * @param toAlign
128 * @param moveAll
129 * @param adjust
130 * @return
131 */
132 public static int Align(List<Item> toAlign, boolean moveAll, int adjust) {
133 Collections.sort(toAlign);
134
135 // Single items dont need alignment
136 if (toAlign.size() < 2)
137 return 0;
138
139 // get the first item
140 Item from = toAlign.get(0);
141 if (from.getParent() == null)
142 from = toAlign.get(1);
143 int x = from.getX();
144
145 Frame curr = from.getParent();
146 Item above = curr.getItemAbove(from);
147
148 String lastBullet = "";
149
150 if (above != null && curr.isNormalTextItem(above))
151 lastBullet = FrameKeyboardActions.getAutoBullet(((Text) above)
152 .getTextNoList());
153 else {
154 lastBullet = FrameKeyboardActions.getBullet(((Text) toAlign.get(0))
155 .getTextNoList());
156 }
157 if (needsRenumbering(lastBullet)) {
158 // renumber...
159 for (int i = 0; i < toAlign.size(); i++) {
160 assert toAlign.get(i) instanceof Text;
161
162 Text currentText = ((Text) toAlign.get(i));
163 String currentBullet = FrameKeyboardActions
164 .getAutoBullet(currentText.getTextNoList());
165
166 if (sameBulletType(lastBullet, currentBullet)) {
167 currentText.stripFirstWord();
168
169 currentText.setText(lastBullet
170 + currentText.getTextNoList());
171 lastBullet = FrameKeyboardActions.getAutoBullet(currentText
172 .getTextNoList());
173 }
174 }
175 }
176
177 // work out the spacing between the first item and the one above it
178
179 int space = 10 + adjust;
180
181 // if we are dropping from the title make the space a little bigger
182 // than normal
183 if (above != curr.getTitle() && above != null) {
184 // Make the gap between all items the same as the gap between
185 // the first two
186 space = (int) (from.getPolygon().getBounds().getMinY() - above
187 .getPolygon().getBounds().getMaxY());
188
189 if (space < MINIMUM_INTERITEM_SPACING)
190 space = MINIMUM_INTERITEM_SPACING;
191
192 if (above != curr.getFrameNameItem() && above != curr.getTitle())
193 x = above.getX();
194
195 space += adjust;
196
197 from.setY((int) above.getPolygon().getBounds().getMaxY()
198 + space
199 + ((int) (from.getY() - from.getPolygon().getBounds()
200 .getMinY())));
201
202 if (moveAll)
203 from.setX(x);
204 }
205
206 for (int i = 1; i < toAlign.size(); i++) {
207 Item current = toAlign.get(i);
208 Item top = toAlign.get(i - 1);
209
210 // The bottom of the previous item
211 int bottom = (int) top.getPolygon().getBounds().getMaxY();
212
213 // the difference between the current item's Y coordinate and
214 // the top of the highlight box
215 int diff = (int) (current.getY() - current.getPolygon().getBounds()
216 .getMinY());
217
218 int newPos = bottom + space + diff;
219
220 if (moveAll) {
221 current.setPosition(x, newPos);
222 } else if (newPos > current.getY()) {
223 current.setY(newPos);
224 }
225
226 }
227
228 // if (insert != null)
229 // return insert.getY();
230
231 // Michael thinks we return the y value for the next new item??
232 int y = from.getY() + from.getBoundsHeight() + space;
233 return y;
234 }
235
236 public static boolean LeavingFrame(Frame current) {
237 // active overlay frames may also require saving if they have been
238 // changed
239 for (Overlay o : current.getOverlays())
240 if (!SaveCheck(o.Frame))
241 return false;
242
243 // if the check fails there is no point continuing
244 if (!SaveCheck(current))
245 return false;
246
247 for (Item i : current.getItems())
248 i.setSelectedMode(Item.SelectedMode.None);
249 return true;
250 }
251
252 private static boolean SaveCheck(Frame toSave) {
253 // don't bother saving frames that haven't changed
254 if (!toSave.hasChanged())
255 return true;
256
257 // if the frame has been changed, then save it
258 if (DisplayIO.isTwinFramesOn()) {
259 Frame opposite = DisplayIO.getOppositeFrame();
260
261 String side = "left";
262 if (DisplayIO.getCurrentSide() == 0)
263 side = "right";
264
265 // if the two frames both have changes, prompt the user for the
266 // next
267 // move
268 if (opposite.hasChanged() && opposite.equals(toSave)) {
269 if (DisplayIO.DisplayConfirmDialog(
270 "Leaving this frame will discard changes made in the "
271 + side + " Frame. Continue?", "Changes",
272 DisplayIO.TYPE_WARNING, DisplayIO.OPTIONS_OK_CANCEL,
273 DisplayIO.RESULT_OK)) {
274 FrameIO.SaveFrame(toSave);
275 DisplayIO.Reload(DisplayIO.FrameOnSide(opposite));
276 return true;
277 } else
278 return false;
279 } else if (opposite.getOverlays().contains(new Overlay(toSave, 1))) {
280 if (opposite.getOverlays().get(
281 opposite.getOverlays().indexOf(new Overlay(toSave, 1))).Frame
282 .hasChanged())
283 if (DisplayIO.DisplayConfirmDialog(
284 "Leaving this frame will discard changes made in the "
285 + side + " Frame. Continue?", "Changes",
286 DisplayIO.TYPE_WARNING,
287 DisplayIO.OPTIONS_OK_CANCEL, DisplayIO.RESULT_OK)) {
288 FrameIO.SaveFrame(toSave);
289 DisplayIO.Reload(DisplayIO.FrameOnSide(opposite));
290 return true;
291 } else
292 return false;
293 }
294
295 // save the current frame and restore the other side
296 FrameIO.SaveFrame(toSave);
297 return true;
298 }
299
300 // single-frame mode can just save and return
301 FrameIO.SaveFrame(toSave);
302 return true;
303 }
304
305 /**
306 * Displays the given Frame on the display. If the current frame has changed
307 * since the last save then it will be saved before the switch is made. The
308 * caller can also dictate whether the current frame is added to the
309 * back-stack or not.
310 *
311 * @param toDisplay
312 * The Frame to display on the screen
313 * @param addToBack
314 * True if the current Frame should be added to the back-stack,
315 * False otherwise
316 */
317 public static void DisplayFrame(Frame toDisplay, boolean addToBack) {
318 if (toDisplay == null)
319 return;
320
321 Frame current = DisplayIO.getCurrentFrame();
322
323 // move any anchored connected items
324 if (Frame.itemAttachedToCursor()) {
325 ArrayList<Item> toAdd = new ArrayList<Item>();
326
327 for (Item i : Frame.FreeItems) {
328 for (Item x : i.getConnected())
329 if (!Frame.FreeItems.contains(x) && !toAdd.contains(x))
330 toAdd.add(x);
331 }
332
333 current.removeAllItems(toAdd);
334
335 boolean oldChange = toDisplay.hasChanged();
336 toDisplay.updateIDs(toAdd);
337 toDisplay.addAllItems(toAdd);
338 toDisplay.setChanged(oldChange);
339 }
340
341 // if the saving happened properly, we can continue
342 if (!LeavingFrame(current)) {
343 FrameGraphics.DisplayMessage("Navigation cancelled");
344 return;
345 }
346
347 if (addToBack && current != toDisplay)
348 DisplayIO.addToBack(current);
349
350 Parse(toDisplay);
351 DisplayIO.setCurrentFrame(toDisplay);
352
353 // update response timer
354 _LastResponse = ResponseTimer.getElapsedSeconds();
355 _ResponseTimeSum += _LastResponse;
356 DisplayIO.UpdateTitle();
357 }
358
359 /**
360 * Loads and displays the Frame with the given framename, and adds the
361 * current frame to the back-stack if required.
362 *
363 * @param framename
364 * The name of the Frame to load and display
365 * @param addToBack
366 * True if the current Frame should be added to the back-stack,
367 * false otherwise
368 */
369 public static void DisplayFrame(String frameName, boolean addToBack) {
370 Frame newFrame = getFrame(frameName);
371
372 if (newFrame != null)
373 // display the frame
374 DisplayFrame(newFrame, addToBack);
375 }
376
377 /**
378 * Loads and displays the Frame with the given framename and adds the
379 * current frame to the back-stack. This is the same as calling
380 * DisplayFrame(framename, true)
381 *
382 * @param framename
383 * The name of the Frame to load and display
384 */
385 public static void DisplayFrame(String framename) {
386 DisplayFrame(framename, true);
387 }
388
389 public static void DisplayHomeFrame() {
390 DisplayFrame(UserSettings.FirstFrame);
391 }
392
393 public static void DisplayProfileFrame() {
394 DisplayFrame(UserSettings.Username + '1');
395 }
396
397 public static Frame getFrame(String frameName) {
398 // if the new frame does not exist then tell the user
399 Frame f = FrameIO.LoadFrame(frameName);
400
401 if (f == null) {
402 FrameGraphics.ErrorMessage("Frame '" + frameName
403 + "' could not be found.");
404 }
405
406 return f;
407 }
408
409 /**
410 * Creates a new Picture Item from the given Text source Item and adds it to
411 * the given Frame.
412 *
413 * @return True if the image was created successfully, false otherwise
414 */
415 private static boolean createPicture(Frame frame, Text txt) {
416 // attempt to create the picture
417 Picture pic = ItemUtils.CreatePicture(txt, frame);
418
419 // if the picture could not be created successfully
420 if (pic == null) {
421 assert (txt.getFirstLine() != null);
422 assert (txt.getFirstLine().split(" ").length > 1);
423
424 FrameGraphics
425 .ErrorMessage("Image " + txt.getFirstLine().split(" ")[1]
426 + " could not be loaded");
427 return false;
428 }
429
430 // replace the Text source with the new Picture
431 frame.removeItem(txt);
432 frame.addItem(pic);
433
434 return true;
435 }
436
437 private static boolean createFramePicture(Frame frame, Text txt) {
438 if (txt.getLink() == null)
439 return false;
440
441 // attempt to create the picture
442 Picture pic = ItemUtils.CreateFramePicture(txt, frame);
443
444 // if the picture could not be created successfully
445 if (pic == null) {
446 FrameGraphics.ErrorMessage("Error loading frame image");
447 return false;
448 }
449
450 // replace the Text source with the new Picture
451 frame.removeItem(txt);
452 frame.addItem(pic);
453
454 return true;
455 }
456
457 /**
458 * Creates an interactive widget and adds it to a frame. If txt has no
459 * parent the parent will be set to frame.
460 *
461 * @param frame
462 * Frame to add widget to. Must not be null.
463 *
464 * @param txt
465 * Text to create the widget from. Must not be null.
466 *
467 * @return True if created/added. False if coul not create.
468 *
469 * @author Brook Novak
470 */
471 private static boolean createWidget(Frame frame, Text txt) {
472
473 if (frame == null)
474 throw new NullPointerException("frame");
475 if (txt == null)
476 throw new NullPointerException("txt");
477
478 // Safety
479 if (txt.getParent() == null)
480 txt.setParent(frame);
481
482 InteractiveWidget iw = null;
483
484 try {
485
486 iw = InteractiveWidget.CreateWidget(txt);
487
488 } catch (InteractiveWidgetNotAvailableException e) {
489 e.printStackTrace();
490 FrameGraphics.ErrorMessage("Cannot create iWidget: "
491 + e.getMessage());
492
493 } catch (IllegalArgumentException e) {
494 e.printStackTrace();
495 FrameGraphics.ErrorMessage("Cannot create iWidget: "
496 + e.getMessage());
497 }
498
499 if (iw == null)
500 return false;
501
502 frame.removeItem(txt);
503
504 frame.addAllItems(iw.getItems());
505
506 return true;
507 }
508
509 public static void ParseProfile(Frame profile) {
510 if (profile == null)
511 return;
512
513 UserSettings.TitleTemplate = profile.getTitle();
514
515 List<Item> items = profile.getItems();
516
517 // check for all tags setting user values
518 for (Item item : items) {
519 if (ItemUtils.isTag(item, "@HomeFrame:")) {
520 String first = getLink(item, UserSettings.FirstFrame);
521 // do not use non-existant frames as the first frame
522 if (FrameIO.isValidFrameName(first)) {
523 UserSettings.FirstFrame = first;
524 }
525 // warn the user
526 else {
527 FrameGraphics.WarningMessage("Home frame: " + first
528 + " is not a valid frame.");
529 UserSettings.FirstFrame = profile.getFrameName();
530 }
531 } else if (ItemUtils.isTag(item, "@MenuFrame:"))
532 UserSettings.MenuFrame = getLink(item, UserSettings.MenuFrame);
533 else if (ItemUtils.isTag(item, "@DefaultFrame:"))
534 UserSettings.DefaultFrame = getLink(item,
535 UserSettings.DefaultFrame);
536 else if (ItemUtils.isTag(item, "@AntiAlias:"))
537 UserSettings.AntiAlias = getBoolean(item,
538 UserSettings.AntiAlias);
539 else if (ItemUtils.isTag(item, "@Gravity:"))
540 UserSettings.Gravity = getInt(item, UserSettings.Gravity);
541 else if (ItemUtils.isTag(item, "@ShowLineHighlight:"))
542 UserSettings.LineHighlight = getBoolean(item,
543 UserSettings.LineHighlight);
544 else if (ItemUtils.isTag(item, "@LineStraightenThreshold:"))
545 UserSettings.LineStraightenThreshold = getInt(item,
546 UserSettings.LineStraightenThreshold);
547 else if (ItemUtils.isTag(item, "@NoOpThreshold:"))
548 UserSettings.NoOpThreshold = getInt(item,
549 UserSettings.NoOpThreshold);
550 else if (ItemUtils.isTag(item, "@InitialWidth:")) {
551 UserSettings.InitialWidth = getInt(item,
552 UserSettings.InitialWidth);
553 } else if (ItemUtils.isTag(item, "@InitialHeight:")) {
554 UserSettings.InitialHeight = getInt(item,
555 UserSettings.InitialHeight);
556 } else if (ItemUtils.isTag(item, "@Logging:")) {
557 UserSettings.Logging = getBoolean(item, UserSettings.Logging);
558 } else if (ItemUtils.isTag(item, ItemUtils.TAG_ITEM_TEMPLATE)) {
559 UserSettings.ItemTemplate = ((Text) item).getTemplateForm();
560 } else if (ItemUtils.isTag(item, ItemUtils.TAG_ANNOTATION_TEMPLATE)) {
561 UserSettings.AnnotationTemplate = ((Text) item)
562 .getTemplateForm();
563 } else if (ItemUtils.isTag(item,
564 ItemUtils.TAG_CODE_COMMENT_TEMPLATE)) {
565 UserSettings.CodeCommentTemplate = ((Text) item)
566 .getTemplateForm();
567 } else if (ItemUtils.isTag(item, "@FramesetDir:")) {
568 String dir = getDir(item, null);
569 if (dir != null)
570 UserSettings.FrameDirs.add(dir);
571 } else if (ItemUtils.isTag(item, "@LogDir:")) {
572 org.expeditee.gui.FrameIO.LOGS_DIR = getDir(item,
573 org.expeditee.gui.FrameIO.LOGS_DIR);
574 } else if (ItemUtils.isTag(item, "@ImageDir:")) {
575 String dir = getDir(item, null);
576 if (dir != null)
577 UserSettings.ImageDirs.add(0, dir);
578 } else if (ItemUtils.isTag(item, "@Threading:")) {
579 UserSettings.Threading = getBoolean(item,
580 UserSettings.Threading);
581 } else if (ItemUtils.isTag(item, "@ColorWheel")) {
582 Item.COLOR_WHEEL = getColorWheel(item);
583 } else if (ItemUtils.isTag(item, "@BackgroundColorWheel")) {
584 Item.FILL_COLOR_WHEEL = getColorWheel(item);
585 } else if (ItemUtils.isTag(item, "@FramesetDirs")) {
586 UserSettings.FrameDirs.addAll(getDirs(item));
587 }
588 }
589
590 if (UserSettings.FirstFrame == null)
591 UserSettings.FirstFrame = profile.getFrameName();
592 else {
593 if (FrameIO.LoadFrame(UserSettings.FirstFrame) == null) {
594 FrameGraphics.WarningMessage("Home frame: "
595 + UserSettings.FirstFrame + " could not be found.");
596 UserSettings.FirstFrame = profile.getFrameName();
597 }
598 }
599
600 }
601
602 private static Color[] getColorWheel(Item item) {
603 String childName = item.getAbsoluteLink();
604 if (childName != null) {
605 Frame child = FrameIO.LoadFrame(childName);
606 if (child != null) {
607 List<Text> textItems = child.getBodyTextItems(true);
608 Color[] colorList = new Color[textItems.size()];
609 for (int i = 0; i < textItems.size(); i++) {
610 colorList[i] = textItems.get(i).getColor();
611 }
612 return colorList;
613 }
614 }
615 return new Color[]{Color.black, Color.white};
616 }
617
618 private static String getLink(Item item, String alt) {
619 if (item == null || !(item instanceof Text))
620 return alt;
621
622 String value = AttributeUtils.stripValue(((Text) item).getFirstLine())
623 .trim();
624 if (value.length() > 0) {
625 item.setLink(value);
626 return value;
627 } else if (item.getLink() != null)
628 return item.getLink();
629
630 return alt;
631 }
632
633 private static boolean getBoolean(Item item, boolean alt) {
634 if (item == null || !(item instanceof Text))
635 return alt;
636
637 String value = AttributeUtils.stripValue(((Text) item).getFirstLine())
638 .trim().toLowerCase();
639 if (value != null && value.length() > 0) {
640 if (value.equals("t") || value.equals("true")
641 || value.equals("yes") || value.equals("y"))
642 return true;
643
644 if (value.equals("f") || value.equals("false")
645 || value.equals("no") || value.equals("n")) {
646 return false;
647 }
648 }
649
650 return alt;
651 }
652
653 private static int getInt(Item item, int alt) {
654 if (item == null || !(item instanceof Text))
655 return alt;
656
657 String value = AttributeUtils.stripValue(((Text) item).getFirstLine())
658 .trim().toLowerCase();
659 try {
660 return Integer.parseInt(value);
661 } catch (Exception e) {
662 }
663
664 return alt;
665 }
666
667 private static String getDir(Item item, String alt) {
668 String name = getString(item, null);
669 if (name != null) {
670 File tester = new File(name);
671 if (tester.exists() && tester.isDirectory()) {
672 if (name.endsWith(File.separator))
673 return name;
674 else
675 return name + File.separator;
676 }
677 }
678
679 return alt;
680 }
681
682 private static ArrayList<String> getDirs(Item item) {
683 ArrayList<String> dirsToAdd = new ArrayList<String>();
684 String dirListFrameName = item.getAbsoluteLink();
685
686 if (dirListFrameName != null) {
687 Frame dirListFrame = FrameIO.LoadFrame(dirListFrameName);
688 for (Text t : dirListFrame.getBodyTextItems(false)) {
689 String dirName = t.getTextNoList().trim();
690 File tester = new File(dirName);
691 if (tester.exists() && tester.isDirectory()) {
692 if (dirName.endsWith(File.separator))
693 dirsToAdd.add(dirName);
694 else
695 dirsToAdd.add(dirName + File.separator);
696 }
697 }
698 }
699
700 return dirsToAdd;
701 }
702
703 /*
704 * private static String FindFile(List<Item> items, String tag, String
705 * alt){ String name = FindString(items, tag, null); if(name != null){ File
706 * tester = new File(name); if(tester.exists()) return name; }
707 *
708 * return alt; }
709 */
710 private static String getString(Item item, String alt) {
711 if (item == null || !(item instanceof Text))
712 return alt;
713
714 String value = AttributeUtils.stripValue(((Text) item).getFirstLine())
715 .trim();
716 if (value != null && value.length() > 0)
717 return value;
718
719 return alt;
720 }
721
722 public static void Parse(Frame toParse) {
723 Parse(toParse, false);
724 }
725
726 /**
727 * Checks for any special Annotation items and updates the display as
728 * necessary. Special Items: Images, overlays, sort.
729 *
730 */
731 public static void Parse(Frame toParse, boolean firstParse) {
732 // System.out.println(firstParse);
733 if (firstParse)
734 ItemUtils.EnclosedCheck(toParse.getItems());
735
736 List<Item> items = toParse.getItems();
737
738 // if XRayMode is on, replace pictures with their underlying text
739 if (FrameGraphics.isXRayMode()) {
740
741 // BROOK: Must handle these a little different
742 List<InteractiveWidget> widgets = toParse.getInteractiveWidgets();
743
744 for (Item i : items) {
745 if (i instanceof Picture) {
746 toParse.removeItem(i);
747 toParse.addItem(((Picture) i).getText());
748 } else if (i instanceof WidgetCorner) {
749 toParse.removeItem(i);
750 } else if (i instanceof WidgetEdge) {
751 toParse.removeItem(i);
752 }
753 }
754
755 for (InteractiveWidget iw : widgets) {
756 toParse.addItem(iw.getSource());
757 }
758
759 // update the list of items
760 items.clear();
761 items.addAll(toParse.getItems());
762 }
763
764 // Text title = null;
765 // Text template = UserSettingsTemplate.copy();
766
767 ArrayList<Overlay> overlays = new ArrayList<Overlay>();
768
769 // disable reading of cached overlays if in twinframes mode
770 if (DisplayIO.isTwinFramesOn())
771 FrameIO.SuspendCache();
772
773 int pointtype = Item.POINTTYPE_SQUARE;
774 boolean filledPoints = true;
775
776 // check for any new overlay items
777 for (Item i : items) {
778 try {
779 /*
780 * if (title == null && i.isTitle()) { title = (Text) i;
781 *
782 * if (title.getX() <= 0 && title.getY() <= 0)
783 * title.resetTitlePosition(); }
784 */
785
786 // check for pointtype settings
787 if (ItemUtils.isTag(i, ItemUtils.TAG_POINTTYPE)) {
788 Text txt = (Text) i;
789 String line = txt.getFirstLine();
790 line = ItemUtils.StripTag(line, ItemUtils
791 .GetTag(ItemUtils.TAG_POINTTYPE));
792
793 if (line != null) {
794 line = line.toLowerCase();
795 if (line.indexOf(" ") > 0) {
796 String fill = line.substring(line.indexOf(" ") + 1);
797 if (fill.startsWith("nofill"))
798 filledPoints = false;
799 else
800 filledPoints = true;
801 }
802
803 if (line.startsWith("circle"))
804 pointtype = Item.POINTTYPE_CIRCLE;
805 else
806 pointtype = Item.POINTTYPE_SQUARE;
807 }
808 }
809
810 // check for Images and widgets
811 if (!FrameGraphics.isXRayMode()) {
812 if (ItemUtils.isTag(i, ItemUtils.TAG_IMAGE))
813 createPicture(toParse, (Text) i);
814 // check for frame images
815 else if (i.getLink() != null
816 && ItemUtils.isTag(i, ItemUtils.TAG_FRAME_IMAGE))
817 createFramePicture(toParse, (Text) i);
818 // Check for interactive widgets
819 else if (ItemUtils.isTag(i, ItemUtils.TAG_IWIDGET)) {
820 createWidget(toParse, (Text) i);
821 }
822 }
823
824 // check for new overlay items
825 if (ItemUtils.isTag(i, ItemUtils.TAG_OVERLAY)
826 && i.getLink() != null) {
827 Frame overlay = FrameIO.LoadFrame(i.getLink());
828 // Parse(overlay);
829 if (overlay != null && !overlays.contains(overlay))
830 overlays
831 .add(new Overlay(overlay, Item.PERMISSION_NONE));
832 }
833
834 // check for new overlay items
835 if (ItemUtils.isTag(i, ItemUtils.TAG_ACTIVE_OVERLAY)
836 && i.getLink() != null) {
837 String link = i.getLink();
838 if (FrameIO.isPositiveInteger(link))
839 link = toParse.getFramesetName() + link;
840 Frame overlay = FrameIO.LoadFrame(link);
841 // Parse(overlay);
842 if (overlay != null && !overlays.contains(overlay)) {
843 // get level if specified
844 String level = ItemUtils.StripTag(((Text) i)
845 .getFirstLine());
846 // default permission (if none is specified)
847 int perm = Item.PERMISSION_FOLLOW_LINKS;
848
849 try {
850 perm = Integer.parseInt(level);
851 } catch (Exception e) {
852 // if this is a text permission level, parse it
853 if (level.length() > 0) {
854 level = level.toLowerCase().trim();
855 if (level.equals("none"))
856 perm = Item.PERMISSION_NONE;
857 else if (level.equals("links")
858 || level.equals("link"))
859 perm = Item.PERMISSION_FOLLOW_LINKS;
860 else if (level.equals("copy"))
861 perm = Item.PERMISSION_COPY;
862 else if (level.equals("tdfc"))
863 perm = Item.PERMISSION_TDFC;
864 else if (level.equals("full")
865 || level.equals("all"))
866 perm = Item.PERMISSION_FULL;
867 else
868 FrameGraphics
869 .DisplayMessage("Permission level '"
870 + level
871 + "' not recognized, using default level (Links)");
872 }
873 }
874
875 overlays.add(new Overlay(overlay, perm));
876 }
877 }
878
879 /*
880 * check for Item templates if (ItemUtils.isTag(i,
881 * ItemUtils.TAG_ITEM_TEMPLATE)) { template = (Text) i; }
882 */
883
884 // only remove items on first parse
885 if (firstParse) {
886 // remove dots of size 1
887 if (i instanceof Dot) {
888 Dot dot = (Dot) i;
889 if (dot.getSize() <= 1
890 && (dot.getLines() == null || dot.getLines()
891 .size() == 0))
892 if (dot.getConstraints() == null
893 || dot.getConstraints().size() == 0) {
894 toParse.removeItem(dot);
895 }
896 }
897
898 // remove Text that is all whitespace
899 if (i instanceof Text) {
900 List<String> text = ((Text) i).getText();
901 // remove empty text items
902 if (text == null || text.size() == 0)
903 toParse.removeItem(i);
904 else {
905 for (String s : text)
906 if (s.trim().length() > 0)
907 break;
908 else
909 toParse.removeItem(i);
910 }
911 }
912
913 }
914
915 } catch (Exception e) {
916 Logger.Log(e);
917 e.printStackTrace();
918 FrameGraphics.WarningMessage("Exception occured when loading "
919 + i.getClass().getSimpleName() + "(ID: " + i.getID()
920 + ") " + e.getMessage());
921 }
922 }
923
924 for (Item i : items) {
925 if (i instanceof Dot) {
926 ((Dot) i).setPointType(pointtype);
927 ((Dot) i).useFilledPoints(filledPoints);
928 }
929 }
930
931 FrameIO.ResumeCache();
932
933 synchronized (toParse) {
934 toParse.clearOverlays();
935 toParse.addAllOverlays(overlays);
936 }
937 }
938
939 /**
940 * Searches through the list of items on this frame to find one at the given
941 * x,y coordinates.
942 *
943 * @param x
944 * The x coordinate
945 * @param y
946 * The y coordinate
947 * @return The Item at the given coordinates, or NULL if none is found.
948 */
949 public static Item onItem(Frame toCheck, int x, int y) {
950 if (toCheck == null)
951 return null;
952
953 List<Item> possibles = new ArrayList<Item>(0);
954
955 // if the mouse is in the message area
956 if (y > FrameGraphics.getMaxFrameSize().getHeight()) {
957 // check the individual message items
958 for (Text message : FrameGraphics.Messages) {
959 if (message != null) {
960 if (message.contains(x, y)) {
961 message.Permission = Item.PERMISSION_COPY;
962 possibles.add(message);
963 } else
964 // Not sure why but if the line below is removed then
965 // several items can be highlighted at once
966 message.setSelectedMode(Item.SelectedMode.None);
967 }
968 }
969
970 // check the link to the message frame
971 if (FrameGraphics.MessageLink != null) {
972 if (FrameGraphics.MessageLink.contains(x, y)) {
973 FrameGraphics.MessageLink.Permission = Item.PERMISSION_COPY;
974 possibles.add(FrameGraphics.MessageLink);
975 }
976 }
977
978 // this is taken into account in contains
979 // y -= FrameGraphics.getMaxFrameSize().height;
980 // otherwise, the mouse is on the frame
981 } else {
982
983 if (LastEdited != null && LastEdited.contains(x, y)
984 && !Frame.FreeItems.contains(LastEdited)
985 && LastEdited.getParent() == DisplayIO.getCurrentFrame()
986 && LastEdited.getParent().getItems().contains(LastEdited)) {
987 LastEdited.Permission = Item.PERMISSION_FULL;
988 return LastEdited;
989 } else
990 LastEdited = null;
991
992 ArrayList<Item> checkList = new ArrayList<Item>();
993 checkList.addAll(toCheck.getItems());
994 checkList.add(toCheck.getFrameNameItem());
995 for (Item i : checkList) {
996 // do not check annotation items in audience mode
997 if (!(FrameGraphics.isAudienceMode() && i.isAnnotation())) {
998 if (i.contains(x, y) && !Frame.FreeItems.contains(i)) {
999 // names have copy permissions only
1000 if (i == toCheck.getFrameNameItem()) {
1001 i.Permission = Item.PERMISSION_TDFC;
1002 possibles.add(i);
1003 } else {
1004 i.Permission = Item.PERMISSION_FULL;
1005 possibles.add(i);
1006 }
1007 }
1008 }
1009 }
1010
1011 for (Overlay o : toCheck.getOverlays()) {
1012 if (o.Level > Item.PERMISSION_NONE) {
1013 Item i = onItem(o.Frame, x, y);
1014
1015 // the message is included above with full permissions,
1016 // it should be ignored here
1017 if (i != null
1018 && /* i != FrameGraphics.TextMessage && */i
1019 .getID() > 0) {
1020 if (o.Level < i.Permission)
1021 i.Permission = o.Level;
1022 possibles.add(i);
1023 }
1024 }
1025 }
1026 }
1027
1028 // if there is only one possibility, return it
1029 if (possibles.size() == 1)
1030 return possibles.get(0);
1031
1032 // if there are no possible items, return null
1033 if (possibles.size() == 0)
1034 return null;
1035
1036 // return closest x,y pair to mouse
1037 Item closest = possibles.get(0);
1038 int distance = (int) Math.sqrt(Math
1039 .pow(Math.abs(closest.getX() - x), 2)
1040 + Math.pow(Math.abs(closest.getY() - y), 2));
1041
1042 for (Item ip : possibles) {
1043 Item i = ip;
1044
1045 int d = (int) Math.sqrt(Math.pow(Math.abs(i.getX() - x), 2)
1046 + Math.pow(Math.abs(i.getY() - y), 2));
1047
1048 if (d < distance) {
1049 distance = d;
1050
1051 // dots take precedence over lines
1052 /**
1053 * TODO: Remove line\dot specification
1054 */
1055 if ((!(closest instanceof Dot && i instanceof Line))
1056 && (!(closest instanceof Text && i instanceof Line)))
1057 closest = ip;
1058
1059 }
1060
1061 }
1062
1063 return closest;
1064 }
1065
1066 public static Item getCurrentItem() {
1067 return onItem(DisplayIO.getCurrentFrame(), DisplayIO.getMouseX(),
1068 DisplayIO.getMouseY());
1069 }
1070
1071 public static List<Item> getCurrentItems() {
1072
1073 List<Item> enclosure = getEnclosingDots();
1074 if (enclosure == null || enclosure.size() == 0)
1075 return null;
1076
1077 List<Item> enclosed = getItemsEnclosedBy(DisplayIO.getCurrentFrame(),
1078 enclosure.get(0).getEnclosedShape());
1079 for (Item i : enclosed) {
1080 if (!enclosure.contains(i))
1081 i.setSelectedMode(Item.SelectedMode.None);
1082 }
1083
1084 return enclosed;
1085 }
1086
1087 public static List<Item> getEnclosingDots() {
1088 // update enclosed shapes
1089 Frame current = DisplayIO.getCurrentFrame();
1090 List<Item> items = current.getItems();
1091
1092 ArrayList<Item> used = new ArrayList<Item>(0);
1093 ArrayList<Item> seen = new ArrayList<Item>(0);
1094
1095 for (Item i : items)
1096 if (i.isLineEnd()) {
1097 if (i.isEnclosed() && !seen.contains(i)) {
1098 Polygon p = i.getEnclosedShape();
1099 if (p
1100 .contains(DisplayIO.getMouseX(), DisplayIO
1101 .getMouseY())) {
1102
1103 used.add(i);
1104 seen.addAll(i.getEnclosingDots());
1105 }
1106 }
1107 }
1108
1109 if (used.size() == 0)
1110 return null;
1111
1112 // if there is only one possibility, return it
1113 if (used.size() == 1) {
1114 return used.get(0).getEnclosingDots();
1115 // otherwise, determine which polygon is closest to the cursor
1116 } else {
1117 Collections.sort(used, new Comparator<Item>() {
1118 public int compare(Item d1, Item d2) {
1119 Polygon p1 = d1.getEnclosedShape();
1120 Polygon p2 = d2.getEnclosedShape();
1121
1122 int closest = Integer.MAX_VALUE;
1123 int close2 = Integer.MAX_VALUE;
1124
1125 int mouseX = DisplayIO.getMouseX();
1126 int mouseY = DisplayIO.getMouseY();
1127
1128 for (int i = 0; i < p1.npoints; i++) {
1129 int diff = Math.abs(p1.xpoints[i] - mouseX)
1130 + Math.abs(p1.ypoints[i] - mouseY);
1131 int diff2 = Integer.MAX_VALUE;
1132
1133 if (i < p2.npoints)
1134 diff2 = Math.abs(p2.xpoints[i] - mouseX)
1135 + Math.abs(p2.ypoints[i] - mouseY);
1136
1137 if (diff < Math.abs(closest)) {
1138 close2 = closest;
1139 closest = diff;
1140 } else if (diff < Math.abs(close2))
1141 close2 = diff;
1142
1143 if (diff2 < Math.abs(closest)) {
1144 close2 = closest;
1145 closest = -diff2;
1146 } else if (diff2 < Math.abs(close2))
1147 close2 = diff2;
1148 }
1149
1150 if (closest > 0 && close2 > 0)
1151 return -10;
1152
1153 if (closest < 0 && close2 < 0)
1154 return 10;
1155
1156 if (closest > 0)
1157 return -10;
1158
1159 return 10;
1160 }
1161
1162 });
1163
1164 return used.get(0).getEnclosingDots();
1165 }
1166 }
1167
1168 public static List<Item> getItemsEnclosedBy(Frame frame, Polygon poly) {
1169 List<Item> contained = frame.getItemsWithin(poly);
1170
1171 ArrayList<Item> results = new ArrayList<Item>(contained.size());
1172
1173 // check for correct permissions
1174 for (Item item : contained) {
1175 // if the item is on the frame
1176 if (item.getParent() == frame || item.getParent() == null) {
1177 item.Permission = Item.PERMISSION_FULL;
1178 results.add(item);
1179 // otherwise, it must be on an overlay frame
1180 } else {
1181 for (Overlay overlay : frame.getOverlays())
1182 if (overlay.Frame == item.getParent()) {
1183 item.Permission = overlay.Level;
1184 results.add(item);
1185 break;
1186 }
1187 }
1188
1189 }
1190
1191 return results;
1192 }
1193
1194 /**
1195 * Fills the given Frame with default profile tags
1196 */
1197 public static void CreateDefaultProfile(Frame profile) {
1198 Text title = profile.getTitle();
1199 title.setText("Profile Frame");
1200 title.setSize(50);
1201 title.setFontStyle("Bold");
1202 title.setFamily("SansSerif");
1203 title.setColor(Color.BLUE);
1204 title.setPosition(25, 50);
1205
1206 int spacing = 50;
1207 final int intialYPos = 75;
1208 int xPos = 75;
1209 int yPos = intialYPos;
1210
1211 yPos += spacing;
1212 profile.addText(xPos, yPos, "@HomeFrame: " + profile.getFrameName(),
1213 null, profile.getFrameName());
1214 yPos += spacing;
1215 String defaultFrameName = profile.getFramesetName() + "0";
1216 profile.addText(xPos, yPos, "@DefaultFrame: " + defaultFrameName, null,
1217 defaultFrameName);
1218 yPos += spacing;
1219
1220 profile.addText(xPos, yPos, "@InitialWidth: "
1221 + UserSettings.InitialWidth, null);
1222 yPos += spacing;
1223
1224 profile.addText(xPos, yPos, "@InitialHeight: "
1225 + UserSettings.InitialHeight, null);
1226 yPos += spacing;
1227
1228 Text t = profile.addText(xPos, yPos, "@ItemTemplate", null);
1229 t.setColor(Color.black);
1230
1231 yPos += spacing;
1232 t = profile.addText(xPos, yPos, "@AnnotationTemplate", null);
1233 t.setColor(Color.magenta);
1234
1235 yPos += spacing;
1236 t = profile.addText(xPos, yPos, "@CommentTemplate", null);
1237 t.setColor(Item.COLOR_WHEEL[3]);
1238
1239 xPos = 600;
1240 yPos = intialYPos;
1241
1242 // Iterate through the help folder and add links
1243 File helpDirectory = new File(FrameIO.HELP_PATH);
1244 if (helpDirectory != null) {
1245 File[] helpFramesets = helpDirectory.listFiles();
1246 if (helpFramesets != null) {
1247
1248 // Add the title for the help index
1249 Text help = profile.addText(xPos, yPos, "Expeditee Help", null);
1250 help.setSize(25);
1251 help.setFontStyle("Bold");
1252 help.setFamily("SansSerif");
1253 help.setColor(Item.COLOR_WHEEL[3]);
1254
1255 xPos = 625;
1256
1257 for (File helpFrameset : helpFramesets) {
1258 String framesetName = helpFrameset.getName();
1259 Frame indexFrame = FrameIO.LoadFrame(framesetName+ '1');
1260 // Look through the folder for help index pages
1261 if (indexFrame != null
1262 && ItemUtils.FindTag(indexFrame.getItems(),
1263 "@HelpIndex") != null) {
1264 yPos += spacing;
1265 t = profile.addText(xPos, yPos, indexFrame
1266 .getFramesetName(), null);
1267 t.setLink(indexFrame.getFrameName());
1268 }
1269 }
1270 }
1271 }
1272
1273 // FrameUtils.Parse(profile);
1274 FrameIO.SaveFrame(profile);
1275 }
1276}
Note: See TracBrowser for help on using the repository browser.