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

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

added back and forward buttons to exploratory search pages

File size: 41.3 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}
Note: See TracBrowser for help on using the repository browser.