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

Last change on this file since 625 was 625, checked in by csl14, 10 years ago

Added startBrowserSession action - Go Browsing button on exploratory search start page creates new browsing session

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