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

Last change on this file since 529 was 529, checked in by jts21, 11 years ago

Add Password widget and profile tag for proxy settings

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