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

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

Added DebugFrame action
Added GetCometStats
Lots of bug fixes

File size: 18.5 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 FrameMouseActions.pickup(text);
273 FrameGraphics.Repaint();
274 }
275
276 /**
277 * Creates a new Text Object containing statistics for moving, deleting and
278 * creating items in the current session. The newly created Text Object is
279 * then attached to the cursor via FrameMouseActions.pickup(Item)
280 */
281 public static void GetItemStats() {
282 CreateTextItem(SessionStats.getItemStats());
283 }
284
285 /**
286 * Creates a new Text Object containing statistics for the time between
287 * events triggered by the user through mouse clicks and key presses. The
288 * newly created Text Object is then attached to the cursor via
289 * FrameMouseActions.pickup(Item)
290 */
291 public static void GetEventStats() {
292 CreateTextItem(SessionStats.getEventStats());
293 }
294
295 /**
296 * Creates a new Text Object containing the contents of the current frames
297 * file.
298 */
299 public static void GetCurrentFrameFile() {
300
301 Frame current = DisplayIO.getCurrentFrame();
302 current.change();
303 String fileContents = FrameIO.SaveFrame(current);
304
305 Text text = current.createNewText();
306 // We dont want the stats to wrap at all
307 text.setMaxSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
308
309 text.setText(fileContents);
310
311 text.setPosition(DisplayIO.getMouseX(), DisplayIO.getMouseY());
312 text.setSize(FRAME_FILE_FONT_SIZE);
313
314 FrameMouseActions.pickup(text);
315
316 FrameGraphics.Repaint();
317 }
318
319 /**
320 * Creates a new Text Object containing the available fonts.
321 */
322 public static void GetAvailableFontFamilyNames() {
323
324 String[] availableFonts = GraphicsEnvironment
325 .getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
326 StringBuilder fontsList = new StringBuilder();
327 for (String s : availableFonts) {
328 fontsList.append(s).append('\n');
329 }
330
331 Text text = DisplayIO.getCurrentFrame().createNewText();
332 // We dont want the stats to wrap at all
333 text.setMaxSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
334 text.setText(fontsList.toString());
335
336 text.setPosition(DisplayIO.getMouseX(), DisplayIO.getMouseY());
337 text.setSize(FRAME_FILE_FONT_SIZE);
338
339 FrameMouseActions.pickup(text);
340
341 FrameGraphics.Repaint();
342 }
343
344 /**
345 * Resets the statistics back to zero.
346 */
347 public static void ResetStats() {
348 StatsLogger.WriteStatsFile();
349 SessionStats.resetStats();
350 }
351
352 /**
353 * Loads a frame with the given name and saves it as a JPEG image.
354 *
355 * @param framename
356 * The name of the Frame to save
357 */
358 public static void JpegFrame(String framename) {
359 ImageFrame(framename, "JPEG");
360 }
361
362 /**
363 * Saves the current frame as a JPEG image. This is the same as calling
364 * JpegFrame(currentFrame.getName())
365 */
366 public static void JpegFrame() {
367 ImageFrame(DisplayIO.getCurrentFrame().getName(), "JPEG");
368 }
369
370 public static void JPGFrame() {
371 JpegFrame();
372 }
373
374 /**
375 * Loads a frame with the given name and saves it as a PNG image.
376 *
377 * @param framename
378 * The name of the Frame to save
379 */
380 public static void PNGFrame(String framename) {
381 ImageFrame(framename, "PNG");
382 }
383
384 /**
385 * Saves the current frame as a PNG image. This is the same as calling
386 * PNGFrame(currentFrame.getName())
387 */
388 public static void PNGFrame() {
389 ImageFrame(DisplayIO.getCurrentFrame().getName(), "PNG");
390 }
391
392 public static String SaveImage(BufferedImage screen, String format,
393 String directory, String fileName) {
394 // Check if we need to append the suffix
395 if (fileName.indexOf('.') < 0)
396 fileName += "." + format.toLowerCase();
397
398 try {
399 // set up the file for output
400 String fullFileName = directory + fileName;
401 File out = new File(fullFileName);
402 if (!out.getParentFile().exists())
403 out.mkdirs();
404
405 // If the image is successfully written out return the fileName
406 if (ImageIO.write(screen, format, out))
407 return fileName;
408
409 } catch (Exception e) {
410 e.printStackTrace();
411 }
412 return null;
413 }
414
415 public static String ImageFrame(Frame frame, String format, String directory) {
416 assert (frame != null);
417
418 FrameGraphics.UpdateBuffer(frame, false);
419
420 BufferedImage screen = null;
421 Image frameBuffer = frame.getBuffer();
422 if (frame.getBuffer() instanceof BufferedImage) {
423 screen = (BufferedImage) frameBuffer;
424 } else if (frameBuffer instanceof VolatileImage) {
425 screen = ((VolatileImage) frameBuffer).getSnapshot();
426 } else {
427 assert (false);
428 }
429 return SaveImage(screen, format, directory, frame.getExportFileName());
430 }
431
432 /**
433 * Saves the Frame with the given Framename as an image of the given format.
434 *
435 * @param framename
436 * The name of the Frame to save as an image
437 * @param format
438 * The Image format to use (i.e. "PNG", "BMP", etc)
439 */
440 public static void ImageFrame(String framename, String format) {
441 Frame loaded = FrameIO.LoadFrame(framename);
442
443 // if the frame was loaded successfully
444 if (loaded != null) {
445 String path = FrameIO.IMAGES_PATH;
446 String frameName = ImageFrame(loaded, format, path);
447 if (frameName != null)
448 FrameGraphics.DisplayMessage("Frame successfully saved to "
449 + path + frameName);
450 else
451 FrameGraphics.ErrorMessage("Could not find image writer for "
452 + format + " format");
453 // if the frame was not loaded successfully, alert the user
454 } else
455 FrameGraphics.DisplayMessage("Frame '" + framename
456 + "' could not be found.");
457 }
458
459 /**
460 * Displays a message in the message box area.
461 *
462 * @param message
463 * the message to display
464 */
465 public static void MessageLn(String message) {
466 FrameGraphics.DisplayMessage(message);
467 }
468
469 public static void MessageLn2(String message, String message2) {
470 FrameGraphics.DisplayMessage(message + " " + message2);
471 }
472
473 public static void CopyFile(String existingFile, String newFileName) {
474 try {
475 // TODO is there a built in method which will do this faster?
476
477 FrameGraphics.DisplayMessage("Copying file " + existingFile
478 + " to " + newFileName + "...");
479 FrameIO.copyFile(existingFile, newFileName);
480 FrameGraphics.DisplayMessage("File copied successfully");
481 } catch (FileNotFoundException e) {
482 FrameGraphics.DisplayMessage("Error opening file: " + existingFile);
483 } catch (Exception e) {
484 FrameGraphics.DisplayMessage("File could not be copied");
485 }
486 }
487
488 /**
489 * Runs two methods alternatively a specified number of times and reports on
490 * the time spent running each method.
491 *
492 * @param fullMethodNameA
493 * @param fullMethodNameB
494 * @param repsPerTest
495 * the number of time each method is run per test
496 * @param tests
497 * the number of tests to conduct
498 *
499 */
500 public static void CompareMethods(String fullMethodNameA,
501 String fullMethodNameB, int repsPerTest, int tests) {
502 try {
503 String classNameA = getClassName(fullMethodNameA);
504 String classNameB = getClassName(fullMethodNameB);
505 String methodNameA = getMethodName(fullMethodNameA);
506 String methodNameB = getMethodName(fullMethodNameB);
507
508 Class classA = Class.forName(classNameA);
509 Class classB = Class.forName(classNameB);
510 Method methodA = classA.getDeclaredMethod(methodNameA,
511 new Class[] {});
512 Method methodB = classB.getDeclaredMethod(methodNameB,
513 new Class[] {});
514 TimeKeeper timeKeeper = new TimeKeeper();
515 long timeA = 0;
516 long timeB = 0;
517 // Run the tests
518 for (int i = 0; i < tests; i++) {
519 // Test methodA
520 timeKeeper.restart();
521 for (int j = 0; j < repsPerTest; j++) {
522 methodA.invoke((Object) null, new Object[] {});
523 }
524 timeA += timeKeeper.getElapsedMillis();
525 timeKeeper.restart();
526 // Test methodB
527 for (int j = 0; j < repsPerTest; j++) {
528 methodB.invoke((Object) null, new Object[] {});
529 }
530 timeB += timeKeeper.getElapsedMillis();
531 }
532
533 float aveTimeA = timeA * 1000F / repsPerTest / tests;
534 float aveTimeB = timeB * 1000F / repsPerTest / tests;
535 // Display Results
536 FrameGraphics.DisplayMessage("Average Execution Time");
537 FrameGraphics.DisplayMessage(methodNameA + ": "
538 + TimeKeeper.Formatter.format(aveTimeA) + "us");
539 FrameGraphics.DisplayMessage(methodNameB + ": "
540 + TimeKeeper.Formatter.format(aveTimeB) + "us");
541 } catch (Exception e) {
542 FrameGraphics.ErrorMessage(e.getClass().getSimpleName() + ": "
543 + e.getMessage());
544 }
545 }
546
547 public static String getClassName(String fullMethodName) {
548 assert (fullMethodName != null);
549 assert (fullMethodName.length() > 0);
550 int lastPeriod = fullMethodName.lastIndexOf('.');
551 if (lastPeriod > 0 && lastPeriod < fullMethodName.length() - 1)
552 return fullMethodName.substring(0, lastPeriod);
553 throw new RuntimeException("Invalid method name: " + fullMethodName);
554 }
555
556 public static String getMethodName(String methodName) {
557 assert (methodName != null);
558 assert (methodName.length() > 0);
559 int lastPeriod = methodName.lastIndexOf('.');
560 if (lastPeriod > 0 && lastPeriod < methodName.length() - 1)
561 return methodName.substring(1 + lastPeriod);
562 throw new RuntimeException("Invalid method name: " + methodName);
563 }
564
565 /**
566 * Loads the Frame linked to by the given Item. The first Item on the Frame
567 * that is not the title or name is then placed on the current frame. The
568 * item that was clicked on is placed on the frame it was linked to and the
569 * link is switched to the item from the child frame. If the given Item has
570 * no link, or no item is found then this is a no-op.
571 *
572 * @param current
573 * The Item that links to the Frame that the Item will be loaded
574 * from.
575 */
576 public static void SwapItemWithItemOnChildFrame(Item current) {
577 Item item = getFirstBodyItemOnChildFrame(current, false);
578 // if no item was found
579 if (item == null) {
580 return;
581 }
582
583 // swap the items parents
584 Frame parentFrame = current.getParent();
585 Frame childFrame = item.getParent();
586 current.setParent(childFrame);
587 item.setParent(parentFrame);
588
589 // swap the items on the frames
590 parentFrame.removeItem(current);
591 childFrame.removeItem(item);
592 parentFrame.addItem(item);
593 childFrame.addItem(current);
594
595 // swap the items links
596 item.setActions(current.getAction());
597 item.setLink(childFrame.getName());
598 current.setLink(parentFrame.getName());
599 // current.setLink(null);
600 current.setActions(null);
601
602 FrameGraphics.Repaint();
603 }
604
605 private static Item getFirstBodyItemOnChildFrame(Item current,
606 boolean textOnly) {
607 // the item must link to a frame
608 if (current.getLink() == null) {
609 FrameGraphics
610 .DisplayMessage("Cannot get item from child - this item has no link");
611 return null;
612 }
613
614 Frame child = FrameIO.LoadFrame(current.getAbsoluteLink());
615
616 // if the frame could not be loaded
617 if (child == null) {
618 FrameGraphics.ErrorMessage("Could not load child frame.");
619 return null;
620 }
621
622 // find the first non-title and non-name item
623 List<Item> body = new ArrayList<Item>();
624 if (textOnly)
625 body.addAll(child.getBodyTextItems(false));
626 else
627 body.addAll(child.getItems());
628 Item item = null;
629
630 for (Item i : body)
631 if (i != child.getTitleItem() && !i.isAnnotation()) {
632 item = i;
633 break;
634 }
635
636 // if no item was found
637 if (item == null) {
638 FrameGraphics.DisplayMessage("No item found to copy");
639 return null;
640 }
641
642 return item;
643 }
644}
Note: See TracBrowser for help on using the repository browser.