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.cleverphl.session;
0025:
0026: import jacareto.catching.AWTEventRecorder;
0027: import jacareto.catching.EventListener;
0028: import jacareto.catching.FileDialogWatcher;
0029: import jacareto.catching.KeyStrokeCatcher;
0030: import jacareto.catching.KeyStrokeObserver;
0031: import jacareto.catching.LastMousePosition;
0032: import jacareto.catching.SwingEventRecorder;
0033: import jacareto.cleverphl.CleverPHL;
0034: import jacareto.cleverphl.gui.CleverPHLConfirmDialog;
0035: import jacareto.comp.ComponentMode;
0036: import jacareto.comp.Components;
0037: import jacareto.comp.manipulation.ManipulationManagement;
0038: import jacareto.conceptualmodel.ConceptualModel;
0039: import jacareto.conceptualmodel.ConceptualModelRoot;
0040: import jacareto.convert.Converter;
0041: import jacareto.convert.SelectionConverter;
0042: import jacareto.dataset.DataSet;
0043: import jacareto.eventmask.AWTEventMaskGroup;
0044: import jacareto.filter.FilterList;
0045: import jacareto.interactionmodel.InteractionModel;
0046: import jacareto.interactionmodel.InteractionModelRoot;
0047: import jacareto.parse.RecordTokenizer;
0048: import jacareto.record.CalendarRecordable;
0049: import jacareto.record.KeyboardStateRecordable;
0050: import jacareto.record.RandomAccessRecord;
0051: import jacareto.record.RecordChangeEvent;
0052: import jacareto.record.RecordChangeListener;
0053: import jacareto.record.RecordException;
0054: import jacareto.record.Recordable;
0055: import jacareto.record.SystemInfoRecordable;
0056: import jacareto.record.VectorRecord;
0057: import jacareto.replay.CursorImages;
0058: import jacareto.replay.Replay;
0059: import jacareto.replay.ReplayMode;
0060: import jacareto.replay.event.ReplayEvent;
0061: import jacareto.replay.event.ReplayListener;
0062: import jacareto.starter.StarterList;
0063: import jacareto.struct.ExternalStructureTools;
0064: import jacareto.struct.RecordStructureCompound;
0065: import jacareto.struct.RootElement;
0066: import jacareto.struct.Structure;
0067: import jacareto.struct.StructureElement;
0068: import jacareto.struct.StructureTree;
0069: import jacareto.struct.XMLStructure;
0070: import jacareto.system.Customization;
0071: import jacareto.system.EnvironmentMember;
0072: import jacareto.test.TestLoader;
0073: import jacareto.test.TestReport;
0074: import jacareto.toolkit.EnhancedHashtable;
0075: import jacareto.toolkit.HashtableChangeEvent;
0076: import jacareto.toolkit.HashtableChangeListener;
0077: import jacareto.toolkit.InsertPoint;
0078: import jacareto.toolkit.JacaretoClassLoader;
0079: import jacareto.toolkit.JacaretoClassLoaderEvent;
0080: import jacareto.toolkit.JacaretoClassLoaderListener;
0081: import jacareto.toolkit.TimeSpanCalculator;
0082: import jacareto.toolkit.UUIDGen;
0083:
0084: import java.awt.Component;
0085: import java.awt.Panel;
0086: import java.awt.Point;
0087: import java.awt.Robot;
0088: import java.awt.Window;
0089: import java.awt.event.ActionEvent;
0090: import java.awt.event.WindowEvent;
0091:
0092: import java.io.File;
0093: import java.io.IOException;
0094:
0095: import java.util.Enumeration;
0096: import java.util.Hashtable;
0097: import java.util.Iterator;
0098: import java.util.Vector;
0099:
0100: import javax.swing.JCheckBoxMenuItem;
0101: import javax.swing.KeyStroke;
0102: import javax.swing.event.ListDataEvent;
0103: import javax.swing.event.ListDataListener;
0104: import javax.swing.tree.TreePath;
0105:
0106: /**
0107: * The CleverPHL session.
0108: *
0109: * @author <a href="mailto:cspannagel@web.de">Christian Spannagel</a>
0110: * @author <a href="mailto:markus.bois@web.de">Markus Bois</a>
0111: * @version 1.05
0112: */
0113: public class Session extends EnvironmentMember implements
0114: ReplayListener, KeyStrokeObserver, RecordChangeListener,
0115: HashtableChangeListener, Runnable, ListDataListener,
0116: JacaretoClassLoaderListener {
0117: /** The CleverPHL instance. */
0118: private CleverPHL cleverPHL;
0119:
0120: /** The session's own customization instance. */
0121: private Customization sessionCustom;
0122:
0123: /** The session's name. */
0124: private String name;
0125:
0126: /** Whether this session is active or not. */
0127: private boolean isActive;
0128:
0129: /** The vector of the session listeners. */
0130: private Vector sessionListeners;
0131:
0132: /** The type of the session. */
0133: private SessionType type;
0134:
0135: /** Whether the replay process is going on or not. */
0136: private boolean isReplaying;
0137:
0138: /** Whether or not replay is in forward mode. */
0139: private boolean isFastForward;
0140:
0141: /** Whether the replay process has been paused or not. */
0142: private boolean isReplayPause;
0143:
0144: /** Whether the capture process is going on ot not. */
0145: private boolean isCapturing;
0146:
0147: /** Indicates that the sessionhas been changed and not saved. */
0148: private boolean isSessionUnsaved;
0149:
0150: /** The components. */
0151: private Components components;
0152:
0153: /** The event listener for the whole session. */
0154: private EventListener sessionEventListener;
0155:
0156: /** The event listener for the capture process. */
0157: private EventListener captureEventListener;
0158:
0159: /** The catcher for key strokes. */
0160: private KeyStrokeCatcher keyStrokeCatcher;
0161:
0162: /** The replay instance. */
0163: private Replay replay;
0164:
0165: /** The last mouse position before the capture process has been paused. */
0166: private LastMousePosition lastMousePosition;
0167:
0168: /** The file dialog watcher. */
0169: private FileDialogWatcher fileDialogWatcher;
0170:
0171: /** The event mask for capturing. */
0172: private AWTEventMaskGroup eventMask;
0173:
0174: /** The list which contains the starters. */
0175: private StarterList starterList;
0176:
0177: /** The filter list. */
0178: private FilterList filterList;
0179:
0180: /** The data sets. */
0181: private Vector dataSets;
0182:
0183: /** The data set converter. */
0184: private Converter dataSetConverter;
0185:
0186: /** The directory of the session. */
0187: private File sessionDir;
0188:
0189: /** Whether or not the session should be stored automatically when exiting CleverPHL. */
0190: private boolean storeOnExit;
0191:
0192: /** The test loader. */
0193: private TestLoader testLoader;
0194:
0195: /** Whether or not cleverphl should be hidden during a capture process. */
0196: private boolean hideCleverPHLCapture;
0197:
0198: /** The classloader which has loaded the target application. */
0199: private JacaretoClassLoader targetApplicationClassLoader;
0200:
0201: /** The session classloader. */
0202: private JacaretoClassLoader sessionClassLoader;
0203:
0204: /** The identifier of the classloader. */
0205: private String classLoaderIdentifier;
0206:
0207: /** The session's test report. */
0208: private TestReport testReport;
0209:
0210: /** The session's cursor images. */
0211: private CursorImages cursorImages;
0212:
0213: /** The insertion mode */
0214: private boolean insertionMode;
0215:
0216: /** The record. */
0217: private RandomAccessRecord record;
0218:
0219: /** The record's structure. */
0220: private Structure structure;
0221:
0222: /** The JTree showing the structure. */
0223: private StructureTree structureTree;
0224:
0225: /** The structure tree listener. */
0226: private StructureTreeListener structureTreeListener;
0227:
0228: /** The InteractionModel */
0229: private InteractionModel interactionModel;
0230:
0231: /** The ConceptualModel */
0232: private ConceptualModel conceptualModel;
0233:
0234: /** The capture helper for marked captures */
0235: private CaptureHelper captureHelper;
0236:
0237: /** The manipulation management. */
0238: private ManipulationManagement manipulationManagement;
0239:
0240: /** The session replay mode. */
0241: private ReplayMode sessionReplayMode;
0242:
0243: /** Some event catchers. */
0244: private AWTEventRecorder awtEventRecorder;
0245: private SwingEventRecorder swingEventRecorder;
0246:
0247: /** The shutdown hook thread. */
0248: private Thread shutdownHookThread;
0249:
0250: /**
0251: * Creates a new non-active session.
0252: *
0253: * @param cleverPHL the CleverPHL instance.
0254: * @param name the session's name
0255: * @param type the type of the session
0256: * @param sessionCustom the session's customization
0257: */
0258: public Session(CleverPHL cleverPHL, String name, SessionType type,
0259: Customization sessionCustom) {
0260: super (cleverPHL.getEnvironment());
0261: this .cleverPHL = cleverPHL;
0262: setType(type);
0263: setName(name);
0264: sessionListeners = new Vector(5);
0265:
0266: classLoaderIdentifier = getName() + ":"
0267: + UUIDGen.getInstance().generateUUID();
0268: sessionClassLoader = new JacaretoClassLoader(cleverPHL
0269: .getEnvironment(), classLoaderIdentifier);
0270: sessionClassLoader.addModules(cleverPHL.getModules());
0271: targetApplicationClassLoader = sessionClassLoader;
0272:
0273: // Set the customization
0274: try {
0275: if (sessionCustom == null) {
0276: this .sessionCustom = new Customization(getEnvironment()
0277: .getFiles().getDir("CUSTOMIZATION_DIR")
0278: + File.separator
0279: + customization.getString(
0280: "CleverPHL.SessionCustomizationFile",
0281: "cleverphl_session.xml"));
0282: } else {
0283: this .sessionCustom = sessionCustom;
0284: }
0285:
0286: customization.addChild("session", this .sessionCustom);
0287: customization.setChildToPutNew(this .sessionCustom);
0288: cleverPHL.getModules().addCustomizations(customization);
0289: customization.setChildToPutNew(null);
0290: applyCustomization();
0291: } catch (IOException i) {
0292: logger.error(i);
0293: }
0294:
0295: this .sessionCustom.addHashtableChangeListener(this );
0296:
0297: // set up interaction-model
0298: try {
0299: interactionModel = new InteractionModel(env,
0300: new InteractionModelRoot(env));
0301: } catch (Exception l) {
0302: cleverPHL.getLogger().error(l.getMessage());
0303: }
0304:
0305: // set up conceptual-model
0306: try {
0307: conceptualModel = new ConceptualModel(env,
0308: new ConceptualModelRoot(env));
0309: } catch (Exception l) {
0310: cleverPHL.getLogger().error(l.getMessage());
0311: }
0312:
0313: // Set up components instance
0314: components = new Components(env, Components.INIT_CUSTOM,
0315: sessionClassLoader);
0316: initComponents();
0317: manipulationManagement = new ManipulationManagement(env,
0318: components, cleverPHL.getDrawingFrame());
0319:
0320: // set up record
0321: try {
0322: record = new VectorRecord(env, SessionUtilities
0323: .getDefaultRecordName(cleverPHL, this ));
0324: record.open();
0325: RootElement.setClassLoader(sessionClassLoader);
0326: structure = new Structure(env, record);
0327: record.addRecordChangeListener(this );
0328: } catch (RecordException l) {
0329: cleverPHL.getLogger().error(l.getMessage());
0330: }
0331:
0332: // set up the capture helper for pointed captures
0333: captureHelper = new CaptureHelper(env, record, structure);
0334:
0335: // Some listeners for the whole session
0336: keyStrokeCatcher = new KeyStrokeCatcher(env);
0337: keyStrokeCatcher.addKeyStrokeObserver(this );
0338: keyStrokeCatcher.applyCustomization("KeyStrokes");
0339: keyStrokeCatcher.setStoppable(false);
0340: sessionEventListener = new EventListener(env, components,
0341: record, EventListener.INIT_EMPTY);
0342: sessionEventListener.setEnabledCheck(false);
0343: sessionEventListener.addCatcher(keyStrokeCatcher, 1100);
0344:
0345: // Set up capture instances
0346: eventMask = new AWTEventMaskGroup(env,
0347: AWTEventMaskGroup.INIT_CUSTOM);
0348:
0349: awtEventRecorder = new AWTEventRecorder(env, eventMask, record,
0350: components);
0351: awtEventRecorder
0352: .setTimeSpanCalculator(new TimeSpanCalculator());
0353:
0354: swingEventRecorder = new SwingEventRecorder(env, record,
0355: components);
0356: lastMousePosition = new LastMousePosition(env);
0357: fileDialogWatcher = new FileDialogWatcher(env, components,
0358: record);
0359: captureEventListener = new EventListener(env, components,
0360: record, EventListener.INIT_CUSTOM, sessionClassLoader);
0361: captureEventListener.addCatcher(keyStrokeCatcher, 1100);
0362: captureEventListener.addCatcher(lastMousePosition, 1000);
0363: captureEventListener.addCatcher(fileDialogWatcher, 1000);
0364: captureEventListener.addCatcher(awtEventRecorder);
0365: captureEventListener.addCatcher(swingEventRecorder);
0366: isCapturing = false;
0367:
0368: // The test report
0369: testReport = new TestReport(env);
0370:
0371: // The cursor images
0372: cursorImages = new CursorImages(env, cleverPHL.getEnvironment()
0373: .getFiles().getDir("CURSOR_IMAGES_DIR").toString());
0374:
0375: // Set up the replay instances
0376: sessionReplayMode = new ReplayMode(env);
0377: sessionReplayMode.applyCustomization();
0378: replay = new Replay(env, components, structure,
0379: (ReplayMode) sessionReplayMode.clone(),
0380: Replay.INIT_CUSTOM, targetApplicationClassLoader);
0381:
0382: //replayMode.setMouseMode (ReplayMode.REALMOUSE);
0383: //replayMode.setTimeMode (ReplayMode.REALTIME);
0384: replay.setJacaretoClassLoader(targetApplicationClassLoader);
0385: replay.addReplayListener(this );
0386: replay.setTestReport(testReport);
0387: replay.setCursorImages(cursorImages);
0388: isReplaying = false;
0389: isReplayPause = false;
0390: isFastForward = false;
0391:
0392: // record some start-up information
0393: try {
0394: writeInitialRecordables();
0395: isSessionUnsaved = true;
0396: } catch (RecordException l) {
0397: env.getLogger().error(l.getMessage());
0398: }
0399:
0400: setStarterList(new StarterList(env, files
0401: .getDir("CLEVERPHL_STARTERS_DIR")
0402: + File.separator
0403: + customization.getString(
0404: "CleverPHL.SessionStarterFile", "default.xml")));
0405: starterList.addListDataListener(this );
0406: filterList = new FilterList(env, "Filters", sessionClassLoader);
0407: dataSets = new Vector(5, 5);
0408: dataSetConverter = new SelectionConverter(env,
0409: "DataCases.Converters", SelectionConverter.INIT_CUSTOM,
0410: sessionClassLoader);
0411:
0412: // Loads the tests
0413: testLoader = new TestLoader(env, components);
0414:
0415: setStoreOnExit(false);
0416:
0417: setActive(false);
0418: }
0419:
0420: /**
0421: * Creates a new non-active session with the type <code>SessionType.COMPLETE</code>.
0422: *
0423: * @param cleverPHL the CleverPHL instance.
0424: * @param name the session's name
0425: * @param sessionCustom the session's customization
0426: */
0427: public Session(CleverPHL cleverPHL, String name,
0428: Customization sessionCustom) {
0429: this (cleverPHL, name, SessionType.COMPLETE, sessionCustom);
0430: }
0431:
0432: /**
0433: * Creates a new non-active session with the default session customization
0434: *
0435: * @param cleverPHL the CleverPHL instance.
0436: * @param name the session's name
0437: * @param type the session's type
0438: */
0439: public Session(CleverPHL cleverPHL, String name, SessionType type) {
0440: this (cleverPHL, name, type, null);
0441: }
0442:
0443: /**
0444: * Creates a new non-active session with the default session customization and the type
0445: * <code>SessionType.COMPLETE</code>.
0446: *
0447: * @param cleverPHL the CleverPHL instance.
0448: * @param name the session's name
0449: */
0450: public Session(CleverPHL cleverPHL, String name) {
0451: this (cleverPHL, name, SessionType.COMPLETE, null);
0452: }
0453:
0454: /**
0455: * Inits the components instance.
0456: */
0457: private void initComponents() {
0458: components.setListeningToPopUps(false);
0459:
0460: // add the main frame as component tree which should be ignored
0461: components.addTree(cleverPHL.getMainFrame(), false, false);
0462: components.addTree(cleverPHL.getMessageFrame(), false, false);
0463: components
0464: .addTree(cleverPHL.getComponentsFrame(), false, false);
0465: components.addTree(cleverPHL.getDataSetFrame(), false, false);
0466: components.addTree(cleverPHL.getInteractionModelFrame(), false,
0467: false);
0468: components.addTree(cleverPHL.getConceptualModelFrame(), false,
0469: false);
0470: components.addTree(cleverPHL.getTrackEditorFrame(), false,
0471: false);
0472: }
0473:
0474: /**
0475: * Applies the customization. This method will be called when a session is created or is set
0476: * active.
0477: */
0478: private void applyCustomization() {
0479: JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) cleverPHL
0480: .getMainFrame().getCleverPHLMenuBar().getMenuItem(
0481: "CleverPHL.Menu.HideCleverPHL");
0482: checkbox.setSelected(customization.getBoolean(
0483: "Capture.HideCleverPHL", false));
0484:
0485: /*JCheckBoxMenuItem checkbox2 = (JCheckBoxMenuItem) cleverPHL.getMainFrame().getCleverPHLMenuBar().getMenuItem("CleverPHL.Menu.CaptureWindowMovingResizing");
0486: boolean captureWindow = customization.getBoolean ("WindowMovingResizing.Capture", false);
0487: checkbox2.setSelected (captureWindow);
0488: if (eventMask != null) {
0489: eventMask.removeMask ("jacareto.eventmask.ComponentEventMask");
0490: if (captureWindow) {
0491: getEventMask().addMask (new ComponentEventMask (getEnvironment()));
0492: }
0493: } */
0494: if (sessionCustom.containsKey("Session.Type")) {
0495: int typeID = sessionCustom.getInt("Session.Type", -1);
0496: Iterator it = SessionType.types();
0497:
0498: while (it.hasNext()) {
0499: SessionType tmpType = (SessionType) it.next();
0500:
0501: if (typeID == tmpType.getID()) {
0502: setType(tmpType);
0503:
0504: break;
0505: }
0506: }
0507: }
0508:
0509: addAccelerators();
0510: }
0511:
0512: /**
0513: * Sets the name of the session.
0514: *
0515: * @param name the new name
0516: */
0517: public void setName(String name) {
0518: String oldName = this .name;
0519: this .name = name;
0520:
0521: if ((oldName != null) && !oldName.equals(name)) {
0522: sessionDir = null;
0523: fireSessionEvent(new SessionEvent(env,
0524: SessionEvent.NAME_CHANGED, this ));
0525: }
0526: }
0527:
0528: /**
0529: * Returns the session's name.
0530: *
0531: * @return DOCUMENT ME!
0532: */
0533: public String getName() {
0534: return name;
0535: }
0536:
0537: /**
0538: * Sets the record structure compound.
0539: *
0540: * @param compound the compound.
0541: *
0542: * @throws RecordException DOCUMENT ME!
0543: */
0544: public void setRecordStructureCompound(
0545: RecordStructureCompound compound) throws RecordException {
0546: if (!record.isOpen()) {
0547: record.open();
0548: }
0549:
0550: if (!record.isEmpty()) {
0551: record.clear();
0552: }
0553:
0554: record.removeRecordChangeListener(this );
0555:
0556: RandomAccessRecord sourceRecord = (RandomAccessRecord) compound
0557: .getRecord();
0558: record = sourceRecord;
0559: record.addRecordChangeListener(this );
0560:
0561: Structure newStructure = compound.getStructure();
0562: this .structure = newStructure;
0563: replay.setStructure(structure);
0564:
0565: if (structureTree != null) {
0566: structureTree.setModel(newStructure);
0567: }
0568:
0569: captureHelper.setRecordStructureCompound(compound);
0570: sessionEventListener.setRecord(record);
0571: captureEventListener.setRecord(record);
0572: awtEventRecorder.setRecord(record);
0573: swingEventRecorder.setRecord(record);
0574: fileDialogWatcher.setRecord(record);
0575:
0576: this .cleverPHL.getTrackEditorFrame().reInit();
0577:
0578: //structure.setRoot (compound.getStructure().getRootElement());
0579: //structure.getRootElement().setRecord (record);
0580: //restructureRecord ();
0581: }
0582:
0583: /**
0584: * Makes this session active.
0585: *
0586: * @param isActive DOCUMENT ME!
0587: */
0588: public void setActive(boolean isActive) {
0589: if (this .isActive != isActive) {
0590: this .isActive = isActive;
0591:
0592: if (isActive) {
0593: // detect windows and exclude them
0594: components.detectComponents(false, false);
0595: sessionEventListener.start();
0596:
0597: // remove the next line???
0598: //replayInputFilter.stop ();
0599: components.restoreVisibility();
0600: customization.addChild("session", sessionCustom);
0601: eventMask.setListeningToHashtableChanges(true);
0602: replay.setListeningToHashtableChanges(true);
0603: applyCustomization();
0604: fireSessionEvent(new SessionEvent(env,
0605: SessionEvent.ACTIVE, this ));
0606: RootElement.setClassLoader(sessionClassLoader);
0607: } else {
0608: // detect windows and add them to the known, included and enabled components
0609: components.detectComponents(true, true);
0610: sessionEventListener.stop();
0611: components.saveVisibility();
0612: components.hideAllComponents();
0613: eventMask.setListeningToHashtableChanges(false);
0614: replay.setListeningToHashtableChanges(false);
0615: customization.removeChild("session");
0616: fireSessionEvent(new SessionEvent(env,
0617: SessionEvent.INACTIVE, this ));
0618: }
0619: }
0620: }
0621:
0622: /**
0623: * Returns whether this session is active or not .
0624: *
0625: * @return DOCUMENT ME!
0626: */
0627: public boolean isActive() {
0628: return isActive;
0629: }
0630:
0631: /**
0632: * Returns the components belonging to the session.
0633: *
0634: * @return DOCUMENT ME!
0635: */
0636: public Components getComponents() {
0637: return components;
0638: }
0639:
0640: /**
0641: * Sets the session type.
0642: *
0643: * @param type DOCUMENT ME!
0644: */
0645: public void setType(SessionType type) {
0646: this .type = type;
0647: }
0648:
0649: /**
0650: * Returns the session type.
0651: *
0652: * @return DOCUMENT ME!
0653: */
0654: public SessionType getType() {
0655: return type;
0656: }
0657:
0658: /**
0659: * Returns the test loader.
0660: *
0661: * @return DOCUMENT ME!
0662: */
0663: public TestLoader getTestLoader() {
0664: return testLoader;
0665: }
0666:
0667: /**
0668: * Returns the starter list.
0669: *
0670: * @return DOCUMENT ME!
0671: */
0672: public StarterList getStarterList() {
0673: return starterList;
0674: }
0675:
0676: /**
0677: * Returns the filter list.
0678: *
0679: * @return DOCUMENT ME!
0680: */
0681: public FilterList getFilterList() {
0682: return filterList;
0683: }
0684:
0685: /**
0686: * Returns the session's test report.
0687: *
0688: * @return DOCUMENT ME!
0689: */
0690: public TestReport getTestReport() {
0691: return testReport;
0692: }
0693:
0694: /**
0695: * Closes the session. All records of this session will be closed, too.
0696: *
0697: * @return <code>true</code> if the session has been closed, otherwise <code>false</code>
0698: */
0699: public boolean close() {
0700: if (isSessionUnsaved()) {
0701: CleverPHLConfirmDialog confirmDialog = new CleverPHLConfirmDialog(
0702: cleverPHL,
0703: cleverPHL.getMainFrame(),
0704: language
0705: .getString("CleverPHL.Session.UnsavedSession"),
0706: language
0707: .getString("CleverPHL.Session.Msg.UnsavedSession"),
0708: language.getString("General.Yes"), language
0709: .getString("General.No"));
0710:
0711: if (confirmDialog.getValue() == CleverPHLConfirmDialog.NO) {
0712: return false;
0713: }
0714: }
0715:
0716: if (isActive()) {
0717: setActive(false);
0718: }
0719:
0720: try {
0721: record.close();
0722: getLogger().debug(
0723: getLanguage().getString(
0724: "CleverPHL.Session.Msg.Closed")
0725: + " " + getName());
0726: } catch (RecordException l) {
0727: getLogger().error(l.getMessage());
0728: }
0729:
0730: setStoreOnExit(false);
0731: removeShutdownHook();
0732:
0733: return true;
0734: }
0735:
0736: /**
0737: * Starts the capture process of this session.
0738: */
0739: public void startCapture() {
0740: if (isActive() && !isCapturing() && !isReplaying()) {
0741: // the next two lines must be at the top of this method, because
0742: // otherwise the CleverPHL window will be in front when the
0743: // capture process has been started
0744: isCapturing = true;
0745: fireSessionEvent(new SessionEvent(env,
0746: SessionEvent.CAPTURE_START, this ));
0747:
0748: manipulationManagement
0749: .setMode(ManipulationManagement.USE_COMPONENTS);
0750:
0751: components.allToFront();
0752:
0753: if (hideCleverPHLCapture) {
0754: cleverPHL.hideAllWindows();
0755: }
0756:
0757: // move the mouse to the position before the capture process has been
0758: // stopped
0759: try {
0760: if ((lastMousePosition != null)
0761: && lastMousePosition.isValid()) {
0762: Component lastComponent = lastMousePosition
0763: .getLastComponent();
0764:
0765: if (lastComponent != null) {
0766: components.toFront(lastComponent);
0767:
0768: Component root = components
0769: .getRoot(lastComponent);
0770:
0771: if (root instanceof Window) {
0772: root.dispatchEvent(new WindowEvent(
0773: (Window) root,
0774: WindowEvent.WINDOW_OPENED));
0775: root.repaint();
0776: }
0777:
0778: Point p = lastComponent.getLocationOnScreen();
0779: int lastX = (lastMousePosition.getLastX() > 0) ? lastMousePosition
0780: .getLastX()
0781: : 0;
0782: int lastY = (lastMousePosition.getLastY() > 0) ? lastMousePosition
0783: .getLastY()
0784: : 0;
0785: Robot robot = new Robot();
0786: robot.mouseMove((int) (p.getX() + lastX),
0787: (int) (p.getY() + lastY));
0788: }
0789: }
0790: } catch (Throwable ignored) {
0791: ;
0792: }
0793:
0794: captureEventListener.start();
0795:
0796: getLogger()
0797: .debug(
0798: getName()
0799: + ": "
0800: + getLanguage()
0801: .getString(
0802: "CleverPHL.Session.Msg.CaptureStart"));
0803: } else {
0804: getLogger()
0805: .warn(
0806: getName()
0807: + ": "
0808: + getLanguage()
0809: .getString(
0810: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
0811: }
0812: }
0813:
0814: /**
0815: * Starts the capture and adds the recordable at the selected point.
0816: */
0817: public void startMarkedCapture() {
0818: InsertPoint insertPoint = calcInsertPoint();
0819:
0820: if (insertPoint != null) {
0821: captureHelper.startCaptureing(insertPoint
0822: .getRecordIndexToAdd(), insertPoint
0823: .getStructureIndexToAdd(), insertPoint
0824: .getStructureToAdd());
0825: startCapture();
0826: }
0827: }
0828:
0829: /**
0830: * Stops the capture process of this session.
0831: */
0832: public void stopCapture() {
0833: if (isActive() && isCapturing()) {
0834: captureEventListener.stop();
0835: isCapturing = false;
0836:
0837: if (captureHelper.isCaptureing()) {
0838: captureHelper.stopCaptureing();
0839: }
0840:
0841: restructureRecord();
0842:
0843: if (hideCleverPHLCapture) {
0844: cleverPHL.restoreVisibility();
0845: components.allToFront();
0846:
0847: Component lastComponent = lastMousePosition
0848: .getLastComponent();
0849:
0850: if (lastComponent != null) {
0851: components.toFront(lastComponent);
0852: }
0853: }
0854:
0855: fireSessionEvent(new SessionEvent(env,
0856: SessionEvent.CAPTURE_STOP, this ));
0857: getLogger()
0858: .debug(
0859: getName()
0860: + ": "
0861: + getLanguage()
0862: .getString(
0863: "CleverPHL.Session.Msg.CaptureStop"));
0864: } else {
0865: getLogger()
0866: .warn(
0867: getName()
0868: + ": "
0869: + getLanguage()
0870: .getString(
0871: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
0872: }
0873: }
0874:
0875: /**
0876: * Start capture semantic events.
0877: */
0878: public void startCaptureSemanticEvents() {
0879: if (isActive() && !isCapturing() && !isReplaying()) {
0880: captureEventListener.setAWT(false);
0881: captureEventListener.setEnabledCheck(false);
0882: captureEventListener.start();
0883: isCapturing = true;
0884: }
0885: }
0886:
0887: /**
0888: * Stop capture semantic events.
0889: */
0890: public void stopCaptureSemanticEvents() {
0891: if (isActive() && isCapturing()) {
0892: captureEventListener.stop();
0893: captureEventListener.setAWT(true);
0894: captureEventListener.setEnabledCheck(true);
0895: isCapturing = false;
0896: }
0897: }
0898:
0899: /**
0900: * Starts the replay process of this session.
0901: */
0902: public void startReplay() {
0903: if (isActive() && !isCapturing() && !isReplaying()) {
0904: isReplaying = true;
0905: isReplayPause = false;
0906:
0907: manipulationManagement
0908: .setMode(ManipulationManagement.USE_COMPONENTS);
0909:
0910: //restructureRecord();
0911: components.removeAll();
0912: testReport.clear();
0913: if (sessionCustom.getBoolean("Session.FullReplayReset",
0914: true)) {
0915: clearClassLoader();
0916: }
0917: initComponents();
0918:
0919: // because recordables will not notify listeners about
0920: // processing time changes, the unsaved flag is set
0921: // explicitly before the replay process starts
0922: isSessionUnsaved = true;
0923: replay.setMode((ReplayMode) sessionReplayMode.clone());
0924: replay.start();
0925: fireSessionEvent(new SessionEvent(env,
0926: SessionEvent.REPLAY_START, this ));
0927: getLogger()
0928: .debug(
0929: getName()
0930: + ": "
0931: + getLanguage()
0932: .getString(
0933: "CleverPHL.Session.Msg.ReplayStart"));
0934: } else {
0935: getLogger()
0936: .warn(
0937: getName()
0938: + ": "
0939: + getLanguage()
0940: .getString(
0941: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
0942: }
0943: }
0944:
0945: /**
0946: * Starts the replay process if it is not running, or continues it if it has already been
0947: * started.
0948: */
0949: public void replay() {
0950: if (isActive() && !isCapturing()) {
0951: if (isReplaying()) {
0952: continueReplay();
0953: } else {
0954: startReplay();
0955: }
0956: } else {
0957: getLogger()
0958: .warn(
0959: getName()
0960: + ": "
0961: + getLanguage()
0962: .getString(
0963: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
0964: }
0965: }
0966:
0967: /**
0968: * Clears the classloader. Should be called before a replay process is started.
0969: */
0970: private void clearClassLoader() {
0971: targetApplicationClassLoader
0972: .removeJacaretoClassLoaderListener(this );
0973: targetApplicationClassLoader = new JacaretoClassLoader(
0974: cleverPHL.getEnvironment(), classLoaderIdentifier);
0975: targetApplicationClassLoader.addModules(cleverPHL.getModules());
0976: targetApplicationClassLoader
0977: .addJacaretoClassLoaderListener(this );
0978: replay.setJacaretoClassLoader(targetApplicationClassLoader);
0979:
0980: // this should be done, but does not work with modules and event object recorders contained in
0981: // modules.
0982: //captureEventListener.setClassLoader (classLoader);
0983: //RootElement.setClassLoader (classLoader);
0984: }
0985:
0986: /**
0987: * Resets the replay process.
0988: */
0989: public void resetReplay() {
0990: if (isActive() && !isCapturing() && isReplayPause()) {
0991: isReplaying = false;
0992: isReplayPause = false;
0993: restructureRecord();
0994: components.removeAll();
0995: initComponents();
0996: replay.reset();
0997: fireSessionEvent(new SessionEvent(env,
0998: SessionEvent.REPLAY_RESET, this ));
0999: getLogger()
1000: .debug(
1001: getName()
1002: + ": "
1003: + getLanguage()
1004: .getString(
1005: "CleverPHL.Session.Msg.ReplayRestart"));
1006: } else {
1007: getLogger()
1008: .warn(
1009: getName()
1010: + ": "
1011: + getLanguage()
1012: .getString(
1013: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
1014: }
1015: }
1016:
1017: /**
1018: * Pauses the replay process of this session.
1019: */
1020: public void pauseReplay() {
1021: if (isActive() && isReplaying() && !isReplayPause()) {
1022: components.saveVisibility();
1023: replay.pause();
1024: isReplayPause = true;
1025: fireSessionEvent(new SessionEvent(env,
1026: SessionEvent.REPLAY_PAUSE, this ));
1027: getLogger()
1028: .debug(
1029: getName()
1030: + ": "
1031: + getLanguage()
1032: .getString(
1033: "CleverPHL.Session.Msg.ReplayPause"));
1034: } else {
1035: getLogger()
1036: .warn(
1037: getName()
1038: + ": "
1039: + getLanguage()
1040: .getString(
1041: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
1042: }
1043: }
1044:
1045: /**
1046: * Continues the replay process after a pause.
1047: */
1048: public void continueReplay() {
1049: if (isActive() && isReplaying() && isReplayPause()) {
1050: components.restoreVisibility();
1051:
1052: //components.allToFront();
1053: manipulationManagement
1054: .setMode(ManipulationManagement.USE_COMPONENTS);
1055:
1056: isReplayPause = false;
1057: replay.continueReplay();
1058: fireSessionEvent(new SessionEvent(env,
1059: SessionEvent.REPLAY_CONTINUE, this ));
1060: getLogger()
1061: .debug(
1062: getName()
1063: + ": "
1064: + getLanguage()
1065: .getString(
1066: "CleverPHL.Session.Msg.ReplayContinue"));
1067: } else {
1068: getLogger()
1069: .warn(
1070: getName()
1071: + ": "
1072: + getLanguage()
1073: .getString(
1074: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
1075: }
1076: }
1077:
1078: /**
1079: * Fast forward.
1080: */
1081: public void fastForward() {
1082: if ((isActive() && (isReplaying() && isReplayPause()))
1083: || (!isCapturing() && !isReplaying())) {
1084: isFastForward = true;
1085:
1086: replay.setFastForward(true);
1087:
1088: if (isReplaying()) {
1089: continueReplay();
1090: } else {
1091: startReplay();
1092: }
1093: } else {
1094: getLogger()
1095: .warn(
1096: getName()
1097: + ": "
1098: + getLanguage()
1099: .getString(
1100: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
1101: }
1102: }
1103:
1104: /**
1105: * Fast forward to next marked position.
1106: */
1107: public void fastForwardToNextMarked() {
1108: if ((isActive() && (isReplaying() && isReplayPause()))
1109: || (!isCapturing() && !isReplaying())) {
1110: TreePath[] paths = structureTree.getSelectionPaths();
1111:
1112: if (paths != null) {
1113: for (int i = 0; i < paths.length; i++) {
1114: StructureElement node = (StructureElement) paths[i]
1115: .getLastPathComponent();
1116: replay.addStopper(node);
1117: }
1118: }
1119:
1120: fastForward();
1121: } else {
1122: getLogger()
1123: .warn(
1124: getName()
1125: + ": "
1126: + getLanguage()
1127: .getString(
1128: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
1129: }
1130: }
1131:
1132: /**
1133: * Fast forward to next the given media time
1134: *
1135: * @param time the time to stop
1136: */
1137: public void fastForwardToTime(long time) {
1138: if ((isActive() && (isReplaying() && isReplayPause()))
1139: || (!isCapturing() && !isReplaying())) {
1140: replay.addTimeToStop(time);
1141: fastForward();
1142: } else {
1143: getLogger()
1144: .warn(
1145: getName()
1146: + ": "
1147: + getLanguage()
1148: .getString(
1149: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
1150: }
1151: }
1152:
1153: /**
1154: * Replay actual element.
1155: */
1156: public void replayActualElement() {
1157: if ((isActive() && (isReplaying() && isReplayPause()))
1158: || (!isCapturing() && !isReplaying())) {
1159: replay.stepwise(true);
1160:
1161: if (isReplaying()) {
1162: continueReplay();
1163: } else {
1164: startReplay();
1165: }
1166: } else {
1167: getLogger()
1168: .warn(
1169: getName()
1170: + ": "
1171: + getLanguage()
1172: .getString(
1173: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
1174: }
1175: }
1176:
1177: /**
1178: * Called when replay state has changed
1179: *
1180: * @param event DOCUMENT ME!
1181: */
1182: public void replayStateChanged(ReplayEvent event) {
1183: if (event.getID() == ReplayEvent.STOPPED) {
1184: if (isActive() && isReplaying()) {
1185: isReplaying = false;
1186: fireSessionEvent(new SessionEvent(env,
1187: SessionEvent.REPLAY_STOP, this ));
1188: getLogger()
1189: .debug(
1190: getName()
1191: + ": "
1192: + getLanguage()
1193: .getString(
1194: "CleverPHL.Session.Msg.ReplayStop"));
1195: } else {
1196: getLogger()
1197: .warn(
1198: getName()
1199: + ": "
1200: + getLanguage()
1201: .getString(
1202: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
1203: }
1204: } else if (event.getID() == ReplayEvent.PAUSED) {
1205: if (isActive() && isReplaying() && !isReplayPause()) {
1206: components.saveVisibility();
1207: isReplayPause = true;
1208: fireSessionEvent(new SessionEvent(env,
1209: SessionEvent.REPLAY_PAUSE, this ));
1210: getLogger()
1211: .debug(
1212: getName()
1213: + ": "
1214: + getLanguage()
1215: .getString(
1216: "CleverPHL.Session.Msg.ReplayPause"));
1217: } else {
1218: getLogger()
1219: .warn(
1220: getName()
1221: + ": "
1222: + getLanguage()
1223: .getString(
1224: "CleverPHL.Session.Error.NotActiveOrIncorrectState"));
1225: }
1226: }
1227:
1228: if (isFastForward
1229: && ((event.getID() == ReplayEvent.STOPPED) || (event
1230: .getID() == ReplayEvent.PAUSED))) {
1231: isFastForward = false;
1232: replay.clearStoppers();
1233: }
1234: }
1235:
1236: /**
1237: * Returns whether the capture process of this session is going on or not at the moment.
1238: *
1239: * @return DOCUMENT ME!
1240: */
1241: public boolean isCapturing() {
1242: return isCapturing;
1243: }
1244:
1245: /**
1246: * Returns whether the replay process of this session is going on or not at the moment.
1247: *
1248: * @return DOCUMENT ME!
1249: */
1250: public boolean isReplaying() {
1251: return isReplaying;
1252: }
1253:
1254: /**
1255: * Returns whether the replay process is paused or not.
1256: *
1257: * @return DOCUMENT ME!
1258: */
1259: public boolean isReplayPause() {
1260: return isReplayPause;
1261: }
1262:
1263: /**
1264: * Records the specified recordable to the record.
1265: *
1266: * @param recordable the recordable to record
1267: */
1268: public void record(Recordable recordable) {
1269: try {
1270: record.record(recordable);
1271: } catch (RecordException l) {
1272: getLogger().error(
1273: getLanguage().getString(
1274: "CleverPHL.Session.Error.RecordWrite"), l);
1275: }
1276: }
1277:
1278: /**
1279: * Returns the event mask.
1280: *
1281: * @return DOCUMENT ME!
1282: */
1283: public AWTEventMaskGroup getEventMask() {
1284: return eventMask;
1285: }
1286:
1287: /**
1288: * Inserts a recordable at a specified position (the selected position in a record
1289: * visualization, for example).
1290: *
1291: * @param recordable the record to insert
1292: */
1293: public void insertRecordable(Recordable recordable) {
1294: InsertPoint insertPoint = calcInsertPoint();
1295:
1296: try {
1297: if (insertPoint != null) {
1298: insertPoint.getStructureToAdd().insertChild(recordable,
1299: insertPoint.getStructureIndexToAdd());
1300: record.insert(recordable, insertPoint
1301: .getRecordIndexToAdd());
1302: }
1303: } catch (RecordException r) {
1304: logger.error(r);
1305: r.printStackTrace();
1306: }
1307: }
1308:
1309: /**
1310: * Inserts a structure element (not a recordable) at a specified position (the selected
1311: * position in a record visualization, for example).
1312: *
1313: * @param element the element to insert
1314: */
1315: public void insertStructureElement(StructureElement element) {
1316: InsertPoint insertPoint = calcInsertPoint();
1317:
1318: if ((insertPoint != null) && !(element instanceof Recordable)) {
1319: insertPoint.getStructureToAdd().insertChild(element,
1320: insertPoint.getStructureIndexToAdd());
1321: }
1322: }
1323:
1324: /**
1325: * Removes all recordables which are selected in the record visualization.
1326: */
1327: public void removeSelectedRecordables() {
1328: TreePath[] paths = structureTree.getSelectionPaths();
1329:
1330: if (paths != null) {
1331: // get the node which should be selected after deletion
1332: StructureElement nodeToSelect = null;
1333:
1334: if (paths.length == 1) {
1335: TreePath leadPath = paths[0];
1336: StructureElement leadNode = (StructureElement) leadPath
1337: .getLastPathComponent();
1338: StructureElement leadParent = (StructureElement) leadNode
1339: .getParent();
1340:
1341: if ((leadParent != null)
1342: && (leadParent.getIndex(leadNode) != (leadParent
1343: .getChildCount() - 1))) {
1344: nodeToSelect = (StructureElement) leadParent
1345: .getChildAt(leadParent.getIndex(leadNode) + 1);
1346: }
1347: }
1348:
1349: // delete all structure elements which are selected in the structure
1350: // tree (which inherits JTree)
1351: for (int i = 0; i < paths.length; i++) {
1352: TreePath path = paths[i];
1353: StructureElement element = (StructureElement) path
1354: .getLastPathComponent();
1355: StructureElement parent = (StructureElement) element
1356: .getParent();
1357:
1358: if (parent != null) {
1359: // only child elements can be removed; the root element must not
1360: // be deleted
1361: // Remove the belonging recordables from the record
1362: Recordable[] recordables = element.getRecordables();
1363:
1364: for (int j = 0; j < recordables.length; j++) {
1365: try {
1366: record.remove(recordables[j]);
1367: } catch (RecordException r) {
1368: logger.error(r);
1369: }
1370: }
1371:
1372: // Remove the belonging structure element from the structure
1373: element.removeFromParent();
1374: }
1375: }
1376:
1377: // Select a node
1378: if (nodeToSelect != null) {
1379: structureTree.setSelectionPath(structure
1380: .getTreePath(nodeToSelect));
1381: }
1382: }
1383: }
1384:
1385: /**
1386: * Selects a structure element.
1387: *
1388: * @param element the element to be selected
1389: */
1390: public void selectStructureElement(StructureElement element) {
1391: structureTree.clearSelection();
1392: structureTree.setSelectionPath(structure.getTreePath(element));
1393: }
1394:
1395: /**
1396: * Selects all structure elements.
1397: */
1398: public void selectAllStructureElements() {
1399: int rowCount = structureTree.getRowCount();
1400: TreePath[] allPaths = new TreePath[rowCount];
1401:
1402: for (int i = 0; i < rowCount; i++) {
1403: allPaths[i] = structureTree.getPathForRow(i);
1404: }
1405:
1406: structureTree.setSelectionPaths(allPaths);
1407: }
1408:
1409: /**
1410: * Selects more than one structure element.
1411: *
1412: * @param elements the elements to be selected.
1413: */
1414: public void selectStructureElements(StructureElement[] elements) {
1415: TreePath[] treePaths = new TreePath[elements.length];
1416:
1417: for (int i = 0; i < elements.length; i++) {
1418: treePaths[i] = structure.getTreePath(elements[i]);
1419: }
1420:
1421: structureTree.setSelectionPaths(treePaths);
1422: }
1423:
1424: /**
1425: * Cuts the selected structure elements out of the structure tree and stores them in the
1426: * clipboard
1427: */
1428: public void cutStructureElements() {
1429: try {
1430: copyStructureElements();
1431: removeSelectedStructureElementsAndRecordables();
1432: } catch (Exception ex) {
1433: logger.error(ex);
1434: ex.printStackTrace();
1435: }
1436: }
1437:
1438: /**
1439: * Copies the selected structure elements out of the structure tree and stores them in the
1440: * clipboard
1441: */
1442: public void copyStructureElements() {
1443: try {
1444: StructureElement[] structureElements = getSelectedStructureElements();
1445: cleverPHL.getClipBoard().setContent(structureElements,
1446: record);
1447: cleverPHL.getMainFrame().getCleverPHLMenuBar()
1448: .setMenuItemEnabled(
1449: "CleverPHL.Menu.InsertRecordables", true);
1450: } catch (Exception ex) {
1451: logger.error(ex);
1452: ex.printStackTrace();
1453: }
1454: }
1455:
1456: /**
1457: * Pastes the structure elements in the clipboard into the structure tree at the selected tree
1458: * path..
1459: */
1460: public void pasteStructureElements() {
1461: InsertPoint insertPoint = calcInsertPoint();
1462: cleverPHL.getClipBoard().paste((VectorRecord) record,
1463: insertPoint);
1464: }
1465:
1466: /**
1467: * Gets the selected StructureElements from the StructureTree
1468: *
1469: * @return StructureElements[]
1470: */
1471: public StructureElement[] getSelectedStructureElements() {
1472: StructureElement[] result = null;
1473: TreePath[] paths = structureTree.getSelectionPaths();
1474:
1475: if (paths != null) {
1476: result = new StructureElement[paths.length];
1477:
1478: for (int i = 0; i < paths.length; i++) {
1479: TreePath path = paths[i];
1480: result[i] = (StructureElement) path
1481: .getLastPathComponent();
1482: }
1483: }
1484:
1485: return result;
1486: }
1487:
1488: public Vector getSelectedRecordables() {
1489: Vector selectedRecordables = new Vector();
1490: TreePath[] paths = structureTree.getSelectionPaths();
1491: Vector helpVector = new Vector();
1492:
1493: try {
1494: if (paths != null) {
1495: // delete all structure elements which are selected in the structure
1496: // tree (which inherits JTree)
1497: for (int i = 0; i < paths.length; i++) {
1498: TreePath path = paths[i];
1499: StructureElement element = (StructureElement) path
1500: .getLastPathComponent();
1501: StructureElement parent = (StructureElement) element
1502: .getParent();
1503:
1504: if (parent != null) {
1505: // only child elements can be removed; the root element must not
1506: // be deleted
1507: // Find the elements that should be cutted of
1508: //Recordable[] recordables = element.getChildren("jacareto.record.recordable");
1509: Recordable[] recordables = element
1510: .getRecordables();
1511:
1512: for (int j = 0; j < recordables.length; j++) {
1513: helpVector.add(recordables[j]);
1514: }
1515: }
1516: }
1517:
1518: int offset = -1;
1519:
1520: // Sort the recordables for insertion.
1521: Recordable[] elements = new Recordable[helpVector
1522: .size()];
1523:
1524: for (int j = 0; j < helpVector.size(); j++) {
1525: int index = record.getIndex((Recordable) helpVector
1526: .get(j));
1527:
1528: if (offset == -1) {
1529: offset = index;
1530: }
1531:
1532: if (index < offset) {
1533: offset = index;
1534: }
1535: }
1536:
1537: for (int j = 0; j < helpVector.size(); j++) {
1538: Recordable toAdd = (Recordable) helpVector.get(j);
1539: int index = record.getIndex(toAdd) - offset;
1540: elements[index] = toAdd;
1541: }
1542:
1543: selectedRecordables = new Vector();
1544:
1545: for (int j = 0; j < helpVector.size(); j++) {
1546: Recordable element = elements[j];
1547: selectedRecordables.add(element);
1548: }
1549: }
1550:
1551: return selectedRecordables;
1552: } catch (RecordException r) {
1553: logger.error(r);
1554:
1555: return null;
1556: }
1557: }
1558:
1559: /**
1560: * Removes the selected structure elements and returns them in a vector, but does not remove
1561: * the recordables from the record.
1562: *
1563: * @return DOCUMENT ME!
1564: */
1565: public Vector removeSelectedStructureElements() {
1566: Vector selectedElements = new Vector();
1567: TreePath[] paths = structureTree.getSelectionPaths();
1568:
1569: try {
1570: if (paths != null) {
1571: // delete all structure elements which are selected in the structure
1572: // tree (which inherits JTree)
1573: for (int i = 0; i < paths.length; i++) {
1574: TreePath path = paths[i];
1575: StructureElement element = (StructureElement) path
1576: .getLastPathComponent();
1577: StructureElement parent = (StructureElement) element
1578: .getParent();
1579:
1580: if (parent != null) {
1581: // only child elements can be removed; the root element must not
1582: // be deleted
1583: selectedElements.add(element);
1584: parent.removeChild(element);
1585: }
1586: }
1587: }
1588:
1589: return selectedElements;
1590: } catch (Exception r) {
1591: logger.error(r);
1592:
1593: return null;
1594: }
1595: }
1596:
1597: /**
1598: * Removed the selected structure elements and their recordable leafs in the record.
1599: */
1600: public void removeSelectedStructureElementsAndRecordables() {
1601: TreePath[] paths = structureTree.getSelectionPaths();
1602:
1603: try {
1604: if (paths != null) {
1605: for (int i = 0; i < paths.length; i++) {
1606: TreePath path = paths[i];
1607: StructureElement element = (StructureElement) path
1608: .getLastPathComponent();
1609: Recordable[] recordables = element.getRecordables();
1610: ((VectorRecord) record).remove(recordables);
1611: }
1612: }
1613:
1614: removeSelectedStructureElements();
1615: } catch (Exception ex) {
1616: logger.error(ex);
1617: ex.printStackTrace();
1618: }
1619: }
1620:
1621: public InsertPoint calcInsertPoint() {
1622: try {
1623: TreePath[] selectedPaths = structureTree
1624: .getSelectionPaths();
1625: TreePath path = null;
1626:
1627: if ((selectedPaths == null) || (selectedPaths.length == 0)) {
1628: structureTree.setSelectionRow(0);
1629: path = structureTree.getLeadSelectionPath();
1630: } else {
1631: path = selectedPaths[0];
1632: }
1633:
1634: StructureElement element = (StructureElement) path
1635: .getLastPathComponent();
1636: TreePath markedNodePath = structure.getTreePath(element);
1637:
1638: if (!(element instanceof RootElement && !structureTree
1639: .isExpanded(markedNodePath))) {
1640: // Get the insertion index in the record (recordIndexToAdd)
1641: // Get the structure where to add the new element (structureToAdd)
1642: // Get the index in the structure (structureIndexToAdd)
1643: int recordIndexToAdd;
1644: StructureElement structureToAdd;
1645: int structureIndexToAdd;
1646:
1647: if (element instanceof Recordable) {
1648: recordIndexToAdd = record
1649: .getIndex((Recordable) element);
1650: structureToAdd = (StructureElement) element
1651: .getParent();
1652: structureIndexToAdd = structureToAdd
1653: .getIndex(element);
1654: } else {
1655: Recordable[] leafs;
1656: StructureElement tmp = element;
1657: boolean inspectLeafs = (!insertionMode
1658: && !structureTree
1659: .isExpanded(markedNodePath) && (element
1660: .getRecordables().length > 0));
1661: recordIndexToAdd = -1;
1662:
1663: do {
1664: leafs = tmp.getRecordables();
1665:
1666: if ((leafs.length == 0) || !inspectLeafs) {
1667: // search for the first recordable after the insertion position
1668: // (the insertion position is after the last recordable leaf contained
1669: // in the subtree of the actual structure, or before the first recordable leaf
1670: // contained in the next structure below the actual structure.)
1671: //
1672: // if there are no recordable leafs (leafs.length == 0) below the actual
1673: // structure, we should get the next structure
1674: // At first we get the parent of the actual structure; if the parent is null,
1675: // the actual structure is the empty root node, or a root node with just empty
1676: // structures, or a root node with just empty structures behind the actual marked
1677: // position.
1678: // Otherwise we must get the next child of the actual structure's parent. If there
1679: // is no next child, we must get the leafs of the next child of the parent's parent.
1680: // Because we must recurse again into the inner parts of that loop without getting
1681: // all leaf nodes of the parent (those can lie above the actual structure),
1682: // we set inspectLeafs to false until we found a next child.
1683: StructureElement tmpParent = (StructureElement) tmp
1684: .getParent();
1685:
1686: if (tmpParent == null) {
1687: recordIndexToAdd = record.size();
1688: } else {
1689: int tmpIndex = tmpParent.getIndex(tmp);
1690:
1691: if (tmpIndex == (tmpParent
1692: .getChildrenCount() - 1)) {
1693: tmp = tmpParent;
1694: inspectLeafs = false;
1695: } else {
1696: tmp = tmpParent
1697: .getChild(tmpIndex + 1);
1698: inspectLeafs = true;
1699: }
1700: }
1701: } else {
1702: // if there are recordable leafs below the marked structure element,
1703: // the new recordable should be inserted at the position of the first
1704: // of them
1705: recordIndexToAdd = record
1706: .getIndex(leafs[0]);
1707: }
1708: } while (recordIndexToAdd == -1);
1709:
1710: // Where to add the recordable in the structure
1711: StructureElement parent = (StructureElement) element
1712: .getParent();
1713:
1714: if (insertionMode
1715: || structureTree.isExpanded(markedNodePath)) {
1716: structureToAdd = element;
1717: structureIndexToAdd = structureToAdd
1718: .getChildrenCount();
1719: } else {
1720: structureToAdd = parent;
1721: structureIndexToAdd = parent.getIndex(element);
1722: }
1723: }
1724:
1725: return new InsertPoint(element, structureToAdd,
1726: structureIndexToAdd, recordIndexToAdd);
1727: }
1728:
1729: return null;
1730: } catch (RecordException r) {
1731: r.printStackTrace();
1732:
1733: return null;
1734: }
1735: }
1736:
1737: /**
1738: * Restructures the record.
1739: */
1740: public void restructureRecord() {
1741: logger.info(language
1742: .getString("CleverPHL.Session.Msg.RecordRestructured"));
1743: structure.rebuild(new RecordTokenizer(env, record));
1744: structure.getRootElement().setRecord(record);
1745: }
1746:
1747: /**
1748: * Returns the session's main record.
1749: *
1750: * @return DOCUMENT ME!
1751: */
1752: public RandomAccessRecord getRecord() {
1753: return record;
1754: }
1755:
1756: /**
1757: * Returns the replay instance.
1758: *
1759: * @return DOCUMENT ME!
1760: */
1761: public Replay getReplay() {
1762: return replay;
1763: }
1764:
1765: /**
1766: * Returns the structure of the session's record.
1767: *
1768: * @return DOCUMENT ME!
1769: */
1770: public Structure getStructure() {
1771: return structure;
1772: }
1773:
1774: /**
1775: * Returns the JTree showing the record.
1776: *
1777: * @return DOCUMENT ME!
1778: */
1779: public StructureTree getStructureTree() {
1780: return structureTree;
1781: }
1782:
1783: /**
1784: * Returns the JTree showing the record.
1785: *
1786: * @param structureTree the structure tree
1787: */
1788: public void setStructureTree(StructureTree structureTree) {
1789: this .structureTree = structureTree;
1790: this .structureTreeListener = new StructureTreeListener(env,
1791: this );
1792: structureTree.addKeyListener(structureTreeListener);
1793: replay.addReplayListener(structureTreeListener);
1794: }
1795:
1796: /**
1797: * Closes the main record.
1798: */
1799: public void closeRecord() {
1800: try {
1801: record.close();
1802: } catch (RecordException l) {
1803: getLogger().error(
1804: getLanguage().getString(
1805: "CleverPHL.Session.Error.RecordClose"), l);
1806: }
1807: }
1808:
1809: /**
1810: * Opens the main record.
1811: */
1812: public void openRecord() {
1813: try {
1814: record.open();
1815: } catch (RecordException l) {
1816: getLogger().error(
1817: getLanguage().getString(
1818: "CleverPHL.Session.Error.RecordOpen"), l);
1819: }
1820: }
1821:
1822: /**
1823: * Clears the main record and records some initial recordables to it.
1824: */
1825: public void clearRecord() {
1826: try {
1827: record.clear();
1828: writeInitialRecordables();
1829: isSessionUnsaved = true;
1830: } catch (RecordException l) {
1831: getLogger().error(
1832: getLanguage().getString(
1833: "CleverPHL.Session.Error.RecordClear"), l);
1834: }
1835: }
1836:
1837: /**
1838: * Returns whether or not the session has been changed and not saved.
1839: *
1840: * @return <code>true</code> if the session has not been saved; otherwise <code>false</code>
1841: */
1842: public boolean isSessionUnsaved() {
1843: return isSessionUnsaved;
1844: }
1845:
1846: /**
1847: * Specifies whether or not the session is unsaved.
1848: *
1849: * @param isSessionUnsaved <code>true</code> if the session has been changed and is not saved,
1850: * otherwise <code>false</code>
1851: */
1852: public void setSessionUnsaved(boolean isSessionUnsaved) {
1853: this .isSessionUnsaved = isSessionUnsaved;
1854: }
1855:
1856: /**
1857: * Called when the record has been changed.
1858: *
1859: * @param event RecordChangeEvent
1860: */
1861: public void recordHasChanged(RecordChangeEvent event) {
1862: isSessionUnsaved = true;
1863: }
1864:
1865: /**
1866: * Sets the session's replay mode.
1867: *
1868: * @param replayMode the new replay mode
1869: */
1870: public void setSessionReplayMode(ReplayMode replayMode) {
1871: this .sessionReplayMode = replayMode;
1872: }
1873:
1874: /**
1875: * Returns the session's replay mode.
1876: *
1877: * @return replayMode the session's replay mode
1878: */
1879: public ReplayMode getSessionReplayMode() {
1880: return sessionReplayMode;
1881: }
1882:
1883: /**
1884: * Writes some initial recordables to the record.
1885: *
1886: * @throws RecordException in case of an error
1887: */
1888: private void writeInitialRecordables() throws RecordException {
1889: record.record(new CalendarRecordable(env));
1890: record.record(new SystemInfoRecordable(env));
1891: record.record(new KeyboardStateRecordable(env, false, false,
1892: false, true, true, true));
1893: record.record((ComponentMode) components.getMode().clone());
1894:
1895: //record.record ((ReplayMode) replay.getMode ().clone ());
1896: }
1897:
1898: /**
1899: * Adds a data set.
1900: *
1901: * @param dataSet DOCUMENT ME!
1902: */
1903: public void addDataSet(DataSet dataSet) {
1904: dataSets.add(dataSet);
1905: fireSessionEvent(new SessionEvent(env,
1906: SessionEvent.DATA_SET_ADDED, this ));
1907: }
1908:
1909: /**
1910: * Adds the accelerator keys to the menu.
1911: */
1912: public void addAccelerators() {
1913: Hashtable keyStrokesMap = customization.getMap("KeyStrokes",
1914: new EnhancedHashtable());
1915: Enumeration keyStrokes = keyStrokesMap.keys();
1916:
1917: while (keyStrokes.hasMoreElements()) {
1918: String keyStroke = (String) keyStrokes.nextElement();
1919: cleverPHL.getMainFrame().getCleverPHLMenuBar()
1920: .setAccelerator(
1921: (String) keyStrokesMap.get(keyStroke),
1922: KeyStroke.getKeyStroke(keyStroke));
1923: }
1924: }
1925:
1926: /**
1927: * Removes the data set at the specified index.
1928: *
1929: * @param i DOCUMENT ME!
1930: */
1931: public void removeDataSet(int i) {
1932: try {
1933: dataSets.remove(i);
1934: fireSessionEvent(new SessionEvent(env,
1935: SessionEvent.DATA_SET_REMOVED, this ));
1936: } catch (Exception e) {
1937: logger
1938: .debug(language
1939: .getString("CleverPHL.Session.Msg.RemoveDataSetFailed"));
1940: }
1941: }
1942:
1943: /**
1944: * Returns the data sets
1945: *
1946: * @return DOCUMENT ME!
1947: */
1948: public Vector getDataSets() {
1949: return dataSets;
1950: }
1951:
1952: /**
1953: * Returns the data set converter.
1954: *
1955: * @return DOCUMENT ME!
1956: */
1957: public Converter getDataSetConverter() {
1958: return dataSetConverter;
1959: }
1960:
1961: /**
1962: * Returns the interaction model
1963: *
1964: * @return DOCUMENT ME!
1965: */
1966: public InteractionModel getInteractionModel() {
1967: return interactionModel;
1968: }
1969:
1970: /**
1971: * Returns the manipulation management.
1972: *
1973: * @return guess!
1974: */
1975: public ManipulationManagement getManipulationManagement() {
1976: return manipulationManagement;
1977: }
1978:
1979: /**
1980: * Sets the interaction model
1981: *
1982: * @param interactionModel DOCUMENT ME!
1983: */
1984: public void setInteractionModel(InteractionModel interactionModel) {
1985: this .interactionModel = interactionModel;
1986: }
1987:
1988: /**
1989: * Returns the ConceptualModel
1990: *
1991: * @return DOCUMENT ME!
1992: */
1993: public ConceptualModel getConceptualModel() {
1994: return conceptualModel;
1995: }
1996:
1997: /**
1998: * Sets the ConceptualModel
1999: *
2000: * @param conceptualModel DOCUMENT ME!
2001: */
2002: public void setConceptualModel(ConceptualModel conceptualModel) {
2003: this .conceptualModel = conceptualModel;
2004: }
2005:
2006: /**
2007: * Stores the session.
2008: */
2009: public void store() {
2010: try {
2011: customization.setNotifying(false);
2012: sessionCustom.put("Session.Type", type.getID());
2013: sessionReplayMode.storeToCustomization();
2014:
2015: if (sessionDir == null) {
2016: files.addDir("CLEVERPHL_SESSIONS_DIR." + name,
2017: new File(files.getDir("CLEVERPHL_SESSIONS_DIR")
2018: .getCanonicalPath()
2019: + File.separator + name));
2020: }
2021:
2022: sessionDir = files.getDir("CLEVERPHL_SESSIONS_DIR." + name);
2023:
2024: // Store the customization
2025: String sessionCustomFilename = sessionDir
2026: .getCanonicalPath()
2027: + File.separator + "session_custom.xml";
2028: sessionCustom.write(sessionCustomFilename);
2029:
2030: // Store the starter list
2031: String starterListFilename = sessionDir.getCanonicalPath()
2032: + File.separator + "starters.xml";
2033: starterList.saveStarters(starterListFilename);
2034:
2035: String filename = sessionDir.getCanonicalPath()
2036: + File.separator + "record.xml";
2037:
2038: // Store the structure
2039: XMLStructure xmlStructure = new XMLStructure(
2040: getEnvironment(), filename, "XMLStructure",
2041: XMLStructure.INIT_CUSTOM, getSessionClassLoader());
2042: xmlStructure.open();
2043:
2044: if (!xmlStructure.isEmpty()) {
2045: getLogger()
2046: .debug(
2047: language
2048: .getString("CleverPHL.SaveRecord.Msg.NotEmpty"));
2049: xmlStructure.clear();
2050: } else {
2051: getLogger()
2052: .debug(
2053: language
2054: .getString("CleverPHL.SaveRecord.Msg.IsEmpty"));
2055: }
2056:
2057: ExternalStructureTools.write(getRecord(), getStructure(),
2058: xmlStructure);
2059: xmlStructure.getRecord().setRecordName(
2060: getRecord().getRecordName());
2061: xmlStructure.close();
2062:
2063: isSessionUnsaved = false;
2064: customization.setNotifying(true);
2065: } catch (Exception i) {
2066: logger.error(language
2067: .getString("CleverPHL.Session.Error.Store"), i);
2068: }
2069: }
2070:
2071: /**
2072: * This method will be called by the key stroke catcher when a key stroke has been dispatched.
2073: *
2074: * @param strokeName the name of the key stroke
2075: */
2076: public void handleKeyStroke(String strokeName) {
2077: if (strokeName.equals("CleverPHL.Menu.StartCapture")) {
2078: if (isActive() && !isCapturing() && !isReplaying()) {
2079: startCapture();
2080: }
2081: } else if (strokeName.equals("CleverPHL.Menu.StopCapture")) {
2082: if (isActive() && isCapturing()) {
2083: stopCapture();
2084: }
2085: } else if (strokeName.equals("CleverPHL.Menu.StartReplay")) {
2086: if (isActive() && !isCapturing()) {
2087: replay();
2088: }
2089: } else if (strokeName.equals("CleverPHL.Menu.PauseReplay")) {
2090: if (isActive() && isReplaying()) {
2091: pauseReplay();
2092: }
2093: } else if (strokeName.equals("CleverPHL.Menu.ResetReplay")) {
2094: if (isActive() && isReplaying() && isReplayPause()) {
2095: resetReplay();
2096: }
2097: } else if (strokeName.equals("CleverPHL.Menu.ReplayStep")) {
2098: if ((isActive() && (isReplaying() && isReplayPause()))
2099: || (!isCapturing() && !isReplaying())) {
2100: replayActualElement();
2101: }
2102: } else if (strokeName
2103: .equals("CleverPHL.Menu.StartMarkedCapture")) {
2104: if (isActive() && !isCapturing() && !isReplaying()) {
2105: startMarkedCapture();
2106: }
2107: } else if (strokeName.equals("CleverPHL.Menu.InsertTest")) {
2108: if (isActive() && !isCapturing() && !isReplaying()) {
2109: cleverPHL.getMainFrame().getCleverPHLMenuBar()
2110: .getMenuItem("CleverPHL.Menu.InsertTest")
2111: .getAction().actionPerformed(
2112: new ActionEvent(new Panel(), 0, null));
2113: }
2114: }
2115: }
2116:
2117: /**
2118: * Adds a session listener to the list of listeners. All listeners will be notified of session
2119: * events.
2120: *
2121: * @param listener the listener to add
2122: */
2123: public void addSessionListener(SessionListener listener) {
2124: sessionListeners.add(listener);
2125: }
2126:
2127: /**
2128: * Removes a session listener from the list of listeners.
2129: *
2130: * @param listener the listener to remove
2131: */
2132: public void removeSessionListener(SessionListener listener) {
2133: sessionListeners.remove(listener);
2134: }
2135:
2136: /**
2137: * Fires a session event to all listeners.
2138: *
2139: * @param event the event
2140: */
2141: protected void fireSessionEvent(SessionEvent event) {
2142: Iterator i = sessionListeners.iterator();
2143:
2144: while (i.hasNext()) {
2145: ((SessionListener) i.next()).sessionStateChanged(event);
2146: }
2147: }
2148:
2149: /**
2150: * This method is called when the session's customization has changed.
2151: *
2152: * @param event DOCUMENT ME!
2153: */
2154: public void hashtableChanged(HashtableChangeEvent event) {
2155: isSessionUnsaved = true;
2156: hideCleverPHLCapture = customization.getBoolean(
2157: "Capture.HideCleverPHL", false);
2158: }
2159:
2160: /**
2161: * This method is called when the start list has changed.
2162: *
2163: * @param event DOCUMENT ME!
2164: */
2165: public void contentsChanged(ListDataEvent event) {
2166: isSessionUnsaved = true;
2167: }
2168:
2169: /**
2170: * This method is called when the start list has changed.
2171: *
2172: * @param event DOCUMENT ME!
2173: */
2174: public void intervalAdded(ListDataEvent event) {
2175: isSessionUnsaved = true;
2176: }
2177:
2178: /**
2179: * This method is called when the start list has changed.
2180: *
2181: * @param event DOCUMENT ME!
2182: */
2183: public void intervalRemoved(ListDataEvent event) {
2184: isSessionUnsaved = true;
2185: }
2186:
2187: /**
2188: * Sets the starter list
2189: *
2190: * @param starterList DOCUMENT ME!
2191: */
2192: public void setStarterList(StarterList starterList) {
2193: this .starterList = starterList;
2194: }
2195:
2196: /**
2197: * Sets whether or not the session should be automatically stored when exiting.
2198: *
2199: * @param storeOnExit DOCUMENT ME!
2200: */
2201: public void setStoreOnExit(boolean storeOnExit) {
2202: this .storeOnExit = storeOnExit;
2203: }
2204:
2205: /**
2206: * Inits the shutdown hook.
2207: */
2208: public void initShutdownHook() {
2209: shutdownHookThread = new Thread(this );
2210: Runtime.getRuntime().addShutdownHook(shutdownHookThread);
2211: }
2212:
2213: /**
2214: * Removes the shutdown hook.
2215: */
2216: public void removeShutdownHook() {
2217: if (shutdownHookThread != null) {
2218: Runtime.getRuntime().removeShutdownHook(shutdownHookThread);
2219: }
2220: }
2221:
2222: /**
2223: * For the shutdown hook
2224: */
2225: public void run() {
2226: if (isSessionUnsaved && storeOnExit) {
2227: store();
2228: }
2229: }
2230:
2231: /**
2232: * Returns the session's customization.
2233: *
2234: * @return DOCUMENT ME!
2235: */
2236: public Customization getSessionCustomization() {
2237: return sessionCustom;
2238: }
2239:
2240: /**
2241: * Returns the class loader which has loaded the target application.
2242: *
2243: * @return DOCUMENT ME!
2244: */
2245: public JacaretoClassLoader getTargetApplicationClassLoader() {
2246: return targetApplicationClassLoader;
2247: }
2248:
2249: /**
2250: * Returns the class loader of the session.
2251: *
2252: * @return DOCUMENT ME!
2253: */
2254: public JacaretoClassLoader getSessionClassLoader() {
2255: return sessionClassLoader;
2256: }
2257:
2258: /**
2259: * Called when the target application class loader has changed. Changes will be sent to the
2260: * session class loader which has to know the classpaths added to the target application class
2261: * loader.
2262: *
2263: * @param event the class loader event
2264: */
2265: public void classLoaderChanged(JacaretoClassLoaderEvent event) {
2266: if (event.getID() == JacaretoClassLoaderEvent.PATHS_ADDED) {
2267: sessionClassLoader.addPaths(event.getAddedPaths());
2268: }
2269: }
2270:
2271: /**
2272: * Returns the insertion mode.
2273: *
2274: * @return DOCUMENT ME!
2275: */
2276: public boolean getInsertionMode() {
2277: return insertionMode;
2278: }
2279:
2280: /**
2281: * Set the insertion mode. True mean insert into structures.
2282: *
2283: * @param mode is the mode that should setted
2284: */
2285: public void setInsertionMode(boolean mode) {
2286: insertionMode = mode;
2287: ((JCheckBoxMenuItem) cleverPHL.getMainFrame()
2288: .getCleverPHLMenuBar().getMenuItem(
2289: "CleverPHL.Menu.InsertionMode"))
2290: .setSelected(mode);
2291: }
2292: }
|