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

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

Fixed rounding errors in Text class...
They caused a whole bunch of problems with small fonts and text items with several lines!

File size: 17.8 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.CometStats;
27import org.expeditee.stats.SessionStats;
28import org.expeditee.stats.StatsLogger;
29import org.expeditee.stats.TreeStats;
30
31/**
32 * A list of miscellaneous 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 String deletedFrame = toDelete.getName();
120 String deletedFrameNameLowercase = deletedFrame.toLowerCase();
121 String errorMessage = "Error deleting " + deletedFrame;
122 try {
123 if (FrameIO.DeleteFrame(toDelete)) {
124 Frame current = DisplayIO.getCurrentFrame();
125 for (Item i : current.getItems())
126 if (i.getLink() != null
127 && i.getAbsoluteLink().toLowerCase().equals(
128 deletedFrameNameLowercase)) {
129 i.setLink(null);
130 }
131 DisplayIO.Back();
132 FrameGraphics.Repaint();
133 FrameGraphics.DisplayMessage(deletedFrame + " deleted");
134 return;
135 }
136 } catch (IOException ioe){
137 if(ioe.getMessage() != null )
138 errorMessage += ". " + ioe.getMessage();
139 } catch (SecurityException se) {
140 if(se.getMessage() != null )
141 errorMessage += ". " + se.getMessage();
142 } catch (Exception e) {
143 e.printStackTrace();
144 }
145 FrameGraphics.ErrorMessage(errorMessage);
146 }
147
148 /**
149 * Loads the Frame linked to by the given Item. The first Item on the Frame
150 * that is not the title or name is then placed on the cursor. If the given
151 * Item has no link, or no item is found then this is a no-op.
152 *
153 * @param current
154 * The Item that links to the Frame that the Item will be loaded
155 * from.
156 */
157 public static void GetItemFromChildFrame(Item current) {
158 getFromChildFrame(current, false);
159 }
160
161 /**
162 * Loads the Frame linked to by the given Item. The first Text Item on the
163 * Frame that is not the title or name is then placed on the cursor. If the
164 * given Item has no link, or no item is found then this is a no-op.
165 *
166 * @param current
167 * The Item that links to the Frame that the Item will be loaded
168 * from.
169 */
170 public static void GetTextFromChildFrame(Item current) {
171 getFromChildFrame(current, true);
172 }
173
174 private static void getFromChildFrame(Item current, boolean textOnly) {
175 Item item = getFirstBodyItemOnChildFrame(current, textOnly);
176 // if no item was found
177 if (item == null) {
178 return;
179 }
180
181 // copy the item and switch
182 item = item.copy();
183 item.setPosition(DisplayIO.getMouseX(), FrameMouseActions.getY());
184 item.setParent(null);
185
186 FrameMouseActions.pickup(item);
187 FrameGraphics.Repaint();
188 }
189
190 /**
191 * Sets the given Item to have the Given Color. Color can be null (for
192 * default)
193 *
194 * @param toChange
195 * The Item to set the Color.
196 * @param toUse
197 * The Color to give the Item.
198 */
199 public static void SetCurrentItemBackgroundColor(Item toChange, Color toUse) {
200 if (toChange == null)
201 return;
202
203 toChange.setBackgroundColor(toUse);
204 FrameGraphics.Repaint();
205 }
206
207 /**
208 * Sets the given Item to have the Given Color. Color can be null (for
209 * default)
210 *
211 * @param toChange
212 * The Item to set the Color.
213 * @param toUse
214 * The Color to give the Item.
215 */
216 public static void SetCurrentItemColor(Item toChange, Color toUse) {
217 if (toChange == null)
218 return;
219
220 toChange.setColor(toUse);
221 FrameGraphics.Repaint();
222 }
223
224 /**
225 * Creates a new Text Object containing general statistics for the current
226 * session. The newly created Text Object is then attached to the cursor via
227 * FrameMouseActions.pickup(Item)
228 */
229 public static void GetSessionStats() {
230 CreateTextItem(SessionStats.getCurrentStats());
231 }
232
233 /**
234 * Creates a new Text Object containing statistics for the current tree.
235 */
236 public static void GetCometStats(Frame frame) {
237 TimeKeeper timer = new TimeKeeper();
238 FrameGraphics.DisplayMessage("Computing comet stats...");
239
240 CometStats cometStats = new CometStats(frame);
241 CreateTextItem(cometStats.toString());
242 FrameGraphics.OverwriteMessage("Comet stats time: "
243 + timer.getElapsedStringSeconds());
244 }
245
246 public static void GetTreeStats(Frame frame) {
247 TimeKeeper timer = new TimeKeeper();
248 FrameGraphics.DisplayMessage("Computing tree stats...");
249
250 TreeStats treeStats = new TreeStats(frame);
251 CreateTextItem(treeStats.toString());
252 FrameGraphics.OverwriteMessage("Tree stats time: "
253 + timer.getElapsedStringSeconds());
254 }
255
256 public static void CreateTextItem(String itemText) {
257 SessionStats.CreatedText();
258 Frame current = DisplayIO.getCurrentFrame();
259 Item text = current.getStatsTextItem(itemText);
260 text.setSelectedMode(Item.SelectedMode.Normal);
261 text.setSelectedMode(Item.SelectedMode.None);
262 FrameMouseActions.pickup(text);
263 FrameGraphics.Repaint();
264 }
265
266 /**
267 * Creates a new Text Object containing statistics for moving, deleting and
268 * creating items in the current session. The newly created Text Object is
269 * then attached to the cursor via FrameMouseActions.pickup(Item)
270 */
271 public static void GetItemStats() {
272 CreateTextItem(SessionStats.getItemStats());
273 }
274
275 /**
276 * Creates a new Text Object containing statistics for the time between
277 * events triggered by the user through mouse clicks and key presses. The
278 * newly created Text Object is then attached to the cursor via
279 * FrameMouseActions.pickup(Item)
280 */
281 public static void GetEventStats() {
282 CreateTextItem(SessionStats.getEventStats());
283 }
284
285 /**
286 * Creates a new Text Object containing the contents of the current frames
287 * file.
288 */
289 public static void GetCurrentFrameFile() {
290
291 Frame current = DisplayIO.getCurrentFrame();
292 current.change();
293 String fileContents = FrameIO.SaveFrame(current);
294
295 Text text = current.createNewText();
296 // We dont want the stats to wrap at all
297 text.setMaxSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
298
299 text.setText(fileContents);
300
301 text.setPosition(DisplayIO.getMouseX(), FrameMouseActions.getY());
302 text.setSize(FRAME_FILE_FONT_SIZE);
303
304 FrameMouseActions.pickup(text);
305
306 FrameGraphics.Repaint();
307 }
308
309 /**
310 * Creates a new Text Object containing the available fonts.
311 */
312 public static void GetAvailableFontFamilyNames() {
313
314 String[] availableFonts = GraphicsEnvironment
315 .getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
316 StringBuilder fontsList = new StringBuilder();
317 for (String s : availableFonts) {
318 fontsList.append(s).append('\n');
319 }
320 fontsList.deleteCharAt(fontsList.length()-1);
321
322 Text text = DisplayIO.getCurrentFrame().createNewText();
323 // We dont want the stats to wrap at all
324 text.setMaxSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
325 text.setText(fontsList.toString());
326
327 text.setPosition(DisplayIO.getMouseX(), FrameMouseActions.getY());
328 text.setSize(FRAME_FILE_FONT_SIZE);
329
330 FrameMouseActions.pickup(text);
331
332 FrameGraphics.Repaint();
333 }
334
335 /**
336 * Resets the statistics back to zero.
337 */
338 public static void ResetStats() {
339 StatsLogger.WriteStatsFile();
340 SessionStats.resetStats();
341 }
342
343 /**
344 * Loads a frame with the given name and saves it as a JPEG image.
345 *
346 * @param framename
347 * The name of the Frame to save
348 */
349 public static void JpegFrame(String framename) {
350 ImageFrame(framename, "JPEG");
351 }
352
353 /**
354 * Saves the current frame as a JPEG image. This is the same as calling
355 * JpegFrame(currentFrame.getName())
356 */
357 public static void JpegFrame() {
358 ImageFrame(DisplayIO.getCurrentFrame().getName(), "JPEG");
359 }
360
361 public static void JPGFrame() {
362 JpegFrame();
363 }
364
365 /**
366 * Loads a frame with the given name and saves it as a PNG image.
367 *
368 * @param framename
369 * The name of the Frame to save
370 */
371 public static void PNGFrame(String framename) {
372 ImageFrame(framename, "PNG");
373 }
374
375 /**
376 * Saves the current frame as a PNG image. This is the same as calling
377 * PNGFrame(currentFrame.getName())
378 */
379 public static void PNGFrame() {
380 ImageFrame(DisplayIO.getCurrentFrame().getName(), "PNG");
381 }
382
383 public static String SaveImage(BufferedImage screen, String format,
384 String directory, String fileName) {
385 // Check if we need to append the suffix
386 if (fileName.indexOf('.') < 0)
387 fileName += "." + format.toLowerCase();
388
389 try {
390 // set up the file for output
391 String fullFileName = directory + fileName;
392 File out = new File(fullFileName);
393 if (!out.getParentFile().exists())
394 out.mkdirs();
395
396 // If the image is successfully written out return the fileName
397 if (ImageIO.write(screen, format, out))
398 return fileName;
399
400 } catch (Exception e) {
401 e.printStackTrace();
402 }
403 return null;
404 }
405
406 public static String ImageFrame(Frame frame, String format, String directory) {
407 assert (frame != null);
408
409 FrameGraphics.UpdateBuffer(frame, false);
410
411 BufferedImage screen = null;
412 Image frameBuffer = frame.getBuffer();
413 if (frame.getBuffer() instanceof BufferedImage) {
414 screen = (BufferedImage) frameBuffer;
415 } else if (frameBuffer instanceof VolatileImage) {
416 screen = ((VolatileImage) frameBuffer).getSnapshot();
417 } else {
418 assert (false);
419 }
420 return SaveImage(screen, format, directory, frame.getExportFileName());
421 }
422
423 /**
424 * Saves the Frame with the given Framename as an image of the given format.
425 *
426 * @param framename
427 * The name of the Frame to save as an image
428 * @param format
429 * The Image format to use (i.e. "PNG", "BMP", etc)
430 */
431 public static void ImageFrame(String framename, String format) {
432 Frame loaded = FrameIO.LoadFrame(framename);
433
434 // if the frame was loaded successfully
435 if (loaded != null) {
436 String path = FrameIO.IMAGES_PATH;
437 String frameName = ImageFrame(loaded, format, path);
438 if (frameName != null)
439 FrameGraphics.DisplayMessage("Frame successfully saved to "
440 + path + frameName);
441 else
442 FrameGraphics.ErrorMessage("Could not find image writer for "
443 + format + " format");
444 // if the frame was not loaded successfully, alert the user
445 } else
446 FrameGraphics.DisplayMessage("Frame '" + framename
447 + "' could not be found.");
448 }
449
450 /**
451 * Displays a message in the message box area.
452 *
453 * @param message
454 * the message to display
455 */
456 public static void MessageLn(String message) {
457 FrameGraphics.DisplayMessage(message);
458 }
459
460 public static void MessageLn2(String message, String message2) {
461 FrameGraphics.DisplayMessage(message + " " + message2);
462 }
463
464 public static void CopyFile(String existingFile, String newFileName) {
465 try {
466 // TODO is there a built in method which will do this faster?
467
468 FrameGraphics.DisplayMessage("Copying file " + existingFile
469 + " to " + newFileName + "...");
470 FrameIO.copyFile(existingFile, newFileName);
471 FrameGraphics.DisplayMessage("File copied successfully");
472 } catch (FileNotFoundException e) {
473 FrameGraphics.DisplayMessage("Error opening file: " + existingFile);
474 } catch (Exception e) {
475 FrameGraphics.DisplayMessage("File could not be copied");
476 }
477 }
478
479 /**
480 * Runs two methods alternatively a specified number of times and reports on
481 * the time spent running each method.
482 *
483 * @param fullMethodNameA
484 * @param fullMethodNameB
485 * @param repsPerTest
486 * the number of time each method is run per test
487 * @param tests
488 * the number of tests to conduct
489 *
490 */
491 public static void CompareMethods(String fullMethodNameA,
492 String fullMethodNameB, int repsPerTest, int tests) {
493 try {
494 String classNameA = getClassName(fullMethodNameA);
495 String classNameB = getClassName(fullMethodNameB);
496 String methodNameA = getMethodName(fullMethodNameA);
497 String methodNameB = getMethodName(fullMethodNameB);
498
499 Class classA = Class.forName(classNameA);
500 Class classB = Class.forName(classNameB);
501 Method methodA = classA.getDeclaredMethod(methodNameA,
502 new Class[] {});
503 Method methodB = classB.getDeclaredMethod(methodNameB,
504 new Class[] {});
505 TimeKeeper timeKeeper = new TimeKeeper();
506 long timeA = 0;
507 long timeB = 0;
508 // Run the tests
509 for (int i = 0; i < tests; i++) {
510 // Test methodA
511 timeKeeper.restart();
512 for (int j = 0; j < repsPerTest; j++) {
513 methodA.invoke((Object) null, new Object[] {});
514 }
515 timeA += timeKeeper.getElapsedMillis();
516 timeKeeper.restart();
517 // Test methodB
518 for (int j = 0; j < repsPerTest; j++) {
519 methodB.invoke((Object) null, new Object[] {});
520 }
521 timeB += timeKeeper.getElapsedMillis();
522 }
523
524 float aveTimeA = timeA * 1000F / repsPerTest / tests;
525 float aveTimeB = timeB * 1000F / repsPerTest / tests;
526 // Display Results
527 FrameGraphics.DisplayMessage("Average Execution Time");
528 FrameGraphics.DisplayMessage(methodNameA + ": "
529 + TimeKeeper.Formatter.format(aveTimeA) + "us");
530 FrameGraphics.DisplayMessage(methodNameB + ": "
531 + TimeKeeper.Formatter.format(aveTimeB) + "us");
532 } catch (Exception e) {
533 FrameGraphics.ErrorMessage(e.getClass().getSimpleName() + ": "
534 + e.getMessage());
535 }
536 }
537
538 public static String getClassName(String fullMethodName) {
539 assert (fullMethodName != null);
540 assert (fullMethodName.length() > 0);
541 int lastPeriod = fullMethodName.lastIndexOf('.');
542 if (lastPeriod > 0 && lastPeriod < fullMethodName.length() - 1)
543 return fullMethodName.substring(0, lastPeriod);
544 throw new RuntimeException("Invalid method name: " + fullMethodName);
545 }
546
547 public static String getMethodName(String methodName) {
548 assert (methodName != null);
549 assert (methodName.length() > 0);
550 int lastPeriod = methodName.lastIndexOf('.');
551 if (lastPeriod > 0 && lastPeriod < methodName.length() - 1)
552 return methodName.substring(1 + lastPeriod);
553 throw new RuntimeException("Invalid method name: " + methodName);
554 }
555
556 /**
557 * Loads the Frame linked to by the given Item. The first Item on the Frame
558 * that is not the title or name is then placed on the current frame. The
559 * item that was clicked on is placed on the frame it was linked to and the
560 * link is switched to the item from the child frame. If the given Item has
561 * no link, or no item is found then this is a no-op.
562 *
563 * @param current
564 * The Item that links to the Frame that the Item will be loaded
565 * from.
566 */
567 public static void SwapItemWithItemOnChildFrame(Item current) {
568 Item item = getFirstBodyItemOnChildFrame(current, false);
569 // if no item was found
570 if (item == null) {
571 return;
572 }
573
574 // swap the items parents
575 Frame parentFrame = current.getParent();
576 Frame childFrame = item.getParent();
577 current.setParent(childFrame);
578 item.setParent(parentFrame);
579
580 // swap the items on the frames
581 parentFrame.removeItem(current);
582 childFrame.removeItem(item);
583 parentFrame.addItem(item);
584 childFrame.addItem(current);
585
586 // swap the items links
587 item.setActions(current.getAction());
588 item.setLink(childFrame.getName());
589 current.setLink(parentFrame.getName());
590 // current.setLink(null);
591 current.setActions(null);
592
593 FrameGraphics.Repaint();
594 }
595
596 private static Item getFirstBodyItemOnChildFrame(Item current,
597 boolean textOnly) {
598 // the item must link to a frame
599 if (current.getLink() == null) {
600 FrameGraphics
601 .DisplayMessage("Cannot get item from child - this item has no link");
602 return null;
603 }
604
605 Frame child = FrameIO.LoadFrame(current.getAbsoluteLink());
606
607 // if the frame could not be loaded
608 if (child == null) {
609 FrameGraphics.ErrorMessage("Could not load child frame.");
610 return null;
611 }
612
613 // find the first non-title and non-name item
614 List<Item> body = new ArrayList<Item>();
615 if (textOnly)
616 body.addAll(child.getBodyTextItems(false));
617 else
618 body.addAll(child.getItems());
619 Item item = null;
620
621 for (Item i : body)
622 if (i != child.getTitleItem() && !i.isAnnotation()) {
623 item = i;
624 break;
625 }
626
627 // if no item was found
628 if (item == null) {
629 FrameGraphics.DisplayMessage("No item found to copy");
630 return null;
631 }
632
633 return item;
634 }
635}
Note: See TracBrowser for help on using the repository browser.