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

Last change on this file since 161 was 161, checked in by ra33, 16 years ago

Adding calculation stuff...

File size: 19.7 KB
Line 
1package org.expeditee.actions;
2
3import java.awt.Color;
4import java.awt.Image;
5import java.awt.image.BufferedImage;
6import java.awt.image.VolatileImage;
7import java.io.File;
8import java.io.FileNotFoundException;
9import java.io.IOException;
10import java.lang.reflect.Method;
11import java.text.NumberFormat;
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.List;
15import java.util.Observable;
16import java.util.Observer;
17
18import javax.imageio.ImageIO;
19
20import org.expeditee.gui.AttributeUtils;
21import org.expeditee.gui.AttributeValuePair;
22import org.expeditee.gui.DisplayIO;
23import org.expeditee.gui.Frame;
24import org.expeditee.gui.FrameGraphics;
25import org.expeditee.gui.FrameIO;
26import org.expeditee.gui.FrameMouseActions;
27import org.expeditee.gui.MessageBay;
28import org.expeditee.gui.TimeKeeper;
29import org.expeditee.items.Item;
30import org.expeditee.items.Text;
31import org.expeditee.simple.ExpediteeJEP;
32import org.expeditee.stats.CometStats;
33import org.expeditee.stats.SessionStats;
34import org.expeditee.stats.StatsLogger;
35import org.expeditee.stats.TreeStats;
36import org.nfunk.jep.Node;
37import org.nfunk.jep.Variable;
38
39/**
40 * A list of miscellaneous Actions and Actions specific to Expeditee
41 *
42 */
43public class Misc {
44 // private static final int FRAME_FILE_FONT_SIZE = 10;
45
46 /**
47 * Causes the system to beep
48 */
49 public static void Beep() {
50 java.awt.Toolkit.getDefaultToolkit().beep();
51 }
52
53 /**
54 * Forces a repaint of the current Frame
55 */
56 public static void Display() {
57 FrameGraphics.ForceRepaint();
58 }
59
60 /**
61 * Restores the current frame to the last saved version currently on the
62 * hard disk
63 */
64 public static void Restore() {
65 FrameIO.Reload();
66 // MessageBay.displayMessage("Restoration complete.");
67 }
68
69 /**
70 * Toggles AudienceMode on or off
71 */
72 public static void ToggleAudienceMode() {
73 FrameGraphics.ToggleAudienceMode();
74 }
75
76 /**
77 * Toggles TwinFrames mode on or off
78 */
79 public static void ToggleTwinFramesMode() {
80 DisplayIO.ToggleTwinFrames();
81 }
82
83 /**
84 * If the given Item is a Text Item, then the text of the Item is
85 * interpreted as actions, if not this method does nothing.
86 *
87 * @param current
88 * The Item to read the Actions from
89 */
90 public static void RunCurrentItem(Item current) {
91 if (current instanceof Text) {
92 List<String> actions = ((Text) current).getTextList();
93 for (String action : actions) {
94 if (!action.equalsIgnoreCase("runcurrentitem")) {
95 Actions.PerformAction(DisplayIO.getCurrentFrame(), current,
96 action);
97 }
98 }
99 } else {
100 MessageBay.errorMessage("Item must be a text item.");
101 }
102 }
103
104 /**
105 * Prompts the user to confirm deletion of the current Frame, and deletes if
106 * the user chooses. After deletion this action calls back(), to ensure the
107 * deleted frame is not still being shown
108 *
109 */
110 public static void DeleteFrame() {
111 Frame toDelete = DisplayIO.getCurrentFrame();
112 String deletedFrame = toDelete.getName();
113 String deletedFrameNameLowercase = deletedFrame.toLowerCase();
114 String errorMessage = "Error deleting " + deletedFrame;
115 try {
116 String deletedFrameName = FrameIO.DeleteFrame(toDelete);
117 if (deletedFrameName != null) {
118 DisplayIO.Back();
119 // Remove any links on the previous frame to the one being
120 // deleted
121 Frame current = DisplayIO.getCurrentFrame();
122 for (Item i : current.getItems())
123 if (i.getLink() != null
124 && i.getAbsoluteLink().toLowerCase().equals(
125 deletedFrameNameLowercase)) {
126 i.setLink(null);
127 }
128 MessageBay.displayMessage(deletedFrame + " renamed "
129 + deletedFrameName);
130 // FrameGraphics.Repaint();
131 return;
132 }
133 } catch (IOException ioe) {
134 if (ioe.getMessage() != null)
135 errorMessage += ". " + ioe.getMessage();
136 } catch (SecurityException se) {
137 if (se.getMessage() != null)
138 errorMessage += ". " + se.getMessage();
139 } catch (Exception e) {
140 e.printStackTrace();
141 }
142 MessageBay.errorMessage(errorMessage);
143 }
144
145 /**
146 * Loads the Frame linked to by the given Item. The first Item on the Frame
147 * that is not the title or name is then placed on the cursor. If the given
148 * Item has no link, or no item is found then this is a no-op.
149 *
150 * @param current
151 * The Item that links to the Frame that the Item will be loaded
152 * from.
153 */
154 public static void GetItemFromChildFrame(Item current) {
155 getFromChildFrame(current, false);
156 }
157
158 /**
159 * Loads the Frame linked to by the given Item. The first Text Item on the
160 * Frame that is not the title or name is then placed on the cursor. If the
161 * given Item has no link, or no item is found then this is a no-op.
162 *
163 * @param current
164 * The Item that links to the Frame that the Item will be loaded
165 * from.
166 */
167 public static void GetTextFromChildFrame(Item current) {
168 getFromChildFrame(current, true);
169 }
170
171 private static void getFromChildFrame(Item current, boolean textOnly) {
172 Item item = getFirstBodyItemOnChildFrame(current, textOnly);
173 // if no item was found
174 if (item == null) {
175 return;
176 }
177
178 // copy the item and switch
179 item = item.copy();
180 item.setPosition(DisplayIO.getMouseX(), FrameMouseActions.getY());
181 item.setParent(null);
182
183 FrameMouseActions.pickup(item);
184 FrameGraphics.Repaint();
185 }
186
187 /**
188 * Sets the given Item to have the Given Color. Color can be null (for
189 * default)
190 *
191 * @param toChange
192 * The Item to set the Color.
193 * @param toUse
194 * The Color to give the Item.
195 */
196 public static void SetCurrentItemBackgroundColor(Item toChange, Color toUse) {
197 if (toChange == null)
198 return;
199
200 toChange.setBackgroundColor(toUse);
201 FrameGraphics.Repaint();
202 }
203
204 /**
205 * Sets the given Item to have the Given Color. Color can be null (for
206 * default)
207 *
208 * @param toChange
209 * The Item to set the Color.
210 * @param toUse
211 * The Color to give the Item.
212 */
213 public static void SetCurrentItemColor(Item toChange, Color toUse) {
214 if (toChange == null)
215 return;
216
217 toChange.setColor(toUse);
218 FrameGraphics.Repaint();
219 }
220
221 /**
222 * Creates a new Text Object containing general statistics for the current
223 * session. The newly created Text Object is then attached to the cursor via
224 * FrameMouseActions.pickup(Item)
225 */
226 public static void GetSessionStats() {
227 attachStatsToCursor(SessionStats.getCurrentStats());
228 }
229
230 /**
231 * Creates a new Text Object containing statistics for the current tree.
232 */
233 public static void GetCometStats(Frame frame) {
234 TimeKeeper timer = new TimeKeeper();
235 MessageBay.displayMessage("Computing comet stats...");
236
237 CometStats cometStats = new CometStats(frame);
238 attachStatsToCursor(cometStats.toString());
239 MessageBay.overwriteMessage("Comet stats time: "
240 + timer.getElapsedStringSeconds());
241 }
242
243 public static void GetTreeStats(Frame frame) {
244 TimeKeeper timer = new TimeKeeper();
245 MessageBay.displayMessage("Computing tree stats...");
246
247 TreeStats treeStats = new TreeStats(frame);
248 attachStatsToCursor(treeStats.toString());
249 MessageBay.overwriteMessage("Tree stats time: "
250 + timer.getElapsedStringSeconds());
251 }
252
253 /**
254 * Creates a text item and attaches it to the cursor.
255 *
256 * @param itemText
257 * the text to attach to the cursor
258 */
259 public static void attachStatsToCursor(String itemText) {
260 SessionStats.CreatedText();
261 Frame current = DisplayIO.getCurrentFrame();
262 Item text = current.getStatsTextItem(itemText);
263 FrameMouseActions.pickup(text);
264 FrameGraphics.Repaint();
265 }
266
267 public static void attachTextToCursor(String itemText) {
268 SessionStats.CreatedText();
269 Frame current = DisplayIO.getCurrentFrame();
270 Item text = current.getTextItem(itemText);
271 FrameMouseActions.pickup(text);
272 FrameGraphics.Repaint();
273 }
274
275 /**
276 * Creates a new Text Object containing statistics for moving, deleting and
277 * creating items in the current session. The newly created Text Object is
278 * then attached to the cursor via FrameMouseActions.pickup(Item)
279 */
280 public static void GetItemStats() {
281 attachStatsToCursor(SessionStats.getItemStats());
282 }
283
284 /**
285 * Creates a new Text Object containing statistics for the time between
286 * events triggered by the user through mouse clicks and key presses. The
287 * newly created Text Object is then attached to the cursor via
288 * FrameMouseActions.pickup(Item)
289 */
290 public static void GetEventStats() {
291 attachStatsToCursor(SessionStats.getEventStats());
292 }
293
294 /**
295 * Creates a new Text Object containing the contents of the current frames
296 * file.
297 */
298 public static void GetCurrentFrameFile() {
299 Frame current = DisplayIO.getCurrentFrame();
300 attachStatsToCursor(FrameIO.ForceSaveFrame(current));
301 }
302
303 /**
304 * Creates a new Text Object containing the available fonts.
305 */
306 public static void getFontNames() {
307
308 Collection<String> availableFonts = Actions.getFonts().values();
309 StringBuilder fontsList = new StringBuilder();
310 for (String s : availableFonts) {
311 fontsList.append(s).append(Text.LINE_SEPARATOR);
312 }
313 fontsList.deleteCharAt(fontsList.length() - 1);
314
315 attachStatsToCursor(fontsList.toString());
316 }
317
318 public static void getUnicodeCharacters(int start, int finish) {
319 if (start < 0 && finish < 0) {
320 throw new RuntimeException("Parameters must be non negative");
321 }
322 // Swap the start and finish if they are inthe wrong order
323 if (start > finish) {
324 start += finish;
325 finish = start - finish;
326 start = start - finish;
327 }
328 StringBuilder charList = new StringBuilder();
329 int count = 0;
330 charList.append(String.format("Unicode block 0x%x - 0x%x", start,
331 finish));
332 System.out.println();
333 // charList.append("Unicode block: ").append(String.format(format,
334 // args))
335 for (char i = (char) start; i < (char) finish; i++) {
336 if (Character.isDefined(i)) {
337 if (count++ % 64 == 0)
338 charList.append(Text.LINE_SEPARATOR);
339 charList.append(Character.valueOf(i));
340 }
341 }
342 attachTextToCursor(charList.toString());
343 }
344
345 /**
346 * Gets a single block of Unicode characters.
347 *
348 * @param start
349 * the start of the block
350 */
351 public static void getUnicodeCharacters(int start) {
352 getUnicodeCharacters(start, start + 256);
353 }
354
355 public static void getMathSymbols() {
356 getUnicodeCharacters('\u2200', '\u2300');
357 }
358
359 /**
360 * Resets the statistics back to zero.
361 */
362 public static void ResetStats() {
363 StatsLogger.WriteStatsFile();
364 SessionStats.resetStats();
365 }
366
367 /**
368 * Loads a frame with the given name and saves it as a JPEG image.
369 *
370 * @param framename
371 * The name of the Frame to save
372 */
373 public static void JpegFrame(String framename) {
374 ImageFrame(framename, "JPEG");
375 }
376
377 /**
378 * Saves the current frame as a JPEG image. This is the same as calling
379 * JpegFrame(currentFrame.getName())
380 */
381 public static void JpegFrame() {
382 ImageFrame(DisplayIO.getCurrentFrame().getName(), "JPEG");
383 }
384
385 public static void JPGFrame() {
386 JpegFrame();
387 }
388
389 /**
390 * Loads a frame with the given name and saves it as a PNG image.
391 *
392 * @param framename
393 * The name of the Frame to save
394 */
395 public static void PNGFrame(String framename) {
396 ImageFrame(framename, "PNG");
397 }
398
399 /**
400 * Saves the current frame as a PNG image. This is the same as calling
401 * PNGFrame(currentFrame.getName())
402 */
403 public static void PNGFrame() {
404 ImageFrame(DisplayIO.getCurrentFrame().getName(), "PNG");
405 }
406
407 public static String SaveImage(BufferedImage screen, String format,
408 String directory, String fileName) {
409 // Check if we need to append the suffix
410 if (fileName.indexOf('.') < 0)
411 fileName += "." + format.toLowerCase();
412
413 try {
414 // set up the file for output
415 String fullFileName = directory + fileName;
416 File out = new File(fullFileName);
417 if (!out.getParentFile().exists())
418 out.mkdirs();
419
420 // If the image is successfully written out return the fileName
421 if (ImageIO.write(screen, format, out))
422 return fileName;
423
424 } catch (Exception e) {
425 e.printStackTrace();
426 }
427 return null;
428 }
429
430 public static String ImageFrame(Frame frame, String format, String directory) {
431 assert (frame != null);
432
433 FrameGraphics.UpdateBuffer(frame, false);
434
435 BufferedImage screen = null;
436 Image frameBuffer = frame.getBuffer();
437 if (frame.getBuffer() instanceof BufferedImage) {
438 screen = (BufferedImage) frameBuffer;
439 } else if (frameBuffer instanceof VolatileImage) {
440 screen = ((VolatileImage) frameBuffer).getSnapshot();
441 } else {
442 assert (false);
443 }
444 return SaveImage(screen, format, directory, frame.getExportFileName());
445 }
446
447 /**
448 * Saves the Frame with the given Framename as an image of the given format.
449 *
450 * @param framename
451 * The name of the Frame to save as an image
452 * @param format
453 * The Image format to use (i.e. "PNG", "BMP", etc)
454 */
455 public static void ImageFrame(String framename, String format) {
456 Frame loaded = FrameIO.LoadFrame(framename);
457
458 // if the frame was loaded successfully
459 if (loaded != null) {
460 String path = FrameIO.IMAGES_PATH;
461 String frameName = ImageFrame(loaded, format, path);
462 if (frameName != null)
463 MessageBay.displayMessage("Frame successfully saved to " + path
464 + frameName);
465 else
466 MessageBay.errorMessage("Could not find image writer for "
467 + format + " format");
468 // if the frame was not loaded successfully, alert the user
469 } else
470 MessageBay.displayMessage("Frame '" + framename
471 + "' could not be found.");
472 }
473
474 /**
475 * Displays a message in the message box area.
476 *
477 * @param message
478 * the message to display
479 */
480 public static void MessageLn(String message) {
481 MessageBay.displayMessage(message);
482 }
483
484 public static void MessageLn2(String message, String message2) {
485 MessageBay.displayMessage(message + " " + message2);
486 }
487
488 public static void CopyFile(String existingFile, String newFileName) {
489 try {
490 // TODO is there a built in method which will do this faster?
491
492 MessageBay.displayMessage("Copying file " + existingFile + " to "
493 + newFileName + "...");
494 FrameIO.copyFile(existingFile, newFileName);
495 MessageBay.displayMessage("File copied successfully");
496 } catch (FileNotFoundException e) {
497 MessageBay.displayMessage("Error opening file: " + existingFile);
498 } catch (Exception e) {
499 MessageBay.displayMessage("File could not be copied");
500 }
501 }
502
503 /**
504 * Runs two methods alternatively a specified number of times and reports on
505 * the time spent running each method.
506 *
507 * @param fullMethodNameA
508 * @param fullMethodNameB
509 * @param repsPerTest
510 * the number of time each method is run per test
511 * @param tests
512 * the number of tests to conduct
513 *
514 */
515 public static void CompareMethods(String fullMethodNameA,
516 String fullMethodNameB, int repsPerTest, int tests) {
517 try {
518 String classNameA = getClassName(fullMethodNameA);
519 String classNameB = getClassName(fullMethodNameB);
520 String methodNameA = getMethodName(fullMethodNameA);
521 String methodNameB = getMethodName(fullMethodNameB);
522
523 Class classA = Class.forName(classNameA);
524 Class classB = Class.forName(classNameB);
525 Method methodA = classA.getDeclaredMethod(methodNameA,
526 new Class[] {});
527 Method methodB = classB.getDeclaredMethod(methodNameB,
528 new Class[] {});
529 TimeKeeper timeKeeper = new TimeKeeper();
530 long timeA = 0;
531 long timeB = 0;
532 // Run the tests
533 for (int i = 0; i < tests; i++) {
534 // Test methodA
535 timeKeeper.restart();
536 for (int j = 0; j < repsPerTest; j++) {
537 methodA.invoke((Object) null, new Object[] {});
538 }
539 timeA += timeKeeper.getElapsedMillis();
540 timeKeeper.restart();
541 // Test methodB
542 for (int j = 0; j < repsPerTest; j++) {
543 methodB.invoke((Object) null, new Object[] {});
544 }
545 timeB += timeKeeper.getElapsedMillis();
546 }
547
548 float aveTimeA = timeA * 1000F / repsPerTest / tests;
549 float aveTimeB = timeB * 1000F / repsPerTest / tests;
550 // Display Results
551 MessageBay.displayMessage("Average Execution Time");
552 MessageBay.displayMessage(methodNameA + ": "
553 + TimeKeeper.Formatter.format(aveTimeA) + "us");
554 MessageBay.displayMessage(methodNameB + ": "
555 + TimeKeeper.Formatter.format(aveTimeB) + "us");
556 } catch (Exception e) {
557 MessageBay.errorMessage(e.getClass().getSimpleName() + ": "
558 + e.getMessage());
559 }
560 }
561
562 public static String getClassName(String fullMethodName) {
563 assert (fullMethodName != null);
564 assert (fullMethodName.length() > 0);
565 int lastPeriod = fullMethodName.lastIndexOf('.');
566 if (lastPeriod > 0 && lastPeriod < fullMethodName.length() - 1)
567 return fullMethodName.substring(0, lastPeriod);
568 throw new RuntimeException("Invalid method name: " + fullMethodName);
569 }
570
571 public static String getMethodName(String methodName) {
572 assert (methodName != null);
573 assert (methodName.length() > 0);
574 int lastPeriod = methodName.lastIndexOf('.');
575 if (lastPeriod > 0 && lastPeriod < methodName.length() - 1)
576 return methodName.substring(1 + lastPeriod);
577 throw new RuntimeException("Invalid method name: " + methodName);
578 }
579
580 /**
581 * Loads the Frame linked to by the given Item. The first Item on the Frame
582 * that is not the title or name is then placed on the current frame. The
583 * item that was clicked on is placed on the frame it was linked to and the
584 * link is switched to the item from the child frame. If the given Item has
585 * no link, or no item is found then this is a no-op.
586 *
587 * @param current
588 * The Item that links to the Frame that the Item will be loaded
589 * from.
590 */
591 public static void SwapItemWithItemOnChildFrame(Item current) {
592 Item item = getFirstBodyItemOnChildFrame(current, false);
593 // if no item was found
594 if (item == null) {
595 return;
596 }
597
598 // swap the items parents
599 Frame parentFrame = current.getParent();
600 Frame childFrame = item.getParent();
601 current.setParent(childFrame);
602 item.setParent(parentFrame);
603
604 // swap the items on the frames
605 parentFrame.removeItem(current);
606 childFrame.removeItem(item);
607 parentFrame.addItem(item);
608 childFrame.addItem(current);
609
610 // swap the items links
611 item.setActions(current.getAction());
612 item.setLink(childFrame.getName());
613 current.setLink(parentFrame.getName());
614 // current.setLink(null);
615 current.setActions(null);
616
617 FrameGraphics.Repaint();
618 }
619
620 private static Item getFirstBodyItemOnChildFrame(Item current,
621 boolean textOnly) {
622 // the item must link to a frame
623 if (current.getLink() == null) {
624 MessageBay
625 .displayMessage("Cannot get item from child - this item has no link");
626 return null;
627 }
628
629 Frame child = FrameIO.LoadFrame(current.getAbsoluteLink());
630
631 // if the frame could not be loaded
632 if (child == null) {
633 MessageBay.errorMessage("Could not load child frame.");
634 return null;
635 }
636
637 // find the first non-title and non-name item
638 List<Item> body = new ArrayList<Item>();
639 if (textOnly)
640 body.addAll(child.getBodyTextItems(false));
641 else
642 body.addAll(child.getItems());
643 Item item = null;
644
645 for (Item i : body)
646 if (i != child.getTitleItem() && !i.isAnnotation()) {
647 item = i;
648 break;
649 }
650
651 // if no item was found
652 if (item == null) {
653 MessageBay.displayMessage("No item found to copy");
654 return null;
655 }
656
657 return item;
658 }
659
660 public static void calculate(Frame frame, Item toCalculate) {
661 if (toCalculate instanceof Text) {
662 Text text = (Text) toCalculate;
663 ExpediteeJEP myParser = new ExpediteeJEP();
664 myParser.addVariables(frame);
665 String linkedFrame = toCalculate.getAbsoluteLink();
666 if (linkedFrame != null) {
667 myParser.addVariables(FrameIO.LoadFrame(linkedFrame));
668 }
669 myParser.addObserver();
670
671 // Do the calculation
672 Node node = myParser.parseExpression(text.getText());
673 if (node == null) {
674 MessageBay.errorMessage(myParser.getErrorInfo().replace("\n",
675 ""));
676 } else {
677 String result = myParser.getResult();
678 if (result == null) {
679 MessageBay.errorMessage(myParser.getErrorInfo().replace("\n",
680 ""));
681 } else {
682 text.setText(result);
683 if (text.isFloating()) {
684 text.setPosition(FrameMouseActions.MouseX,
685 FrameMouseActions.MouseY);
686 FrameMouseActions.resetOffset();
687 }
688 }
689 }
690
691 }
692 }
693}
Note: See TracBrowser for help on using the repository browser.