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

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

Fix image and widget panning

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