0001: /*
0002: * Jacareto Copyright (c) 2002-2005
0003: * Applied Computer Science Research Group, Darmstadt University of
0004: * Technology, Institute of Mathematics & Computer Science,
0005: * Ludwigsburg University of Education, and Computer Based
0006: * Learning Research Group, Aachen University. All rights reserved.
0007: *
0008: * Jacareto is free software; you can redistribute it and/or
0009: * modify it under the terms of the GNU General Public
0010: * License as published by the Free Software Foundation; either
0011: * version 2 of the License, or (at your option) any later version.
0012: *
0013: * Jacareto is distributed in the hope that it will be useful,
0014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0016: * General Public License for more details.
0017: *
0018: * You should have received a copy of the GNU General Public
0019: * License along with Jacareto; if not, write to the Free
0020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
0021: *
0022: */
0023:
0024: package jacareto.replay;
0025:
0026: import jacareto.catching.EventListener;
0027: import jacareto.catching.PopUpCatcher;
0028: import jacareto.comp.Components;
0029: import jacareto.comp.glasspanes.GlassPaneCompound;
0030: import jacareto.comp.glasspanes.GlassPaneManager;
0031: import jacareto.comp.glasspanes.MarkModeGlassPane;
0032: import jacareto.comp.glasspanes.PseudoMousePointerGlassPane;
0033: import jacareto.record.InputEventRecordable;
0034: import jacareto.record.MediaClipRecordable;
0035: import jacareto.record.MouseEventRecordable;
0036: import jacareto.record.Recordable;
0037: import jacareto.replay.event.ReplayEvent;
0038: import jacareto.replay.event.ReplayListener;
0039: import jacareto.replay.exception.ComponentNotFoundException;
0040: import jacareto.struct.RootElement;
0041: import jacareto.struct.Structure;
0042: import jacareto.struct.StructureElement;
0043: import jacareto.struct.event.StructureElementEvent;
0044: import jacareto.struct.event.StructureElementListener;
0045: import jacareto.system.Customization;
0046: import jacareto.system.Environment;
0047: import jacareto.system.EnvironmentMember;
0048: import jacareto.system.Language;
0049: import jacareto.test.TestReport;
0050: import jacareto.toolkit.EnhancedHashtable;
0051: import jacareto.toolkit.HashtableChangeEvent;
0052: import jacareto.toolkit.HashtableChangeListener;
0053: import jacareto.toolkit.JacaretoClassLoader;
0054: import jacareto.toolkit.PriorityList;
0055: import jacareto.toolkit.ProcTimeCalculator;
0056: import jacareto.toolkit.StringToolkit;
0057: import jacareto.track.block.BlockType;
0058: import jacareto.track.sync.SyncController;
0059: import jacareto.track.sync.SyncControllerListener;
0060: import jacareto.track.sync.SyncMode;
0061:
0062: import org.apache.log4j.Logger;
0063:
0064: import java.awt.Component;
0065: import java.awt.Point;
0066: import java.awt.Window;
0067:
0068: import java.lang.reflect.Constructor;
0069: import java.lang.reflect.InvocationTargetException;
0070:
0071: import java.util.Enumeration;
0072: import java.util.HashMap;
0073: import java.util.Hashtable;
0074: import java.util.Iterator;
0075: import java.util.Map;
0076: import java.util.Stack;
0077: import java.util.Vector;
0078:
0079: import javax.swing.SwingUtilities;
0080:
0081: /**
0082: * The module which manages the replay process.
0083: *
0084: * @author Thomas Leonhardt
0085: * @author <a href="mailto:cspannagel@web.de">Christian Spannagel</a> (Version 1.1)
0086: * @version 1.20
0087: */
0088: public class Replay extends EnvironmentMember implements Runnable,
0089: HashtableChangeListener, StructureElementListener,
0090: SyncController {
0091: /** Load the replayers from the customization at the beginning. */
0092: public static final int INIT_CUSTOM = 0;
0093:
0094: /** The replay should have no replayers at the beginning. */
0095: public static final int INIT_EMPTY = 1;
0096: private static Logger LOG = Logger.getLogger(Replay.class);
0097:
0098: /** The thread an instance of this class is running in. */
0099: private Thread thread;
0100:
0101: /** The record structure to replay. */
0102: private Structure structure;
0103:
0104: /** The instance which knows the components. */
0105: private Components components;
0106:
0107: /** The replay mode. */
0108: private ReplayMode replayMode;
0109:
0110: /** The list of replayers. */
0111: private PriorityList replayers;
0112:
0113: /** The robot which simulates user interactions. */
0114: private JacaretoRobot robot;
0115:
0116: /** The actual structure elemenr during replay. */
0117: private StructureElement actualElement;
0118:
0119: /** Is the replay running? */
0120: private boolean isRunning;
0121:
0122: /** Is the replay paused? */
0123: private boolean isPaused;
0124:
0125: /** Is safe mode enabled? */
0126: private boolean isSafeMode;
0127:
0128: /** <code>true</code> if the instance print many debug messages. */
0129: private boolean debugVerbose;
0130:
0131: /** The vector of replay listeners; */
0132: private Vector replayListeners;
0133:
0134: /** Last glass pane where the mark has been set. */
0135: private GlassPaneCompound actualCompound;
0136:
0137: /** Whether or not this instance is listening to hashtable changes. */
0138: private boolean isListeningToHashtableChanges;
0139:
0140: /** The replay stack. */
0141: private Stack replayStack;
0142:
0143: /** Has the replay been successful? */
0144: private boolean replayWasSuccessful;
0145:
0146: /** The Hashtable of elements where the replay instance should pause. */
0147: private Hashtable stoppers;
0148:
0149: /** Just replay one step. */
0150: private boolean stepwise;
0151:
0152: /** The last mouse motion event recordable. */
0153: private MouseEventRecordable lastMouseMotionEventRecordable;
0154:
0155: /** The filter which only allows events dipatched by this instance to be executed. */
0156: private ReplayInputFilter actualReplayInputFilter;
0157:
0158: /** The replay input filter for real mouse mode. */
0159: private ReplayInputFilter realInputFilter;
0160:
0161: /** The replay input filter for pseudo mouse and no mouse modes. */
0162: private ReplayInputFilter pseudoInputFilter;
0163:
0164: /** The test report. */
0165: private TestReport testReport;
0166:
0167: /** The cursor images for the pseudo mouse mode. */
0168: private CursorImages cursorImages;
0169:
0170: /** The management of modal dialogs. */
0171: private ModalDialogManagement modalDialogManagement;
0172:
0173: /** The jacareto class loader. */
0174: private JacaretoClassLoader jacaretoClassLoader;
0175:
0176: /** The glasspane manager. */
0177: private GlassPaneManager glassPaneManager;
0178:
0179: /** Indicates that replay should be done fast forward. */
0180: private boolean isFastForward;
0181:
0182: /** Saves the replay mode when changing to fast forward. */
0183: private ReplayMode oldReplayMode;
0184:
0185: /** The event listener of the replay instance. */
0186: private EventListener eventListener;
0187:
0188: /** Calculator for processing times of elements */
0189: private ProcTimeCalculator procTimeCalc = new ProcTimeCalculator();
0190:
0191: /** temp variable to store newly calculated times */
0192: long calculatedProcTime;
0193:
0194: /** The currently Recordable being replayed */
0195: Recordable current;
0196:
0197: /** The calculator to get the media time */
0198:
0199: //MediaTimeCalculator mediaTimeCalculator = new MediaTimeCalculator();
0200: /** The SyncMode of this controller */
0201: private SyncMode syncMode;
0202:
0203: /** The Map where the buffer times are stored */
0204: private Map bufferMap = new HashMap();
0205:
0206: /** The object which allows to play mouse and keyboard sounds. */
0207: private ReplaySounds replaySounds;
0208:
0209: /** Table which stored messages of unsupported operation exceptions. */
0210: private Hashtable unsupportedOperationMessages;
0211:
0212: /** The media time. */
0213: private long mediaTime;
0214:
0215: /** The time to stop in fast forward mode. */
0216: private long timeToStop;
0217:
0218: /** Whether or not the time to stop is active. */
0219: private boolean timeToStopIsActive;
0220:
0221: /**
0222: * Creates a new replay object. The initial options will be read from the customization. The
0223: * replay object will also listen to changes of the customization instance and adapt its own
0224: * values. The given classloader will be used for loading replayer classes.
0225: *
0226: * @param env the environment
0227: * @param components the instance for the components
0228: * @param structure the record structure to replay
0229: * @param init where to get the replayers from at the beginning
0230: * @param classLoader the class loader
0231: */
0232: public Replay(Environment env, Components components,
0233: Structure structure, int init, ClassLoader classLoader) {
0234: this (env, components, structure, new ReplayMode(env), init,
0235: classLoader);
0236: applyCustomization();
0237: }
0238:
0239: /**
0240: * Creates a new replay object. The initial options will be read from the customization. The
0241: * replay object will also listen to changes of the customization instance and adapt its own
0242: * values. The default classloader will be used.
0243: *
0244: * @param env the environment
0245: * @param components the instance for the components
0246: * @param structure the record structure to replay
0247: * @param init where to get the replayers from at the beginning
0248: */
0249: public Replay(Environment env, Components components,
0250: Structure structure, int init) {
0251: this (env, components, structure, init, null);
0252: }
0253:
0254: /**
0255: * Creates a new replay object. The initial options will be read from the customization. The
0256: * replay object will also listen to changes of the customization instance and adapt its own
0257: * values. The default classloader will be used.
0258: *
0259: * @param env the environment
0260: * @param components the instance for the components
0261: * @param init where to get the replayers from at the beginning
0262: */
0263: public Replay(Environment env, Components components, int init) {
0264: this (env, components, null, init, null);
0265: }
0266:
0267: /**
0268: * Creates a new replay object. The initial options will be read from the customization. The
0269: * replay object will also listen to changes of the customization instance and adapt its own
0270: * values. The given classloader will be used for loading replayer classes.
0271: *
0272: * @param env the environment
0273: * @param components the instance for the components
0274: * @param init where to get the replayers from at the beginning
0275: * @param classLoader the class loader
0276: */
0277: public Replay(Environment env, Components components, int init,
0278: ClassLoader classLoader) {
0279: this (env, components, null, new ReplayMode(env), init,
0280: classLoader);
0281: applyCustomization();
0282: }
0283:
0284: /**
0285: * Creates a new replay object with the specified values and the default class loader.
0286: *
0287: * @param env the environment
0288: * @param components the instance for the components
0289: * @param structure the record structure to replay
0290: * @param replayMode the replay mode
0291: * @param init where to get the replayers from at the beginning
0292: */
0293: public Replay(Environment env, Components components,
0294: Structure structure, ReplayMode replayMode, int init) {
0295: this (env, components, structure, replayMode, init, null);
0296: }
0297:
0298: /**
0299: * Creates a new replay object with the specified values.
0300: *
0301: * @param env the environment
0302: * @param components the instance for the components
0303: * @param structure the record structure to replay
0304: * @param replayMode the replay mode
0305: * @param init where to get the replayers from at the beginning
0306: * @param classLoader the class loader to use
0307: */
0308: public Replay(Environment env, Components components,
0309: Structure structure, ReplayMode replayMode, int init,
0310: ClassLoader classLoader) {
0311: super (env);
0312:
0313: this .structure = structure;
0314: this .components = components;
0315: this .glassPaneManager = components.getGlassPaneManager();
0316:
0317: setMode(replayMode);
0318: isRunning = false;
0319: isPaused = false;
0320:
0321: isSafeMode = false;
0322:
0323: this .actualCompound = null;
0324: modalDialogManagement = new ModalDialogManagement(env, this );
0325: replaySounds = new ReplaySounds(env);
0326:
0327: replayers = new PriorityList();
0328:
0329: realInputFilter = new ReplayInputFilter(env, components,
0330: ReplayInputFilter.FILTER_MOUSE_AND_KEY_EVENTS);
0331:
0332: pseudoInputFilter = new ReplayInputFilter(env, components,
0333: ReplayInputFilter.FILTER_KEY_EVENTS);
0334:
0335: actualReplayInputFilter = null;
0336:
0337: unsupportedOperationMessages = new Hashtable();
0338:
0339: realInputFilter.setReplay(this );
0340: pseudoInputFilter.setReplay(this );
0341: replayListeners = new Vector(5);
0342:
0343: createRobot();
0344:
0345: if (init == INIT_CUSTOM) {
0346: loadReplayers(classLoader);
0347: }
0348:
0349: env.getCustomization().addHashtableChangeListener(this );
0350: setListeningToHashtableChanges(true);
0351: actualElement = null;
0352: replayStack = new Stack();
0353: stoppers = new Hashtable();
0354: timeToStop = 0;
0355: timeToStopIsActive = false;
0356: stepwise = false;
0357: testReport = null;
0358: setFastForward(false);
0359:
0360: PopUpCatcher popUpCatcher = new PopUpCatcher(env);
0361: popUpCatcher.addWaitingInstance(components);
0362:
0363: eventListener = new EventListener(env, components,
0364: ((structure != null) ? structure.getRecord() : null),
0365: EventListener.INIT_EMPTY);
0366: eventListener.addCatcher(popUpCatcher, 100);
0367: eventListener.addCatcher(modalDialogManagement, 200);
0368:
0369: // add media time calculator to listeners to measure the correct media time
0370: //this.addReplayListener (this.mediaTimeCalculator);
0371: }
0372:
0373: /**
0374: * Register a replayer with a specified priority. A Replayer is responsible for an object
0375: * during the replay process. A greater value of priority symbolizes a higher priority.
0376: *
0377: * @param replayer the replayer to add
0378: * @param priority the priority
0379: */
0380: public void addReplayer(Replayer replayer, int priority) {
0381: if (priority >= 0) {
0382: replayers.add(replayer, priority);
0383: } else {
0384: replayers.add(replayer);
0385: }
0386: }
0387:
0388: /**
0389: * Register a replayer with the lowest priority. A Replayer is responsible for an object during
0390: * the replay process.
0391: *
0392: * @param replayer the replayer to add
0393: */
0394: public void addReplayer(Replayer replayer) {
0395: addReplayer(replayer, -1);
0396: }
0397:
0398: /**
0399: * Removes a replayer.
0400: *
0401: * @param replayer the replayer to remove
0402: */
0403: public void removeReplayer(Replayer replayer) {
0404: if (replayers.contains(replayer)) {
0405: replayers.remove(replayer);
0406: }
0407: }
0408:
0409: /**
0410: * Returns the first replayer which feels responsible for the given element. If no replayer is
0411: * responsible, <code>null</code> will be returned.
0412: *
0413: * @param element the structure elemenr
0414: *
0415: * @return the first replayer which feels responsible, or <code>null</code> if no replayer is
0416: * responsible.
0417: */
0418: public Replayer getFirstResponsibleForElement(
0419: StructureElement element) {
0420: Replayer replayer;
0421: Iterator i = replayers.iterator();
0422:
0423: while (i.hasNext()) {
0424: replayer = (Replayer) i.next();
0425:
0426: if (replayer.handlesElement(element)) {
0427: return replayer;
0428: }
0429: }
0430:
0431: return null;
0432: }
0433:
0434: /**
0435: * Adds an element where the replay instance should pause.
0436: *
0437: * @param element DOCUMENT ME!
0438: */
0439: public void addStopper(StructureElement element) {
0440: stoppers.put(element, "");
0441: }
0442:
0443: /**
0444: * Removes an element from the stoppers.
0445: *
0446: * @param element DOCUMENT ME!
0447: */
0448: public void removeStopper(StructureElement element) {
0449: if (stoppers.containsKey(element)) {
0450: stoppers.remove(element);
0451: }
0452: }
0453:
0454: /**
0455: * Removes all stoppers.
0456: */
0457: public void clearStoppers() {
0458: stoppers.clear();
0459: }
0460:
0461: /**
0462: * Adds a time to stop.
0463: *
0464: * @param timeToStop the time to stop
0465: */
0466: public void addTimeToStop(long timeToStop) {
0467: this .timeToStop = timeToStop;
0468: this .timeToStopIsActive = true;
0469: }
0470:
0471: /**
0472: * Removes the time to stop.
0473: */
0474: public void removeTimeToStop() {
0475: this .timeToStop = 0;
0476: this .timeToStopIsActive = false;
0477: }
0478:
0479: /**
0480: * Returns the priority list of replayers.
0481: *
0482: * @return the list
0483: */
0484: public PriorityList getReplayers() {
0485: return replayers;
0486: }
0487:
0488: /**
0489: * Sets the fast forward mode.
0490: *
0491: * @param isFastForward whether or not replay should be done fast forward
0492: */
0493: public void setFastForward(boolean isFastForward) {
0494: this .isFastForward = isFastForward;
0495: }
0496:
0497: /**
0498: * Returns whether or not fast forward mode is activated
0499: *
0500: * @return <code>true</code> if replay is done fast forward, otherwise <code>false</code>
0501: */
0502: public boolean getFastForward() {
0503: return isFastForward;
0504: }
0505:
0506: /**
0507: * Starts the replay process.
0508: */
0509: public void start() {
0510: if (!isRunning() && (structure != null)) {
0511: isRunning = true;
0512: actualElement = null;
0513: mediaTime = 0;
0514:
0515: applyReplayMode();
0516:
0517: // clear all pseudo mouse panes
0518: GlassPaneCompound[] compounds = glassPaneManager
0519: .getGlassPaneCompounds();
0520:
0521: for (int i = 0; i < compounds.length; i++) {
0522: PseudoMousePointerGlassPane pseudoPane = (PseudoMousePointerGlassPane) compounds[i]
0523: .getGlassPane(GlassPaneCompound.PSEUDO_MOUSE_PANE);
0524:
0525: if (pseudoPane != null) {
0526: pseudoPane.clear();
0527: }
0528: }
0529:
0530: thread = new Thread(this , "Jacareto.Replay_Thread");
0531:
0532: eventListener.start();
0533: thread.start();
0534: }
0535: }
0536:
0537: /**
0538: * Stops the replay process.
0539: */
0540: public void stop() {
0541: if (isRunning()) {
0542: isRunning = false;
0543:
0544: eventListener.stop();
0545:
0546: if (actualReplayInputFilter != null) {
0547: actualReplayInputFilter.clear();
0548: actualReplayInputFilter.stop();
0549: }
0550:
0551: if (isFastForward) {
0552: this .replayMode = oldReplayMode;
0553: oldReplayMode = null;
0554: setFastForward(false);
0555: }
0556:
0557: glassPaneManager.setVisible(
0558: GlassPaneCompound.PSEUDO_MOUSE_PANE, false);
0559: glassPaneManager.setVisible(
0560: GlassPaneCompound.MARK_MODE_PANE, false);
0561: actualCompound = null;
0562: fireReplayEvent(new ReplayEvent(this , ReplayEvent.STOPPED));
0563: }
0564: }
0565:
0566: /**
0567: * Pauses the replay process.
0568: */
0569: public void pause() {
0570: if (isRunning() && !isPaused()) {
0571: isPaused = true;
0572:
0573: eventListener.stop();
0574:
0575: if (actualReplayInputFilter != null) {
0576: actualReplayInputFilter.stop();
0577: }
0578:
0579: glassPaneManager.setVisible(
0580: GlassPaneCompound.PSEUDO_MOUSE_PANE, false);
0581: glassPaneManager.setVisible(
0582: GlassPaneCompound.MARK_MODE_PANE, false);
0583:
0584: if (isFastForward) {
0585: this .replayMode = oldReplayMode;
0586: oldReplayMode = null;
0587: setFastForward(false);
0588: }
0589:
0590: actualCompound = null;
0591: fireReplayEvent(new ReplayEvent(this , ReplayEvent.PAUSED));
0592: }
0593: }
0594:
0595: /**
0596: * Whether or not the next element should be replayed stepwise.
0597: *
0598: * @param stepwise DOCUMENT ME!
0599: */
0600: public void stepwise(boolean stepwise) {
0601: this .stepwise = stepwise;
0602: }
0603:
0604: /**
0605: * Continues after a pause.
0606: */
0607: public void continueReplay() {
0608: if (isRunning() && isPaused()) {
0609: isPaused = false;
0610: applyReplayMode();
0611: eventListener.start();
0612:
0613: fireReplayEvent(new ReplayEvent(this , ReplayEvent.CONTINUED));
0614: }
0615: }
0616:
0617: /**
0618: * Resets the replay process.
0619: */
0620: public void reset() {
0621: if (isRunning() && isPaused()) {
0622: replayStack.clear();
0623: isPaused = false;
0624: isRunning = false;
0625: replayWasSuccessful = true;
0626: mediaTime = 0;
0627: glassPaneManager.setVisible(
0628: GlassPaneCompound.PSEUDO_MOUSE_PANE, false);
0629: glassPaneManager.setVisible(
0630: GlassPaneCompound.MARK_MODE_PANE, false);
0631: actualCompound = null;
0632: modalDialogManagement.reset();
0633: fireReplayEvent(new ReplayEvent(this , ReplayEvent.RESTARTED));
0634: }
0635: }
0636:
0637: /**
0638: * Sets the structure to be replayed. The replay instance will also be resetted with the {@link
0639: * #reset()} method.
0640: *
0641: * @param structure the structure to be replayed.
0642: */
0643: public void setStructure(Structure structure) {
0644: reset();
0645: this .structure = structure;
0646: }
0647:
0648: /**
0649: * Returns the structure contained in the replay instance.
0650: *
0651: * @return the structure, or <code>null</code> if no structure is registered
0652: */
0653: public Structure getStructure() {
0654: return structure;
0655: }
0656:
0657: /**
0658: * Returns whether the replay is paused or not.
0659: *
0660: * @return DOCUMENT ME!
0661: */
0662: public boolean isPaused() {
0663: return isPaused;
0664: }
0665:
0666: /**
0667: * Replays the recorded user interactions. This method is called automatically by invoking the
0668: * method {@link #start()}.
0669: */
0670: public void run() {
0671: replayWasSuccessful = true;
0672: fireReplayEvent(new ReplayEvent(this , ReplayEvent.STARTED));
0673:
0674: /*try {
0675: thread.sleep(1500);
0676: } catch(InterruptedException ex) {}
0677: */
0678: lastMouseMotionEventRecordable = null;
0679: modalDialogManagement.reset();
0680: logger.debug(getLanguage().getString("Replay.Msg.Start"));
0681:
0682: // the loop on the structure elements
0683: // the next element to replay lies on the top of the stack
0684: replayStack.clear();
0685: replayStack.push(structure.getRootElement());
0686:
0687: // as long as replay has not been stopped
0688: while (isRunning()) {
0689: // pause status
0690: while (isPaused()) {
0691: try {
0692: Thread.sleep(500);
0693: } catch (InterruptedException ignored) {
0694: ;
0695: }
0696: }
0697:
0698: if (!isRunning) {
0699: break;
0700: }
0701:
0702: if (replayWasSuccessful) {
0703: if (!replayStack.empty()) {
0704: Object element = replayStack.pop();
0705:
0706: if (element instanceof StructureElement) {
0707: actualElement = (StructureElement) element;
0708: fireReplayEvent(new ReplayEvent(this ,
0709: ReplayEvent.ACTUAL_ELEMENT_CHANGED));
0710: } else if ((element instanceof String)
0711: && ((String) element).equals("STOP")) {
0712: replayWasSuccessful = true;
0713: pause();
0714:
0715: continue;
0716: }
0717: } else {
0718: break;
0719: }
0720: }
0721:
0722: // enter pause after every element
0723: if (stepwise) {
0724: replayStack.push("STOP");
0725:
0726: if (!(actualElement instanceof RootElement)) {
0727: stepwise = false;
0728: }
0729: }
0730:
0731: if (actualElement != null) {
0732: // check if user wants to stop the process at this element
0733: if (stoppers.containsKey(actualElement)) {
0734: replayWasSuccessful = false;
0735: pause();
0736: } else if (timeToStopIsActive
0737: && (timeToStop < getMediaTime())) {
0738: replayWasSuccessful = false;
0739: removeTimeToStop();
0740: pause();
0741: } else {
0742: // Just allow the actual element to be executed and no events dispatched by the
0743: // user during the replay process
0744: if (actualReplayInputFilter != null) {
0745: if (actualElement instanceof InputEventRecordable) {
0746: actualReplayInputFilter
0747: .setNextInputEvent((InputEventRecordable) actualElement);
0748: } else {
0749: actualReplayInputFilter
0750: .setNextInputEvent(null);
0751: }
0752: }
0753:
0754: Replayer replayer = getFirstResponsibleForElement(actualElement);
0755:
0756: if (replayer != null) {
0757: if (isDebugVerbose()) {
0758: logger
0759: .debug(language
0760: .getString("Replay.Msg.ReplayingWith")
0761: + " "
0762: + replayer.getClass()
0763: .getName());
0764: }
0765:
0766: try {
0767: /**
0768: * Adds the MediaClipReplayer to the replay listeners to listen to
0769: * STOPPED events.
0770: */
0771: if (replayer instanceof MediaClipReplayer) {
0772: this
0773: .addReplayListener((MediaClipReplayer) replayer);
0774: }
0775:
0776: /**
0777: * Inform SyncModel about currently replayed blocks/elements
0778: */
0779: if ((actualElement instanceof Recordable)
0780: && !((actualElement instanceof RootElement))) {
0781: this .current = (Recordable) actualElement;
0782:
0783: fireReplayEvent(new ReplayEvent(
0784: this ,
0785: ReplayEvent.REPLAYED_ELEMENT_CHANGED,
0786: this .current));
0787: }
0788:
0789: if (this .replayMode.getTimeMode() == ReplayMode.REALTIME) {
0790: /** Get Buffer from bufferMap and call snoozeBuffer() */
0791: Long buffer = (Long) this .bufferMap
0792: .get(actualElement);
0793:
0794: if (buffer != null) {
0795: this .bufferSnooze(buffer
0796: .longValue());
0797: }
0798: }
0799:
0800: // start measuring of procTime
0801: procTimeCalc.startProcTimeMeasure();
0802:
0803: try {
0804: replayWasSuccessful = replayer
0805: .replay(actualElement);
0806:
0807: if (!(actualElement instanceof MediaClipRecordable)) {
0808: mediaTime += actualElement
0809: .getDuration();
0810: }
0811: } catch (UnsupportedOperationException uoex) {
0812: // Catching operations which are not supported on every platform
0813: String message = uoex.getMessage();
0814:
0815: if (StringToolkit.isDefined(message)
0816: && !unsupportedOperationMessages
0817: .containsKey(message)) {
0818: logger
0819: .info(language
0820: .getString("Replay.Msg.UnsupportedOperationException"));
0821: logger.info(message);
0822: unsupportedOperationMessages.put(
0823: message, "");
0824: }
0825:
0826: replayWasSuccessful = true;
0827: }
0828:
0829: // stop measuring of procTime, calculate new procTime and return it
0830: calculatedProcTime = procTimeCalc
0831: .stopProcTimeMeasure(actualElement
0832: .getProcTime());
0833:
0834: if (actualElement.hasProcTime()) {
0835: actualElement
0836: .setProcTime(calculatedProcTime); // set new procTime
0837: }
0838: } catch (Exception ex) {
0839: logger.error(ex.getMessage());
0840:
0841: if (!replayMode.getIgnoreExceptions()) {
0842: replayWasSuccessful = false;
0843: }
0844:
0845: ex.printStackTrace();
0846: }
0847:
0848: if (!replayWasSuccessful) {
0849: logger
0850: .error(language
0851: .getString("Replay.Error.DuringReplay"));
0852: pause();
0853: }
0854: } else if (actualElement.hasChildren()) {
0855: // push the children on the stack
0856: for (int i = actualElement.getChildrenCount() - 1; i >= 0; i--) {
0857: replayStack.push(actualElement.getChild(i));
0858: }
0859:
0860: replayWasSuccessful = true;
0861: } else {
0862: logger.debug(language
0863: .getString("Replay.Msg.NoReplayer")
0864: + " " + actualElement.getElementName());
0865:
0866: if (!(actualElement instanceof MediaClipRecordable)) {
0867: mediaTime += actualElement.getDuration();
0868: }
0869:
0870: replayWasSuccessful = true;
0871: }
0872: }
0873: }
0874: }
0875:
0876: actualElement = null;
0877: logger.debug(getLanguage().getString("Replay.Msg.Stop"));
0878: stop();
0879: }
0880:
0881: /**
0882: * Returns the actual structure element during replay, or <code>null</code> if the replay
0883: * process has not yet been started.
0884: *
0885: * @return DOCUMENT ME!
0886: */
0887: public StructureElement getActualElement() {
0888: return actualElement;
0889: }
0890:
0891: /**
0892: * Sets the jacareto class loader. This class loader can be used by replayers which want to add
0893: * paths to the resources paths.
0894: *
0895: * @param jacaretoClassLoader DOCUMENT ME!
0896: */
0897: public void setJacaretoClassLoader(
0898: JacaretoClassLoader jacaretoClassLoader) {
0899: this .jacaretoClassLoader = jacaretoClassLoader;
0900: }
0901:
0902: /**
0903: * Returns the jacareto class loader.
0904: *
0905: * @return DOCUMENT ME!
0906: */
0907: public JacaretoClassLoader getJacaretoClassLoader() {
0908: return (jacaretoClassLoader != null) ? jacaretoClassLoader
0909: : new JacaretoClassLoader(env);
0910: }
0911:
0912: /**
0913: * <p>
0914: * This method calls the sleep-method of the replay-thread.
0915: * </p>
0916: *
0917: * <p>
0918: * If the specified time is greater than the maximum delay, the latter on will be taken.
0919: * </p>
0920: *
0921: * @param timeToSleep the time to sleep, in msec
0922: */
0923: private void bufferSnooze(long timeToSleep) {
0924: try {
0925: long maxDelay = replayMode.getMaxDelay();
0926: long sleepTime = (timeToSleep < maxDelay) ? timeToSleep
0927: : maxDelay;
0928:
0929: if (timeToSleep < 0) {
0930: timeToSleep = 0;
0931: }
0932:
0933: Thread.sleep(sleepTime);
0934: } catch (InterruptedException ex) {
0935: logger.debug(getLanguage().getString(
0936: "Replay.Msg.SnoozeInterrupt"));
0937: }
0938: }
0939:
0940: /**
0941: * This method calls the sleep-method of the replay-thread. Replayers can use it if they want
0942: * the replay process to sleep for a while. If the specified time is greater than the maximum
0943: * delay, the latter on will be taken.
0944: *
0945: * @param timeToSleep the time to sleep, in msec
0946: */
0947: public void snooze(long timeToSleep) {
0948: try {
0949: long maxDelay = replayMode.getMaxDelay();
0950: long sleepTime = (timeToSleep < maxDelay) ? timeToSleep
0951: : maxDelay;
0952: Thread.sleep(sleepTime);
0953: } catch (InterruptedException ex) {
0954: logger.debug(getLanguage().getString(
0955: "Replay.Msg.SnoozeInterrupt"));
0956: }
0957: }
0958:
0959: /**
0960: * Returns the actual glasspane compound.
0961: *
0962: * @return the glasspane compound
0963: */
0964: protected GlassPaneCompound getActualCompound() {
0965: return actualCompound;
0966: }
0967:
0968: /**
0969: * This method returns the robot. Replayers can use this method if they need the robot.
0970: *
0971: * @return the robot
0972: */
0973: public JacaretoRobot getRobot() {
0974: return robot;
0975: }
0976:
0977: /**
0978: * Returns the actual pseudo mouse glass pane.
0979: *
0980: * @param component DOCUMENT ME!
0981: *
0982: * @return DOCUMENT ME!
0983: */
0984: protected PseudoMousePointerGlassPane getPseudoMousePane(
0985: Component component) {
0986: GlassPaneCompound compound = getGlassPaneCompound(component);
0987:
0988: if (compound != null) {
0989: if (!compound
0990: .isVisible(GlassPaneCompound.PSEUDO_MOUSE_PANE)
0991: && isRunning() && !isPaused()) {
0992: compound.setVisible(
0993: GlassPaneCompound.PSEUDO_MOUSE_PANE, true);
0994: }
0995:
0996: return (PseudoMousePointerGlassPane) compound
0997: .getGlassPane(GlassPaneCompound.PSEUDO_MOUSE_PANE);
0998: } else {
0999: return null;
1000: }
1001: }
1002:
1003: /**
1004: * Returns the last event used in the moveMouse method.
1005: *
1006: * @return DOCUMENT ME!
1007: */
1008: public MouseEventRecordable getLastMouseMotionEventRecordable() {
1009: return lastMouseMotionEventRecordable;
1010: }
1011:
1012: /**
1013: * Sets the replay mode.
1014: *
1015: * @param replayMode the new replay mode
1016: */
1017: public void setMode(ReplayMode replayMode) {
1018: if (oldReplayMode != null) {
1019: oldReplayMode.removeStructureElementListener(this );
1020: }
1021:
1022: if (this .replayMode != null) {
1023: this .replayMode.removeStructureElementListener(this );
1024: }
1025:
1026: this .replayMode = replayMode;
1027: replayMode.addStructureElementListener(this );
1028:
1029: applyReplayMode();
1030: fireReplayEvent(new ReplayEvent(this , ReplayEvent.MODE_CHANGED));
1031: }
1032:
1033: /**
1034: * Returns the actual replay mode.
1035: *
1036: * @return the replay mode
1037: */
1038: public ReplayMode getMode() {
1039: return replayMode;
1040: }
1041:
1042: /**
1043: * Returns the sounds object.
1044: *
1045: * @return the instance which allows to play sounds.
1046: */
1047: public ReplaySounds getSounds() {
1048: return replaySounds;
1049: }
1050:
1051: /**
1052: * Sets the mark on the specified component at the specified coordinates. If the given point is
1053: * <code>null</code>, then the whole component gets a border as mark. This method replaces the
1054: * glasspane of the parent window with a mouse trail glass pane. This new glass pane is able
1055: * to mark the mouse trail and components. If the given component is child of a non-swing
1056: * window (a subclass of <code>java.awt.Frame</code> or <code>java.awt.Dialog</code>, then no
1057: * mark will be set, because these components do not have a glasspane.
1058: *
1059: * @param component the component
1060: * @param position the position on the component
1061: */
1062: public void mark(Component component, Point position) {
1063: if (!((replayMode.getTimeMode() == ReplayMode.FIXEDTIME) && replayMode
1064: .getIsMarkMode())) {
1065: return;
1066: }
1067:
1068: // replace the window's glass pane with a new glass pane compound
1069: // if it is not already one
1070: GlassPaneCompound compound = getGlassPaneCompound(component);
1071: MarkModeGlassPane mouseTrailPane = null;
1072:
1073: if ((compound != null) && isRunning() && !isPaused()) {
1074: if (!compound.isVisible(GlassPaneCompound.MARK_MODE_PANE)) {
1075: compound.setVisible(GlassPaneCompound.MARK_MODE_PANE,
1076: true);
1077: }
1078:
1079: mouseTrailPane = (MarkModeGlassPane) compound
1080: .getGlassPane(GlassPaneCompound.MARK_MODE_PANE);
1081:
1082: if (position != null) {
1083: // mark the position on the component
1084: mouseTrailPane.mark(component, position);
1085: } else {
1086: // mark the whole component (border)
1087: mouseTrailPane.mark(component);
1088: }
1089:
1090: mouseTrailPane.repaint();
1091: } else {
1092: return;
1093: }
1094: }
1095:
1096: private GlassPaneCompound getGlassPaneCompound(Component component) {
1097: Window window = SwingUtilities.getWindowAncestor(component);
1098: GlassPaneCompound compound = null;
1099:
1100: if (window != null) {
1101: compound = glassPaneManager.getGlassPaneCompound(window);
1102:
1103: // If the window is changing, clear the glass pane
1104: // of the old window
1105: if ((compound != null) && (compound != actualCompound)) {
1106: if (actualCompound != null) {
1107: ((MarkModeGlassPane) actualCompound
1108: .getGlassPane(GlassPaneCompound.MARK_MODE_PANE))
1109: .clear();
1110:
1111: // TO DO Pseudomouse
1112: }
1113:
1114: actualCompound = compound;
1115: }
1116: }
1117:
1118: return compound;
1119: }
1120:
1121: /**
1122: * Tells the replay instance to print all debug messages or not.
1123: *
1124: * @param debugVerbose DOCUMENT ME!
1125: */
1126: public void setDebugVerbose(boolean debugVerbose) {
1127: this .debugVerbose = debugVerbose;
1128: }
1129:
1130: /**
1131: * Returns whether the "debug verbose" mode it active or not.
1132: *
1133: * @return DOCUMENT ME!
1134: */
1135: public boolean isDebugVerbose() {
1136: return debugVerbose;
1137: }
1138:
1139: /**
1140: * Returns the component specified by its iternal name. If the component does not exist or is
1141: * not visible, the method will try to find this component until a timeout has been reached
1142: * (in this case an exception will be thrown).
1143: *
1144: * @param name the name of the component.
1145: * @param userDefinedName the user defined component name (used when the component could not be
1146: * found by the first name.
1147: * @param componentSearchTimeout the timeout, in msec.
1148: *
1149: * @return the component
1150: *
1151: * @throws ComponentNotFoundException if the component cannot be found or is invisible
1152: */
1153: public Component getVisibleComponent(String name,
1154: String userDefinedName, long componentSearchTimeout)
1155: throws ComponentNotFoundException {
1156: Component result = null;
1157: Logger logger = getLogger();
1158: Language language = getLanguage();
1159: boolean messagePrinted = false;
1160: boolean firstTimeSearching = true;
1161:
1162: long timeWaited = 0;
1163: long componentSearchStep = replayMode.getComponentSearchStep();
1164: boolean isComponentSearchTimeoutEnabled = replayMode
1165: .getComponentSearchTimeoutEnabled();
1166:
1167: do {
1168: result = components.getComponent(name);
1169:
1170: if ((result == null)
1171: && StringToolkit.isDefined(userDefinedName)) {
1172: result = components
1173: .getComponentByUserDefinedName(userDefinedName);
1174: }
1175:
1176: if ((result == null) || !result.isVisible()) {
1177: if (!firstTimeSearching) {
1178: if (!messagePrinted) {
1179: logger
1180: .info(language
1181: .getString("Replay.Msg.SearchingForComponent")
1182: + " " + name);
1183:
1184: if (isComponentSearchTimeoutEnabled) {
1185: logger.info(language
1186: .getString("Replay.Msg.Timeout")
1187: + " "
1188: + componentSearchTimeout
1189: + " "
1190: + language
1191: .getString("General.Msec"));
1192: } else {
1193: logger.info(language
1194: .getString("Replay.Msg.NoTimeout"));
1195: }
1196:
1197: messagePrinted = true;
1198: }
1199:
1200: if ((timeWaited % 1000) == 0) {
1201: if (isComponentSearchTimeoutEnabled) {
1202: logger
1203: .info("["
1204: + ((componentSearchTimeout - timeWaited) / 1000)
1205: + "]");
1206: } else {
1207: logger.info(".");
1208: }
1209: }
1210:
1211: try {
1212: Thread.sleep(componentSearchStep);
1213: timeWaited += componentSearchStep;
1214: } catch (InterruptedException i) {
1215: ;
1216: }
1217: }
1218:
1219: components.update();
1220: result = components.getComponent(name);
1221:
1222: if (result == null) {
1223: components.validatePath(name);
1224: }
1225:
1226: if (firstTimeSearching) {
1227: components.setDebugPrinting(false);
1228: firstTimeSearching = false;
1229: }
1230: }
1231: } while ((!isComponentSearchTimeoutEnabled || (timeWaited < componentSearchTimeout))
1232: && ((result == null) || !result.isVisible())
1233: && !isPaused());
1234:
1235: // component which is not visible is not a result
1236: if ((result != null) && !result.isVisible()) {
1237: result = null;
1238: }
1239:
1240: if (result == null) {
1241: String messageString = language
1242: .getString("Replay.Error.ComponentNotFound")
1243: + " " + name + "\n";
1244: messageString += actualElement.getElementName();
1245: throw (new ComponentNotFoundException(messageString));
1246: } else if (messagePrinted) {
1247: logger.info(language.getString("Replay.Msg.ComponentFound")
1248: + " " + name);
1249: }
1250:
1251: components.setDebugPrinting(true);
1252:
1253: return result;
1254: }
1255:
1256: /**
1257: * Returns the component specified by its iternal name. If the component does not exist or is
1258: * not visible, the method will try to find this component until a timeout has been reached
1259: * (in this case <code>null</code> will be returned). The component will also be put to the
1260: * front. The timeout is the default timeout.
1261: *
1262: * @param name the name of the component.
1263: * @param userDefinedName the user defined component name (used when the component could not be
1264: * found by the first name.
1265: *
1266: * @return the component
1267: *
1268: * @throws ComponentNotFoundException if the component cannot be found or is invisible
1269: */
1270: public Component getVisibleComponent(String name,
1271: String userDefinedName) throws ComponentNotFoundException {
1272: return getVisibleComponent(name, userDefinedName, replayMode
1273: .getComponentSearchTimeout());
1274: }
1275:
1276: /**
1277: * Returns whether the replay process is going on or not.
1278: *
1279: * @return true if the replay is running, otherwise false.
1280: */
1281: public boolean isRunning() {
1282: return isRunning;
1283: }
1284:
1285: /**
1286: * Returns the instance which manages the components
1287: *
1288: * @return the <code>Components</code> instance
1289: */
1290: public Components getComponents() {
1291: return components;
1292: }
1293:
1294: /**
1295: * Sets the test report of the replay instance.
1296: *
1297: * @param testReport DOCUMENT ME!
1298: */
1299: public void setTestReport(TestReport testReport) {
1300: this .testReport = testReport;
1301: }
1302:
1303: /**
1304: * Returns the test report, or <code>null</code> if the test report has not have been set.
1305: *
1306: * @return DOCUMENT ME!
1307: */
1308: public TestReport getTestReport() {
1309: return testReport;
1310: }
1311:
1312: /**
1313: * Sets the cursor images for the pseudo mouse mode.
1314: *
1315: * @param cursorImages DOCUMENT ME!
1316: */
1317: public void setCursorImages(CursorImages cursorImages) {
1318: this .cursorImages = cursorImages;
1319: }
1320:
1321: /**
1322: * Returns the cursor images for the pseudo mouse mode.
1323: *
1324: * @return DOCUMENT ME!
1325: */
1326: public CursorImages getCursorImages() {
1327: return cursorImages;
1328: }
1329:
1330: /**
1331: * Creates the robot which is able to simulate user interactions.
1332: */
1333: private void createRobot() {
1334: robot = null;
1335:
1336: try {
1337: robot = new JacaretoRobot(env, this );
1338: } catch (java.awt.AWTException exception) {
1339: getLogger().error(
1340: getLanguage().getString(
1341: "Replay.Error.RobotCreation"), exception);
1342: } finally {
1343: if (robot == null) {
1344: getLogger().error(
1345: getLanguage().getString(
1346: "Replay.Error.RobotNull"));
1347: }
1348: }
1349: }
1350:
1351: /**
1352: * Sets the last mouse motion event recordable.
1353: *
1354: * @param recordable DOCUMENT ME!
1355: */
1356: protected void setLastMouseMotionEventRecordable(
1357: MouseEventRecordable recordable) {
1358: lastMouseMotionEventRecordable = recordable;
1359: }
1360:
1361: /**
1362: * Returns the replay input filter.
1363: *
1364: * @return DOCUMENT ME!
1365: */
1366: public ReplayInputFilter getInputFilter() {
1367: return actualReplayInputFilter;
1368: }
1369:
1370: /**
1371: * Loads the replayers from the {@link jacareto.system.Customization} instance of the {@link
1372: * jacareto.system.Environment} object with the default classloader.
1373: */
1374: private void loadReplayers() {
1375: loadReplayers(ClassLoader.getSystemClassLoader());
1376: }
1377:
1378: /**
1379: * Loads the replayers from the {@link jacareto.system.Customization} instance of the {@link
1380: * jacareto.system.Environment} object.
1381: *
1382: * @param classLoader the class loader to use
1383: */
1384: private void loadReplayers(ClassLoader classLoader) {
1385: Logger logger = getLogger();
1386: Language language = getLanguage();
1387:
1388: if (classLoader == null) {
1389: classLoader = ClassLoader.getSystemClassLoader();
1390: }
1391:
1392: String replayerClassName = null;
1393:
1394: // some reflection instances
1395: Class replayerClass = null;
1396: Class[] parameterTypes = new Class[2];
1397: Object[] parameters = new Object[2];
1398:
1399: try {
1400: replayerClass = Class.forName("jacareto.replay.Replayer",
1401: true, classLoader);
1402: parameterTypes[0] = Class.forName(
1403: "jacareto.system.Environment", true, classLoader);
1404: parameterTypes[1] = Class.forName("jacareto.replay.Replay",
1405: true, classLoader);
1406:
1407: parameters[0] = env;
1408: parameters[1] = this ;
1409: } catch (ClassNotFoundException c) {
1410: logger.error(language
1411: .getString("Replay.Error.MissingClass"), c);
1412:
1413: return;
1414: }
1415:
1416: // load the map of replayers
1417: EnhancedHashtable replayersMap = getCustomization().getMap(
1418: "Replayers", new EnhancedHashtable());
1419: Enumeration enumeration = replayersMap.keys();
1420:
1421: while (enumeration.hasMoreElements()) {
1422: try {
1423: replayerClassName = (String) enumeration.nextElement();
1424:
1425: Class repClass = null;
1426: repClass = Class.forName(replayerClassName, true,
1427: classLoader);
1428:
1429: Constructor replayerConstructor = repClass
1430: .getConstructor(parameterTypes);
1431:
1432: if (replayerClass.isAssignableFrom(repClass)) {
1433: try {
1434: int priority = replayersMap.getInt(
1435: replayerClassName, -1);
1436: logger.debug(language
1437: .getString("Replay.Msg.Loading")
1438: + " "
1439: + replayerClassName
1440: + ", "
1441: + language
1442: .getString("General.Priority")
1443: + ": " + priority);
1444: addReplayer((Replayer) replayerConstructor
1445: .newInstance(parameters), priority);
1446: } catch (InstantiationException inst) {
1447: logger
1448: .debug(
1449: language
1450: .getString("Replay.Error.Construction"),
1451: inst);
1452: } catch (IllegalAccessException ill) {
1453: logger
1454: .debug(
1455: language
1456: .getString("Replay.Error.Construction"),
1457: ill);
1458: } catch (IllegalArgumentException ila) {
1459: logger
1460: .debug(
1461: language
1462: .getString("Replay.Error.Construction"),
1463: ila);
1464: } catch (InvocationTargetException inv) {
1465: logger
1466: .debug(
1467: language
1468: .getString("Replay.Error.Construction"),
1469: inv);
1470: }
1471: } else {
1472: logger.warn(language
1473: .getString("Replay.Msg.NotSubclass")
1474: + ": " + replayerClassName);
1475: }
1476: } catch (ClassNotFoundException c) {
1477: logger.debug(language
1478: .getString("Replay.Error.MissingClass")
1479: + " " + replayerClassName);
1480: } catch (NoSuchMethodException n) {
1481: logger.debug(language
1482: .getString("Replay.Error.MissingConstructor"),
1483: n);
1484: }
1485: }
1486: }
1487:
1488: /**
1489: * Invoked when the customization has changed.
1490: *
1491: * @param event the hashtable change event
1492: */
1493: public void hashtableChanged(HashtableChangeEvent event) {
1494: if (isListeningToHashtableChanges) {
1495: applyCustomization();
1496: }
1497: }
1498:
1499: /**
1500: * Specifies whether or not this instance is listening to changes of the customization.
1501: *
1502: * @param isListening DOCUMENT ME!
1503: */
1504: public void setListeningToHashtableChanges(boolean isListening) {
1505: this .isListeningToHashtableChanges = isListening;
1506: }
1507:
1508: /**
1509: * Returns whether or not this instance is listening to changes of the customization.
1510: *
1511: * @return DOCUMENT ME!
1512: */
1513: public boolean isListeningToHashtableChanges() {
1514: return isListeningToHashtableChanges;
1515: }
1516:
1517: /**
1518: * Adds a replay listener to the list of listeners. All listeners will be notified of replay
1519: * events.
1520: *
1521: * @param listener the listener to add
1522: */
1523: public void addReplayListener(ReplayListener listener) {
1524: replayListeners.add(listener);
1525: }
1526:
1527: /**
1528: * Removes a replay listener from the list of listeners.
1529: *
1530: * @param listener the listener to remove
1531: */
1532: public void removeReplayListener(ReplayListener listener) {
1533: if (replayListeners.contains(listener)) {
1534: replayListeners.remove(listener);
1535: }
1536: }
1537:
1538: /**
1539: * Fires a session event to all listeners.
1540: *
1541: * @param event the event
1542: */
1543: protected void fireReplayEvent(ReplayEvent event) {
1544: // copy into new vector because of concurrent
1545: // modification exceptions when using iterators...
1546: // Logger.getLogger(this.getClass()).debug("Replay.fireReplayEvent(): " + event.getID());
1547: if (replayListeners != null) {
1548: Iterator i = new Vector(replayListeners).iterator();
1549:
1550: while (i.hasNext()) {
1551: ((ReplayListener) i.next()).replayStateChanged(event);
1552: }
1553: }
1554: }
1555:
1556: /**
1557: * Reads the attribute values from the customization.
1558: */
1559: private void applyCustomization() {
1560: Customization customization = getCustomization();
1561: setDebugVerbose(customization.getBoolean("Replay.DebugVerbose",
1562: false));
1563: }
1564:
1565: /**
1566: * Called then the state of the replay mode has changed.
1567: *
1568: * @param event the structure element event
1569: */
1570: public void structureElementChanged(StructureElementEvent event) {
1571: if (event.getSource() == replayMode) {
1572: applyReplayMode();
1573: }
1574: }
1575:
1576: /**
1577: * Applies the replay mode.
1578: */
1579: private void applyReplayMode() {
1580: if (isRunning()) {
1581: if (!isPaused()) {
1582: if (actualReplayInputFilter != null) {
1583: actualReplayInputFilter.stop();
1584: }
1585: eventListener.removeCatcher(actualReplayInputFilter);
1586:
1587: ReplayInputFilter newReplayInputFilter = null;
1588:
1589: if (replayMode.getMouseMode() == ReplayMode.REALMOUSE) {
1590: newReplayInputFilter = realInputFilter;
1591: } else {
1592: newReplayInputFilter = pseudoInputFilter;
1593: }
1594:
1595: actualReplayInputFilter = newReplayInputFilter;
1596:
1597: isSafeMode = replayMode.getIsSafeMode();
1598:
1599: if (isSafeMode) {
1600: eventListener.addCatcher(actualReplayInputFilter);
1601: actualReplayInputFilter.start();
1602: }
1603:
1604: boolean isPseudoMouse = replayMode.getMouseMode() == ReplayMode.PSEUDOMOUSE;
1605: boolean isNoMouse = replayMode.getMouseMode() == ReplayMode.NOMOUSE;
1606: boolean isMarkMode = replayMode.getIsMarkMode();
1607: glassPaneManager.setVisible(
1608: GlassPaneCompound.PSEUDO_MOUSE_PANE,
1609: isPseudoMouse || isNoMouse);
1610: glassPaneManager.setVisible(
1611: GlassPaneCompound.MARK_MODE_PANE, isMarkMode);
1612: }
1613:
1614: if (isFastForward) {
1615: adaptModeToFastForward();
1616: }
1617: }
1618: }
1619:
1620: /**
1621: * Adapts the replay mode to fast forward.
1622: */
1623: private void adaptModeToFastForward() {
1624: oldReplayMode = replayMode;
1625: replayMode = (ReplayMode) oldReplayMode.clone();
1626: replayMode.setNotificationEnabled(false);
1627: replayMode.setTimeMode(ReplayMode.FIXEDTIME);
1628: replayMode.setFixedTimeDelay(replayMode.getFastForwardDelay());
1629: }
1630:
1631: /**
1632: * Returns the correct/real time the replay process is running
1633: *
1634: * @return long the media time
1635: */
1636: public long getMediaTime() {
1637: return mediaTime;
1638:
1639: //return this.mediaTimeCalculator.getCompleteMediaTime ();
1640: }
1641:
1642: /**
1643: * Does nothing because the main controller should not be disabled
1644: *
1645: * @param enabled boolean
1646: */
1647: public void setEnabled(boolean enabled) {
1648: }
1649:
1650: public BlockType getType() {
1651: return BlockType.EVENT;
1652: }
1653:
1654: /**
1655: * Dummy
1656: *
1657: * @param listener {@link SyncControllerListener}
1658: */
1659: public void addControllerListener(SyncControllerListener listener) {
1660: }
1661:
1662: /**
1663: * Dummy
1664: *
1665: * @param listener {@link SyncControllerListener}
1666: */
1667: public void removeControllerListener(SyncControllerListener listener) {
1668: }
1669:
1670: /**
1671: * Sets the {@link SyncMode} for this controller
1672: *
1673: * @param syncMode the new {@link SyncMode} to be set
1674: */
1675: public void setSyncMode(SyncMode syncMode) {
1676: this .syncMode = syncMode;
1677: }
1678:
1679: /**
1680: * Sets the buffer map for this controller
1681: *
1682: * @param bufferMap Map
1683: */
1684: public void setBufferMap(Map bufferMap) {
1685: this .bufferMap = bufferMap;
1686: }
1687:
1688: /**
1689: * {@inheritDoc}
1690: */
1691: public void updateBufferMap(Object blockRepresentation,
1692: Long bufferTime) {
1693: this .bufferMap.put(blockRepresentation, bufferTime);
1694: }
1695:
1696: /**
1697: * {@inheritDoc}
1698: */
1699: public Map getBufferMap() {
1700: return this .bufferMap;
1701: }
1702:
1703: /**
1704: * {@inheritDoc}
1705: */
1706: public Long getBuffer(Object blockRepresentation) {
1707: return (Long) this.bufferMap.get(blockRepresentation);
1708: }
1709: }
|