blob: 3c731a43ddec6bcda86277cc12a5449a364b402a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Ericsson
* 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:
* Isaac Arvestad (Ericsson) - initial API and implementation
*******************************************************************************/
package org.eclipse.swtbot.generator.client.views;
import org.eclipse.jdt.core.ElementChangedEvent;
import org.eclipse.jdt.core.IElementChangedListener;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.text.source.VerticalRuler;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swtbot.generator.client.Recorder;
import org.eclipse.swtbot.generator.client.Recorder.ConnectionState;
import org.eclipse.swtbot.generator.client.RecorderClientStatusListener;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.plugin.AbstractUIPlugin;
/**
* RecorderClientView shows SWTBot recorder output as it is received from a
* RecorderServer.
*/
public class RecorderClientView extends ViewPart implements RecorderClientStatusListener, IElementChangedListener {
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "org.eclipse.swtbot.generator.client.view.recorder.client";
private static int DEFAULT_PORT_NUMBER = 8000;
private static String IS_CONNECTED_LABEL = "Connected";
private static String TRYING_CONNECT_LABEL = "Connecting...";
private static String NOT_CONNECTED_LABEL = "No connection";
private static String CONNECT_LABEL = " Connect ";
private static String CANCEL_CONNECT_LABEL = "Cancel";
private static String DISCONNECT_LABEL = "Disconnect";
private static String ADD_TO_METHOD_TOGGLE_LABEL = "Add to method: ";
private static String START_RECORDING_LABEL = "Record";
private static String STOP_RECORDING_LABEL = "Stop recording";
private Button connectButton;
private Text portText;
private Label statusLabel;
private ComboViewer availableMethodsDropDown;
private Button addToMethodToggle;
private Button refreshAvailableMethodsButton;
private Button recordingButton;
private SourceViewer viewer;
/**
* Initialize the Recorder singleton. If it already is initialized, reset
* it.
*/
public RecorderClientView() {
if (Recorder.INSTANCE.isInitialized() == false) {
Recorder.INSTANCE.initialize();
} else {
Recorder.INSTANCE.reset();
}
Recorder.INSTANCE.addStatusListener(this);
}
@Override
public void dispose() {
Recorder.INSTANCE.removeStatusListener(this);
super.dispose();
}
/**
* Updates the UI state for any connection state change.
*/
public void updateUI() {
updateUIForConnectionState(Recorder.INSTANCE.getConnectionState());
portText.setText(String.valueOf(Recorder.INSTANCE.getPort()));
}
/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
@Override
public void createPartControl(Composite parent) {
Group group = new Group(parent, SWT.NONE);
group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
group.setLayout(new GridLayout(1, false));
Composite launchContainer = new Composite(group, SWT.NONE);
launchContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
launchContainer.setLayout(new GridLayout(2, false));
connectButton = new Button(launchContainer, SWT.PUSH);
connectButton.setText(CONNECT_LABEL);
connectButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
connectButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (Recorder.INSTANCE.getConnectionState() == ConnectionState.CONNECTED) {
Recorder.INSTANCE.interruptRecorderClient();
} else if (Recorder.INSTANCE.getConnectionState() == ConnectionState.CONNECTING) {
Recorder.INSTANCE.interruptRecorderClient();
} else {
Recorder.INSTANCE.startRecorderClient(getPort());
}
updateUIForConnectionState(Recorder.INSTANCE.getConnectionState());
}
});
Composite portLaunchContainer = new Composite(launchContainer, SWT.NONE);
portLaunchContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
portLaunchContainer.setLayout(new GridLayout(2, false));
Label portLabel = new Label(portLaunchContainer, SWT.NONE);
portLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
portLabel.setText("port:");
portText = new Text(portLaunchContainer, SWT.RIGHT);
portText.setText(String.valueOf(DEFAULT_PORT_NUMBER));
portText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
portText.addVerifyListener(new VerifyListener() {
@Override
public void verifyText(VerifyEvent e) {
String port = portText.getText() + e.text;
try {
Integer.parseInt(port);
} catch (NumberFormatException e2) {
if (port.length() > 0) {
e.doit = false;
}
}
}
});
statusLabel = new Label(group, SWT.SHADOW_IN);
statusLabel.setText("No connection");
Label horizontalSeparator = new Label(group, SWT.SEPARATOR | SWT.HORIZONTAL);
horizontalSeparator.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
Composite methodSelectionContainer = new Composite(group, SWT.NONE);
methodSelectionContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
methodSelectionContainer.setLayout(new GridLayout(3, false));
addToMethodToggle = new Button(methodSelectionContainer, SWT.CHECK);
addToMethodToggle.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
addToMethodToggle.setText(ADD_TO_METHOD_TOGGLE_LABEL);
addToMethodToggle.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (Recorder.INSTANCE.isInsertingDirectlyInEditor()) {
Recorder.INSTANCE.setInsertingDirectlyInEditor(false);
availableMethodsDropDown.getControl().setEnabled(false);
refreshAvailableMethodsButton.setEnabled(false);
} else {
Recorder.INSTANCE.setInsertingDirectlyInEditor(true);
availableMethodsDropDown.getControl().setEnabled(true);
refreshAvailableMethodsButton.setEnabled(true);
// If the list is empty we refresh.
if (availableMethodsDropDown.getInput() == null
|| ((IMethod[]) availableMethodsDropDown.getInput()).length == 0) {
updateMethodSelectionDropDown();
}
}
}
});
addToMethodToggle.setEnabled(false);
availableMethodsDropDown = new ComboViewer(methodSelectionContainer);
availableMethodsDropDown.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
availableMethodsDropDown.getControl().setEnabled(false);
availableMethodsDropDown.setContentProvider(ArrayContentProvider.getInstance());
availableMethodsDropDown.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
IMethod method = (IMethod) element;
String parameterNamesString = "";
try {
String[] parameterNames = method.getParameterNames();
for (int i = 0; i < parameterNames.length; i++) {
if (i == 0) {
parameterNamesString += parameterNames[i];
} else {
parameterNamesString += ", " + parameterNames[i];
}
}
} catch (JavaModelException e) {
e.printStackTrace();
}
return method.getElementName() + "(" + parameterNamesString + ")";
}
});
availableMethodsDropDown.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
Recorder.INSTANCE.setSelectedMethod((IMethod) selection.getFirstElement());
}
});
refreshAvailableMethodsButton = new Button(methodSelectionContainer, SWT.PUSH);
refreshAvailableMethodsButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
refreshAvailableMethodsButton.setEnabled(false);
refreshAvailableMethodsButton.setImage(AbstractUIPlugin
.imageDescriptorFromPlugin("org.eclipse.swtbot.generator.client", "icons/refresh.gif").createImage());
refreshAvailableMethodsButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateMethodSelectionDropDown();
}
});
recordingButton = new Button(group, SWT.PUSH);
recordingButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
recordingButton.setText(START_RECORDING_LABEL);
recordingButton.setEnabled(false);
recordingButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (Recorder.INSTANCE.isRecording()) {
recordingButton.setText(START_RECORDING_LABEL);
Recorder.INSTANCE.setRecording(false);
} else {
recordingButton.setText(STOP_RECORDING_LABEL);
Recorder.INSTANCE.setRecording(true);
}
}
});
viewer = new SourceViewer(group, new VerticalRuler(0), SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
viewer.setDocument(Recorder.INSTANCE.getDocument());
viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
getSite().setSelectionProvider(viewer);
JavaCore.addElementChangedListener(this);
updateUIForConnectionState(Recorder.INSTANCE.getConnectionState());
updateMethodSelectionDropDown();
}
/**
* Passing the focus request to the viewer's control.
*/
@Override
public void setFocus() {
viewer.getControl().setFocus();
}
/**
* @return The currently chosen port.
*/
private int getPort() {
return Integer.parseInt(portText.getText());
}
@Override
public void connectionStarted() {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
updateMethodSelectionDropDown();
updateUIForConnectionState(ConnectionState.CONNECTED);
}
});
}
@Override
public void connectionEnded() {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
updateUIForConnectionState(ConnectionState.DISCONNECTED);
}
});
}
/**
* Updates all UI elements to match a new connection state.
*
* @param state
* The new connection state.
*/
private void updateUIForConnectionState(ConnectionState state) {
switch (state) {
case CONNECTED:
statusLabel.setText(IS_CONNECTED_LABEL);
recordingButton.setText(START_RECORDING_LABEL);
connectButton.setText(DISCONNECT_LABEL);
addToMethodToggle.setSelection(false);
recordingButton.setEnabled(true);
connectButton.setEnabled(true);
portText.setEnabled(false);
addToMethodToggle.setEnabled(true);
availableMethodsDropDown.getControl().setEnabled(false);
refreshAvailableMethodsButton.setEnabled(false);
break;
case CONNECTING:
statusLabel.setText(TRYING_CONNECT_LABEL);
recordingButton.setText(START_RECORDING_LABEL);
connectButton.setText(CANCEL_CONNECT_LABEL);
addToMethodToggle.setSelection(false);
recordingButton.setEnabled(false);
connectButton.setEnabled(true);
portText.setEnabled(false);
addToMethodToggle.setEnabled(false);
availableMethodsDropDown.getControl().setEnabled(false);
refreshAvailableMethodsButton.setEnabled(false);
break;
case DISCONNECTED:
statusLabel.setText(NOT_CONNECTED_LABEL);
recordingButton.setText(START_RECORDING_LABEL);
connectButton.setText(CONNECT_LABEL);
addToMethodToggle.setSelection(false);
recordingButton.setEnabled(false);
connectButton.setEnabled(true);
portText.setEnabled(true);
addToMethodToggle.setEnabled(false);
availableMethodsDropDown.getControl().setEnabled(false);
refreshAvailableMethodsButton.setEnabled(false);
break;
}
}
/**
* Updates the method selection drop down if the change event is likely to
* affect the currently available methods in the method selection drop down.
*/
@Override
public void elementChanged(ElementChangedEvent event) {
if (Recorder.INSTANCE.shouldUpdateMethodSelectionViewer(event)) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
updateMethodSelectionDropDown();
}
});
}
}
/**
* Returns the active editor or null if it fails.
*
* @return The active editor.
*/
private IEditorPart getActiveEditor() {
IWorkbench workbench = PlatformUI.getWorkbench();
if (workbench == null) {
return null;
}
IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow();
if (workbenchWindow == null) {
return null;
}
IWorkbenchPage workbenchPage = workbenchWindow.getActivePage();
if (workbenchPage == null) {
return null;
}
return workbenchPage.getActiveEditor();
}
/**
* Updates the method selection drop down.
*/
@SuppressWarnings("restriction")
private void updateMethodSelectionDropDown() {
IEditorPart activeEditor = getActiveEditor();
if (activeEditor == null) {
Recorder.INSTANCE.setSelectedMethod(null);
Recorder.INSTANCE.setSelectedMethodDocument(null);
availableMethodsDropDown.setInput(null);
} else if (activeEditor instanceof JavaEditor) {
ITypeRoot root = EditorUtility.getEditorInputJavaElement(activeEditor, false);
IType type = root.findPrimaryType();
final IMethod[] methods;
try {
methods = type.getMethods();
IMethod methodToSelect = null;
if (Recorder.INSTANCE.getSelectedMethod() != null) {
methodToSelect = findSimilarMethod(Recorder.INSTANCE.getSelectedMethod(), methods);
}
IDocument currentActiveDocument = ((JavaEditor) activeEditor).getDocumentProvider()
.getDocument(activeEditor.getEditorInput());
Recorder.INSTANCE.setSelectedMethod(methodToSelect);
Recorder.INSTANCE.setSelectedMethodDocument(currentActiveDocument);
availableMethodsDropDown.setInput(methods);
// If methodToSelect is non-null we want to select it to
// maintain the user's previous selection.
if (methodToSelect != null) {
ISelection selection = new StructuredSelection(methodToSelect);
availableMethodsDropDown.setSelection(selection);
}
} catch (JavaModelException e) {
e.printStackTrace();
}
}
}
/**
* Tries to find a similar method in an array of IMethod instances using
* <code>IMethod.isSimilar</code>
*
* @param method
* The method to search for.
* @param methods
* The array to search through.
* @return The first similar method found or null if no similar method was
* found.
*/
private IMethod findSimilarMethod(IMethod method, IMethod[] methods) {
IMethod similarMethod = null;
for (IMethod candidate : methods) {
if (method.isSimilar(candidate)) {
similarMethod = candidate;
break;
}
}
return similarMethod;
}
}