mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-05 08:46:02 +02:00
Bug 293679: Allow multi-select when attaching to processes
This commit is contained in:
parent
d7092b12c9
commit
079dc72df6
4 changed files with 234 additions and 48 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2008, 2009 Ericsson and others.
|
* Copyright (c) 2008, 2011 Ericsson and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -7,12 +7,15 @@
|
||||||
*
|
*
|
||||||
* Contributors:
|
* Contributors:
|
||||||
* Ericsson - initial API and implementation
|
* Ericsson - initial API and implementation
|
||||||
|
* Marc Khouzam (Ericsson) - Add support for multi-attach (Bug 293679)
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.dsf.gdb.internal.ui.actions;
|
package org.eclipse.cdt.dsf.gdb.internal.ui.actions;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
|
||||||
|
@ -21,6 +24,7 @@ import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
|
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
|
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
|
||||||
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
|
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
|
||||||
|
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.Query;
|
import org.eclipse.cdt.dsf.concurrent.Query;
|
||||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||||
|
@ -31,6 +35,7 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
|
||||||
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
|
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
|
||||||
import org.eclipse.cdt.dsf.gdb.actions.IConnect;
|
import org.eclipse.cdt.dsf.gdb.actions.IConnect;
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
|
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
|
||||||
|
import org.eclipse.cdt.dsf.gdb.internal.ui.launching.LaunchUIMessages;
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.ui.launching.ProcessPrompter.PrompterInfo;
|
import org.eclipse.cdt.dsf.gdb.internal.ui.launching.ProcessPrompter.PrompterInfo;
|
||||||
import org.eclipse.cdt.dsf.gdb.launching.IProcessExtendedInfo;
|
import org.eclipse.cdt.dsf.gdb.launching.IProcessExtendedInfo;
|
||||||
import org.eclipse.cdt.dsf.gdb.launching.LaunchMessages;
|
import org.eclipse.cdt.dsf.gdb.launching.LaunchMessages;
|
||||||
|
@ -41,8 +46,10 @@ import org.eclipse.cdt.dsf.gdb.service.SessionType;
|
||||||
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
|
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
|
||||||
import org.eclipse.cdt.dsf.service.DsfSession;
|
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
import org.eclipse.core.runtime.IProgressMonitor;
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
import org.eclipse.core.runtime.IStatus;
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.Path;
|
||||||
import org.eclipse.core.runtime.Status;
|
import org.eclipse.core.runtime.Status;
|
||||||
import org.eclipse.core.runtime.jobs.Job;
|
import org.eclipse.core.runtime.jobs.Job;
|
||||||
import org.eclipse.debug.core.DebugPlugin;
|
import org.eclipse.debug.core.DebugPlugin;
|
||||||
|
@ -58,6 +65,14 @@ public class GdbConnectCommand implements IConnect {
|
||||||
private final DsfExecutor fExecutor;
|
private final DsfExecutor fExecutor;
|
||||||
private final DsfServicesTracker fTracker;
|
private final DsfServicesTracker fTracker;
|
||||||
|
|
||||||
|
// A map of processName to path, that allows us to remember the path to the binary file
|
||||||
|
// for a process with a particular name. We can then re-use the same binary for another
|
||||||
|
// process with the same name. This allows a user to connect to multiple processes
|
||||||
|
// with the same name without having to be prompted each time for a path.
|
||||||
|
// This map is associated to the current debug session only, therefore the user can
|
||||||
|
// reset it by using a new debug session.
|
||||||
|
private Map<String, String> fProcessNameToBinaryMap = new HashMap<String, String>();
|
||||||
|
|
||||||
public GdbConnectCommand(DsfSession session) {
|
public GdbConnectCommand(DsfSession session) {
|
||||||
fExecutor = session.getExecutor();
|
fExecutor = session.getExecutor();
|
||||||
fTracker = new DsfServicesTracker(GdbUIPlugin.getBundleContext(), session.getId());
|
fTracker = new DsfServicesTracker(GdbUIPlugin.getBundleContext(), session.getId());
|
||||||
|
@ -94,7 +109,12 @@ public class GdbConnectCommand implements IConnect {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need a job because prompter.handleStatus will block
|
/**
|
||||||
|
* This job will prompt the user to select a set of processes
|
||||||
|
* to attach too.
|
||||||
|
* We need a job because prompter.handleStatus will block and
|
||||||
|
* we don't want to block the executor.
|
||||||
|
*/
|
||||||
protected class PromptForPidJob extends Job {
|
protected class PromptForPidJob extends Job {
|
||||||
|
|
||||||
// The list of processes used in the case of an ATTACH session
|
// The list of processes used in the case of an ATTACH session
|
||||||
|
@ -131,7 +151,7 @@ public class GdbConnectCommand implements IConnect {
|
||||||
Object result = prompter.handleStatus(processPromptStatus, info);
|
Object result = prompter.handleStatus(processPromptStatus, info);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
fRequestMonitor.cancel();
|
fRequestMonitor.cancel();
|
||||||
} else if (result instanceof Integer || result instanceof String) {
|
} else if (result instanceof IProcessExtendedInfo[] || result instanceof String) {
|
||||||
fRequestMonitor.setData(result);
|
fRequestMonitor.setData(result);
|
||||||
} else {
|
} else {
|
||||||
fRequestMonitor.setStatus(NO_PID_STATUS);
|
fRequestMonitor.setStatus(NO_PID_STATUS);
|
||||||
|
@ -145,32 +165,49 @@ public class GdbConnectCommand implements IConnect {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Need a job to free the executor while we prompt the user for a binary path
|
/**
|
||||||
// Bug 344892
|
* This job will prompt the user for a path to the binary to use,
|
||||||
|
* and then will attach to the process.
|
||||||
|
* We need a job to free the executor while we prompt the user for
|
||||||
|
* a binary path. Bug 344892
|
||||||
|
*/
|
||||||
private class PromptAndAttachToProcessJob extends UIJob {
|
private class PromptAndAttachToProcessJob extends UIJob {
|
||||||
private final String fPid;
|
private final String fPid;
|
||||||
private final RequestMonitor fRm;
|
private final RequestMonitor fRm;
|
||||||
|
private final String fTitle;
|
||||||
|
private final String fProcName;
|
||||||
|
|
||||||
public PromptAndAttachToProcessJob(String pid, RequestMonitor rm) {
|
public PromptAndAttachToProcessJob(String pid, String title, String procName, RequestMonitor rm) {
|
||||||
super(""); //$NON-NLS-1$
|
super(""); //$NON-NLS-1$
|
||||||
fPid = pid;
|
fPid = pid;
|
||||||
|
fTitle = title;
|
||||||
|
fProcName = procName;
|
||||||
fRm = rm;
|
fRm = rm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IStatus runInUIThread(IProgressMonitor monitor) {
|
public IStatus runInUIThread(IProgressMonitor monitor) {
|
||||||
String binaryPath = null;
|
// Have we already see the binary for a process with this name?
|
||||||
|
String binaryPath = fProcessNameToBinaryMap.get(fProcName);
|
||||||
Shell shell = Display.getCurrent().getActiveShell();
|
|
||||||
if (shell != null) {
|
|
||||||
FileDialog fd = new FileDialog(shell, SWT.NONE);
|
|
||||||
binaryPath = fd.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (binaryPath == null) {
|
||||||
|
// prompt for the binary path
|
||||||
|
Shell shell = Display.getCurrent().getActiveShell();
|
||||||
|
if (shell != null) {
|
||||||
|
FileDialog fd = new FileDialog(shell, SWT.NONE);
|
||||||
|
fd.setText(fTitle);
|
||||||
|
binaryPath = fd.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (binaryPath == null) {
|
if (binaryPath == null) {
|
||||||
// The user pressed the cancel button, so we cancel the attach gracefully
|
// The user pressed the cancel button, so we cancel the attach gracefully
|
||||||
fRm.done();
|
fRm.done();
|
||||||
} else {
|
} else {
|
||||||
|
// Store the path of the binary so we can use it again for another process
|
||||||
|
// with the same name
|
||||||
|
fProcessNameToBinaryMap.put(fProcName, binaryPath);
|
||||||
|
|
||||||
final String finalBinaryPath = binaryPath;
|
final String finalBinaryPath = binaryPath;
|
||||||
fExecutor.execute(new DsfRunnable() {
|
fExecutor.execute(new DsfRunnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -232,7 +269,7 @@ public class GdbConnectCommand implements IConnect {
|
||||||
@Override
|
@Override
|
||||||
protected void handleSuccess() {
|
protected void handleSuccess() {
|
||||||
new PromptForPidJob(
|
new PromptForPidJob(
|
||||||
"Prompt for Process", newProcessSupported, procInfoList.toArray(new IProcessExtendedInfo[0]), //$NON-NLS-1$
|
LaunchUIMessages.getString("ProcessPrompter.PromptJob"), newProcessSupported, procInfoList.toArray(new IProcessExtendedInfo[0]), //$NON-NLS-1$
|
||||||
new DataRequestMonitor<Object>(fExecutor, rm) {
|
new DataRequestMonitor<Object>(fExecutor, rm) {
|
||||||
@Override
|
@Override
|
||||||
protected void handleCancel() {
|
protected void handleCancel() {
|
||||||
|
@ -241,36 +278,15 @@ public class GdbConnectCommand implements IConnect {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected void handleSuccess() {
|
protected void handleSuccess() {
|
||||||
// New cycle, look for service again
|
Object data = getData();
|
||||||
final IGDBProcesses procService = fTracker.getService(IGDBProcesses.class);
|
if (data instanceof String) {
|
||||||
if (procService != null) {
|
// User wants to start a new process
|
||||||
Object data = getData();
|
startNewProcess(controlCtx, (String)data, rm);
|
||||||
if (data instanceof String) {
|
} else if (data instanceof IProcessExtendedInfo[]) {
|
||||||
// User wants to start a new process
|
attachToProcesses(controlCtx, (IProcessExtendedInfo[])data, rm);
|
||||||
String binaryPath = (String)data;
|
} else {
|
||||||
procService.debugNewProcess(
|
rm.setStatus(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Invalid return type for process prompter", null)); //$NON-NLS-1$
|
||||||
controlCtx, binaryPath,
|
rm.done();
|
||||||
// khouzam, maybe we should at least pass stopOnMain?
|
|
||||||
new HashMap<String, Object>(), new DataRequestMonitor<IDMContext>(fExecutor, rm));
|
|
||||||
} else if (data instanceof Integer) {
|
|
||||||
String pidStr = Integer.toString((Integer)data);
|
|
||||||
final IGDBBackend backend = fTracker.getService(IGDBBackend.class);
|
|
||||||
if (backend != null && backend.getSessionType() == SessionType.REMOTE) {
|
|
||||||
// For remote attach, we must set the binary first so we need to prompt the user.
|
|
||||||
// Because the prompt is a very long operation, we need to run outside the
|
|
||||||
// executor, so we don't lock it.
|
|
||||||
// Bug 344892
|
|
||||||
new PromptAndAttachToProcessJob(pidStr, rm).schedule();
|
|
||||||
} else {
|
|
||||||
// For a local attach, GDB can figure out the binary automatically,
|
|
||||||
// so we don't need to prompt for it.
|
|
||||||
IProcessDMContext procDmc = procService.createProcessContext(controlCtx, pidStr);
|
|
||||||
procService.attachDebuggerToProcess(procDmc, null, new DataRequestMonitor<IDMContext>(fExecutor, rm));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Invalid return type for process prompter", null)); //$NON-NLS-1$
|
|
||||||
rm.done();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).schedule();
|
}).schedule();
|
||||||
|
@ -350,4 +366,93 @@ public class GdbConnectCommand implements IConnect {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startNewProcess(ICommandControlDMContext controlDmc, String binaryPath, RequestMonitor rm) {
|
||||||
|
final IGDBProcesses procService = fTracker.getService(IGDBProcesses.class);
|
||||||
|
procService.debugNewProcess(
|
||||||
|
controlDmc, binaryPath,
|
||||||
|
new HashMap<String, Object>(), new DataRequestMonitor<IDMContext>(fExecutor, rm));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attachToProcesses(final ICommandControlDMContext controlDmc, IProcessExtendedInfo[] processes, final RequestMonitor rm) {
|
||||||
|
|
||||||
|
// For a local attach, GDB can figure out the binary automatically,
|
||||||
|
// so we don't need to prompt for it.
|
||||||
|
final IGDBProcesses procService = fTracker.getService(IGDBProcesses.class);
|
||||||
|
final IGDBBackend backend = fTracker.getService(IGDBBackend.class);
|
||||||
|
|
||||||
|
if (procService != null && backend != null) {
|
||||||
|
// Attach to each process in a sequential fashion. We must do this
|
||||||
|
// to be able to check if we are allowed to attach to the next process.
|
||||||
|
// Attaching to all of them in parallel would assume that all attach are supported.
|
||||||
|
|
||||||
|
// Create a list of all our processes so we can attach to one at a time.
|
||||||
|
// We need to create a new list so that we can remove elements from it.
|
||||||
|
final List<IProcessExtendedInfo> procList = new ArrayList<IProcessExtendedInfo>(Arrays.asList(processes));
|
||||||
|
|
||||||
|
class AttachToProcessRequestMonitor extends DataRequestMonitor<IDMContext> {
|
||||||
|
public AttachToProcessRequestMonitor() {
|
||||||
|
super(ImmediateExecutor.getInstance(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
if (!isSuccess()) {
|
||||||
|
// Failed to attach to a process. Just ignore it and move on.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that we have a process to attach to
|
||||||
|
if (procList.size() > 0) {
|
||||||
|
|
||||||
|
// Check that we can actually attach to the process.
|
||||||
|
// This is because some backends may not support multi-process.
|
||||||
|
// If the backend does not support multi-process, we only attach to the first process.
|
||||||
|
procService.isDebuggerAttachSupported(controlDmc, new DataRequestMonitor<Boolean>(ImmediateExecutor.getInstance(), null) {
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
if (isSuccess() && getData()) {
|
||||||
|
// Can attach to process
|
||||||
|
|
||||||
|
// Remove process from list and attach to it.
|
||||||
|
IProcessExtendedInfo process = procList.remove(0);
|
||||||
|
String pidStr = Integer.toString(process.getPid());
|
||||||
|
|
||||||
|
if (backend.getSessionType() == SessionType.REMOTE) {
|
||||||
|
// For remote attach, we must set the binary first so we need to prompt the user.
|
||||||
|
// Because the prompt is a very long operation, we need to run outside the
|
||||||
|
// executor, so we don't lock it.
|
||||||
|
// Bug 344892
|
||||||
|
IPath processPath = new Path(process.getName());
|
||||||
|
String processShortName = processPath.lastSegment();
|
||||||
|
new PromptAndAttachToProcessJob(pidStr,
|
||||||
|
LaunchUIMessages.getString("ProcessPrompterDialog.TitlePrefix") + process.getName(), //$NON-NLS-1$
|
||||||
|
processShortName, new AttachToProcessRequestMonitor()).schedule();
|
||||||
|
} else {
|
||||||
|
IProcessDMContext procDmc = procService.createProcessContext(controlDmc, pidStr);
|
||||||
|
procService.attachDebuggerToProcess(procDmc, null, new AttachToProcessRequestMonitor());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not allowed to attach to another process. Just stop.
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// No other process to attach to
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Trigger the first attach.
|
||||||
|
new AttachToProcessRequestMonitor().done();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Cannot find service", null)); //$NON-NLS-1$
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -226,5 +226,6 @@ LocalCDILaunchDelegate.10=Failed to set program arguments, environment or workin
|
||||||
|
|
||||||
ProcessPrompter.Core=core
|
ProcessPrompter.Core=core
|
||||||
ProcessPrompter.Cores=cores
|
ProcessPrompter.Cores=cores
|
||||||
|
ProcessPrompter.PromptJob=Prompt for Process
|
||||||
ProcessPrompterDialog.New=New...
|
ProcessPrompterDialog.New=New...
|
||||||
|
ProcessPrompterDialog.TitlePrefix=Choose binary for process:
|
|
@ -8,6 +8,7 @@
|
||||||
* Contributors:
|
* Contributors:
|
||||||
* QNX Software Systems - initial API and implementation
|
* QNX Software Systems - initial API and implementation
|
||||||
* Ericsson - Modified for DSF
|
* Ericsson - Modified for DSF
|
||||||
|
* Marc Khouzam (Ericsson) - Add support for multi-attach (Bug 293679)
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.dsf.gdb.internal.ui.launching;
|
package org.eclipse.cdt.dsf.gdb.internal.ui.launching;
|
||||||
|
|
||||||
|
@ -150,6 +151,9 @@ public class ProcessPrompter implements IStatusHandler {
|
||||||
dialog.setTitle(LaunchMessages.getString("LocalAttachLaunchDelegate.Select_Process")); //$NON-NLS-1$
|
dialog.setTitle(LaunchMessages.getString("LocalAttachLaunchDelegate.Select_Process")); //$NON-NLS-1$
|
||||||
dialog.setMessage(LaunchMessages.getString("LocalAttachLaunchDelegate.Select_Process_to_attach_debugger_to")); //$NON-NLS-1$
|
dialog.setMessage(LaunchMessages.getString("LocalAttachLaunchDelegate.Select_Process_to_attach_debugger_to")); //$NON-NLS-1$
|
||||||
|
|
||||||
|
// Allow for multiple selection
|
||||||
|
dialog.setMultipleSelection(true);
|
||||||
|
|
||||||
dialog.setElements(plist);
|
dialog.setElements(plist);
|
||||||
if (dialog.open() == Window.OK) {
|
if (dialog.open() == Window.OK) {
|
||||||
// First check if the user pressed the New button
|
// First check if the user pressed the New button
|
||||||
|
@ -158,9 +162,13 @@ public class ProcessPrompter implements IStatusHandler {
|
||||||
return binaryPath;
|
return binaryPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
IProcessExtendedInfo processInfo = (IProcessExtendedInfo)dialog.getFirstResult();
|
Object[] results = dialog.getResult();
|
||||||
if (processInfo != null) {
|
if (results != null) {
|
||||||
return new Integer(processInfo.getPid());
|
IProcessExtendedInfo[] processes = new IProcessExtendedInfo[results.length];
|
||||||
|
for (int i=0; i<processes.length; i++) {
|
||||||
|
processes[i] = (IProcessExtendedInfo)results[i];
|
||||||
|
}
|
||||||
|
return processes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,45 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Ericsson 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:
|
||||||
|
* Marc Khouzam (Ericsson) - initial API and implementation
|
||||||
|
* Marc Khouzam (Ericsson) - Add support for multi-attach (Bug 293679)
|
||||||
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.dsf.gdb.internal.ui.launching;
|
package org.eclipse.cdt.dsf.gdb.internal.ui.launching;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.eclipse.jface.viewers.ILabelProvider;
|
import org.eclipse.jface.viewers.ILabelProvider;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.widgets.Button;
|
import org.eclipse.swt.widgets.Button;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Event;
|
||||||
import org.eclipse.swt.widgets.FileDialog;
|
import org.eclipse.swt.widgets.FileDialog;
|
||||||
|
import org.eclipse.swt.widgets.Listener;
|
||||||
import org.eclipse.swt.widgets.Shell;
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
import org.eclipse.swt.widgets.Table;
|
||||||
import org.eclipse.ui.dialogs.TwoPaneElementSelector;
|
import org.eclipse.ui.dialogs.TwoPaneElementSelector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process prompter that allows the user to select one or more entries
|
||||||
|
* in the top pane. Those entries are displayed in the bottom pane.
|
||||||
|
* No selection is allowed in the bottom pane. The result returned
|
||||||
|
* is the list of all selections of the top pane (shown in the bottom
|
||||||
|
* pane).
|
||||||
|
*
|
||||||
|
* The dialog also has a "New..." button that allows to start a new
|
||||||
|
* process. If the method getBinaryPath() returns a non-null string,
|
||||||
|
* it implies that a new process should be created and the return
|
||||||
|
* string indicates the location of the binary.
|
||||||
|
*
|
||||||
|
* Note that getBinaryPath() should be checked before calling getResult()
|
||||||
|
* as it takes precedence over it.
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class ProcessPrompterDialog extends TwoPaneElementSelector {
|
public class ProcessPrompterDialog extends TwoPaneElementSelector {
|
||||||
private static final int NEW_BUTTON_ID = 9876;
|
private static final int NEW_BUTTON_ID = 9876;
|
||||||
private String fBinaryPath;
|
private String fBinaryPath;
|
||||||
|
@ -43,4 +75,44 @@ public class ProcessPrompterDialog extends TwoPaneElementSelector {
|
||||||
return fBinaryPath;
|
return fBinaryPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The result should be every selected element.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void computeResult() {
|
||||||
|
setResult(Arrays.asList(getSelectedElements()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable the ability to select items in the bottom pane.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Table createLowerList(Composite parent) {
|
||||||
|
final Table list = super.createLowerList(parent);
|
||||||
|
|
||||||
|
// First remove listeners such as the double click.
|
||||||
|
// We don't want the user to trigger the action by
|
||||||
|
// double-clicking on the bottom pane.
|
||||||
|
int[] events = { SWT.Selection, SWT.MouseDoubleClick };
|
||||||
|
for (int event : events) {
|
||||||
|
Listener[] selectionListeners = list.getListeners(event);
|
||||||
|
for (Listener listener : selectionListeners) {
|
||||||
|
list.removeListener(event, listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now add a listener to prevent selection
|
||||||
|
list.addListener(SWT.EraseItem, new Listener() {
|
||||||
|
public void handleEvent(Event event) {
|
||||||
|
if ((event.detail & SWT.SELECTED) != 0) {
|
||||||
|
event.detail &= ~SWT.SELECTED;
|
||||||
|
// Removing the SELECTED event did not work properly.
|
||||||
|
// The foreground text became invisible.
|
||||||
|
// Let's simply deselect everything
|
||||||
|
list.deselectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue