blob: 98324eeca75d663e4584d2fa35de2c833eed7357 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.internal.ui.tests.macro;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Vector;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.PlatformUI;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class MacroManager {
public static final String IGNORE = "__macro_ignore__";
public static final int IDLE = 0;
public static final int RUNNING = 1;
public static final int DONE = 2;
private Macro currentMacro;
private IIndexHandler indexHandler;
class DisplayListener implements Listener {
public void handleEvent(Event event) {
onEvent(event);
}
}
class JobListener extends JobChangeAdapter {
private int state = IDLE;
public void running(IJobChangeEvent event) {
if (!event.getJob().isSystem() && state == IDLE)
state = RUNNING;
}
public void done(IJobChangeEvent event) {
if (!event.getJob().isSystem() && state == RUNNING)
state = DONE;
}
public void reset() {
state = IDLE;
}
public int getState() {
return state;
}
}
private DisplayListener listener;
private JobListener jobListener;
private Vector listeners;
private ArrayList widgetResolvers;
private SAXParser parser;
public MacroManager() {
listener = new DisplayListener();
jobListener = new JobListener();
listeners = new Vector();
}
public void addRecorderListener(IRecorderListener listener) {
if (!listeners.contains(listener))
listeners.add(listener);
}
public void addIndex(String indexId) {
if (currentMacro != null) {
currentMacro.addIndex(indexId);
}
}
public void removeRecorderListener(IRecorderListener listener) {
if (listeners.contains(listener))
listeners.remove(listener);
}
public boolean isRecording() {
return currentMacro != null;
}
public void startRecording() {
Display display = PlatformUI.getWorkbench().getDisplay();
hookListeners(display);
currentMacro = new Macro();
currentMacro.initializeForRecording(display);
IRecorderListener[] array = (IRecorderListener[]) listeners.toArray(new IRecorderListener[listeners.size()]);
for (int i = 0; i < array.length; i++) {
array[i].recordingStarted();
}
}
public String[] getExistingIndices() {
if (currentMacro != null) {
return currentMacro.getExistingIndices();
}
return new String[0];
}
public Macro stopRecording() {
Display display = PlatformUI.getWorkbench().getDisplay();
unhookListeners(display);
currentMacro.stopRecording();
Macro newMacro = currentMacro;
currentMacro = null;
IRecorderListener[] array = (IRecorderListener[]) listeners.toArray(new IRecorderListener[listeners.size()]);
for (int i = 0; i < array.length; i++) {
array[i].recordingStopped();
}
return newMacro;
}
public void hookListeners(Display display) {
display.addFilter(SWT.KeyDown, listener);
display.addFilter(SWT.Selection, listener);
display.addFilter(SWT.DefaultSelection, listener);
display.addFilter(SWT.Expand, listener);
display.addFilter(SWT.Collapse, listener);
display.addFilter(SWT.Modify, listener);
display.addFilter(SWT.Activate, listener);
display.addFilter(SWT.Close, listener);
display.addFilter(SWT.FocusIn, listener);
IJobManager jobManager = Platform.getJobManager();
jobManager.addJobChangeListener(jobListener);
}
public void unhookListeners(Display display) {
display.removeFilter(SWT.KeyDown, listener);
display.removeFilter(SWT.Selection, listener);
display.removeFilter(SWT.DefaultSelection, listener);
display.removeFilter(SWT.Expand, listener);
display.removeFilter(SWT.Collapse, listener);
display.removeFilter(SWT.Modify, listener);
display.removeFilter(SWT.Activate, listener);
display.removeFilter(SWT.Close, listener);
display.removeFilter(SWT.FocusIn, listener);
IJobManager jobManager = Platform.getJobManager();
jobManager.removeJobChangeListener(jobListener);
}
public void shutdown() {
if (currentMacro != null) {
Display display = PlatformUI.getWorkbench().getDisplay();
unhookListeners(display);
currentMacro.stopRecording();
currentMacro = null;
}
}
/**
* Plays a provided macro stream. The method will close the input stream
* upon parsing.
*
* @param is
* @throws CoreException
*/
public boolean play(final Display display, IRunnableContext context, String scriptName, InputStream is) throws CoreException {
XMLDefaultHandler handler = createMacroDocument(is);
Node root = handler.getDocumentElement();
NodeList children = root.getChildNodes();
final Macro macro = new Macro(scriptName);
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child.getNodeName().equals("shell")) {
macro.addShell(child, handler.getLineTable());
}
}
// discard the DOM
handler = null;
macro.setIndexHandler(getIndexHandler());
final boolean[] result = new boolean[1];
IRunnableWithProgress op = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException {
try {
//System.out.println("Start macro: "+macro.getName());
result[0] = macro.playback(display, null, monitor);
} catch (CoreException e) {
throw new InvocationTargetException(e);
} catch (ClassCastException e) {
throw new InvocationTargetException(e);
} finally {
monitor.done();
//System.out.println("Stop macro: "+macro.getName());
}
}
};
try {
context.run(true, true, op);
} catch (InterruptedException e) {
} catch (InvocationTargetException e) {
MacroPlugin.logException(e);
return false;
}
return result[0];
}
private XMLDefaultHandler createMacroDocument(InputStream is) throws CoreException {
XMLDefaultHandler handler = null;
try {
SAXParser parser = getParser();
handler = new XMLDefaultHandler();
parser.parse(is, handler);
} catch (SAXException e) {
MacroUtil.throwCoreException("Error parsing the macro file", 0, e);
} catch (IOException e) {
MacroUtil.throwCoreException("Error parsing the macro file", 0, e);
} finally {
try {
is.close();
} catch (IOException e) {
}
}
return handler;
}
private SAXParser getParser() throws CoreException {
if (parser == null) {
try {
return SAXParserFactory.newInstance().newSAXParser();
} catch (ParserConfigurationException e) {
MacroUtil.throwCoreException("Error parsing the macro file", 0, e);
} catch (SAXException e) {
MacroUtil.throwCoreException("Error parsing the macro file", 0, e);
}
}
return parser;
}
private void onEvent(Event event) {
try {
if (event.type == SWT.KeyDown) {
if ((event.stateMask & SWT.SHIFT) != 0 && (event.stateMask & SWT.CTRL) != 0) {
int key = event.keyCode & SWT.KEY_MASK;
if (key == SWT.F11)
notifyInterrupt(IRecorderListener.STOP);
else if (key == SWT.F10)
notifyInterrupt(IRecorderListener.INDEX);
}
return;
}
if ((event.type == SWT.Close || event.type == SWT.Activate) && !(event.widget instanceof Shell))
return;
if (jobListener.getState() == RUNNING || jobListener.getState() == DONE)
currentMacro.addPause();
jobListener.reset();
boolean stop = currentMacro.addEvent(event);
if (stop) {
notifyInterrupt(IRecorderListener.STOP);
}
} catch (Exception e) {
MacroPlugin.logException(e);
stopRecording();
}
}
private void notifyInterrupt(int type) {
IRecorderListener[] array = (IRecorderListener[]) listeners.toArray(new IRecorderListener[listeners.size()]);
for (int i = 0; i < array.length; i++) {
array[i].recordingInterrupted(type);
}
}
public String resolveWidget(Widget widget) {
if (widgetResolvers == null)
loadWidgetResolvers();
for (int i = 0; i < widgetResolvers.size(); i++) {
IWidgetResolver resolver = (IWidgetResolver) widgetResolvers.get(i);
String id = resolver.getUniqueId(widget);
if (id != null)
return id;
}
return null;
}
private void loadWidgetResolvers() {
widgetResolvers = new ArrayList();
IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.pde.ui.tests.macroSupport");
for (int i = 0; i < elements.length; i++) {
if (elements[i].getName().equals("widgetResolver")) {
try {
Object obj = elements[i].createExecutableExtension("class");
if (obj instanceof IWidgetResolver)
widgetResolvers.add(obj);
} catch (CoreException e) {
System.out.println(e);
}
}
}
}
public IIndexHandler getIndexHandler() {
return indexHandler;
}
public void setIndexHandler(IIndexHandler indexHandler) {
this.indexHandler = indexHandler;
}
}