/*******************************************************************************
* Copyright (c) 2007 - 2010 QNX Software Systems 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:
* QNX Software Systems - Initial API and implementation
* Andy Jin - Hardware debugging UI improvements, bug 229946
* Anna Dushistova(MontaVista) - bug 241279
* - Hardware Debugging: Host name or ip address not saving in
* the debug configuration
* Andy Jin (QNX) - Added DSF debugging, bug 248593
* Bruce Griffith, Sage Electronic Engineering, LLC - bug 305943
* - API generalization to become transport-independent (e.g. to
* allow connections via serial ports and pipes).
*******************************************************************************/
package org.eclipse.cdt.debug.gdbjtag.ui;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import org.eclipse.cdt.debug.gdbjtag.core.Activator;
import org.eclipse.cdt.debug.gdbjtag.core.IGDBJtagConnection;
import org.eclipse.cdt.debug.gdbjtag.core.IGDBJtagConstants;
import org.eclipse.cdt.debug.gdbjtag.core.jtagdevice.GDBJtagDeviceContribution;
import org.eclipse.cdt.debug.gdbjtag.core.jtagdevice.GDBJtagDeviceContributionFactory;
import org.eclipse.cdt.debug.gdbjtag.core.jtagdevice.IGDBJtagDevice;
import org.eclipse.cdt.debug.mi.core.IMILaunchConfigurationConstants;
import org.eclipse.cdt.debug.mi.core.MIPlugin;
import org.eclipse.cdt.debug.mi.core.command.factories.CommandFactoryDescriptor;
import org.eclipse.cdt.debug.mi.core.command.factories.CommandFactoryManager;
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
import org.eclipse.debug.ui.StringVariableSelectionDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
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.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
/**
* @author Doug Schaefer, Adrian Petrescu
*
*/
public class GDBJtagDebuggerTab extends AbstractLaunchConfigurationTab {
private static final String TAB_NAME = "Debugger";
private static final String TAB_ID = "org.eclipse.cdt.debug.gdbjtag.ui.debuggertab.cdi";
private CommandFactoryDescriptor[] cfDescs;
private Text gdbCommand;
private Combo commandFactory;
private Combo miProtocol;
private Button verboseMode;
private Button useRemote;
private Combo jtagDevice;
private Composite remoteConnectionParameters;
private StackLayout remoteConnectParmsLayout;
private Composite remoteTcpipBox;
private Text ipAddress;
private Text portNumber;
private Composite remoteConnectionBox;
private Text connection;
private String savedJtagDevice;
public String getName() {
return TAB_NAME;
}
public Image getImage() {
return GDBJtagImages.getDebuggerTabImage();
}
public void createControl(Composite parent) {
ScrolledComposite sc = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL);
sc.setExpandHorizontal(true);
sc.setExpandVertical(true);
setControl(sc);
Composite comp = new Composite(sc, SWT.NONE);
sc.setContent(comp);
GridLayout layout = new GridLayout();
comp.setLayout(layout);
Group group = new Group(comp, SWT.NONE);
layout = new GridLayout();
group.setLayout(layout);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
group.setLayoutData(gd);
group.setText(Messages.getString("GDBJtagDebuggerTab.gdbSetupGroup_Text"));
createCommandControl(group);
createCommandFactoryControl(group);
createProtocolControl(group);
createVerboseModeControl(group);
createRemoteControl(comp);
}
private void browseButtonSelected(String title, Text text) {
FileDialog dialog = new FileDialog(getShell(), SWT.NONE);
dialog.setText(title);
String str = text.getText().trim();
int lastSeparatorIndex = str.lastIndexOf(File.separator);
if (lastSeparatorIndex != -1)
dialog.setFilterPath(str.substring(0, lastSeparatorIndex));
str = dialog.open();
if (str != null)
text.setText(str);
}
private void variablesButtonSelected(Text text) {
StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(
getShell());
if (dialog.open() == StringVariableSelectionDialog.OK) {
text.append(dialog.getVariableExpression());
}
}
private void createCommandControl(Composite parent) {
Composite comp = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 3;
comp.setLayout(layout);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 1;
comp.setLayoutData(gd);
Label label = new Label(comp, SWT.NONE);
label.setText(Messages.getString("GDBJtagDebuggerTab.gdbCommandLabel"));
gd = new GridData();
gd.horizontalSpan = 3;
label.setLayoutData(gd);
gdbCommand = new Text(comp, SWT.SINGLE | SWT.BORDER);
gd = new GridData(GridData.FILL_HORIZONTAL);
gdbCommand.setLayoutData(gd);
gdbCommand.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
scheduleUpdateJob(); // provides much better performance for Text listeners
}
});
Button button = new Button(comp, SWT.NONE);
button.setText(Messages.getString("GDBJtagDebuggerTab.gdbCommandBrowse"));
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
browseButtonSelected(Messages.getString("GDBJtagDebuggerTab.gdbCommandBrowse_Title"), gdbCommand);
}
});
button = new Button(comp, SWT.NONE);
button.setText(Messages.getString("GDBJtagDebuggerTab.gdbCommandVariable"));
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
variablesButtonSelected(gdbCommand);
}
});
}
private void createCommandFactoryControl(Composite parent) {
Composite comp = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(2, false);
comp.setLayout(layout);
Label label = new Label(comp, SWT.NONE);
label.setText(Messages.getString("GDBJtagDebuggerTab.commandFactoryLabel"));
commandFactory = new Combo(comp, SWT.READ_ONLY | SWT.DROP_DOWN);
// Get the command sets
CommandFactoryManager cfManager = MIPlugin.getDefault().getCommandFactoryManager();
cfDescs = cfManager.getDescriptors(IGDBJtagConstants.DEBUGGER_ID);
for (int i = 0; i < cfDescs.length; ++i) {
commandFactory.add(cfDescs[i].getName());
}
commandFactory.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
commandFactoryChanged();
scheduleUpdateJob(); // provides much better performance for Text listeners
}
});
}
private void createProtocolControl(Composite parent) {
Composite comp = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(2, false);
comp.setLayout(layout);
Label label = new Label(comp, SWT.NONE);
label.setText(Messages.getString("GDBJtagDebuggerTab.miProtocolLabel"));
miProtocol = new Combo(comp, SWT.READ_ONLY | SWT.DROP_DOWN);
miProtocol.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
scheduleUpdateJob(); // provides much better performance for Text listeners
}
});
}
private void commandFactoryChanged() {
int currsel = miProtocol.getSelectionIndex();
String currProt = null;
if (currsel >= 0)
currProt = miProtocol.getItem(currsel);
miProtocol.removeAll();
int cfsel = commandFactory.getSelectionIndex();
if (cfsel >= 0) {
String[] protocols = cfDescs[cfsel].getMIVersions();
for (int i = 0; i < protocols.length; ++i) {
miProtocol.add(protocols[i]);
if (currProt != null && protocols[i].equals(currProt))
miProtocol.select(i);
}
}
if (miProtocol.getSelectionIndex() < 0 && miProtocol.getItemCount() > 0)
miProtocol.select(0);
}
private void createVerboseModeControl(Composite parent) {
verboseMode = new Button(parent, SWT.CHECK);
verboseMode.setText(Messages.getString("GDBJtagDebuggerTab.verboseModeLabel"));
verboseMode.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
updateLaunchConfigurationDialog();
}
});
}
private void createRemoteControl(Composite parent) {
Group group = new Group(parent, SWT.NONE);
GridLayout layout = new GridLayout();
group.setLayout(layout);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
group.setLayoutData(gd);
group.setText(Messages.getString("GDBJtagDebuggerTab.remoteGroup_Text"));
useRemote = new Button(group, SWT.CHECK);
useRemote.setText(Messages.getString("GDBJtagDebuggerTab.useRemote_Text"));
useRemote.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
useRemoteChanged();
updateLaunchConfigurationDialog();
}
});
Composite comp = new Composite(group, SWT.NONE);
layout = new GridLayout();
layout.numColumns = 2;
comp.setLayout(layout);
Label label = new Label(comp, SWT.NONE);
label.setText(Messages.getString("GDBJtagDebuggerTab.jtagDeviceLabel"));
jtagDevice = new Combo(comp, SWT.READ_ONLY | SWT.DROP_DOWN);
GDBJtagDeviceContribution[] availableDevices = GDBJtagDeviceContributionFactory.
getInstance().getGDBJtagDeviceContribution();
for (int i = 0; i < availableDevices.length; i++) {
jtagDevice.add(availableDevices[i].getDeviceName());
}
jtagDevice.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
updateDeviceIpPort(jtagDevice.getText());
scheduleUpdateJob(); // provides much better performance for Text listeners
}
});
remoteConnectionParameters = new Composite(group, SWT.NO_TRIM | SWT.NO_FOCUS);
remoteConnectParmsLayout = new StackLayout();
remoteConnectionParameters.setLayout(remoteConnectParmsLayout);
//
// Create entry fields for TCP/IP connections
//
{
remoteTcpipBox = new Composite(remoteConnectionParameters, SWT.NO_TRIM | SWT.NO_FOCUS);
layout = new GridLayout();
layout.numColumns = 2;
remoteTcpipBox.setLayout(layout);
remoteTcpipBox.setBackground(remoteConnectionParameters.getParent().getBackground());
label = new Label(remoteTcpipBox, SWT.NONE);
label.setText(Messages.getString("GDBJtagDebuggerTab.ipAddressLabel")); //$NON-NLS-1$
ipAddress = new Text(remoteTcpipBox, SWT.BORDER);
gd = new GridData();
gd.widthHint = 125;
ipAddress.setLayoutData(gd);
label = new Label(remoteTcpipBox, SWT.NONE);
label.setText(Messages.getString("GDBJtagDebuggerTab.portNumberLabel")); //$NON-NLS-1$
portNumber = new Text(remoteTcpipBox, SWT.BORDER);
gd = new GridData();
gd.widthHint = 125;
portNumber.setLayoutData(gd);
}
//
// Create entry fields for other types of connections
//
{
remoteConnectionBox = new Composite(remoteConnectionParameters, SWT.NO_TRIM | SWT.NO_FOCUS);
layout = new GridLayout();
layout.numColumns = 2;
remoteConnectionBox.setLayout(layout);
remoteConnectionBox.setBackground(remoteConnectionParameters.getParent().getBackground());
label = new Label(remoteConnectionBox, SWT.NONE);
label.setText(Messages.getString("GDBJtagDebuggerTab.connectionLabel")); //$NON-NLS-1$
connection = new Text(remoteConnectionBox, SWT.BORDER);
gd = new GridData();
gd.widthHint = 125;
connection.setLayoutData(gd);
}
//
// Add watchers for user data entry
//
ipAddress.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
scheduleUpdateJob(); // provides much better performance for Text listeners
}
});
portNumber.addVerifyListener(new VerifyListener() {
public void verifyText(VerifyEvent e) {
e.doit = Character.isDigit(e.character) || Character.isISOControl(e.character);
}
});
portNumber.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
scheduleUpdateJob(); // provides much better performance for Text listeners
}
});
connection.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
scheduleUpdateJob(); // provides much better performance for Text listeners
}
});
}
/**
* @param text
*/
@SuppressWarnings("deprecation")
protected void updateDeviceIpPort(String selectedDeviceName) {
if (selectedDeviceName.equals(savedJtagDevice)) {
return;
}
GDBJtagDeviceContribution[] availableDevices = GDBJtagDeviceContributionFactory.getInstance()
.getGDBJtagDeviceContribution();
IGDBJtagDevice selectedDevice = null;
for (int i = 0; i < availableDevices.length; i++) {
String name = availableDevices[i].getDeviceName();
if (name.equals(selectedDeviceName)) {
selectedDevice = availableDevices[i].getDevice();
if (selectedDevice != null) {
if (selectedDevice instanceof IGDBJtagConnection) {
IGDBJtagConnection connectionDevice = (IGDBJtagConnection)selectedDevice;
connection.setText(connectionDevice.getDefaultDeviceConnection());
} else {
// legacy way
ipAddress.setText(selectedDevice.getDefaultIpAddress());
portNumber.setText(selectedDevice.getDefaultPortNumber());
}
useRemoteChanged();
updateLaunchConfigurationDialog();
break;
}
}
}
}
private void useRemoteChanged() {
boolean enabled = useRemote.getSelection();
jtagDevice.setEnabled(enabled);
ipAddress.setEnabled(enabled);
portNumber.setEnabled(enabled);
connection.setEnabled(enabled);
GDBJtagDeviceContribution selectedDeviceEntry = findJtagDeviceByName(jtagDevice.getText());
if ((selectedDeviceEntry == null) || (selectedDeviceEntry.getDevice() == null)) {
remoteConnectParmsLayout.topControl = null;
remoteConnectionParameters.layout();
} else {
IGDBJtagDevice device = selectedDeviceEntry.getDevice();
if (device instanceof IGDBJtagConnection) {
remoteConnectParmsLayout.topControl = remoteConnectionBox;
remoteConnectionBox.getParent().layout();
} else {
remoteConnectParmsLayout.topControl = remoteTcpipBox;
remoteTcpipBox.getParent().layout();
}
}
}
private GDBJtagDeviceContribution findJtagDeviceByName(String name) {
GDBJtagDeviceContribution[] availableDevices = GDBJtagDeviceContributionFactory.getInstance().getGDBJtagDeviceContribution();
for (GDBJtagDeviceContribution device : availableDevices) {
if (device.getDeviceName().equals(name)) {
return device;
}
}
return null;
}
public void initializeFrom(ILaunchConfiguration configuration) {
try {
String gdbCommandAttr = configuration.getAttribute(IMILaunchConfigurationConstants.ATTR_DEBUG_NAME, IMILaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT);
gdbCommand.setText(gdbCommandAttr);
CommandFactoryManager cfManager = MIPlugin.getDefault().getCommandFactoryManager();
CommandFactoryDescriptor defDesc = cfManager.getDefaultDescriptor(IGDBJtagConstants.DEBUGGER_ID);
String commandFactoryAttr = configuration.getAttribute(IMILaunchConfigurationConstants.ATTR_DEBUGGER_COMMAND_FACTORY, defDesc.getName());
int cfid = 0;
for (int i = 0; i < cfDescs.length; ++i)
if (cfDescs[i].getName().equals(commandFactoryAttr)) {
cfid = i;
break;
}
commandFactory.select(cfid); // populates protocol list too
String miProtocolAttr = configuration.getAttribute(IMILaunchConfigurationConstants.ATTR_DEBUGGER_PROTOCOL, defDesc.getMIVersions()[0]);
int n = miProtocol.getItemCount();
for (int i = 0; i < n; ++i) {
if (miProtocol.getItem(i).equals(miProtocolAttr)) {
miProtocol.select(i);
}
}
boolean verboseModeAttr = configuration.getAttribute(IMILaunchConfigurationConstants.ATTR_DEBUGGER_VERBOSE_MODE, IMILaunchConfigurationConstants.DEBUGGER_VERBOSE_MODE_DEFAULT);
verboseMode.setSelection(verboseModeAttr);
boolean useRemoteAttr = configuration.getAttribute(IGDBJtagConstants.ATTR_USE_REMOTE_TARGET, IGDBJtagConstants.DEFAULT_USE_REMOTE_TARGET);
useRemote.setSelection(useRemoteAttr);
useRemoteChanged();
savedJtagDevice = configuration.getAttribute(IGDBJtagConstants.ATTR_JTAG_DEVICE, ""); //$NON-NLS-1$
if (savedJtagDevice.length() == 0) {
jtagDevice.select(0);
} else {
String storedAddress = ""; //$NON-NLS-1$
int storedPort = 0;
String storedConnection = ""; //$NON-NLS-1$
for (int i = 0; i < jtagDevice.getItemCount(); i++) {
if (jtagDevice.getItem(i).equals(savedJtagDevice)) {
storedAddress = configuration.getAttribute(IGDBJtagConstants.ATTR_IP_ADDRESS, IGDBJtagConstants.DEFAULT_IP_ADDRESS); //$NON-NLS-1$
storedPort = configuration.getAttribute(IGDBJtagConstants.ATTR_PORT_NUMBER, IGDBJtagConstants.DEFAULT_PORT_NUMBER);
storedConnection = configuration.getAttribute(IGDBJtagConstants.ATTR_CONNECTION, IGDBJtagConstants.DEFAULT_CONNECTION); //$NON-NLS-1$
jtagDevice.select(i);
break;
}
}
// New generic connection settings
try {
connection.setText(new URI(storedConnection).getSchemeSpecificPart());
} catch (URISyntaxException e) {
Activator.log(e);
}
// Legacy TCP/IP based settings
ipAddress.setText(storedAddress);
String portString = (0<storedPort)&&(storedPort<=65535) ? Integer.valueOf(storedPort).toString() : ""; //$NON-NLS-1$
portNumber.setText(portString);
}
} catch (CoreException e) {
Activator.getDefault().getLog().log(e.getStatus());
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#getId()
*/
@Override
public String getId() {
return TAB_ID;
}
public void performApply(ILaunchConfigurationWorkingCopy configuration) {
configuration.setAttribute(IMILaunchConfigurationConstants.ATTR_DEBUG_NAME, gdbCommand.getText().trim());
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME, gdbCommand.getText().trim()); // DSF
configuration.setAttribute(IMILaunchConfigurationConstants.ATTR_DEBUGGER_COMMAND_FACTORY, commandFactory.getText());
configuration.setAttribute(IMILaunchConfigurationConstants.ATTR_DEBUGGER_PROTOCOL, miProtocol.getText());
configuration.setAttribute(IMILaunchConfigurationConstants.ATTR_DEBUGGER_VERBOSE_MODE, verboseMode.getSelection());
savedJtagDevice = jtagDevice.getText();
configuration.setAttribute(IGDBJtagConstants.ATTR_JTAG_DEVICE, savedJtagDevice);
configuration.setAttribute(IGDBJtagConstants.ATTR_USE_REMOTE_TARGET, useRemote.getSelection());
if (savedJtagDevice.length() > 0) {
try {
IGDBJtagDevice device = findJtagDeviceByName(jtagDevice.getText()).getDevice();
if (device instanceof IGDBJtagConnection) {
String conn = connection.getText().trim();
URI uri = new URI("gdb", conn, ""); //$NON-NLS-1$ //$NON-NLS-2$
configuration.setAttribute(IGDBJtagConstants.ATTR_CONNECTION, uri.toString());
} else {
String ip = ipAddress.getText().trim();
configuration.setAttribute(IGDBJtagConstants.ATTR_IP_ADDRESS, ip);
int port = Integer.valueOf(portNumber.getText().trim()).intValue();
configuration.setAttribute(IGDBJtagConstants.ATTR_PORT_NUMBER, port);
}
} catch (URISyntaxException e) {
Activator.log(e);
} catch (NumberFormatException e) {
Activator.log(e);
}
}
}
public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
configuration.setAttribute(IMILaunchConfigurationConstants.ATTR_DEBUG_NAME, IMILaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT);
CommandFactoryManager cfManager = MIPlugin.getDefault().getCommandFactoryManager();
CommandFactoryDescriptor defDesc = cfManager.getDefaultDescriptor(IGDBJtagConstants.DEBUGGER_ID);
configuration.setAttribute(IMILaunchConfigurationConstants.ATTR_DEBUGGER_COMMAND_FACTORY, defDesc.getName());
configuration.setAttribute(IMILaunchConfigurationConstants.ATTR_DEBUGGER_PROTOCOL, defDesc.getMIVersions()[0]);
configuration.setAttribute(IMILaunchConfigurationConstants.ATTR_DEBUGGER_VERBOSE_MODE, IMILaunchConfigurationConstants.DEBUGGER_VERBOSE_MODE_DEFAULT);
configuration.setAttribute(IGDBJtagConstants.ATTR_USE_REMOTE_TARGET, IGDBJtagConstants.DEFAULT_USE_REMOTE_TARGET);
}
}