source: trunk/src/org/expeditee/actions/Misc.java@ 582

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

Don't use XML formatting since it's overly verbose

File size: 40.9 KB
Line 
1package org.expeditee.actions;
2
3import java.awt.Color;
4import java.awt.Desktop;
5import java.awt.Image;
6import java.awt.Polygon;
7import java.awt.image.BufferedImage;
8import java.awt.image.VolatileImage;
9import java.io.File;
10import java.io.FileNotFoundException;
11import java.io.IOException;
12import java.io.StringWriter;
13import java.io.Writer;
14import java.lang.reflect.Method;
15import java.util.ArrayList;
16import java.util.Collection;
17import java.util.LinkedList;
18import java.util.List;
19
20import javax.imageio.ImageIO;
21import javax.script.ScriptEngine;
22import javax.script.ScriptEngineManager;
23
24import org.expeditee.gui.AttributeUtils;
25import org.expeditee.gui.Browser;
26import org.expeditee.gui.DisplayIO;
27import org.expeditee.gui.Frame;
28import org.expeditee.gui.FrameGraphics;
29import org.expeditee.gui.FrameIO;
30import org.expeditee.gui.FrameMouseActions;
31import org.expeditee.gui.FrameUtils;
32import org.expeditee.gui.FreeItems;
33import org.expeditee.gui.MessageBay;
34import org.expeditee.gui.Reminders;
35import org.expeditee.gui.TimeKeeper;
36import org.expeditee.importer.FrameDNDTransferHandler;
37import org.expeditee.io.JavaWriter;
38import org.expeditee.io.WebParser;
39import org.expeditee.io.Exp2Writer;
40import org.expeditee.io.flowlayout.XGroupItem;
41import org.expeditee.items.Item;
42import org.expeditee.items.ItemUtils;
43import org.expeditee.items.Line;
44import org.expeditee.items.Text;
45import org.expeditee.items.widgets.InteractiveWidget;
46import org.expeditee.items.widgets.JfxBrowser;
47import org.expeditee.math.ExpediteeJEP;
48import org.expeditee.simple.SString;
49import org.expeditee.stats.CometStats;
50import org.expeditee.stats.DocumentStatsFast;
51import org.expeditee.stats.SessionStats;
52import org.expeditee.stats.StatsLogger;
53import org.expeditee.stats.TreeStats;
54import org.nfunk.jep.Node;
55import org.nfunk.jep.ParseException;
56
57
58
59/**
60 * A list of miscellaneous Actions and Actions specific to Expeditee
61 *
62 */
63public class Misc {
64
65 /**
66 * Causes the system to beep
67 */
68 public static void beep() {
69 java.awt.Toolkit.getDefaultToolkit().beep();
70 }
71
72 /**
73 * Returns an Item located at the specified position.
74 * kgas1 - 23/01/2012
75 * @param x
76 * @param y
77 * @return
78 */
79 public static Item getItemAtPosition(int x, int y, Frame f)
80 {
81 Frame current = f;
82 List<Item> allItems = current.getItems();
83
84 for(Item i : allItems)
85 {
86 if(i.getX() == x && i.getY() == y)
87 return i;
88 }
89
90 return null;
91 }
92
93 /**
94 * Returns an item containing a specified piece of data.
95 * kgas1 - 7/06/2012
96 * @param s
97 * @param f
98 * @return
99 */
100 public static Item getItemContainingData(String s, Frame f){
101
102 Frame current = f;
103
104 List<Item> allItems = current.getItems();
105
106
107 for(Item i : allItems){
108
109
110 if(i.getData() != null && i.getData().size() > 0){
111 if(i.getData().contains(s)){
112 return i;
113 }
114 }
115 }
116
117 return null;
118 }
119
120 /**
121 * Forces a repaint of the current Frame
122 */
123 public static void display() {
124 FrameGraphics.refresh(false);
125 }
126
127 public static String getWindowSize() {
128 return Browser.getWindows()[0].getSize().toString();
129 }
130
131 /**
132 * Restores the current frame to the last saved version currently on the
133 * hard disk
134 */
135 public static void restore() {
136 FrameIO.Reload();
137 // MessageBay.displayMessage("Restoration complete.");
138 }
139
140 /**
141 * Toggles AudienceMode on or off
142 */
143 public static void toggleAudienceMode() {
144 FrameGraphics.ToggleAudienceMode();
145 }
146
147 /**
148 * Toggles TwinFrames mode on or off
149 */
150 public static void toggleTwinFramesMode() {
151 DisplayIO.ToggleTwinFrames();
152 }
153
154 /**
155 * If the given Item is a Text Item, then the text of the Item is
156 * interpreted as actions, if not this method does nothing.
157 *
158 * @param current
159 * The Item to read the Actions from
160 */
161 public static void runItem(Item current) throws Exception {
162 if (current instanceof Text) {
163 List<String> actions = ((Text) current).getTextList();
164 for (String action : actions) {
165 if (!action.equalsIgnoreCase("runitem")) {
166 Actions.PerformAction(DisplayIO.getCurrentFrame(), current,
167 action);
168 }
169 }
170 } else {
171 MessageBay.errorMessage("Item must be a text item.");
172 }
173 }
174
175 /**
176 * Prompts the user to confirm deletion of the current Frame, and deletes if
177 * the user chooses. After deletion this action calls back(), to ensure the
178 * deleted frame is not still being shown
179 *
180 */
181 public static void DeleteFrame(Frame toDelete) {
182 String deletedFrame = toDelete.getName();
183 String deletedFrameNameLowercase = deletedFrame.toLowerCase();
184 String errorMessage = "Error deleting " + deletedFrame;
185 try {
186 String deletedFrameName = FrameIO.DeleteFrame(toDelete);
187 if (deletedFrameName != null) {
188 DisplayIO.Back();
189 // Remove any links on the previous frame to the one being
190 // deleted
191 Frame current = DisplayIO.getCurrentFrame();
192 for (Item i : current.getItems())
193 if (i.getLink() != null
194 && i.getAbsoluteLink().toLowerCase().equals(
195 deletedFrameNameLowercase)) {
196 i.setLink(null);
197 }
198 MessageBay.displayMessage(deletedFrame + " renamed "
199 + deletedFrameName);
200 // FrameGraphics.Repaint();
201 return;
202 }
203 } catch (IOException ioe) {
204 if (ioe.getMessage() != null)
205 errorMessage += ". " + ioe.getMessage();
206 } catch (SecurityException se) {
207 if (se.getMessage() != null)
208 errorMessage += ". " + se.getMessage();
209 } catch (Exception e) {
210 e.printStackTrace();
211 }
212 MessageBay.errorMessage(errorMessage);
213 }
214
215 /**
216 * Loads the Frame linked to by the given Item. The first Item on the Frame
217 * that is not the title or name is then placed on the cursor. If the given
218 * Item has no link, or no item is found then this is a no-op.
219 *
220 * @param current
221 * The Item that links to the Frame that the Item will be loaded
222 * from.
223 */
224 public static Item GetItemFromChildFrame(Item current) {
225 return getFromChildFrame(current, false);
226 }
227
228 public static void GetItemsFromChildFrame(Item current) {
229 getItemsFromChildFrame(current, false);
230 }
231
232 /**
233 * Loads the Frame linked to by the given Item. The first Text Item on the
234 * Frame that is not the title or name is then placed on the cursor. If the
235 * given Item has no link, or no item is found then this is a no-op.
236 *
237 * @param current
238 * The Item that links to the Frame that the Item will be loaded
239 * from.
240 */
241 public static Item GetTextFromChildFrame(Item current) {
242 return getFromChildFrame(current, true);
243 }
244
245 private static Item getFromChildFrame(Item current, boolean textOnly) {
246 Item item = getFirstBodyItemOnChildFrame(current, textOnly);
247 // if no item was found
248 if (item != null) {
249 // copy the item and switch
250 item = item.copy();
251 item.setPosition(DisplayIO.getMouseX(), FrameMouseActions.getY());
252 }
253 return item;
254 }
255
256 private static void getItemsFromChildFrame(Item current, boolean textOnly) {
257 Collection<Item> items = getItemsOnChildFrame(current, textOnly);
258 // if no item was found
259 if (items == null || items.size() == 0) {
260 return;
261 }
262
263 // copy the item and switch
264 Collection<Item> copies = ItemUtils.CopyItems(items);
265 Item first = items.iterator().next();
266 float deltaX = DisplayIO.getMouseX() - first.getX();
267 float deltaY = FrameMouseActions.getY() - first.getY();
268 for (Item i : copies) {
269 if (i.isVisible())
270 i.setXY(i.getX() + deltaX, i.getY() + deltaY);
271 i.setParent(null);
272 }
273 FrameMouseActions.pickup(copies);
274 FrameGraphics.Repaint();
275 }
276
277 /**
278 * Sets the given Item to have the Given Color. Color can be null (for
279 * default)
280 *
281 * @param toChange
282 * The Item to set the Color.
283 * @param toUse
284 * The Color to give the Item.
285 */
286 public static void SetItemBackgroundColor(Item toChange, Color toUse) {
287 if (toChange == null)
288 return;
289
290 toChange.setBackgroundColor(toUse);
291 FrameGraphics.Repaint();
292 }
293
294 /**
295 * Sets the given Item to have the Given Color. Color can be null (for
296 * default)
297 *
298 * @param toChange
299 * The Item to set the Color.
300 * @param toUse
301 * The Color to give the Item.
302 */
303 public static void SetItemColor(Item toChange, Color toUse) {
304 if (toChange == null)
305 return;
306
307 toChange.setColor(toUse);
308 FrameGraphics.Repaint();
309 }
310
311 /**
312 * Creates a new Text Object containing general statistics for the current
313 * session. The newly created Text Object is then attached to the cursor via
314 * FrameMouseActions.pickup(Item)
315 */
316 public static void GetSessionStats() {
317 attachStatsToCursor(SessionStats.getCurrentStats());
318 }
319
320 /**
321 * Creates a new Text Object containing statistics for the current tree.
322 */
323 public static String GetCometStats(Frame frame) {
324 TimeKeeper timer = new TimeKeeper();
325 MessageBay.displayMessage("Computing comet stats...");
326 CometStats cometStats = new CometStats(frame);
327 String result = cometStats.toString();
328 MessageBay.overwriteMessage("Comet stats time: "
329 + timer.getElapsedStringSeconds());
330 return result;
331 }
332
333 public static String GetTreeStats(Frame frame) {
334 TimeKeeper timer = new TimeKeeper();
335 MessageBay.displayMessage("Computing tree stats...");
336
337 TreeStats treeStats = new TreeStats(frame);
338 String result = treeStats.toString();
339 MessageBay.overwriteMessage("Tree stats time: "
340 + timer.getElapsedStringSeconds());
341 return result;
342
343 }
344
345 public static String GetDocumentStats(Frame frame) {
346 TimeKeeper timer = new TimeKeeper();
347 MessageBay.displayMessage("Computing document stats...");
348 FrameIO.ForceSaveFrame(frame);
349 DocumentStatsFast docStats = new DocumentStatsFast(frame.getName(),
350 frame.getTitle());
351 String result = docStats.toString();
352
353 MessageBay.overwriteMessage("Document stats time: "
354 + timer.getElapsedStringSeconds());
355 return result;
356
357 }
358
359 /**
360 * Creates a text item and attaches it to the cursor.
361 *
362 * @param itemText
363 * the text to attach to the cursor
364 */
365 public static void attachStatsToCursor(String itemText) {
366 SessionStats.CreatedText();
367 Frame current = DisplayIO.getCurrentFrame();
368 Item text = current.getStatsTextItem(itemText);
369 FrameMouseActions.pickup(text);
370 FrameGraphics.Repaint();
371 }
372
373 public static void attachTextToCursor(String itemText) {
374 SessionStats.CreatedText();
375 Frame current = DisplayIO.getCurrentFrame();
376 Item text = current.getTextItem(itemText);
377 FrameMouseActions.pickup(text);
378 FrameGraphics.Repaint();
379 }
380
381 /**
382 * Creates a new Text Object containing statistics for moving, deleting and
383 * creating items in the current session. The newly created Text Object is
384 * then attached to the cursor via FrameMouseActions.pickup(Item)
385 */
386 public static String getItemStats() {
387 return SessionStats.getItemStats();
388 }
389
390 /**
391 * Creates a new Text Object containing statistics for the time between
392 * events triggered by the user through mouse clicks and key presses. The
393 * newly created Text Object is then attached to the cursor via
394 * FrameMouseActions.pickup(Item)
395 */
396 public static String getEventStats() {
397 return SessionStats.getEventStats();
398 }
399
400 /**
401 * Creates a new Text Object containing the contents of the current frames
402 * file.
403 */
404 public static String getFrameFile(Frame frame) {
405 return FrameIO.ForceSaveFrame(frame);
406 }
407
408 /**
409 * Creates a new Text Object containing the available fonts.
410 */
411 public static String getFontNames() {
412 Collection<String> availableFonts = Actions.getFonts().values();
413 StringBuilder fontsList = new StringBuilder();
414 for (String s : availableFonts) {
415 fontsList.append(s).append(Text.LINE_SEPARATOR);
416 }
417 fontsList.deleteCharAt(fontsList.length() - 1);
418
419 return fontsList.toString();
420 }
421
422 public static String getUnicodeCharacters(int start, int finish) {
423 if (start < 0 && finish < 0) {
424 throw new RuntimeException("Parameters must be non negative");
425 }
426 // Swap the start and finish if they are inthe wrong order
427 if (start > finish) {
428 start += finish;
429 finish = start - finish;
430 start = start - finish;
431 }
432 StringBuilder charList = new StringBuilder();
433 int count = 0;
434 charList.append(String.format("Unicode block 0x%x - 0x%x", start,
435 finish));
436 System.out.println();
437 // charList.append("Unicode block: ").append(String.format(format,
438 // args))
439 for (char i = (char) start; i < (char) finish; i++) {
440 if (Character.isDefined(i)) {
441 if (count++ % 64 == 0)
442 charList.append(Text.LINE_SEPARATOR);
443 charList.append(Character.valueOf(i));
444 }
445 }
446 return charList.toString();
447 }
448
449 /**
450 * Gets a single block of Unicode characters.
451 *
452 * @param start
453 * the start of the block
454 */
455 public static String getUnicodeCharacters(int start) {
456 return getUnicodeCharacters(start, start + 256);
457 }
458
459 public static String getMathSymbols() {
460 return getUnicodeCharacters('\u2200', '\u2300');
461 }
462
463 /**
464 * Resets the statistics back to zero.
465 */
466 public static void repaint() {
467 StatsLogger.WriteStatsFile();
468 SessionStats.resetStats();
469 }
470
471 /**
472 * Loads a frame with the given name and saves it as a JPEG image.
473 *
474 * @param framename
475 * The name of the Frame to save
476 */
477 public static void jpegFrame(String framename) {
478 ImageFrame(framename, "JPEG");
479 }
480
481 /**
482 * Saves the current frame as a JPEG image. This is the same as calling
483 * JpegFrame(currentFrame.getName())
484 */
485 public static void jpegFrame() {
486 ImageFrame(DisplayIO.getCurrentFrame().getName(), "JPEG");
487 }
488
489 public static void jpgFrame() {
490 jpegFrame();
491 }
492
493 /**
494 * Loads a frame with the given name and saves it as a PNG image.
495 *
496 * @param framename
497 * The name of the Frame to save
498 */
499 public static void PNGFrame(String framename) {
500 ImageFrame(framename, "PNG");
501 }
502
503 /**
504 * Saves the current frame as a PNG image. This is the same as calling
505 * PNGFrame(currentFrame.getName())
506 */
507 public static void PNGFrame(Frame frame) {
508 ImageFrame(frame.getName(), "PNG");
509 }
510
511 public static String SaveImage(BufferedImage screen, String format,
512 String directory, String fileName) {
513 String suffix = "." + format.toLowerCase();
514 String shortFileName = fileName;
515 // Check if we need to append the suffix
516 if (fileName.indexOf('.') < 0)
517 fileName += suffix;
518 else
519 shortFileName = fileName.substring(0, fileName.length() - suffix.length());
520
521 try {
522 int count = 2;
523 // set up the file for output
524 File out = new File(directory + fileName);
525 while (out.exists()) {
526 fileName = shortFileName + "_" + count++ + suffix;
527 out = new File(directory + fileName);
528 }
529
530 if (!out.getParentFile().exists())
531 out.mkdirs();
532
533 // If the image is successfully written out return the fileName
534 if (ImageIO.write(screen, format, out))
535 return fileName;
536
537 } catch (Exception e) {
538 e.printStackTrace();
539 }
540 return null;
541 }
542
543 public static String ImageFrame(Frame frame, String format, String directory) {
544 assert (frame != null);
545
546 Image oldBuffer = frame.getBuffer();
547 frame.setBuffer(null);
548 // Jpeg only works properly with volitile frames
549 // Png transparency only works with bufferedImage form
550 Image frameBuffer = FrameGraphics.getBuffer(frame, false, format
551 .equalsIgnoreCase("jpeg"));
552 // Make sure overlay stuff doesnt disapear on the frame visible on the
553 // screen
554 frame.setBuffer(oldBuffer);
555 BufferedImage screen = null;
556
557 if (frameBuffer instanceof VolatileImage) {
558 // If its the current frame it will be a volitive image
559 screen = ((VolatileImage) frameBuffer).getSnapshot();
560 } else {
561 assert (frameBuffer instanceof BufferedImage);
562 screen = (BufferedImage) frameBuffer;
563 }
564 return SaveImage(screen, format, directory, frame.getExportFileName());
565 }
566
567 /**
568 * Saves the Frame with the given Framename as an image of the given format.
569 *
570 * @param framename
571 * The name of the Frame to save as an image
572 * @param format
573 * The Image format to use (i.e. "PNG", "BMP", etc)
574 */
575 public static void ImageFrame(String framename, String format) {
576 Frame loaded = FrameIO.LoadFrame(framename);
577
578 // if the frame was loaded successfully
579 if (loaded != null) {
580 String path = FrameIO.EXPORTS_DIR;
581 String frameName = ImageFrame(loaded, format, path);
582 if (frameName != null)
583 MessageBay.displayMessage("Frame successfully saved to " + path
584 + frameName);
585 else
586 MessageBay.errorMessage("Could not find image writer for "
587 + format + " format");
588 // if the frame was not loaded successfully, alert the user
589 } else {
590 MessageBay.displayMessage("Frame '" + framename
591 + "' could not be found.");
592 }
593 }
594
595 public static void MessageLn(Item message) {
596 if (message instanceof Text)
597 MessageBay.displayMessage((Text) message);
598 }
599
600 /**
601 * Displays a message in the message box area.
602 *
603 * @param message
604 * the message to display
605 */
606 public static void MessageLn(String message) {
607 MessageBay.displayMessage(message);
608 }
609
610 public static void MessageLn2(String message, String message2) {
611 MessageBay.displayMessage(message + " " + message2);
612 }
613
614 public static void CopyFile(String existingFile, String newFileName) {
615 try {
616 // TODO is there a built in method which will do this faster?
617
618 MessageBay.displayMessage("Copying file " + existingFile + " to "
619 + newFileName + "...");
620 FrameIO.copyFile(existingFile, newFileName);
621 MessageBay.displayMessage("File copied successfully");
622 } catch (FileNotFoundException e) {
623 MessageBay.displayMessage("Error opening file: " + existingFile);
624 } catch (Exception e) {
625 MessageBay.displayMessage("File could not be copied");
626 }
627 }
628
629 /**
630 * Runs two methods alternatively a specified number of times and reports on
631 * the time spent running each method.
632 *
633 * @param fullMethodNameA
634 * @param fullMethodNameB
635 * @param repsPerTest
636 * the number of time each method is run per test
637 * @param tests
638 * the number of tests to conduct
639 *
640 */
641 public static void CompareMethods(String fullMethodNameA,
642 String fullMethodNameB, int repsPerTest, int tests) {
643 try {
644 String classNameA = getClassName(fullMethodNameA);
645 String classNameB = getClassName(fullMethodNameB);
646 String methodNameA = getMethodName(fullMethodNameA);
647 String methodNameB = getMethodName(fullMethodNameB);
648
649 Class<?> classA = Class.forName(classNameA);
650 Class<?> classB = Class.forName(classNameB);
651 Method methodA = classA.getDeclaredMethod(methodNameA,
652 new Class[] {});
653 Method methodB = classB.getDeclaredMethod(methodNameB,
654 new Class[] {});
655 TimeKeeper timeKeeper = new TimeKeeper();
656 long timeA = 0;
657 long timeB = 0;
658 // Run the tests
659 for (int i = 0; i < tests; i++) {
660 // Test methodA
661 timeKeeper.restart();
662 for (int j = 0; j < repsPerTest; j++) {
663 methodA.invoke((Object) null, new Object[] {});
664 }
665 timeA += timeKeeper.getElapsedMillis();
666 timeKeeper.restart();
667 // Test methodB
668 for (int j = 0; j < repsPerTest; j++) {
669 methodB.invoke((Object) null, new Object[] {});
670 }
671 timeB += timeKeeper.getElapsedMillis();
672 }
673
674 float aveTimeA = timeA * 1000F / repsPerTest / tests;
675 float aveTimeB = timeB * 1000F / repsPerTest / tests;
676 // Display Results
677 MessageBay.displayMessage("Average Execution Time");
678 MessageBay.displayMessage(methodNameA + ": "
679 + TimeKeeper.Formatter.format(aveTimeA) + "us");
680 MessageBay.displayMessage(methodNameB + ": "
681 + TimeKeeper.Formatter.format(aveTimeB) + "us");
682 } catch (Exception e) {
683 MessageBay.errorMessage(e.getClass().getSimpleName() + ": "
684 + e.getMessage());
685 }
686 }
687
688 public static String getClassName(String fullMethodName) {
689 assert (fullMethodName != null);
690 assert (fullMethodName.length() > 0);
691 int lastPeriod = fullMethodName.lastIndexOf('.');
692 if (lastPeriod > 0 && lastPeriod < fullMethodName.length() - 1)
693 return fullMethodName.substring(0, lastPeriod);
694 throw new RuntimeException("Invalid method name: " + fullMethodName);
695 }
696
697 public static String getMethodName(String methodName) {
698 assert (methodName != null);
699 assert (methodName.length() > 0);
700 int lastPeriod = methodName.lastIndexOf('.');
701 if (lastPeriod > 0 && lastPeriod < methodName.length() - 1)
702 return methodName.substring(1 + lastPeriod);
703 throw new RuntimeException("Invalid method name: " + methodName);
704 }
705
706 /**
707 * Loads the Frame linked to by the given Item. The first Item on the Frame
708 * that is not the title or name is then placed on the current frame. The
709 * item that was clicked on is placed on the frame it was linked to and the
710 * link is switched to the item from the child frame. If the given Item has
711 * no link, or no item is found then this is a no-op.
712 *
713 * @param current
714 * The Item that links to the Frame that the Item will be loaded
715 * from.
716 */
717 public static void SwapItemWithItemOnChildFrame(Item current) {
718 Item item = getFirstBodyItemOnChildFrame(current, false);
719 // if no item was found
720 if (item == null) {
721 return;
722 }
723
724 // swap the items parents
725 Frame parentFrame = current.getParent();
726 Frame childFrame = item.getParent();
727 current.setParent(childFrame);
728 item.setParent(parentFrame);
729
730 // swap the items on the frames
731 parentFrame.removeItem(current);
732 childFrame.removeItem(item);
733 parentFrame.addItem(item);
734 childFrame.addItem(current);
735
736 // swap the items links
737 item.setActions(current.getAction());
738 item.setLink(childFrame.getName());
739 current.setLink(parentFrame.getName());
740 // current.setLink(null);
741 current.setActions(null);
742
743 FrameGraphics.Repaint();
744 }
745
746 private static Item getFirstBodyItemOnChildFrame(Item current,
747 boolean textOnly) {
748 // the item must link to a frame
749 if (current.getLink() == null) {
750 MessageBay
751 .displayMessage("Cannot get item from child - this item has no link");
752 return null;
753 }
754
755 Frame child = FrameIO.LoadFrame(current.getAbsoluteLink());
756
757 // if the frame could not be loaded
758 if (child == null) {
759 MessageBay.errorMessage("Could not load child frame.");
760 return null;
761 }
762
763 // find the first non-title and non-name item
764 List<Item> body = new ArrayList<Item>();
765 if (textOnly)
766 body.addAll(child.getBodyTextItems(false));
767 else
768 body.addAll(child.getItems());
769 Item item = null;
770
771 for (Item i : body)
772 if (i != child.getTitleItem() && !i.isAnnotation()) {
773 item = i;
774 break;
775 }
776
777 // if no item was found
778 if (item == null) {
779 MessageBay.displayMessage("No item found to copy");
780 return null;
781 }
782
783 return item;
784 }
785
786 private static Collection<Item> getItemsOnChildFrame(Item current,
787 boolean textOnly) {
788 // the item must link to a frame
789 if (current.getLink() == null) {
790 MessageBay
791 .displayMessage("Cannot get item from child - this item has no link");
792 return null;
793 }
794 Frame child = FrameIO.LoadFrame(current.getAbsoluteLink());
795
796 // if the frame could not be loaded
797 if (child == null) {
798 MessageBay.errorMessage("Could not load child frame.");
799 return null;
800 }
801
802 // find the first non-title and non-name item
803 Collection<Item> body = new ArrayList<Item>();
804 if (textOnly)
805 body.addAll(child.getBodyTextItems(false));
806 else
807 body.addAll(child.getItems());
808
809 return body;
810 }
811
812 public static void calculate(Frame frame, Item toCalculate) {
813 if (toCalculate instanceof Text) {
814 Text text = (Text) toCalculate;
815 ExpediteeJEP myParser = new ExpediteeJEP();
816 myParser.addVariables(frame);
817 String linkedFrame = toCalculate.getAbsoluteLink();
818 if (linkedFrame != null) {
819 myParser.addVariables(FrameIO.LoadFrame(linkedFrame));
820 }
821 myParser.resetObserver();
822
823 // Do the calculation
824 String formulaFullCase = text.getText().replace('\n', ' ');
825 String formula = formulaFullCase.toLowerCase();
826
827 try {
828 Node node = myParser.parse(formula);
829 Object result = myParser.evaluate(node);
830 text.setText(result.toString(), true);
831 text.setFormula(formulaFullCase);
832 if (text.isFloating()) {
833 text.setPosition(FrameMouseActions.MouseX,
834 FrameMouseActions.MouseY);
835 FrameMouseActions.resetOffset();
836 } else {
837 text.getParentOrCurrentFrame().change();
838 }
839 } catch (ParseException e) {
840 MessageBay.errorMessage("Parse error "
841 + e.getMessage().replace("\n", ""));
842 } catch (Exception e) {
843 MessageBay.errorMessage("evaluation error "
844 + e.getMessage().replace("\n", ""));
845 e.printStackTrace();
846 }
847 }
848 }
849
850 /**
851 * Attach an item to the cursor.
852 *
853 * @param item
854 */
855 public static void attachToCursor(Item item) {
856 item.setParent(null);
857 FrameMouseActions.pickup(item);
858 FrameGraphics.Repaint();
859 }
860
861 public static void attachToCursor(Collection<Item> items) {
862 for (Item i : items) {
863 i.setParent(null);
864 i.invalidateAll();
865 }
866 FrameMouseActions.pickup(items);
867 // TODO figure out why this isnt repainting stuff immediately
868 // All of text item doesnt repaint until the cursor is moved
869 FrameGraphics.requestRefresh(true);
870 }
871
872 public static void importFiles(Item item) {
873 List<File> files = new LinkedList<File>();
874 for (String s : item.getText().split("\\s+")) {
875 File file = new File(s.trim());
876 if (file.exists()) {
877 files.add(file);
878 }
879 }
880 try {
881 FrameDNDTransferHandler.getInstance().importFileList(files,
882 FrameMouseActions.getPosition());
883 } catch (Exception e) {
884 }
885 }
886
887 public static void importFile(Item item) {
888 File file = new File(item.getText().trim());
889 if (file.exists()) {
890 try {
891 FrameDNDTransferHandler.getInstance().importFile(file,
892 FrameMouseActions.getPosition());
893 } catch (Exception e) {
894 e.printStackTrace();
895 }
896 }
897 }
898
899 public static Item createPolygon(Item item, int sides) {
900 if (item instanceof Text) {
901 try {
902 SString s = new SString(item.getText());
903 sides = s.integerValue().intValue();
904 } catch (NumberFormatException e) {
905 }
906 }
907
908 if (sides < 3) {
909 MessageBay.errorMessage("Shapes must have at least 3 sides");
910 }
911 double angle = -(180 - ((sides - 2) * 180.0F) / sides);
912 double curAngle = 0;
913 double size = 50F;
914 if (item.isLineEnd() && item.getLines().size() > 0) {
915 item = item.getLines().get(0);
916 }
917 // Use line length to determine the size of the shape
918 if (item instanceof Line) {
919 size = ((Line) item).getLength();
920 }
921
922 float curX = FrameMouseActions.MouseX;
923 float curY = FrameMouseActions.MouseY;
924
925 Collection<Item> newItems = new LinkedList<Item>();
926 Item[] d = new Item[sides];
927 // create dots
928 Frame current = DisplayIO.getCurrentFrame();
929 for (int i = 0; i < d.length; i++) {
930 d[i] = current.createDot();
931 newItems.add(d[i]);
932 d[i].setPosition(curX, curY);
933 curX += (float) (Math.cos((curAngle) * Math.PI / 180.0) * size);
934 curY += (float) (Math.sin((curAngle) * Math.PI / 180.0) * size);
935
936 curAngle += angle;
937 }
938 // create lines
939 for (int i = 1; i < d.length; i++) {
940 newItems.add(new Line(d[i - 1], d[i], current.getNextItemID()));
941 }
942 newItems.add(new Line(d[d.length - 1], d[0], current.getNextItemID()));
943
944 current.addAllItems(newItems);
945 if (item instanceof Text) {
946 for (Item i : item.getAllConnected()) {
947 if (i instanceof Line) {
948 item = i;
949 break;
950 }
951 }
952 }
953
954 Color newColor = item.getColor();
955 if (newColor != null) {
956 d[0].setColor(item.getColor());
957 if (item instanceof Text && item.getBackgroundColor() != null) {
958 d[0].setFillColor(item.getBackgroundColor());
959 } else {
960 d[0].setFillColor(item.getFillColor());
961 }
962 }
963 float newThickness = item.getThickness();
964 if (newThickness > 0) {
965 d[0].setThickness(newThickness);
966 }
967
968 ItemUtils.EnclosedCheck(newItems);
969 FrameGraphics.refresh(false);
970
971 return d[0];
972 }
973
974 public static void StopReminder() {
975 Reminders.stop();
976 }
977
978 public static void print(String file) {
979 try {
980 if (Browser._theBrowser.isMinimumVersion6()) {
981 if (Desktop.isDesktopSupported()) {
982 Desktop.getDesktop().print(new File(file));
983 }
984 }
985 } catch (Exception e) {
986 MessageBay.errorMessage("Printing error: " + e.getMessage());
987 }
988 }
989
990 public static int wordCount(String paragraph) {
991 return paragraph.trim().split("\\s+").length + 1;
992 }
993
994 public static int wordCount(Frame frame) {
995 int count = 0;
996
997 for (Text t : frame.getBodyTextItems(false)) {
998 count += wordCount(t.getText());
999 }
1000
1001 return count;
1002 }
1003
1004 public static void moveToPublic(Frame frame) {
1005 FrameIO.moveFrameset(frame.getFramesetName(), FrameIO.PUBLIC_PATH);
1006 }
1007
1008 public static void moveToPrivate(Frame frame) {
1009 FrameIO.moveFrameset(frame.getFramesetName(), FrameIO.FRAME_PATH);
1010 }
1011
1012 /**
1013 * Returns the value of a specified item attribute.
1014 *
1015 * @param item
1016 * from which to extract the value
1017 * @param attribute
1018 * name of an items attribute
1019 * @return the value of the attribute
1020 */
1021 public static String extract(Item item, String attribute) {
1022 return AttributeUtils.getAttribute(item, attribute);
1023 }
1024
1025 /**
1026 * Launches items.widgets.Browser and uses Text item as URL.
1027 * @param text Text item which passes contents as URL for browser.
1028 * @throws Exception
1029 */
1030 public static void startLoboBrowser(Item text) throws Exception {
1031 if (!(text instanceof Text)) {
1032 MessageBay.errorMessage("Must be a text item.");
1033 return;
1034 }
1035 if(text.getLink() != null) {
1036 MessageBay.errorMessage("Text item cannot have link.");
1037 return;
1038 }
1039
1040 FreeItems.getInstance().clear(); // remove url text from cursor
1041
1042 Text wt = new Text("@iw:org.expeditee.items.widgets.Browser"); // create new text item for browser widget
1043 wt.setParent(DisplayIO.getCurrentFrame()); // set parent of text source for InteractiveWidget.createWidget()
1044 wt.setXY(FrameMouseActions.getX(), FrameMouseActions.getY());
1045 // create widget from text item
1046 org.expeditee.items.widgets.Browser browser = (org.expeditee.items.widgets.Browser) InteractiveWidget.createWidget(wt);
1047
1048 if(FreeItems.textOnlyAttachedToCursor()) { // navigates to url specified by the text item
1049 browser.navigate(text.getText());
1050 } else {
1051 browser.navigate("http://www.waikato.ac.nz");
1052 }
1053
1054 FrameMouseActions.pickup(browser.getItems()); // attach browser widget to mouse
1055 }
1056
1057 /**
1058 * Text item becomes link to new frame containing items.widgets.Browser and uses Text item as URL for browser.
1059 * @param text Text item which passes contents as URL for browser and becomes link to the browser's new frame.
1060 * @throws Exception
1061 */
1062 public static void startLoboBrowserNewFrame(Item text) throws Exception {
1063 if (!(text instanceof Text)) {
1064 MessageBay.errorMessage("Must be a text item.");
1065 return;
1066 }
1067 if(text.getLink() != null) { // text item can't already have a link
1068 MessageBay.errorMessage("Text item already has link.");
1069 return;
1070 }
1071
1072 // Create new frame and text item for browser widget and parse created frame; loads browser widget
1073 Frame frame = FrameIO.CreateNewFrame(text);
1074 frame.addText(0, 50, "@iw:org.expeditee.items.widgets.Browser", null);
1075 FrameUtils.Parse(frame);
1076
1077 for(InteractiveWidget iw : frame.getInteractiveWidgets()) { // may be other widgets on frame
1078 if(iw instanceof org.expeditee.items.widgets.Browser) {
1079 // Set browser to 'full screen'
1080 iw.setSize(-1, -1, -1, -1, Browser._theBrowser.getWidth(), Browser._theBrowser.getHeight()
1081 - MessageBay.MESSAGE_BUFFER_HEIGHT - 80);
1082
1083 // If there is a text item attached to cursor use it as url for browser
1084 if(FreeItems.textOnlyAttachedToCursor()) {
1085 text.setLink("" + frame.getNumber());
1086 ((org.expeditee.items.widgets.Browser)iw).navigate(text.getText());
1087 } else {
1088 // Navigate to www.waikato.ac.nz by default if no url supplied and create new text item to be the link
1089 ((org.expeditee.items.widgets.Browser)iw).navigate("http://www.waikato.ac.nz");
1090 Text t = new Text("http://www.waikato.ac.nz");
1091 t.setParent(DisplayIO.getCurrentFrame()); // set parent of text source for InteractiveWidget.createWidget()
1092 t.setXY(FrameMouseActions.getX(), FrameMouseActions.getY());
1093 t.setLink("" + frame.getNumber()); // link url text to new browser frame
1094 FrameMouseActions.pickup(t); // Attach new text link to cursor
1095 }
1096 }
1097 }
1098
1099 FrameIO.SaveFrame(frame); // save frame to disk
1100 }
1101
1102 /**
1103 * Launches items.widgets.JfxBrowser and uses Text item as URL.
1104 * Note: currently doesn't work
1105 * @param text Text item which passes contents as URL for browser.
1106 * @throws Exception
1107 */
1108 public static void startBrowser(Item text) throws Exception {
1109 if (!(text instanceof Text)) {
1110 MessageBay.errorMessage("Must be a text item.");
1111 return;
1112 }
1113 if(text.getLink() != null) {
1114 MessageBay.errorMessage("Text item cannot have link.");
1115 return;
1116 }
1117
1118 Text wt = new Text("@iw:org.expeditee.items.widgets.JfxBrowser"); // create new text item for browser widget
1119
1120 if(FreeItems.textOnlyAttachedToCursor()) { // navigates to url specified by the text item
1121 wt.appendText(":" + text.getText());
1122 } else {
1123 wt.appendText(":http://www.waikato.ac.nz");
1124 }
1125
1126 FreeItems.getInstance().clear(); // remove url text from cursor
1127
1128 wt.setParent(DisplayIO.getCurrentFrame()); // set parent of text source for InteractiveWidget.createWidget()
1129 wt.setXY(FrameMouseActions.getX(), FrameMouseActions.getY());
1130 // create widget from text item
1131 JfxBrowser browser = (JfxBrowser) InteractiveWidget.createWidget(wt);
1132
1133 FrameMouseActions.pickup(browser.getItems()); // attach browser widget to mouse
1134 }
1135
1136 /**
1137 * Text item becomes link to new frame containing items.widgets.JfxBrowser and uses Text item as URL for browser.
1138 * Note: currently doesn't work
1139 * @param text Text item which passes contents as URL for browser and becomes link to the browser's new frame.
1140 * @throws Exception
1141 */
1142 public static void startBrowserNewFrame(Item text) throws Exception {
1143 if (!(text instanceof Text)) {
1144 MessageBay.errorMessage("Must be a text item.");
1145 return;
1146 }
1147 if(text.getLink() != null) { // text item can't already have a link
1148 MessageBay.errorMessage("Text item already has link.");
1149 return;
1150 }
1151
1152 // If no text with url is passed to action create a new text item with http://www.waikato.ac.nz for a default url
1153 if(!FreeItems.textOnlyAttachedToCursor()) {
1154 text = DisplayIO.getCurrentFrame().addText(FrameMouseActions.getX(), FrameMouseActions.getY(),
1155 "http://www.waikato.ac.nz", null);
1156 text.setParent(DisplayIO.getCurrentFrame()); // set parent of text source for InteractiveWidget.createWidget()
1157 FrameMouseActions.pickup(text); // Attach new text link to cursor
1158 }
1159
1160 // Create JfxBrowser widget on a new frame
1161 Frame frame = FrameIO.CreateNewFrame(text); // create new frame for browser
1162 text.setLink("" + frame.getNumber()); // link this text item to new frame
1163 // Create widget via text annotation
1164 Text wt = frame.addText(0, JfxBrowser.VERT_OFFSET, "@iw: org.expeditee.items.widgets.JfxBrowser "+ (Browser._theBrowser.getWidth() - JfxBrowser.HORZ_CROP)+
1165 " " + (Browser._theBrowser.getHeight() - JfxBrowser.VERT_CROP) + " : ".concat(text.getText()), null);
1166 InteractiveWidget.createWidget(wt);
1167
1168 FrameIO.SaveFrame(frame); // save frame to disk
1169 }
1170
1171 private static boolean startWidget(String name) throws Exception {
1172 String fullName = Actions.getClassName(name);
1173 if(fullName == null) {
1174 return false;
1175 }
1176 MessageBay.displayMessage("Creating new \"" + fullName + "\"");
1177
1178 FreeItems.getInstance().clear();
1179 Text wt = new Text("@iw:" + fullName); // create new text item for browser widget
1180 wt.setParent(DisplayIO.getCurrentFrame()); // set parent of text source for InteractiveWidget.createWidget()
1181 wt.setXY(FrameMouseActions.getX(), FrameMouseActions.getY()); // move to the mouse cursor
1182 InteractiveWidget widget = InteractiveWidget.createWidget(wt);
1183 FrameMouseActions.pickup(widget.getItems());
1184
1185 return true;
1186 }
1187
1188 private static void runUnknown(String command) throws Exception {
1189 if(startWidget(command)) {
1190 return;
1191 }
1192
1193 Actions.PerformAction(DisplayIO.getCurrentFrame(), null, command);
1194 }
1195
1196 public static void run(String command) throws Exception {
1197 if(command == null) {
1198 MessageBay.warningMessage("Please provide a command to run");
1199 return;
1200 }
1201 int firstSpace = command.indexOf(" ");
1202 if(firstSpace == -1) {
1203 runUnknown(command);
1204 return;
1205 }
1206 String argLower = command.toLowerCase();
1207 String name = argLower.substring(0, firstSpace).trim(); // first word
1208 String args = argLower.substring(firstSpace).trim(); // remainder after first word
1209 if(name == "action" || name == "agent") {
1210 if(args.length() > 0) {
1211 Actions.PerformAction(DisplayIO.getCurrentFrame(), null, args);
1212 } else {
1213 MessageBay.displayMessage("Please specify an action/agent name");
1214 }
1215 } else if(name == "widget") {
1216 if(args.length() > 0) {
1217 if(!startWidget(args)) {
1218 MessageBay.displayMessage("Widget \"" + name + "\" does not exist");
1219 }
1220 } else {
1221 MessageBay.displayMessage("Please specify a widget name");
1222 }
1223 } else {
1224 runUnknown(command);
1225 }
1226 }
1227
1228 public static void run(Item item) throws Exception {
1229 if(item == null) {
1230 MessageBay.warningMessage("Please provide a command to run");
1231 return;
1232 }
1233 run(((Text)item).getText());
1234 }
1235
1236 // Javascript stuff. Probably completely pointless since there is already a Javascript class,
1237 // but I couldn't get the existing Javascript engine to work for some reason
1238 private static ScriptEngineManager sem = new ScriptEngineManager();
1239 private static ScriptEngine se = sem.getEngineByMimeType("application/javascript");
1240
1241 private static class JSParser {
1242 private List<Frame> seen = new LinkedList<Frame>();
1243 private StringBuffer sb = new StringBuffer();
1244
1245 public JSParser(Frame frame, boolean followLinks) throws Exception {
1246 parseScript(frame, followLinks);
1247 }
1248
1249 private void parseScript(Frame frame, boolean followLinks) throws Exception {
1250
1251 if(frame == null) {
1252 return;
1253 }
1254
1255 // make sure we don't get into an infinite loop
1256 // TODO: find a smarter way to do this that allows reusing frames but still stops infinite loops?
1257 seen.add(frame);
1258
1259 // get all items on the frame
1260 List<Item> y_ordered_items = (List<Item>)frame.getItems();
1261 // remove the title item
1262 y_ordered_items.remove(frame.getTitleItem());
1263
1264 XGroupItem toplevel_xgroup = new XGroupItem(frame,y_ordered_items);
1265 // ... following on from Steps 1 and 2 in the Constructor in XGroupItem ...
1266
1267 // Step 3: Reposition any 'out-of-flow' XGroupItems
1268 toplevel_xgroup.repositionOutOfFlowGroups(toplevel_xgroup);
1269
1270 // Step 4: Now add in the remaining (nested) XGroupItems
1271 List<XGroupItem> grouped_item_list = toplevel_xgroup.getGroupedItemList();
1272 toplevel_xgroup.mapInXGroupItemsRecursive(grouped_item_list);
1273
1274 // Finally, retrieve linear list of all Items, (ordered, Y by X, allowing for overlap, nested-boxing, and arrow flow)
1275 List<Item> overlapping_y_ordered_items = toplevel_xgroup.getYXOverlappingItemList();
1276
1277 // Loop through the items looking for code and links to new frames
1278 for(Item i : overlapping_y_ordered_items) {
1279 if(followLinks && i.hasLink()) {
1280 Frame child = i.getChild();
1281 if(child != null && !seen.contains(child)) {
1282 this.parseScript(child, true);
1283 }
1284 }
1285 if(i instanceof Text && !i.isAnnotation()) {
1286 sb.append(((Text)i).getText() + "\n");
1287 }
1288 }
1289 }
1290
1291 public String getScript() {
1292 System.out.println("*****\n" + sb.toString() + "\n*****");
1293 return sb.toString();
1294 }
1295 }
1296
1297 public static void runJSFrame(Frame frame) throws Exception {
1298 se.eval(new JSParser(frame, true).getScript());
1299 }
1300
1301 public static void runJSItem(Item item) throws Exception {
1302 // if the user clicked on the action without an item on their cursor
1303 if(item.hasAction()) {
1304 for(String s : item.getAction()) {
1305 if(!s.equalsIgnoreCase("runJSItem")) {
1306 return;
1307 }
1308 }
1309 item.getParent().getNonAnnotationText(true);
1310 // Check if there is an arrow pointing from the action to a link
1311 // Seemed like a cool idea before I made it, but the arrows kind of get in the way when trying to click on the action
1312 Collection<Item> itemsWithin = item.getParentOrCurrentFrame().getItemsWithin(item.getPolygon());
1313 for(Item i : itemsWithin) {
1314 if(i instanceof Line && itemsWithin.contains(((Line)i).getStartItem())) {
1315 Polygon p = ((Line)i).getEndItem().getPolygon();
1316 for(Item j : ((Line)i).getEndItem().getParent().getAllItems()) {
1317 if(p.intersects(j.getArea().getBounds2D()) && j instanceof Text && j.hasLink()) {
1318 Frame child = j.getChild();
1319 if(child == null) {
1320 continue;
1321 }
1322 runJSFrame(child);
1323 return;
1324 }
1325 }
1326 }
1327 }
1328
1329 runJSFrame(item.getParentOrCurrentFrame());
1330 return;
1331 }
1332 Frame frame = item.getChild();
1333 if(frame == null) {
1334 frame = FrameIO.CreateNewFrame(item);
1335 item.setLink("" + frame.getNumber());
1336 frame.addText(100, 100, "print(\"test\");", null);
1337 FrameIO.SaveFrame(frame);
1338 } else {
1339 runJSFrame(frame);
1340 }
1341 }
1342
1343 public static void parsePage(Item text) throws Exception {
1344 if (!(text instanceof Text) || !FreeItems.textOnlyAttachedToCursor()) {
1345 MessageBay.errorMessage("Must provide a text item.");
1346 return;
1347 }
1348 if(text.getLink() != null) { // text item can't already have a link
1349 MessageBay.errorMessage("Text item already has link.");
1350 return;
1351 }
1352
1353 // Create JfxBrowser widget on a new frame
1354 Frame frame = FrameIO.CreateNewFrame(text); // create new frame for browser
1355 text.setLink("" + frame.getNumber()); // link this text item to new frame
1356 frame.addText(100, 100, "test", null);
1357
1358 WebParser.parseURL(text.getText(), frame);
1359 System.out.println(text.getText());
1360 }
1361
1362 public static void testWriter(Frame frame) {
1363 try {
1364 new Exp2Writer().writeFrame(frame);
1365 } catch (Exception e) {
1366 e.printStackTrace();
1367 }
1368 }
1369}
Note: See TracBrowser for help on using the repository browser.