source: trunk/org/expeditee/gui/FrameUtils.java@ 4

Last change on this file since 4 was 4, checked in by davidb, 16 years ago

Starting source code to Expeditee

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