001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.ui.tests.macro;
011:
012: import java.io.IOException;
013: import java.io.InputStream;
014: import java.lang.reflect.InvocationTargetException;
015: import java.util.ArrayList;
016: import java.util.Vector;
017:
018: import javax.xml.parsers.ParserConfigurationException;
019: import javax.xml.parsers.SAXParser;
020: import javax.xml.parsers.SAXParserFactory;
021:
022: import org.eclipse.core.runtime.CoreException;
023: import org.eclipse.core.runtime.IConfigurationElement;
024: import org.eclipse.core.runtime.IProgressMonitor;
025: import org.eclipse.core.runtime.Platform;
026: import org.eclipse.core.runtime.jobs.IJobChangeEvent;
027: import org.eclipse.core.runtime.jobs.IJobManager;
028: import org.eclipse.core.runtime.jobs.JobChangeAdapter;
029: import org.eclipse.jface.operation.IRunnableContext;
030: import org.eclipse.jface.operation.IRunnableWithProgress;
031: import org.eclipse.swt.SWT;
032: import org.eclipse.swt.widgets.Display;
033: import org.eclipse.swt.widgets.Event;
034: import org.eclipse.swt.widgets.Listener;
035: import org.eclipse.swt.widgets.Shell;
036: import org.eclipse.swt.widgets.Widget;
037: import org.eclipse.ui.PlatformUI;
038: import org.w3c.dom.Node;
039: import org.w3c.dom.NodeList;
040: import org.xml.sax.SAXException;
041:
042: public class MacroManager {
043: public static final String IGNORE = "__macro_ignore__";
044: public static final int IDLE = 0;
045:
046: public static final int RUNNING = 1;
047:
048: public static final int DONE = 2;
049:
050: private Macro currentMacro;
051:
052: private IIndexHandler indexHandler;
053:
054: class DisplayListener implements Listener {
055: public void handleEvent(Event event) {
056: onEvent(event);
057: }
058: }
059:
060: class JobListener extends JobChangeAdapter {
061: private int state = IDLE;
062:
063: public void running(IJobChangeEvent event) {
064: if (!event.getJob().isSystem() && state == IDLE)
065: state = RUNNING;
066: }
067:
068: public void done(IJobChangeEvent event) {
069: if (!event.getJob().isSystem() && state == RUNNING)
070: state = DONE;
071: }
072:
073: public void reset() {
074: state = IDLE;
075: }
076:
077: public int getState() {
078: return state;
079: }
080: }
081:
082: private DisplayListener listener;
083:
084: private JobListener jobListener;
085:
086: private Vector listeners;
087:
088: private ArrayList widgetResolvers;
089: private SAXParser parser;
090:
091: public MacroManager() {
092: listener = new DisplayListener();
093: jobListener = new JobListener();
094: listeners = new Vector();
095: }
096:
097: public void addRecorderListener(IRecorderListener listener) {
098: if (!listeners.contains(listener))
099: listeners.add(listener);
100: }
101:
102: public void addIndex(String indexId) {
103: if (currentMacro != null) {
104: currentMacro.addIndex(indexId);
105: }
106: }
107:
108: public void removeRecorderListener(IRecorderListener listener) {
109: if (listeners.contains(listener))
110: listeners.remove(listener);
111: }
112:
113: public boolean isRecording() {
114: return currentMacro != null;
115: }
116:
117: public void startRecording() {
118: Display display = PlatformUI.getWorkbench().getDisplay();
119: hookListeners(display);
120: currentMacro = new Macro();
121: currentMacro.initializeForRecording(display);
122: IRecorderListener[] array = (IRecorderListener[]) listeners
123: .toArray(new IRecorderListener[listeners.size()]);
124: for (int i = 0; i < array.length; i++) {
125: array[i].recordingStarted();
126: }
127: }
128:
129: public String[] getExistingIndices() {
130: if (currentMacro != null) {
131: return currentMacro.getExistingIndices();
132: }
133: return new String[0];
134: }
135:
136: public Macro stopRecording() {
137: Display display = PlatformUI.getWorkbench().getDisplay();
138: unhookListeners(display);
139: currentMacro.stopRecording();
140: Macro newMacro = currentMacro;
141: currentMacro = null;
142: IRecorderListener[] array = (IRecorderListener[]) listeners
143: .toArray(new IRecorderListener[listeners.size()]);
144: for (int i = 0; i < array.length; i++) {
145: array[i].recordingStopped();
146: }
147: return newMacro;
148: }
149:
150: public void hookListeners(Display display) {
151: display.addFilter(SWT.KeyDown, listener);
152: display.addFilter(SWT.Selection, listener);
153: display.addFilter(SWT.DefaultSelection, listener);
154: display.addFilter(SWT.Expand, listener);
155: display.addFilter(SWT.Collapse, listener);
156: display.addFilter(SWT.Modify, listener);
157: display.addFilter(SWT.Activate, listener);
158: display.addFilter(SWT.Close, listener);
159: display.addFilter(SWT.FocusIn, listener);
160: IJobManager jobManager = Platform.getJobManager();
161: jobManager.addJobChangeListener(jobListener);
162: }
163:
164: public void unhookListeners(Display display) {
165: display.removeFilter(SWT.KeyDown, listener);
166: display.removeFilter(SWT.Selection, listener);
167: display.removeFilter(SWT.DefaultSelection, listener);
168: display.removeFilter(SWT.Expand, listener);
169: display.removeFilter(SWT.Collapse, listener);
170: display.removeFilter(SWT.Modify, listener);
171: display.removeFilter(SWT.Activate, listener);
172: display.removeFilter(SWT.Close, listener);
173: display.removeFilter(SWT.FocusIn, listener);
174: IJobManager jobManager = Platform.getJobManager();
175: jobManager.removeJobChangeListener(jobListener);
176: }
177:
178: public void shutdown() {
179: if (currentMacro != null) {
180: Display display = PlatformUI.getWorkbench().getDisplay();
181: unhookListeners(display);
182: currentMacro.stopRecording();
183: currentMacro = null;
184: }
185: }
186:
187: /**
188: * Plays a provided macro stream. The method will close the input stream
189: * upon parsing.
190: *
191: * @param is
192: * @throws CoreException
193: */
194: public boolean play(final Display display,
195: IRunnableContext context, String scriptName, InputStream is)
196: throws CoreException {
197: XMLDefaultHandler handler = createMacroDocument(is);
198: Node root = handler.getDocumentElement();
199: NodeList children = root.getChildNodes();
200:
201: final Macro macro = new Macro(scriptName);
202: for (int i = 0; i < children.getLength(); i++) {
203: Node child = children.item(i);
204: if (child.getNodeName().equals("shell")) {
205: macro.addShell(child, handler.getLineTable());
206: }
207: }
208: // discard the DOM
209: handler = null;
210:
211: macro.setIndexHandler(getIndexHandler());
212:
213: final boolean[] result = new boolean[1];
214:
215: IRunnableWithProgress op = new IRunnableWithProgress() {
216: public void run(IProgressMonitor monitor)
217: throws InvocationTargetException {
218: try {
219: //System.out.println("Start macro: "+macro.getName());
220: result[0] = macro.playback(display, null, monitor);
221: } catch (CoreException e) {
222: throw new InvocationTargetException(e);
223: } catch (ClassCastException e) {
224: throw new InvocationTargetException(e);
225: } finally {
226: monitor.done();
227: //System.out.println("Stop macro: "+macro.getName());
228: }
229: }
230: };
231: try {
232: context.run(true, true, op);
233: } catch (InterruptedException e) {
234: } catch (InvocationTargetException e) {
235: MacroPlugin.logException(e);
236: return false;
237: }
238: return result[0];
239: }
240:
241: private XMLDefaultHandler createMacroDocument(InputStream is)
242: throws CoreException {
243: XMLDefaultHandler handler = null;
244: try {
245: SAXParser parser = getParser();
246: handler = new XMLDefaultHandler();
247: parser.parse(is, handler);
248: } catch (SAXException e) {
249: MacroUtil.throwCoreException(
250: "Error parsing the macro file", 0, e);
251: } catch (IOException e) {
252: MacroUtil.throwCoreException(
253: "Error parsing the macro file", 0, e);
254: } finally {
255: try {
256: is.close();
257: } catch (IOException e) {
258: }
259: }
260: return handler;
261: }
262:
263: private SAXParser getParser() throws CoreException {
264: if (parser == null) {
265: try {
266: return SAXParserFactory.newInstance().newSAXParser();
267: } catch (ParserConfigurationException e) {
268: MacroUtil.throwCoreException(
269: "Error parsing the macro file", 0, e);
270: } catch (SAXException e) {
271: MacroUtil.throwCoreException(
272: "Error parsing the macro file", 0, e);
273: }
274: }
275: return parser;
276: }
277:
278: private void onEvent(Event event) {
279: try {
280: if (event.type == SWT.KeyDown) {
281: if ((event.stateMask & SWT.SHIFT) != 0
282: && (event.stateMask & SWT.CTRL) != 0) {
283: int key = event.keyCode & SWT.KEY_MASK;
284: if (key == SWT.F11)
285: notifyInterrupt(IRecorderListener.STOP);
286: else if (key == SWT.F10)
287: notifyInterrupt(IRecorderListener.INDEX);
288: }
289: return;
290: }
291: if ((event.type == SWT.Close || event.type == SWT.Activate)
292: && !(event.widget instanceof Shell))
293: return;
294: if (jobListener.getState() == RUNNING
295: || jobListener.getState() == DONE)
296: currentMacro.addPause();
297: jobListener.reset();
298: boolean stop = currentMacro.addEvent(event);
299: if (stop) {
300: notifyInterrupt(IRecorderListener.STOP);
301: }
302: } catch (Exception e) {
303: MacroPlugin.logException(e);
304: stopRecording();
305: }
306: }
307:
308: private void notifyInterrupt(int type) {
309: IRecorderListener[] array = (IRecorderListener[]) listeners
310: .toArray(new IRecorderListener[listeners.size()]);
311: for (int i = 0; i < array.length; i++) {
312: array[i].recordingInterrupted(type);
313: }
314: }
315:
316: public String resolveWidget(Widget widget) {
317: if (widgetResolvers == null)
318: loadWidgetResolvers();
319: for (int i = 0; i < widgetResolvers.size(); i++) {
320: IWidgetResolver resolver = (IWidgetResolver) widgetResolvers
321: .get(i);
322: String id = resolver.getUniqueId(widget);
323: if (id != null)
324: return id;
325: }
326: return null;
327: }
328:
329: private void loadWidgetResolvers() {
330: widgetResolvers = new ArrayList();
331: IConfigurationElement[] elements = Platform
332: .getExtensionRegistry().getConfigurationElementsFor(
333: "org.eclipse.pde.ui.tests.macroSupport");
334: for (int i = 0; i < elements.length; i++) {
335: if (elements[i].getName().equals("widgetResolver")) {
336: try {
337: Object obj = elements[i]
338: .createExecutableExtension("class");
339: if (obj instanceof IWidgetResolver)
340: widgetResolvers.add(obj);
341: } catch (CoreException e) {
342: System.out.println(e);
343: }
344: }
345: }
346: }
347:
348: public IIndexHandler getIndexHandler() {
349: return indexHandler;
350: }
351:
352: public void setIndexHandler(IIndexHandler indexHandler) {
353: this.indexHandler = indexHandler;
354: }
355:
356: }
|