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

Last change on this file since 813 was 812, checked in by davidb, 10 years ago

When setting an anchor left/rightr/top/bottom on a Dot, it now looks for connected items that are constrained to the the same x (vertical) or y (horizontal) value, and sets the anchor status of that item to be the same.

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