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

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

Added some more unit tests
Did a bunch of refactoring
AND added a few new features... @b @v were the most significant

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