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

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

Fixed some stuff with the SIMPLE debugger
Refactored the way the interpretor works to make it easier to give better error messages.

File size: 18.6 KB
Line 
1package org.expeditee.actions;
2
3import java.awt.Color;
4import java.awt.Dimension;
5import java.awt.GraphicsEnvironment;
6import java.awt.Image;
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.sql.Time;
14import java.util.ArrayList;
15import java.util.List;
16
17import javax.imageio.ImageIO;
18
19import org.expeditee.gui.DisplayIO;
20import org.expeditee.gui.Frame;
21import org.expeditee.gui.FrameGraphics;
22import org.expeditee.gui.FrameIO;
23import org.expeditee.gui.FrameMouseActions;
24import org.expeditee.gui.TimeKeeper;
25import org.expeditee.io.Logger;
26import org.expeditee.items.Item;
27import org.expeditee.items.Text;
28import org.expeditee.stats.SessionStats;
29import org.expeditee.stats.StatsLogger;
30
31/**
32 * A list of miscellaneous KMS Actions and Actions specific to Expeditee
33 *
34 */
35public class Misc {
36 private static final int FRAME_FILE_FONT_SIZE = 10;
37
38 /**
39 * Causes the system to beep
40 */
41 public static void Beep() {
42 java.awt.Toolkit.getDefaultToolkit().beep();
43 }
44
45 /**
46 * Forces a repaint of the current Frame
47 */
48 public static void Display() {
49 FrameGraphics.ForceRepaint();
50 }
51
52 /**
53 * Restores the current frame to the last saved version currently on the
54 * hard disk
55 */
56 public static void Restore() {
57 FrameIO.Reload();
58 //FrameGraphics.DisplayMessage("Restoration complete.");
59 }
60
61 /**
62 * Toggles AudienceMode on or off
63 */
64 public static void ToggleAudienceMode() {
65 FrameGraphics.ToggleAudienceMode();
66 }
67
68 /**
69 * Toggles TwinFrames mode on or off
70 */
71 public static void ToggleTwinFramesMode() {
72 DisplayIO.ToggleTwinFrames();
73 }
74
75 /**
76 * Exits the System
77 */
78 public static void Exit() {
79 /**
80 * TODO: Prompt the user etc.
81 */
82 FrameIO.SaveFrame(DisplayIO.getCurrentFrame());
83
84 while (FrameIO.DeleteFrameset("messages"))
85 ;
86
87 StatsLogger.WriteStatsFile();
88
89 System.exit(0);
90 }
91
92 /**
93 * If the given Item is a Text Item, then the text of the Item is
94 * interpreted as actions, if not this method does nothing.
95 *
96 * @param current
97 * The Item to read the Actions from
98 */
99 public static void RunCurrentItem(Item current) {
100 if (current instanceof Text) {
101 List<String> actions = ((Text) current).getTextList();
102
103 for (String action : actions) {
104 Actions.PerformAction(DisplayIO.getCurrentFrame(), current,
105 action);
106 }
107 }
108
109 }
110
111 /**
112 * Prompts the user to confirm deletion of the current Frame, and deletes if
113 * the user chooses. After deletion this action calls back(), to ensure the
114 * deleted frame is not still being shown
115 *
116 */
117 public static void DeleteFrame() {
118 Frame toDelete = DisplayIO.getCurrentFrame();
119 DisplayIO.Back();
120 String deletedFrame = toDelete.getName();
121 String deletedFrameNameLowercase = deletedFrame.toLowerCase();
122 try {
123 boolean del = FrameIO.DeleteFrame(toDelete);
124 if (!del) {
125 FrameGraphics.ErrorMessage("Error trying to delete "
126 + toDelete.getName());
127 } else {
128 Frame current = DisplayIO.getCurrentFrame();
129 for (Item i : current.getItems())
130 if (i.getLink() != null
131 && i.getAbsoluteLink().toLowerCase().equals(
132 deletedFrameNameLowercase)) {
133 i.setLink(null);
134 }
135
136 FrameGraphics.Repaint();
137 FrameGraphics.DisplayMessage(deletedFrame + " Deleted.");
138 }
139 } catch (IOException ioe) {
140 FrameGraphics.ErrorMessage("Error trying to delete " + deletedFrame
141 + ":\n" + ioe.getMessage());
142 }
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(), DisplayIO.getMouseY());
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 CreateTextItem(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 FrameGraphics.DisplayMessage("Extracting comet stats...");
235
236 StringBuffer sb = new StringBuffer();
237 Time active = frame.getCometActiveTime(true);
238 Time dark = frame.getCometDarkTime(true);
239 Time total = new Time(active.getTime() + dark.getTime());
240 int length = frame.getCometLength();
241 sb.append("CometName: ").append(frame.getName()).append('\n');
242 sb.append("Length: ").append(length).append('\n');
243 sb.append(" Current Average Total").append('\n');
244 Time averageActive = new Time((long) (0.5 + active.getTime()
245 / (1.0 * length)));
246 Time averageDark = new Time((long) (0.5 + dark.getTime()
247 / (1.0 * length)));
248 Time averageTotal = new Time((long) (0.5 + total.getTime()
249 / (1.0 * length)));
250 Time currentActive = SessionStats.getFrameActiveTime();
251 Time currentDark = SessionStats.getFrameDarkTime();
252 Time currentTotal = SessionStats.getFrameTotalTime();
253
254 sb.append("ActiveTime: ").append(Logger.EasyTimeFormat(currentActive)).append(
255 ' ').append(Logger.EasyTimeFormat(averageActive)).append(
256 ' ').append(Logger.EasyTimeFormat(active)).append('\n');
257 sb.append(" DarkTime: ").append(Logger.EasyTimeFormat(currentDark)).append(
258 ' ').append(Logger.EasyTimeFormat(averageDark)).append(
259 ' ').append(Logger.EasyTimeFormat(dark)).append('\n');
260 sb.append(" TotalTime: ").append(Logger.EasyTimeFormat(currentTotal)).append(
261 ' ').append(Logger.EasyTimeFormat(averageTotal)).append(
262 ' ').append(Logger.EasyTimeFormat(total));
263 CreateTextItem(sb.toString());
264
265 FrameGraphics.OverwriteMessage("Comet stats complete");
266 }
267
268 public static void CreateTextItem(String itemText) {
269 SessionStats.CreatedText();
270 Frame current = DisplayIO.getCurrentFrame();
271 Item text = current.getStatsTextItem(itemText);
272 text.setSelectedMode(Item.SelectedMode.Normal);
273 text.setSelectedMode(Item.SelectedMode.None);
274 FrameMouseActions.pickup(text);
275 FrameGraphics.Repaint();
276 }
277
278 /**
279 * Creates a new Text Object containing statistics for moving, deleting and
280 * creating items in the current session. The newly created Text Object is
281 * then attached to the cursor via FrameMouseActions.pickup(Item)
282 */
283 public static void GetItemStats() {
284 CreateTextItem(SessionStats.getItemStats());
285 }
286
287 /**
288 * Creates a new Text Object containing statistics for the time between
289 * events triggered by the user through mouse clicks and key presses. The
290 * newly created Text Object is then attached to the cursor via
291 * FrameMouseActions.pickup(Item)
292 */
293 public static void GetEventStats() {
294 CreateTextItem(SessionStats.getEventStats());
295 }
296
297 /**
298 * Creates a new Text Object containing the contents of the current frames
299 * file.
300 */
301 public static void GetCurrentFrameFile() {
302
303 Frame current = DisplayIO.getCurrentFrame();
304 current.change();
305 String fileContents = FrameIO.SaveFrame(current);
306
307 Text text = current.createNewText();
308 // We dont want the stats to wrap at all
309 text.setMaxSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
310
311 text.setText(fileContents);
312
313 text.setPosition(DisplayIO.getMouseX(), DisplayIO.getMouseY());
314 text.setSize(FRAME_FILE_FONT_SIZE);
315
316 FrameMouseActions.pickup(text);
317
318 FrameGraphics.Repaint();
319 }
320
321 /**
322 * Creates a new Text Object containing the available fonts.
323 */
324 public static void GetAvailableFontFamilyNames() {
325
326 String[] availableFonts = GraphicsEnvironment
327 .getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
328 StringBuilder fontsList = new StringBuilder();
329 for (String s : availableFonts) {
330 fontsList.append(s).append('\n');
331 }
332
333 Text text = DisplayIO.getCurrentFrame().createNewText();
334 // We dont want the stats to wrap at all
335 text.setMaxSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
336 text.setText(fontsList.toString());
337
338 text.setPosition(DisplayIO.getMouseX(), DisplayIO.getMouseY());
339 text.setSize(FRAME_FILE_FONT_SIZE);
340
341 FrameMouseActions.pickup(text);
342
343 FrameGraphics.Repaint();
344 }
345
346 /**
347 * Resets the statistics back to zero.
348 */
349 public static void ResetStats() {
350 StatsLogger.WriteStatsFile();
351 SessionStats.resetStats();
352 }
353
354 /**
355 * Loads a frame with the given name and saves it as a JPEG image.
356 *
357 * @param framename
358 * The name of the Frame to save
359 */
360 public static void JpegFrame(String framename) {
361 ImageFrame(framename, "JPEG");
362 }
363
364 /**
365 * Saves the current frame as a JPEG image. This is the same as calling
366 * JpegFrame(currentFrame.getName())
367 */
368 public static void JpegFrame() {
369 ImageFrame(DisplayIO.getCurrentFrame().getName(), "JPEG");
370 }
371
372 public static void JPGFrame() {
373 JpegFrame();
374 }
375
376 /**
377 * Loads a frame with the given name and saves it as a PNG image.
378 *
379 * @param framename
380 * The name of the Frame to save
381 */
382 public static void PNGFrame(String framename) {
383 ImageFrame(framename, "PNG");
384 }
385
386 /**
387 * Saves the current frame as a PNG image. This is the same as calling
388 * PNGFrame(currentFrame.getName())
389 */
390 public static void PNGFrame() {
391 ImageFrame(DisplayIO.getCurrentFrame().getName(), "PNG");
392 }
393
394 public static String SaveImage(BufferedImage screen, String format,
395 String directory, String fileName) {
396 // Check if we need to append the suffix
397 if (fileName.indexOf('.') < 0)
398 fileName += "." + format.toLowerCase();
399
400 try {
401 // set up the file for output
402 String fullFileName = directory + fileName;
403 File out = new File(fullFileName);
404 if (!out.getParentFile().exists())
405 out.mkdirs();
406
407 // If the image is successfully written out return the fileName
408 if (ImageIO.write(screen, format, out))
409 return fileName;
410
411 } catch (Exception e) {
412 e.printStackTrace();
413 }
414 return null;
415 }
416
417 public static String ImageFrame(Frame frame, String format, String directory) {
418 assert (frame != null);
419
420 FrameGraphics.UpdateBuffer(frame, false);
421
422 BufferedImage screen = null;
423 Image frameBuffer = frame.getBuffer();
424 if (frame.getBuffer() instanceof BufferedImage) {
425 screen = (BufferedImage) frameBuffer;
426 } else if (frameBuffer instanceof VolatileImage) {
427 screen = ((VolatileImage) frameBuffer).getSnapshot();
428 } else {
429 assert (false);
430 }
431 return SaveImage(screen, format, directory, frame.getExportFileName());
432 }
433
434 /**
435 * Saves the Frame with the given Framename as an image of the given format.
436 *
437 * @param framename
438 * The name of the Frame to save as an image
439 * @param format
440 * The Image format to use (i.e. "PNG", "BMP", etc)
441 */
442 public static void ImageFrame(String framename, String format) {
443 Frame loaded = FrameIO.LoadFrame(framename);
444
445 // if the frame was loaded successfully
446 if (loaded != null) {
447 String path = FrameIO.IMAGES_PATH;
448 String frameName = ImageFrame(loaded, format, path);
449 if (frameName != null)
450 FrameGraphics.DisplayMessage("Frame successfully saved to "
451 + path + frameName);
452 else
453 FrameGraphics.ErrorMessage("Could not find image writer for "
454 + format + " format");
455 // if the frame was not loaded successfully, alert the user
456 } else
457 FrameGraphics.DisplayMessage("Frame '" + framename
458 + "' could not be found.");
459 }
460
461 /**
462 * Displays a message in the message box area.
463 *
464 * @param message
465 * the message to display
466 */
467 public static void MessageLn(String message) {
468 FrameGraphics.DisplayMessage(message);
469 }
470
471 public static void MessageLn2(String message, String message2) {
472 FrameGraphics.DisplayMessage(message + " " + message2);
473 }
474
475 public static void CopyFile(String existingFile, String newFileName) {
476 try {
477 // TODO is there a built in method which will do this faster?
478
479 FrameGraphics.DisplayMessage("Copying file " + existingFile
480 + " to " + newFileName + "...");
481 FrameIO.copyFile(existingFile, newFileName);
482 FrameGraphics.DisplayMessage("File copied successfully");
483 } catch (FileNotFoundException e) {
484 FrameGraphics.DisplayMessage("Error opening file: " + existingFile);
485 } catch (Exception e) {
486 FrameGraphics.DisplayMessage("File could not be copied");
487 }
488 }
489
490 /**
491 * Runs two methods alternatively a specified number of times and reports on
492 * the time spent running each method.
493 *
494 * @param fullMethodNameA
495 * @param fullMethodNameB
496 * @param repsPerTest
497 * the number of time each method is run per test
498 * @param tests
499 * the number of tests to conduct
500 *
501 */
502 public static void CompareMethods(String fullMethodNameA,
503 String fullMethodNameB, int repsPerTest, int tests) {
504 try {
505 String classNameA = getClassName(fullMethodNameA);
506 String classNameB = getClassName(fullMethodNameB);
507 String methodNameA = getMethodName(fullMethodNameA);
508 String methodNameB = getMethodName(fullMethodNameB);
509
510 Class classA = Class.forName(classNameA);
511 Class classB = Class.forName(classNameB);
512 Method methodA = classA.getDeclaredMethod(methodNameA,
513 new Class[] {});
514 Method methodB = classB.getDeclaredMethod(methodNameB,
515 new Class[] {});
516 TimeKeeper timeKeeper = new TimeKeeper();
517 long timeA = 0;
518 long timeB = 0;
519 // Run the tests
520 for (int i = 0; i < tests; i++) {
521 // Test methodA
522 timeKeeper.restart();
523 for (int j = 0; j < repsPerTest; j++) {
524 methodA.invoke((Object) null, new Object[] {});
525 }
526 timeA += timeKeeper.getElapsedMillis();
527 timeKeeper.restart();
528 // Test methodB
529 for (int j = 0; j < repsPerTest; j++) {
530 methodB.invoke((Object) null, new Object[] {});
531 }
532 timeB += timeKeeper.getElapsedMillis();
533 }
534
535 float aveTimeA = timeA * 1000F / repsPerTest / tests;
536 float aveTimeB = timeB * 1000F / repsPerTest / tests;
537 // Display Results
538 FrameGraphics.DisplayMessage("Average Execution Time");
539 FrameGraphics.DisplayMessage(methodNameA + ": "
540 + TimeKeeper.Formatter.format(aveTimeA) + "us");
541 FrameGraphics.DisplayMessage(methodNameB + ": "
542 + TimeKeeper.Formatter.format(aveTimeB) + "us");
543 } catch (Exception e) {
544 FrameGraphics.ErrorMessage(e.getClass().getSimpleName() + ": "
545 + e.getMessage());
546 }
547 }
548
549 public static String getClassName(String fullMethodName) {
550 assert (fullMethodName != null);
551 assert (fullMethodName.length() > 0);
552 int lastPeriod = fullMethodName.lastIndexOf('.');
553 if (lastPeriod > 0 && lastPeriod < fullMethodName.length() - 1)
554 return fullMethodName.substring(0, lastPeriod);
555 throw new RuntimeException("Invalid method name: " + fullMethodName);
556 }
557
558 public static String getMethodName(String methodName) {
559 assert (methodName != null);
560 assert (methodName.length() > 0);
561 int lastPeriod = methodName.lastIndexOf('.');
562 if (lastPeriod > 0 && lastPeriod < methodName.length() - 1)
563 return methodName.substring(1 + lastPeriod);
564 throw new RuntimeException("Invalid method name: " + methodName);
565 }
566
567 /**
568 * Loads the Frame linked to by the given Item. The first Item on the Frame
569 * that is not the title or name is then placed on the current frame. The
570 * item that was clicked on is placed on the frame it was linked to and the
571 * link is switched to the item from the child frame. If the given Item has
572 * no link, or no item is found then this is a no-op.
573 *
574 * @param current
575 * The Item that links to the Frame that the Item will be loaded
576 * from.
577 */
578 public static void SwapItemWithItemOnChildFrame(Item current) {
579 Item item = getFirstBodyItemOnChildFrame(current, false);
580 // if no item was found
581 if (item == null) {
582 return;
583 }
584
585 // swap the items parents
586 Frame parentFrame = current.getParent();
587 Frame childFrame = item.getParent();
588 current.setParent(childFrame);
589 item.setParent(parentFrame);
590
591 // swap the items on the frames
592 parentFrame.removeItem(current);
593 childFrame.removeItem(item);
594 parentFrame.addItem(item);
595 childFrame.addItem(current);
596
597 // swap the items links
598 item.setActions(current.getAction());
599 item.setLink(childFrame.getName());
600 current.setLink(parentFrame.getName());
601 // current.setLink(null);
602 current.setActions(null);
603
604 FrameGraphics.Repaint();
605 }
606
607 private static Item getFirstBodyItemOnChildFrame(Item current,
608 boolean textOnly) {
609 // the item must link to a frame
610 if (current.getLink() == null) {
611 FrameGraphics
612 .DisplayMessage("Cannot get item from child - this item has no link");
613 return null;
614 }
615
616 Frame child = FrameIO.LoadFrame(current.getAbsoluteLink());
617
618 // if the frame could not be loaded
619 if (child == null) {
620 FrameGraphics.ErrorMessage("Could not load child frame.");
621 return null;
622 }
623
624 // find the first non-title and non-name item
625 List<Item> body = new ArrayList<Item>();
626 if (textOnly)
627 body.addAll(child.getBodyTextItems(false));
628 else
629 body.addAll(child.getItems());
630 Item item = null;
631
632 for (Item i : body)
633 if (i != child.getTitleItem() && !i.isAnnotation()) {
634 item = i;
635 break;
636 }
637
638 // if no item was found
639 if (item == null) {
640 FrameGraphics.DisplayMessage("No item found to copy");
641 return null;
642 }
643
644 return item;
645 }
646}
Note: See TracBrowser for help on using the repository browser.