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

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

resetHomeFrame action wipes and rebuilds home frame, startpages home button now works for all users

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