Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/META-INF/MANIFEST.MF3
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/icons/obj16/c_app.gifbin0 -> 606 bytes
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/plugin.properties18
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/plugin.xml185
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/launch/ContextSelection.java25
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/launch/TCFCDTLaunchDelegate.java144
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/ImageCache.java68
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFSteppingModeTarget.java9
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/disassembly/TCFDisassemblyBackendFactory.java9
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/hover/ExpressionInformationControlCreator.java4
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/FileSystemBrowserControl.java515
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/PeerListControl.java639
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessListControl.java507
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessPrompter.java39
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessSelectionDialog.java120
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/RemoteCMainTab.java437
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/RemoteFileSelectionDialog.java170
17 files changed, 2880 insertions, 12 deletions
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.tm.tcf.cdt.ui/META-INF/MANIFEST.MF
index 7ae23baa6..310b7fd2f 100644
--- a/plugins/org.eclipse.tm.tcf.cdt.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/META-INF/MANIFEST.MF
@@ -19,7 +19,8 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.tm.tcf.debug,
org.eclipse.tm.tcf.debug.ui,
org.eclipse.jface.text;bundle-version="3.5.0",
- org.eclipse.core.expressions
+ org.eclipse.core.expressions,
+ org.eclipse.cdt.launch;bundle-version="6.1.0"
Bundle-ActivationPolicy: lazy
Eclipse-LazyStart: true
Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/icons/obj16/c_app.gif b/plugins/org.eclipse.tm.tcf.cdt.ui/icons/obj16/c_app.gif
new file mode 100644
index 000000000..504ef509f
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/icons/obj16/c_app.gif
Binary files differ
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.properties b/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.properties
index 9e7046604..f152f3e65 100644
--- a/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.properties
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.properties
@@ -10,3 +10,21 @@
###############################################################################
pluginName = TCF/CDT Integration UI (Incubation)
providerName = Eclipse.org - DSDP
+
+launchConfigType.remoteApplication.name=TCF Remote Application
+
+launchTab.main.name=Main
+launchTab.arguments.name=Arguments
+launchTab.debugger.name=Debugger
+launchTab.target.name=Target
+launchTab.sourceLookup.name=Source
+launchTab.pathMap.name=Path Map
+launchTab.common.name=Common
+launchTab.environment.name=Environment
+
+launchDelegate.localApplication.name=TCF Create Process
+launchDelegate.localApplication.description=Start new application under control of a local TCF agent.
+launchDelegate.remoteApplication.name=TCF Remote Process
+launchDelegate.remoteApplication.description=Start new application on a remote system under control of a remote TCF agent.
+launchDelegate.attach.name=TCF Attach to Process
+launchDelegate.attach.description=Attach to a running local or remote program.
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.xml b/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.xml
index 3b93e0180..da24f11fe 100644
--- a/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.xml
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.xml
@@ -78,4 +78,189 @@
</modelContextBinding>
</extension>
+ <!-- Remote Application Launch config type -->
+ <!-- TODO: Move to common CDT plugin? -->
+ <extension
+ point="org.eclipse.debug.core.launchConfigurationTypes">
+ <launchConfigurationType
+ public="true"
+ sourcePathComputerId="org.eclipse.cdt.debug.core.sourcePathComputer"
+ name="%launchConfigType.remoteApplication.name"
+ id="org.eclipse.tcf.cdt.launch.remoteApplicationLaunchType"
+ modes="debug,run">
+ </launchConfigurationType>
+ </extension>
+
+ <extension point="org.eclipse.debug.core.launchDelegates">
+ <launchDelegate
+ id="org.eclipse.tcf.cdt.launch.localCLaunch"
+ type="org.eclipse.cdt.launch.applicationLaunchType"
+ modes="debug"
+ delegate="org.eclipse.tm.internal.tcf.cdt.launch.TCFCDTLaunchDelegate"
+ name="%launchDelegate.localApplication.name"
+ delegateDescription="%launchDelegate.localApplication.description"
+ sourceLocatorId="org.eclipse.tm.tcf.debug.SourceLocator"
+ sourcePathComputerId="org.eclipse.cdt.debug.core.sourcePathComputer">
+ </launchDelegate>
+ <launchDelegate
+ id="org.eclipse.tcf.cdt.launch.attachCLaunch"
+ type="org.eclipse.cdt.launch.attachLaunchType"
+ modes="debug"
+ delegate="org.eclipse.tm.internal.tcf.cdt.launch.TCFCDTLaunchDelegate"
+ name="%launchDelegate.attach.name"
+ delegateDescription="%launchDelegate.attach.description"
+ sourceLocatorId="org.eclipse.tm.tcf.debug.SourceLocator"
+ sourcePathComputerId="org.eclipse.cdt.debug.core.sourcePathComputer">
+ </launchDelegate>
+ <launchDelegate
+ id="org.eclipse.tcf.cdt.launch.remoteCLaunch"
+ type="org.eclipse.tcf.cdt.launch.remoteApplicationLaunchType"
+ modes="debug"
+ delegate="org.eclipse.tm.internal.tcf.cdt.launch.TCFCDTLaunchDelegate"
+ name="%launchDelegate.remoteApplication.name"
+ delegateDescription="%launchDelegate.remoteApplication.description"
+ sourceLocatorId="org.eclipse.tm.tcf.debug.SourceLocator"
+ sourcePathComputerId="org.eclipse.cdt.debug.core.sourcePathComputer">
+ </launchDelegate>
+ </extension>
+
+ <extension
+ point="org.eclipse.debug.ui.launchConfigurationTabs">
+ <!-- Local application launch tabs-->
+ <tab id="org.eclipse.tcf.cdt.launch.mainTab"
+ group="org.eclipse.cdt.launch.applicationLaunchTabGroup"
+ name="%launchTab.main.name"
+ class="org.eclipse.cdt.launch.ui.CMainTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.localCLaunch"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.argumentsTab"
+ group="org.eclipse.cdt.launch.applicationLaunchTabGroup"
+ name="%launchTab.arguments.name"
+ class="org.eclipse.cdt.launch.ui.CArgumentsTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.localCLaunch"/>
+ <placement after="org.eclipse.cdt.cdi.launch.mainTab"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.environmentTab"
+ group="org.eclipse.cdt.launch.applicationLaunchTabGroup"
+ name="%launchTab.environment.name"
+ class="org.eclipse.debug.ui.EnvironmentTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.localCLaunch"/>
+ <placement after="org.eclipse.cdt.cdi.launch.argumentsTab"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.pathMapTab"
+ group="org.eclipse.cdt.launch.applicationLaunchTabGroup"
+ name="%launchTab.pathMap.name"
+ class="org.eclipse.tm.internal.tcf.debug.ui.launch.TCFPathMapTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.localCLaunch"/>
+ <placement after="org.eclipse.debug.ui.environmentTab"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.sourceLookupTab"
+ group="org.eclipse.cdt.launch.applicationLaunchTabGroup"
+ name="%launchTab.sourceLookup.name"
+ class="org.eclipse.debug.ui.sourcelookup.SourceLookupTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.localCLaunch"/>
+ <placement after="org.eclipse.tm.tcf.launch.pathMapTab"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.commonTab"
+ group="org.eclipse.cdt.launch.applicationLaunchTabGroup"
+ name="%launchTab.common.name"
+ class="org.eclipse.debug.ui.CommonTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.localCLaunch"/>
+ <placement after="org.eclipse.debug.ui.sourceLookupTab"/>
+ </tab>
+
+ <!-- Attach launch tabs-->
+ <tab id="org.eclipse.tcf.cdt.launch.attach.pathMapTab"
+ group="org.eclipse.cdt.launch.attachLaunchTabGroup"
+ name="%launchTab.pathMap.name"
+ class="org.eclipse.tm.internal.tcf.debug.ui.launch.TCFPathMapTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.attachCLaunch"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.attach.sourceLookupTab"
+ group="org.eclipse.cdt.launch.attachLaunchTabGroup"
+ name="%launchTab.sourceLookup.name"
+ class="org.eclipse.debug.ui.sourcelookup.SourceLookupTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.attachCLaunch"/>
+ <placement after="org.eclipse.tm.tcf.launch.pathMapTab"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.attach.commonTab"
+ group="org.eclipse.cdt.launch.attachLaunchTabGroup"
+ name="%launchTab.common.name"
+ class="org.eclipse.debug.ui.CommonTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.attachCLaunch"/>
+ <placement after="org.eclipse.debug.ui.sourceLookupTab"/>
+ </tab>
+
+ <!-- Remote application launch tabs -->
+ <tab id="org.eclipse.tcf.cdt.launch.remote.mainTab"
+ group="org.eclipse.tm.tcf.cdt.ui.remoteApplicationLaunchTabGroup"
+ name="%launchTab.main.name"
+ class="org.eclipse.tm.internal.tcf.cdt.ui.launch.RemoteCMainTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.remoteCLaunch"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.remote.argumentsTab"
+ group="org.eclipse.tm.tcf.cdt.ui.remoteApplicationLaunchTabGroup"
+ name="%launchTab.arguments.name"
+ class="org.eclipse.cdt.launch.ui.CArgumentsTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.remoteCLaunch"/>
+ <placement after="org.eclipse.cdt.cdi.launch.mainTab"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.remote.environmentTab"
+ group="org.eclipse.tm.tcf.cdt.ui.remoteApplicationLaunchTabGroup"
+ name="%launchTab.environment.name"
+ class="org.eclipse.debug.ui.EnvironmentTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.remoteCLaunch"/>
+ <placement after="org.eclipse.cdt.cdi.launch.argumentsTab"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.remote.pathMapTab"
+ group="org.eclipse.tm.tcf.cdt.ui.remoteApplicationLaunchTabGroup"
+ name="%launchTab.pathMap.name"
+ class="org.eclipse.tm.internal.tcf.debug.ui.launch.TCFPathMapTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.remoteCLaunch"/>
+ <placement after="org.eclipse.cdt.cdi.launch.argumentsTab"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.remote.sourceLookupTab"
+ group="org.eclipse.tm.tcf.cdt.ui.remoteApplicationLaunchTabGroup"
+ name="%launchTab.sourceLookup.name"
+ class="org.eclipse.debug.ui.sourcelookup.SourceLookupTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.remoteCLaunch"/>
+ <placement after="org.eclipse.tm.tcf.launch.pathMapTab"/>
+ </tab>
+ <tab id="org.eclipse.tcf.cdt.launch.remote.commonTab"
+ group="org.eclipse.tm.tcf.cdt.ui.remoteApplicationLaunchTabGroup"
+ name="%launchTab.common.name"
+ class="org.eclipse.debug.ui.CommonTab">
+ <associatedDelegate delegate="org.eclipse.tcf.cdt.launch.remoteCLaunch"/>
+ <placement after="org.eclipse.debug.ui.sourceLookupTab"/>
+ </tab>
+ </extension>
+
+ <extension
+ point="org.eclipse.debug.ui.launchConfigurationTabGroups">
+ <launchConfigurationTabGroup
+ class="org.eclipse.cdt.debug.internal.ui.launch.PlaceHolderLaunchConfigurationTabGroup"
+ id="org.eclipse.tm.tcf.cdt.ui.remoteApplicationLaunchTabGroup"
+ type="org.eclipse.tcf.cdt.launch.remoteApplicationLaunchType">
+ </launchConfigurationTabGroup>
+ </extension>
+
+ <extension
+ point="org.eclipse.debug.ui.launchConfigurationTypeImages">
+ <launchConfigurationTypeImage
+ icon="icons/obj16/c_app.gif"
+ configTypeID="org.eclipse.tcf.cdt.launch.remoteApplicationLaunchType"
+ id="org.eclipse.tcf.cdt.ui.remoteApplicationLaunchType.image">
+ </launchConfigurationTypeImage>
+ </extension>
+
+ <extension
+ point="org.eclipse.debug.core.statusHandlers">
+ <statusHandler
+ class="org.eclipse.tm.internal.tcf.cdt.ui.launch.ProcessPrompter"
+ code="100"
+ id="org.eclipse.tm.tcf.cdt.ui.processPrompter"
+ plugin="org.eclipse.tm.tcf.cdt.core">
+ </statusHandler>
+ </extension>
+
</plugin>
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/launch/ContextSelection.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/launch/ContextSelection.java
new file mode 100644
index 000000000..402284f2b
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/launch/ContextSelection.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.cdt.launch;
+
+public class ContextSelection {
+ public String fPeerId;
+ public String fContextId;
+ public boolean fIsAttached;
+ public ContextSelection(String peerId, String contextId) {
+ this(peerId, contextId, true);
+ }
+ public ContextSelection(String peerId, String contextId, boolean isAttached) {
+ fPeerId = peerId;
+ fContextId = contextId;
+ fIsAttached = isAttached;
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/launch/TCFCDTLaunchDelegate.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/launch/TCFCDTLaunchDelegate.java
new file mode 100644
index 000000000..ceabd7c18
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/launch/TCFCDTLaunchDelegate.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.cdt.launch;
+
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.IStatusHandler;
+import org.eclipse.tm.internal.tcf.debug.launch.TCFLaunchDelegate;
+import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.tcf.protocol.Protocol;
+
+/**
+ * TCF launch delegate for CDT based launch configuration types.
+ * The launch configuration is converted on the fly to be compatible
+ * with the TCFLaunch.
+ */
+public class TCFCDTLaunchDelegate extends TCFLaunchDelegate {
+
+ @Override
+ public ILaunch getLaunch(ILaunchConfiguration configuration, final String mode) throws CoreException {
+ final ILaunchConfiguration tcfLaunchConfig = convertToTcfConfig(configuration);
+ return super.getLaunch(tcfLaunchConfig, mode);
+ }
+
+ public void launch(ILaunchConfiguration configuration, final String mode,
+ final ILaunch launch, final IProgressMonitor monitor) throws CoreException {
+
+ ILaunchConfiguration tcfLaunchConfig = convertToTcfConfig(configuration);
+ final String peerId;
+ if (isAttachLaunch(tcfLaunchConfig)) {
+ ContextSelection selection = promptForContext(tcfLaunchConfig);
+ if (selection == null) {
+ // canceled
+ throw new CoreException(Status.OK_STATUS);
+ }
+ launch.setAttribute("attach_to_context", selection.fContextId);
+ if (!selection.fIsAttached) {
+ launch.setAttribute("attach_to_process", selection.fContextId);
+ }
+ peerId = selection.fPeerId;
+ } else if (isRemoteLaunch(tcfLaunchConfig)) {
+ peerId = tcfLaunchConfig.getAttribute(TCFLaunchDelegate.ATTR_PEER_ID, (String) null);
+ } else {
+ peerId = null;
+ }
+ if (peerId == null) {
+ super.launch(tcfLaunchConfig, mode, launch, monitor);
+ } else {
+ if (monitor != null) monitor.beginTask("Launching TCF debugger session", 1); //$NON-NLS-1$
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ ((TCFLaunch)launch).launchTCF(mode, peerId);
+ if (monitor != null) monitor.done();
+ }
+ });
+ }
+ }
+
+ private boolean isAttachLaunch(ILaunchConfiguration config) throws CoreException {
+ String configTypeName = config.getType().getIdentifier();
+ return ICDTLaunchConfigurationConstants.ID_LAUNCH_C_ATTACH.equals(configTypeName);
+ }
+
+ private boolean isRemoteLaunch(ILaunchConfiguration config) throws CoreException {
+ String configTypeName = config.getType().getIdentifier();
+ return "org.eclipse.tcf.cdt.launch.remoteApplicationLaunchType".equals(configTypeName);
+ }
+
+ private ContextSelection promptForContext(ILaunchConfiguration config) throws CoreException {
+ IStatus promptStatus = new Status(IStatus.INFO, "org.eclipse.debug.ui", 200, "", null); //$NON-NLS-1$//$NON-NLS-2$
+ IStatus contextPrompt = new Status(IStatus.INFO, "org.eclipse.tm.tcf.cdt.core", 100, "", null); //$NON-NLS-1$//$NON-NLS-2$
+ // consult a status handler
+ IStatusHandler prompter = DebugPlugin.getDefault().getStatusHandler(promptStatus);
+ if (prompter != null) {
+ Object result = prompter.handleStatus(contextPrompt, config);
+ if (result instanceof ContextSelection) {
+ return (ContextSelection) result;
+ }
+ }
+ return null;
+ }
+
+ protected ILaunchConfiguration convertToTcfConfig(ILaunchConfiguration orig) throws CoreException {
+ ILaunchConfigurationWorkingCopy copy = orig.copy(orig.getName());
+ boolean changed = copyStringAttribute(orig, copy, ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME,
+ TCFLaunchDelegate.ATTR_PROJECT_NAME);
+ if (isAttachLaunch(orig)) {
+ changed = setStringAttribute(copy, TCFLaunchDelegate.ATTR_LOCAL_PROGRAM_FILE, null) || changed;
+ changed = setStringAttribute(copy, TCFLaunchDelegate.ATTR_REMOTE_PROGRAM_FILE, null) || changed;
+ } else {
+ changed = copyStringAttribute(orig, copy, ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME,
+ TCFLaunchDelegate.ATTR_LOCAL_PROGRAM_FILE) || changed;
+ changed = copyStringAttribute(orig, copy, ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
+ TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS) || changed;
+ changed = copyStringAttribute(orig, copy, ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
+ TCFLaunchDelegate.ATTR_WORKING_DIRECTORY) || changed;
+ changed = copyBooleanAttribute(orig, copy, ICDTLaunchConfigurationConstants.ATTR_USE_TERMINAL,
+ TCFLaunchDelegate.ATTR_USE_TERMINAL) || changed;
+ }
+ return changed ? copy.doSave() : orig;
+ }
+
+ private boolean copyStringAttribute(ILaunchConfiguration orig, ILaunchConfigurationWorkingCopy copy, String origAttr,
+ String newAttr) throws CoreException {
+ String newValue = orig.getAttribute(newAttr, (String) null);
+ return setStringAttribute(copy, newAttr, newValue);
+ }
+
+ private boolean setStringAttribute(ILaunchConfigurationWorkingCopy copy, String attr, String newValue) throws CoreException {
+ String origValue = copy.getAttribute(attr, (String) null);
+ if (origValue == newValue || origValue != null && origValue.equals(newValue)) {
+ return false;
+ }
+ copy.setAttribute(attr, newValue);
+ return true;
+ }
+
+ private boolean copyBooleanAttribute(ILaunchConfiguration orig, ILaunchConfigurationWorkingCopy copy, String origAttr,
+ String newAttr) throws CoreException {
+ boolean origValue = orig.getAttribute(origAttr, false);
+ boolean newValue = orig.getAttribute(newAttr, false);
+ if (origValue == newValue) {
+ return false;
+ }
+ copy.setAttribute(newAttr, origValue);
+ return true;
+ }
+
+}
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/ImageCache.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/ImageCache.java
new file mode 100644
index 000000000..7ace5d2c2
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/ImageCache.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2011 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.cdt.ui;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.osgi.framework.Bundle;
+
+public class ImageCache {
+
+ public static final String
+ IMG_TARGET_TAB = "icons/target_tab.gif";
+
+ private static final Map<String,ImageDescriptor> desc_cache = new HashMap<String,ImageDescriptor>();
+ private static final Map<ImageDescriptor,Image> image_cache = new HashMap<ImageDescriptor,Image>();
+
+ public static synchronized ImageDescriptor getImageDescriptor(String name) {
+ if (name == null) return null;
+ ImageDescriptor descriptor = desc_cache.get(name);
+ if (descriptor == null) {
+ Bundle bundle = Platform.getBundle("org.eclipse.tm.tcf.debug.ui");
+ if (bundle != null){
+ URL url = FileLocator.find(bundle, new Path(name), null);
+ if (url != null) descriptor = ImageDescriptor.createFromURL(url);
+ }
+ if (descriptor == null) {
+ bundle = Platform.getBundle("org.eclipse.debug.ui");
+ if (bundle != null){
+ URL url = FileLocator.find(bundle, new Path(name), null);
+ if (url != null) descriptor = ImageDescriptor.createFromURL(url);
+ }
+ }
+ if (descriptor == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ }
+ desc_cache.put(name, descriptor);
+ }
+ return descriptor;
+ }
+
+ public static synchronized Image getImage(ImageDescriptor desc) {
+ Image image = image_cache.get(desc);
+ if (image == null) {
+ image = desc.createImage();
+ image_cache.put(desc, image);
+ }
+ return image;
+ }
+
+ public static synchronized Image getImage(String name) {
+ return getImage(getImageDescriptor(name));
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFSteppingModeTarget.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFSteppingModeTarget.java
index 0c0681624..4972ef11d 100644
--- a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFSteppingModeTarget.java
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFSteppingModeTarget.java
@@ -1,8 +1,9 @@
/*******************************************************************************
- * Copyright (c) 2010 Wind River Systems, Inc. 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
+ * Copyright (c) 2010 Wind River Systems, Inc. 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:
* Wind River Systems - initial API and implementation
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/disassembly/TCFDisassemblyBackendFactory.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/disassembly/TCFDisassemblyBackendFactory.java
index d6bbfae92..a25e6fdbe 100644
--- a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/disassembly/TCFDisassemblyBackendFactory.java
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/disassembly/TCFDisassemblyBackendFactory.java
@@ -1,8 +1,9 @@
/*******************************************************************************
- * Copyright (c) 2010 Wind River Systems, Inc. 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
+ * Copyright (c) 2010 Wind River Systems, Inc. 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:
* Wind River Systems - initial API and implementation
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/hover/ExpressionInformationControlCreator.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/hover/ExpressionInformationControlCreator.java
index f390c1bc6..e78cf8cbf 100644
--- a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/hover/ExpressionInformationControlCreator.java
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/hover/ExpressionInformationControlCreator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2010 IBM Corporation and others.
+ * Copyright (c) 2008, 2011 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
@@ -58,8 +58,6 @@ import org.eclipse.ui.IWorkbenchPartSite;
* <code>ExpressionInformationControlCreator</code>.
*
* @noextend This class is not intended to be subclassed by clients.
- *
- * @since 2.1
*/
@SuppressWarnings("restriction")
public class ExpressionInformationControlCreator implements
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/FileSystemBrowserControl.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/FileSystemBrowserControl.java
new file mode 100644
index 000000000..eec09c544
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/FileSystemBrowserControl.java
@@ -0,0 +1,515 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.cdt.ui.launch;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener;
+import org.eclipse.tm.tcf.protocol.IPeer;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.IFileSystem;
+import org.eclipse.tm.tcf.services.IFileSystem.DirEntry;
+import org.eclipse.tm.tcf.services.IFileSystem.FileSystemException;
+import org.eclipse.tm.tcf.services.IFileSystem.IFileHandle;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+
+public class FileSystemBrowserControl {
+
+ static class FileInfo {
+ String name;
+ String fullname;
+ boolean isDir;
+ FileInfo[] children;
+ Throwable children_error;
+ int index;
+ boolean children_pending;
+ FileInfo parent;
+ }
+
+ private Tree fileTree;
+ private Display fDisplay;
+ private IPeer fPeer;
+ private final FileInfo fRootInfo = new FileInfo();
+ private IChannel fChannel;
+ private IFileSystem fFileSystem;
+ private String fFileToSelect;
+ private LinkedList<String> fPathToSelect;
+ private FileInfo fLastSelectedFileInfo;
+ private final boolean fDirectoriesOnly;
+
+ public FileSystemBrowserControl(Composite parent, boolean directoriesOnly) {
+ fDirectoriesOnly = directoriesOnly;
+ fDisplay = parent.getDisplay();
+ parent.addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ handleDispose();
+ }
+ });
+ createFileListArea(parent);
+ }
+
+ public void setInput(IPeer peer) {
+ if (peer == fPeer) {
+ return;
+ }
+ if (fPeer != null) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ disconnectPeer();
+ }
+ });
+ }
+ fileTree.setItemCount(0);
+ fRootInfo.children = null;
+ fPeer = peer;
+ if (fPeer != null) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ connectPeer();
+ }
+ });
+ }
+ }
+
+ public Tree getTree() {
+ return fileTree;
+ }
+
+ private void createFileListArea(Composite parent) {
+ Font font = parent.getFont();
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setFont(font);
+ GridLayout layout = new GridLayout(1, false);
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ composite.setLayout(layout);
+ composite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+
+ fileTree = new Tree(composite, SWT.VIRTUAL | SWT.BORDER | SWT.SINGLE);
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ gd.minimumHeight = 300;
+ gd.minimumWidth = 350;
+ fileTree.setLayoutData(gd);
+ fileTree.setFont(font);
+ fileTree.addListener(SWT.SetData, new Listener() {
+ public void handleEvent(Event event) {
+ TreeItem item = (TreeItem)event.item;
+ FileInfo info = findFileInfo(item);
+ if (info == null) {
+ updateItems(item.getParentItem(), false);
+ }
+ else {
+ fillItem(item, info);
+ }
+ }
+ });
+ }
+
+ private void handleDispose() {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ disconnectPeer();
+ fFileSystem = null;
+ fDisplay = null;
+ }
+ });
+ }
+
+ protected void disconnectPeer() {
+ if (fChannel != null && fChannel.getState() != IChannel.STATE_CLOSED) {
+ fChannel.close();
+ }
+ }
+
+ protected void connectPeer() {
+ final IChannel channel = fPeer.openChannel();
+ fChannel = channel;
+ fFileSystem = null;
+ channel.addChannelListener(new IChannelListener() {
+ public void congestionLevel(int level) {
+ }
+ public void onChannelClosed(final Throwable error) {
+ if (fChannel != channel) return;
+ fChannel = null;
+ if (fDisplay != null) {
+ fDisplay.asyncExec(new Runnable() {
+ public void run() {
+ if (fRootInfo.children_pending) return;
+ fRootInfo.children = null;
+ fRootInfo.children_error = error;
+ updateItems(fRootInfo);
+ }
+ });
+ }
+ }
+ public void onChannelOpened() {
+ if (fChannel != channel) return;
+ fFileSystem = fChannel.getRemoteService(IFileSystem.class);
+ if (fFileSystem != null) {
+ if (fFileToSelect != null && fFileToSelect.length() > 0) {
+ final LinkedList<String> filePath = new LinkedList<String>();
+ filePath.addAll(Arrays.asList(fFileToSelect.split("[/\\\\]", -1)));
+ if (fFileToSelect.charAt(0) == '/') {
+ filePath.set(0, "/");
+ }
+ fPathToSelect = filePath;
+ fLastSelectedFileInfo = fRootInfo;
+ }
+ }
+ if (fDisplay != null) {
+ fDisplay.asyncExec(new Runnable() {
+ public void run() {
+ if (fRootInfo.children_pending) return;
+ fRootInfo.children = null;
+ fRootInfo.children_error = null;
+ updateItems(fRootInfo);
+ }
+ });
+ }
+ }
+ });
+ }
+
+ private void updateItems(TreeItem parent_item, boolean reload) {
+ final FileInfo parent_info = findFileInfo(parent_item);
+ if (parent_info == null) {
+ parent_item.setText("Invalid");
+ }
+ else {
+ if (reload && parent_info.children_error != null) {
+ loadChildren(parent_info);
+ }
+ fDisplay.asyncExec(new Runnable() {
+ public void run() {
+ updateItems(parent_info);
+ }
+ });
+ }
+ }
+
+ private void updateItems(final FileInfo parent) {
+ if (fDisplay == null) return;
+ assert Thread.currentThread() == fDisplay.getThread();
+ TreeItem[] items = null;
+ boolean expanded = true;
+ if (parent.children == null || parent.children_error != null) {
+ if (parent == fRootInfo) {
+ fileTree.setItemCount(1);
+ items = fileTree.getItems();
+ }
+ else {
+ TreeItem item = findItem(parent);
+ if (item == null) return;
+ expanded = item.getExpanded();
+ item.setItemCount(1);
+ items = item.getItems();
+ }
+ assert items.length == 1;
+ items[0].removeAll();
+ if (parent.children_pending) {
+ items[0].setForeground(fDisplay.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+ items[0].setText("Pending...");
+ }
+ else if (parent.children_error != null) {
+ String msg = parent.children_error.getMessage();
+ if (msg == null) msg = parent.children_error.getClass().getName();
+ else msg = msg.replace('\n', ' ');
+ items[0].setForeground(fDisplay.getSystemColor(SWT.COLOR_RED));
+ items[0].setText(msg);
+ items[0].setImage((Image) null);
+ }
+ else if (expanded) {
+ loadChildren(parent);
+ items[0].setForeground(fDisplay.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+ items[0].setText("Pending...");
+ }
+ else {
+ items[0].setText("");
+ }
+ }
+ else {
+ FileInfo[] arr = parent.children;
+ if (parent == fRootInfo) {
+ fileTree.setItemCount(arr.length);
+ items = fileTree.getItems();
+ }
+ else {
+ TreeItem item = findItem(parent);
+ if (item == null) return;
+ expanded = item.getExpanded();
+ item.setItemCount(expanded ? arr.length : 1);
+ items = item.getItems();
+ }
+ if (expanded) {
+ assert items.length == arr.length;
+ for (int i = 0; i < items.length; i++) fillItem(items[i], arr[i]);
+ expandSelect();
+ }
+ else {
+ items[0].setText("");
+ }
+ }
+ }
+
+ private void expandSelect() {
+ if (fPathToSelect == null) return;
+ if (fPathToSelect.isEmpty()) {
+ fPathToSelect = null;
+ fFileToSelect = null;
+ return;
+ }
+ do {
+ String name = fPathToSelect.getFirst();
+ if (name.length() == 0) {
+ fPathToSelect.removeFirst();
+ continue;
+ }
+ FileInfo info = findFileInfo(fLastSelectedFileInfo, name);
+ if (info == null) break;
+ TreeItem item = findItem(info);
+ if (item == null) break;
+ fPathToSelect.removeFirst();
+ if (fPathToSelect.isEmpty()) {
+ fileTree.setSelection(item);
+ fileTree.showItem(item);
+ } else {
+ item.setExpanded(true);
+ fileTree.showItem(item);
+ }
+ fLastSelectedFileInfo = info;
+ } while (!fPathToSelect.isEmpty());
+ }
+
+ private void loadChildren(final FileInfo parent) {
+ assert Thread.currentThread() == fDisplay.getThread();
+ if (parent.children_pending) return;
+ assert parent.children == null;
+ parent.children_pending = true;
+ parent.children_error = null;
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ final IFileSystem fs = fFileSystem;
+ if (fs == null || !canHaveChildren(parent)) {
+ doneLoadChildren(parent, null, new FileInfo[0]);
+ return;
+ }
+ if (parent.fullname == null) {
+ fs.roots(new IFileSystem.DoneRoots() {
+ public void doneRoots(IToken token, FileSystemException error, DirEntry[] entries) {
+ if (error != null) {
+ doneLoadChildren(parent, error, null);
+ } else {
+ final List<FileInfo> fileInfos = new ArrayList<FileInfo>(entries.length);
+ for (DirEntry entry : entries) {
+ FileInfo info = new FileInfo();
+ info.parent = parent;
+ String name = entry.filename;
+ int length = name.length();
+ if (length > 1 && (name.endsWith("\\") || name.endsWith("/"))) {
+ name = name.substring(0, length - 1);
+ }
+ info.name = name;
+ info.fullname = entry.longname != null ? entry.longname : entry.filename;
+ info.isDir = entry.attrs != null ? entry.attrs.isDirectory() : false;
+ if (!fDirectoriesOnly || info.isDir) {
+ fileInfos.add(info);
+ }
+ }
+ doneLoadChildren(parent, null, fileInfos.toArray(new FileInfo[fileInfos.size()]));
+ }
+ }
+ });
+ return;
+ }
+ fs.opendir(parent.fullname, new IFileSystem.DoneOpen() {
+ final List<FileInfo> fileInfos = new ArrayList<FileInfo>();
+ public void doneOpen(IToken token, FileSystemException error, final IFileHandle handle) {
+ if (error != null) {
+ doneLoadChildren(parent, error, null);
+ return;
+ }
+ fs.readdir(handle, new IFileSystem.DoneReadDir() {
+ public void doneReadDir(IToken token, FileSystemException error, DirEntry[] entries, boolean eof) {
+ if (entries != null) {
+ for (DirEntry entry : entries) {
+ FileInfo info = new FileInfo();
+ info.parent = parent;
+ info.name = entry.filename;
+ info.fullname = entry.longname != null ? entry.longname : (new Path(parent.fullname).append(info.name).toString());
+ info.isDir = entry.attrs != null ? entry.attrs.isDirectory() : false;
+ if (!fDirectoriesOnly || info.isDir) {
+ fileInfos.add(info);
+ }
+ }
+ }
+ if (error != null || eof) {
+ fs.close(handle, new IFileSystem.DoneClose() {
+ public void doneClose(IToken token, FileSystemException error) {
+ // ignore error
+ }
+ });
+ int size = fileInfos.size();
+ if (size == 0 && error != null) {
+ doneLoadChildren(parent, error, null);
+ } else {
+ doneLoadChildren(parent, null, fileInfos.toArray(new FileInfo[size]));
+ }
+ } else {
+ fs.readdir(handle, this);
+ }
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
+ private void doneLoadChildren(final FileInfo parent, final Throwable error, final FileInfo[] children) {
+ assert Protocol.isDispatchThread();
+ assert error == null || children == null;
+ if (fDisplay == null) return;
+ Arrays.sort(children, new Comparator<FileInfo>() {
+ public int compare(FileInfo o1, FileInfo o2) {
+ if (o1.isDir == o2.isDir)
+ return o1.name.compareTo(o2.name);
+ if (o1.isDir) return 1;
+ return -1;
+ }});
+ int i = 0;
+ for (FileInfo fileInfo : children) {
+ fileInfo.index = i++;
+ }
+ fDisplay.asyncExec(new Runnable() {
+ public void run() {
+ assert parent.children_pending;
+ assert parent.children == null;
+ parent.children_pending = false;
+ parent.children = children;
+ parent.children_error = error;
+ updateItems(parent);
+ }
+ });
+ }
+
+ public FileInfo findFileInfo(TreeItem item) {
+ assert Thread.currentThread() == fDisplay.getThread();
+ if (item == null) return fRootInfo ;
+ TreeItem parent = item.getParentItem();
+ FileInfo info = findFileInfo(parent);
+ if (info == null) return null;
+ if (info.children == null) return null;
+ if (info.children_error != null) return null;
+ int i = parent == null ? fileTree.indexOf(item) : parent.indexOf(item);
+ if (i < 0 || i >= info.children.length) return null;
+ assert info.children[i].index == i;
+ return info.children[i];
+ }
+
+ private FileInfo findFileInfo(FileInfo parent, String name) {
+ assert Thread.currentThread() == fDisplay.getThread();
+ if (name == null) return fRootInfo;
+ if (name.equals(parent.name)) return parent;
+ FileInfo[] childInfos = parent.children;
+ if (childInfos != null) {
+ for (FileInfo fileInfo : childInfos) {
+ FileInfo found = findFileInfo(fileInfo, name);
+ if (found != null) {
+ return found;
+ }
+ }
+ }
+ return null;
+ }
+
+ private TreeItem findItem(FileInfo info) {
+ if (info == null) return null;
+ assert info.parent != null;
+ if (info.parent == fRootInfo) {
+ int n = fileTree.getItemCount();
+ if (info.index >= n) return null;
+ return fileTree.getItem(info.index);
+ }
+ TreeItem i = findItem(info.parent);
+ if (i == null) return null;
+ int n = i.getItemCount();
+ if (info.index >= n) return null;
+ return i.getItem(info.index);
+ }
+
+ private void fillItem(TreeItem item, FileInfo info) {
+ assert Thread.currentThread() == fDisplay.getThread();
+ Object data = item.getData("TCFContextInfo");
+ if (data != null && data != info) item.removeAll();
+ item.setData("TCFContextInfo", info);
+ String text = info.name != null ? info.name : info.fullname;
+ item.setText(text);
+ item.setForeground(fDisplay.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+ item.setImage(getImage(info));
+ if (!canHaveChildren(info)) item.setItemCount(0);
+ else if (info.children == null || info.children_error != null) item.setItemCount(1);
+ else item.setItemCount(info.children.length);
+ }
+
+ private boolean canHaveChildren(FileInfo info) {
+ return info.isDir || info == fRootInfo;
+ }
+
+ private Image getImage(FileInfo info) {
+ if (info.isDir) {
+ return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER);
+ } else {
+ return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FILE);
+ }
+ }
+
+ public void setInitialSelection(final String filename) {
+ fPathToSelect = null;
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ fFileToSelect = filename;
+ }
+ });
+ }
+
+ public FileInfo getSelection() {
+ if (fileTree != null) {
+ TreeItem[] items = fileTree.getSelection();
+ if (items.length > 0) {
+ FileInfo info = findFileInfo(items[0]);
+ return info;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/PeerListControl.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/PeerListControl.java
new file mode 100644
index 000000000..9590d5ec0
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/PeerListControl.java
@@ -0,0 +1,639 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.cdt.ui.launch;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.TreeEvent;
+import org.eclipse.swt.events.TreeListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.tm.internal.tcf.cdt.ui.Activator;
+import org.eclipse.tm.internal.tcf.cdt.ui.ImageCache;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener;
+import org.eclipse.tm.tcf.protocol.IPeer;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.ILocator;
+
+// Cloned from TCFTargetTab
+public class PeerListControl implements ISelectionProvider {
+
+ private Tree peer_tree;
+ private final PeerInfo peer_info = new PeerInfo();
+ private Display display;
+ private final ListenerList fSelectionListeners = new ListenerList(ListenerList.IDENTITY);
+ private String fInitialPeerId = "*";
+
+ static class PeerInfo {
+ PeerInfo parent;
+ int index;
+ String id;
+ Map<String,String> attrs;
+ PeerInfo[] children;
+ boolean children_pending;
+ Throwable children_error;
+ IPeer peer;
+ IChannel channel;
+ ILocator locator;
+ LocatorListener listener;
+ }
+
+ private class LocatorListener implements ILocator.LocatorListener {
+
+ private final PeerInfo parent;
+
+ LocatorListener(PeerInfo parent) {
+ this.parent = parent;
+ }
+
+ public void peerAdded(final IPeer peer) {
+ if (display == null) return;
+ final String id = peer.getID();
+ final HashMap<String,String> attrs = new HashMap<String,String>(peer.getAttributes());
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (parent.children_error != null) return;
+ PeerInfo[] arr = parent.children;
+ String agentId = attrs.get(IPeer.ATTR_AGENT_ID);
+ for (PeerInfo p : arr) {
+ assert !p.id.equals(id);
+ if (agentId != null && agentId.equals(p.attrs.get(IPeer.ATTR_AGENT_ID)))
+ return;
+ }
+ PeerInfo[] buf = new PeerInfo[arr.length + 1];
+ System.arraycopy(arr, 0, buf, 0, arr.length);
+ PeerInfo info = new PeerInfo();
+ info.parent = parent;
+ info.index = arr.length;
+ info.id = id;
+ info.attrs = attrs;
+ info.peer = peer;
+ buf[arr.length] = info;
+ parent.children = buf;
+ updateItems(parent);
+ }
+ });
+ }
+
+ public void peerChanged(final IPeer peer) {
+ if (display == null) return;
+ final String id = peer.getID();
+ final HashMap<String,String> attrs = new HashMap<String,String>(peer.getAttributes());
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (parent.children_error != null) return;
+ PeerInfo[] arr = parent.children;
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i].id.equals(id)) {
+ arr[i].attrs = attrs;
+ arr[i].peer = peer;
+ updateItems(parent);
+ }
+ }
+ }
+ });
+ }
+
+ public void peerRemoved(final String id) {
+ if (display == null) return;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (parent.children_error != null) return;
+ PeerInfo[] arr = parent.children;
+ PeerInfo[] buf = new PeerInfo[arr.length - 1];
+ int j = 0;
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i].id.equals(id)) {
+ final PeerInfo info = arr[i];
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ disconnectPeer(info);
+ }
+ });
+ }
+ else {
+ arr[i].index = j;
+ buf[j++] = arr[i];
+ }
+ }
+ parent.children = buf;
+ updateItems(parent);
+ }
+ });
+ }
+
+ public void peerHeartBeat(final String id) {
+ if (display == null) return;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (parent.children_error != null) return;
+ PeerInfo[] arr = parent.children;
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i].id.equals(id)) {
+ if (arr[i].children_error != null) {
+ TreeItem item = findItem(arr[i]);
+ boolean visible = item != null;
+ while (visible && item != null) {
+ if (!item.getExpanded()) visible = false;
+ item = item.getParentItem();
+ }
+ if (visible) loadChildren(arr[i]);
+ }
+ break;
+ }
+ }
+ }
+ });
+ }
+ }
+
+ public PeerListControl(Composite parent) {
+ display = parent.getDisplay();
+ parent.addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ handleDispose();
+ }
+ });
+ loadChildren(peer_info);
+ createPeerListArea(parent);
+ }
+
+ public void setInitialSelectedPeerId(String peerId) {
+ fInitialPeerId = peerId;
+ }
+
+ public Tree getTree() {
+ return peer_tree;
+ }
+
+ private void createPeerListArea(Composite parent) {
+ Font font = parent.getFont();
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setFont(font);
+ GridLayout layout = new GridLayout(1, false);
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ composite.setLayout(layout);
+ composite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+
+ peer_tree = new Tree(composite, SWT.VIRTUAL | SWT.BORDER | SWT.SINGLE);
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ gd.heightHint = 80;
+ gd.minimumWidth = 400;
+ peer_tree.setLayoutData(gd);
+
+ for (int i = 0; i < 5; i++) {
+ TreeColumn column = new TreeColumn(peer_tree, SWT.LEAD, i);
+ column.setMoveable(true);
+ switch (i) {
+ case 0:
+ column.setText("Name");
+ column.setWidth(160);
+ break;
+ case 1:
+ column.setText("OS");
+ column.setWidth(100);
+ break;
+ case 2:
+ column.setText("Transport");
+ column.setWidth(60);
+ break;
+ case 3:
+ column.setText("Host");
+ column.setWidth(100);
+ break;
+ case 4:
+ column.setText("Port");
+ column.setWidth(40);
+ break;
+ }
+ }
+
+ peer_tree.setHeaderVisible(true);
+ peer_tree.setFont(font);
+ peer_tree.addListener(SWT.SetData, new Listener() {
+ public void handleEvent(Event event) {
+ TreeItem item = (TreeItem)event.item;
+ PeerInfo info = findPeerInfo(item);
+ if (info == null) {
+ updateItems(item.getParentItem(), false);
+ }
+ else {
+ fillItem(item, info);
+ }
+ }
+ });
+ peer_tree.addTreeListener(new TreeListener() {
+ public void treeCollapsed(TreeEvent e) {
+ updateItems((TreeItem)e.item, false);
+ }
+ public void treeExpanded(TreeEvent e) {
+ updateItems((TreeItem)e.item, true);
+ }
+ });
+ peer_tree.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fireSelectionChangedEvent();
+ }
+ });
+ }
+
+ private void handleDispose() {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ disconnectPeer(peer_info);
+ display = null;
+ }
+ });
+ }
+
+ private void disconnectPeer(final PeerInfo info) {
+ assert Protocol.isDispatchThread();
+ if (info.children != null) {
+ for (PeerInfo p : info.children) disconnectPeer(p);
+ }
+ if (info.listener != null) {
+ info.locator.removeListener(info.listener);
+ info.listener = null;
+ info.locator = null;
+ }
+ if (info.channel != null) {
+ info.channel.close();
+ }
+ }
+
+ private boolean canHaveChildren(PeerInfo parent) {
+ return parent == peer_info || parent.attrs.get(IPeer.ATTR_PROXY) != null;
+ }
+
+ private void loadChildren(final PeerInfo parent) {
+ assert Thread.currentThread() == display.getThread();
+ if (parent.children_pending) return;
+ assert parent.children == null;
+ parent.children_pending = true;
+ parent.children_error = null;
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ assert parent.listener == null;
+ assert parent.channel == null;
+ if (!canHaveChildren(parent)) {
+ doneLoadChildren(parent, null, new PeerInfo[0]);
+ }
+ else if (parent == peer_info) {
+ peer_info.locator = Protocol.getLocator();
+ doneLoadChildren(parent, null, createLocatorListener(peer_info));
+ }
+ else {
+ final IChannel channel = parent.peer.openChannel();
+ parent.channel = channel;
+ parent.channel.addChannelListener(new IChannelListener() {
+ boolean opened = false;
+ boolean closed = false;
+ public void congestionLevel(int level) {
+ }
+ public void onChannelClosed(final Throwable error) {
+ assert !closed;
+ if (parent.channel != channel) return;
+ if (!opened) {
+ doneLoadChildren(parent, error, null);
+ }
+ else {
+ if (display != null) {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (parent.children_pending) return;
+ parent.children = null;
+ parent.children_error = error;
+ updateItems(parent);
+ }
+ });
+ }
+ }
+ closed = true;
+ parent.channel = null;
+ parent.locator = null;
+ parent.listener = null;
+ }
+ public void onChannelOpened() {
+ assert !opened;
+ assert !closed;
+ if (parent.channel != channel) return;
+ opened = true;
+ parent.locator = parent.channel.getRemoteService(ILocator.class);
+ if (parent.locator == null) {
+ doneLoadChildren(parent, new Exception("Service not supported: " + ILocator.NAME), null);
+ parent.channel.close();
+ }
+ else {
+ doneLoadChildren(parent, null, createLocatorListener(parent));
+ }
+ }
+ });
+ }
+ }
+ });
+ }
+
+ private PeerInfo[] createLocatorListener(PeerInfo peer) {
+ assert Protocol.isDispatchThread();
+ Map<String,IPeer> map = peer.locator.getPeers();
+ List<PeerInfo> filteredPeers = new ArrayList<PeerInfo>();
+ Set<String> agentIds = new HashSet<String>();
+ for (IPeer p : map.values()) {
+ String agentID = p.getAgentID();
+ if (agentID != null && agentIds.add(agentID)) {
+ PeerInfo info = new PeerInfo();
+ info.parent = peer;
+ info.index = filteredPeers.size();
+ info.id = p.getID();
+ info.attrs = new HashMap<String,String>(p.getAttributes());
+ info.peer = p;
+ filteredPeers.add(info);
+ }
+ }
+ PeerInfo[] buf = (PeerInfo[]) filteredPeers.toArray(new PeerInfo[filteredPeers.size()]);
+ peer.listener = new LocatorListener(peer);
+ peer.locator.addListener(peer.listener);
+ return buf;
+ }
+
+ private void doneLoadChildren(final PeerInfo parent, final Throwable error, final PeerInfo[] children) {
+ assert Protocol.isDispatchThread();
+ assert error == null || children == null;
+ if (display == null) return;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ assert parent.children_pending;
+ assert parent.children == null;
+ parent.children_pending = false;
+ parent.children = children;
+ parent.children_error = error;
+ updateItems(parent);
+ }
+ });
+ }
+
+ private void updateItems(TreeItem parent_item, boolean reload) {
+ final PeerInfo parent_info = findPeerInfo(parent_item);
+ if (parent_info == null) {
+ parent_item.setText("Invalid");
+ }
+ else {
+ if (reload && parent_info.children_error != null) {
+ loadChildren(parent_info);
+ }
+ display.asyncExec(new Runnable() {
+ public void run() {
+ updateItems(parent_info);
+ }
+ });
+ }
+ }
+
+ private void updateItems(final PeerInfo parent) {
+ if (display == null) return;
+ assert Thread.currentThread() == display.getThread();
+ TreeItem[] items = null;
+ boolean expanded = true;
+ if (parent.children == null || parent.children_error != null) {
+ if (parent == peer_info) {
+ peer_tree.setItemCount(1);
+ items = peer_tree.getItems();
+ }
+ else {
+ TreeItem item = findItem(parent);
+ if (item == null) return;
+ expanded = item.getExpanded();
+ item.setItemCount(1);
+ items = item.getItems();
+ }
+ assert items.length == 1;
+ items[0].removeAll();
+ if (parent.children_pending) {
+ items[0].setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+ items[0].setText("Connecting...");
+ }
+ else if (parent.children_error != null) {
+ String msg = parent.children_error.getMessage();
+ if (msg == null) msg = parent.children_error.getClass().getName();
+ else msg = msg.replace('\n', ' ');
+ items[0].setForeground(display.getSystemColor(SWT.COLOR_RED));
+ items[0].setText(msg);
+ }
+ else if (expanded) {
+ loadChildren(parent);
+ items[0].setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+ items[0].setText("Connecting...");
+ }
+ else {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ disconnectPeer(parent);
+ }
+ });
+ items[0].setText("");
+ }
+ int n = peer_tree.getColumnCount();
+ for (int i = 1; i < n; i++) items[0].setText(i, "");
+ items[0].setImage((Image)null);
+ }
+ else {
+ PeerInfo[] arr = parent.children;
+ if (parent == peer_info) {
+ peer_tree.setItemCount(arr.length);
+ items = peer_tree.getItems();
+ }
+ else {
+ TreeItem item = findItem(parent);
+ if (item == null) return;
+ expanded = item.getExpanded();
+ item.setItemCount(expanded ? arr.length : 1);
+ items = item.getItems();
+ }
+ if (expanded) {
+ assert items.length == arr.length;
+ for (int i = 0; i < items.length; i++) fillItem(items[i], arr[i]);
+ if (fInitialPeerId != null) {
+ if ("*".equals(fInitialPeerId)) {
+ fInitialPeerId = null;
+ peer_tree.setSelection(items[0]);
+ fireSelectionChangedEvent();
+ } else {
+ int i = 0;
+ for (PeerInfo peerInfo : arr) {
+ if (fInitialPeerId.equals(peerInfo.id)) {
+ fInitialPeerId = null;
+ peer_tree.setSelection(items[i]);
+ fireSelectionChangedEvent();
+ break;
+ }
+ i++;
+ }
+ }
+ }
+ }
+ else {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ disconnectPeer(parent);
+ }
+ });
+ items[0].setText("");
+ int n = peer_tree.getColumnCount();
+ for (int i = 1; i < n; i++) items[0].setText(i, "");
+ }
+ }
+ }
+
+ public PeerInfo findPeerInfo(String peerId) {
+ return findPeerInfo(peer_info, peerId);
+ }
+
+ private PeerInfo findPeerInfo(PeerInfo parent, String peerId) {
+ if (peerId.equals(parent.id)) return parent;
+ PeerInfo[] children = parent.children;
+ if (children == null) return null;
+ for (PeerInfo child : children) {
+ PeerInfo info = findPeerInfo(child, peerId);
+ if (info != null) return info;
+ }
+ return null;
+ }
+
+ public PeerInfo findPeerInfo(TreeItem item) {
+ assert Thread.currentThread() == display.getThread();
+ if (item == null) return peer_info;
+ TreeItem parent = item.getParentItem();
+ PeerInfo info = findPeerInfo(parent);
+ if (info == null) return null;
+ if (info.children == null) return null;
+ if (info.children_error != null) return null;
+ int i = parent == null ? peer_tree.indexOf(item) : parent.indexOf(item);
+ if (i < 0 || i >= info.children.length) return null;
+ assert info.children[i].index == i;
+ return info.children[i];
+ }
+
+ private TreeItem findItem(PeerInfo info) {
+ if (info == null) return null;
+ assert info.parent != null;
+ if (info.parent == peer_info) {
+ int n = peer_tree.getItemCount();
+ if (info.index >= n) return null;
+ return peer_tree.getItem(info.index);
+ }
+ TreeItem i = findItem(info.parent);
+ if (i == null) return null;
+ int n = i.getItemCount();
+ if (info.index >= n) return null;
+ return i.getItem(info.index);
+ }
+
+ private void fillItem(TreeItem item, PeerInfo info) {
+ assert Thread.currentThread() == display.getThread();
+ Object data = item.getData("TCFPeerInfo");
+ if (data != null && data != info) item.removeAll();
+ item.setData("TCFPeerInfo", info);
+ String text[] = new String[5];
+ text[0] = info.attrs.get(IPeer.ATTR_NAME);
+ text[1] = info.attrs.get(IPeer.ATTR_OS_NAME);
+ text[2] = info.attrs.get(IPeer.ATTR_TRANSPORT_NAME);
+ text[3] = info.attrs.get(IPeer.ATTR_IP_HOST);
+ text[4] = info.attrs.get(IPeer.ATTR_IP_PORT);
+ for (int i = 0; i < text.length; i++) {
+ if (text[i] == null) text[i] = "";
+ }
+ item.setText(text);
+ item.setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+ item.setImage(ImageCache.getImage(getImageName(info)));
+ if (!canHaveChildren(info)) item.setItemCount(0);
+ else if (info.children == null || info.children_error != null) item.setItemCount(1);
+ else item.setItemCount(info.children.length);
+ }
+
+ private String getImageName(PeerInfo info) {
+ return ImageCache.IMG_TARGET_TAB;
+ }
+
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ fSelectionListeners .add(listener);
+ }
+
+ public ISelection getSelection() {
+ TreeItem[] items = peer_tree.getSelection();
+ PeerInfo[] peers = new PeerInfo[items.length];
+ int i = 0;
+ for (TreeItem item : items) {
+ peers[i++] = findPeerInfo(item);
+ }
+ return new StructuredSelection(peers);
+ }
+
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ fSelectionListeners.remove(listener);
+ }
+
+ public void setSelection(ISelection selection) {
+ peer_tree.deselectAll();
+ if (selection instanceof IStructuredSelection) {
+ Object[] elements = ((IStructuredSelection) selection).toArray();
+ for (Object object : elements) {
+ if (object instanceof PeerInfo) {
+ TreeItem item = findItem((PeerInfo) object);
+ if (item != null) {
+ peer_tree.select(item);
+ }
+ }
+ }
+ }
+ }
+
+ private void fireSelectionChangedEvent() {
+ SelectionChangedEvent event = new SelectionChangedEvent(this, getSelection());
+ Object[] listeners = fSelectionListeners.getListeners();
+ for (Object listener : listeners) {
+ try {
+ ((ISelectionChangedListener) listener).selectionChanged(event);
+ } catch (Exception e) {
+ Activator.log(e);
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessListControl.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessListControl.java
new file mode 100644
index 000000000..256fc7110
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessListControl.java
@@ -0,0 +1,507 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.cdt.ui.launch;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener;
+import org.eclipse.tm.tcf.protocol.IPeer;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.IProcesses;
+import org.eclipse.tm.tcf.services.IProcesses.ProcessContext;
+
+public class ProcessListControl {
+
+ private final class ProcessListener implements IProcesses.ProcessesListener {
+ public void exited(final String process_id, int exit_code) {
+ if (display != null) {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ ProcessInfo info = findProcessInfo(root_info, process_id);
+ if (info != null && info.parent != null && info.parent.children != null) {
+ info.parent.children = null;
+ loadChildren(info.parent);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ static class ProcessInfo {
+ String name;
+ String id;
+ boolean isContainer;
+ ProcessInfo[] children;
+ Throwable children_error;
+ int index;
+ boolean children_pending;
+ ProcessInfo parent;
+ protected boolean isAttached;
+ }
+
+ private Tree fProcessTree;
+ private Display display;
+ private IPeer fPeer;
+ private final ProcessInfo root_info = new ProcessInfo();
+ private IChannel fChannel;
+ private IProcesses fProcesses;
+ protected final ProcessListener fProcessListener = new ProcessListener();
+ private String fContextToSelect;
+ private LinkedList<String> fPathToSelect;
+ private Composite fComposite;
+
+ public ProcessListControl(Composite parent) {
+ display = parent.getDisplay();
+ parent.addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ handleDispose();
+ }
+ });
+ createProcessListArea(parent);
+ }
+
+ public void setInput(IPeer peer) {
+ if (peer == fPeer) {
+ return;
+ }
+ if (fPeer != null) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ disconnectPeer();
+ }
+ });
+ }
+ fProcessTree.setItemCount(0);
+ root_info.children = null;
+ fPeer = peer;
+ if (fPeer != null) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ connectPeer();
+ }
+ });
+ }
+ }
+
+ public Control getControl() {
+ return fComposite;
+ }
+
+ public Tree getTree() {
+ return fProcessTree;
+ }
+
+ public ProcessInfo getSelection() {
+ if (fProcessTree != null) {
+ TreeItem[] items = fProcessTree.getSelection();
+ if (items.length > 0) {
+ ProcessInfo info = findProcessInfo(items[0]);
+ return info;
+ }
+ }
+ return null;
+ }
+
+ private void createProcessListArea(Composite parent) {
+ Font font = parent.getFont();
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setFont(font);
+ GridLayout layout = new GridLayout(1, false);
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ composite.setLayout(layout);
+ composite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+ fComposite = composite;
+
+ fProcessTree = new Tree(composite, SWT.VIRTUAL | SWT.BORDER | SWT.SINGLE);
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ gd.minimumHeight = 150;
+ gd.minimumWidth = 470;
+ fProcessTree.setLayoutData(gd);
+ fProcessTree.setFont(font);
+ fProcessTree.addListener(SWT.SetData, new Listener() {
+ public void handleEvent(Event event) {
+ TreeItem item = (TreeItem)event.item;
+ ProcessInfo info = findProcessInfo(item);
+ if (info == null) {
+ updateItems(item.getParentItem(), false);
+ }
+ else {
+ fillItem(item, info);
+ }
+ }
+ });
+ }
+
+ private void handleDispose() {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ disconnectPeer();
+ if (fProcesses != null) {
+ fProcesses.removeListener(fProcessListener);
+ fProcesses = null;
+ }
+ display = null;
+ }
+ });
+ }
+
+ protected void disconnectPeer() {
+ if (fChannel != null && fChannel.getState() != IChannel.STATE_CLOSED) {
+ fChannel.close();
+ }
+ }
+
+ protected void connectPeer() {
+ final IChannel channel = fPeer.openChannel();
+ fChannel = channel;
+ fProcesses = null;
+ channel.addChannelListener(new IChannelListener() {
+ public void congestionLevel(int level) {
+ }
+ public void onChannelClosed(final Throwable error) {
+ if (fChannel != channel) return;
+ fChannel = null;
+ if (display != null) {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (root_info.children_pending) return;
+ root_info.children = null;
+ root_info.children_error = error;
+ updateItems(root_info);
+ }
+ });
+ }
+ }
+ public void onChannelOpened() {
+ if (fChannel != channel) return;
+ fProcesses = fChannel.getRemoteService(IProcesses.class);
+ if (fProcesses != null) {
+ fProcesses.addListener(fProcessListener);
+ if (fContextToSelect != null) {
+ final LinkedList<String> contextPath = new LinkedList<String>();
+ contextPath.addFirst(fContextToSelect);
+ fProcesses.getContext(fContextToSelect, new IProcesses.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, ProcessContext context) {
+ if (error == null) {
+ String parentId = context.getParentID();
+ if (parentId != null) {
+ contextPath.addFirst(parentId);
+ fProcesses.getContext(parentId, this);
+ return;
+ }
+ if (display != null) {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ fPathToSelect = contextPath;
+ expandSelect();
+ }
+ });
+ }
+ }
+ }
+ });
+ }
+ }
+ if (display != null) {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (root_info.children_pending) return;
+ root_info.children = null;
+ root_info.children_error = null;
+ updateItems(root_info);
+ }
+ });
+ }
+ }
+ });
+ }
+
+ private void updateItems(TreeItem parent_item, boolean reload) {
+ final ProcessInfo parent_info = findProcessInfo(parent_item);
+ if (parent_info == null) {
+ parent_item.setText("Invalid");
+ }
+ else {
+ if (reload && parent_info.children_error != null) {
+ loadChildren(parent_info);
+ }
+ display.asyncExec(new Runnable() {
+ public void run() {
+ updateItems(parent_info);
+ }
+ });
+ }
+ }
+
+ private void updateItems(final ProcessInfo parent) {
+ if (display == null) return;
+ assert Thread.currentThread() == display.getThread();
+ TreeItem[] items = null;
+ boolean expanded = true;
+ if (parent.children == null || parent.children_error != null) {
+ if (parent == root_info) {
+ fProcessTree.setItemCount(1);
+ items = fProcessTree.getItems();
+ }
+ else {
+ TreeItem item = findItem(parent);
+ if (item == null) return;
+ expanded = item.getExpanded();
+ item.setItemCount(1);
+ items = item.getItems();
+ }
+ assert items.length == 1;
+ items[0].removeAll();
+ if (parent.children_pending) {
+ items[0].setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+ items[0].setText("Pending...");
+ }
+ else if (parent.children_error != null) {
+ String msg = parent.children_error.getMessage();
+ if (msg == null) msg = parent.children_error.getClass().getName();
+ else msg = msg.replace('\n', ' ');
+ items[0].setForeground(display.getSystemColor(SWT.COLOR_RED));
+ items[0].setText(msg);
+ items[0].setImage((Image) null);
+ }
+ else if (expanded) {
+ loadChildren(parent);
+ items[0].setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+ items[0].setText("Pending...");
+ }
+ else {
+ items[0].setText("");
+ }
+ }
+ else {
+ ProcessInfo[] arr = parent.children;
+ if (parent == root_info) {
+ fProcessTree.setItemCount(arr.length);
+ items = fProcessTree.getItems();
+ }
+ else {
+ TreeItem item = findItem(parent);
+ if (item == null) return;
+ expanded = item.getExpanded();
+ item.setItemCount(expanded ? arr.length : 1);
+ items = item.getItems();
+ }
+ if (expanded) {
+ assert items.length == arr.length;
+ for (int i = 0; i < items.length; i++) fillItem(items[i], arr[i]);
+ // auto-expand single children
+ if (items.length == 1 && !items[0].getExpanded()) {
+ items[0].setExpanded(true);
+ }
+ expandSelect();
+ }
+ else {
+ items[0].setText("");
+ }
+ }
+ }
+
+ private void expandSelect() {
+ if (fPathToSelect == null) return;
+ if (fPathToSelect.isEmpty()) {
+ fPathToSelect = null;
+ fContextToSelect = null;
+ return;
+ }
+ do {
+ String id = fPathToSelect.get(0);
+ ProcessInfo info = findProcessInfo(root_info, id);
+ if (info == null) break;
+ TreeItem item = findItem(info);
+ if (item == null) break;
+ fPathToSelect.removeFirst();
+ if (fPathToSelect.isEmpty()) {
+ fProcessTree.setSelection(item);
+ } else {
+ item.setExpanded(true);
+ }
+ } while (!fPathToSelect.isEmpty());
+ }
+
+ private void loadChildren(final ProcessInfo parent) {
+ assert Thread.currentThread() == display.getThread();
+ if (parent.children_pending) return;
+ assert parent.children == null;
+ parent.children_pending = true;
+ parent.children_error = null;
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ final IProcesses proc = fProcesses;
+ if (proc == null || !canHaveChildren(parent)) {
+ doneLoadChildren(parent, null, new ProcessInfo[0]);
+ }
+ else {
+ proc.getChildren(parent.id, false, new IProcesses.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] context_ids) {
+ if (error != null) {
+ doneLoadChildren(parent, error, null);
+ } else if (context_ids.length > 0){
+ final List<ProcessInfo> contextInfos = new ArrayList<ProcessInfo>(context_ids.length);
+ final Set<IToken> pending = new HashSet<IToken>();
+ int i = 0;
+ for (String id : context_ids) {
+ final int idx = i++;
+ pending.add(proc.getContext(id, new IProcesses.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, ProcessContext context) {
+ if (error == null) {
+ ProcessInfo info = new ProcessInfo();
+ info.parent = parent;
+ info.id = context.getID();
+ info.name = context.getName();
+ if (info.name == null || info.name.length() == 0) {
+ info.name = info.id;
+ } else {
+ info.name += " [" + info.id + ']';
+ }
+ info.isContainer = false;
+ info.isAttached = context.isAttached();
+ info.index = idx;
+ contextInfos.add(info);
+ }
+ pending.remove(token);
+ if (pending.isEmpty()) {
+ doneLoadChildren(parent, null, contextInfos.toArray(new ProcessInfo[contextInfos.size()]));
+ }
+ }
+ }));
+ }
+ } else {
+ doneLoadChildren(parent, null, new ProcessInfo[0]);
+ }
+ }
+ });
+ }
+ }
+ });
+ }
+
+ private void doneLoadChildren(final ProcessInfo parent, final Throwable error, final ProcessInfo[] children) {
+ assert Protocol.isDispatchThread();
+ assert error == null || children == null;
+ if (display == null) return;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ assert parent.children_pending;
+ assert parent.children == null;
+ parent.children_pending = false;
+ parent.children = children;
+ parent.children_error = error;
+ updateItems(parent);
+ }
+ });
+ }
+
+ public ProcessInfo findProcessInfo(TreeItem item) {
+ assert Thread.currentThread() == display.getThread();
+ if (item == null) return root_info ;
+ TreeItem parent = item.getParentItem();
+ ProcessInfo info = findProcessInfo(parent);
+ if (info == null) return null;
+ if (info.children == null) return null;
+ if (info.children_error != null) return null;
+ int i = parent == null ? fProcessTree.indexOf(item) : parent.indexOf(item);
+ if (i < 0 || i >= info.children.length) return null;
+ assert info.children[i].index == i;
+ return info.children[i];
+ }
+
+ public ProcessInfo findProcessInfo(ProcessInfo parent, String id) {
+ assert Thread.currentThread() == display.getThread();
+ if (id == null) return root_info;
+ if (id.equals(parent.id)) return parent;
+ ProcessInfo[] childInfos = parent.children;
+ if (childInfos != null) {
+ for (ProcessInfo contextInfo : childInfos) {
+ ProcessInfo found = findProcessInfo(contextInfo, id);
+ if (found != null) {
+ return found;
+ }
+ }
+ }
+ return null;
+ }
+
+ private TreeItem findItem(ProcessInfo info) {
+ if (info == null) return null;
+ assert info.parent != null;
+ if (info.parent == root_info) {
+ int n = fProcessTree.getItemCount();
+ if (info.index >= n) return null;
+ return fProcessTree.getItem(info.index);
+ }
+ TreeItem i = findItem(info.parent);
+ if (i == null) return null;
+ int n = i.getItemCount();
+ if (info.index >= n) return null;
+ return i.getItem(info.index);
+ }
+
+ private void fillItem(TreeItem item, ProcessInfo info) {
+ assert Thread.currentThread() == display.getThread();
+ Object data = item.getData("TCFContextInfo");
+ if (data != null && data != info) item.removeAll();
+ item.setData("TCFContextInfo", info);
+ String text = info.name != null ? info.name : info.id;
+ item.setText(text);
+ item.setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+ item.setImage(getImage(info));
+ if (!canHaveChildren(info)) item.setItemCount(0);
+ else if (info.children == null || info.children_error != null) item.setItemCount(1);
+ else item.setItemCount(info.children.length);
+ }
+
+ private boolean canHaveChildren(ProcessInfo info) {
+ return info.isContainer || info == root_info;
+ }
+
+ private Image getImage(ProcessInfo info) {
+ return DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_OS_PROCESS);
+ }
+
+ public void selectContext(final String contextId) {
+ fPathToSelect = null;
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ fContextToSelect = contextId;
+ }
+ });
+ }
+
+}
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessPrompter.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessPrompter.java
new file mode 100644
index 000000000..a328bb2b4
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessPrompter.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.cdt.ui.launch;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.IStatusHandler;
+import org.eclipse.jface.window.Window;
+import org.eclipse.tm.internal.tcf.cdt.launch.ContextSelection;
+import org.eclipse.tm.internal.tcf.debug.launch.TCFLaunchDelegate;
+import org.eclipse.ui.PlatformUI;
+
+public class ProcessPrompter implements IStatusHandler {
+
+ public Object handleStatus(IStatus status, Object source) throws CoreException {
+ ILaunchConfiguration config = (ILaunchConfiguration) source;
+ String peerId = config.getAttribute(TCFLaunchDelegate.ATTR_PEER_ID, (String) null);
+ String contextId = config.getAttribute("attach_to_process", (String) null);
+ if (peerId == null || contextId == null) {
+ ContextSelection selection = new ContextSelection(peerId, contextId);
+ ProcessSelectionDialog diag = new ProcessSelectionDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+ diag.setSelection(selection);
+ if (diag.open() == Window.OK) {
+ return diag.getSelection();
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessSelectionDialog.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessSelectionDialog.java
new file mode 100644
index 000000000..e45cfc4b3
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/ProcessSelectionDialog.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.cdt.ui.launch;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.tm.internal.tcf.cdt.launch.ContextSelection;
+import org.eclipse.tm.internal.tcf.cdt.ui.launch.PeerListControl.PeerInfo;
+import org.eclipse.tm.internal.tcf.cdt.ui.launch.ProcessListControl.ProcessInfo;
+
+/**
+ * Dialog to select a peer and context.
+ */
+public class ProcessSelectionDialog extends Dialog {
+
+ private ContextSelection fSelection;
+ private ProcessListControl fContextList;
+
+ protected ProcessSelectionDialog(IShellProvider parentShell) {
+ super(parentShell);
+ }
+
+ public void setSelection(ContextSelection selection) {
+ fSelection = selection;
+ }
+
+ public ContextSelection getSelection() {
+ return fSelection;
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ newShell.setText("Select Peer and Context");
+ super.configureShell(newShell);
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ Control control = super.createContents(parent);
+ updateButtonState();
+ return control;
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = (Composite) super.createDialogArea(parent);
+ new Label(composite, SWT.NONE).setText("TCF Peers:");
+ final PeerListControl peerList = new PeerListControl(composite);
+ new Label(composite, SWT.NONE).setText("Contexts:");
+ fContextList = new ProcessListControl(composite);
+ peerList.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ ISelection selection = event.getSelection();
+ if (selection instanceof IStructuredSelection) {
+ IStructuredSelection ss = (IStructuredSelection) selection;
+ Object element = ss.getFirstElement();
+ if (element instanceof PeerInfo) {
+ handlePeerSelected((PeerInfo) element);
+ }
+ }
+ }
+ });
+ fContextList.getTree().addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ ProcessInfo contextInfo = fContextList.findProcessInfo((TreeItem) e.item);
+ if (contextInfo != null) {
+ handleContextSelected(contextInfo);
+ }
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ widgetSelected(e);
+ if (getButton(IDialogConstants.OK_ID).isEnabled()) {
+ buttonPressed(IDialogConstants.OK_ID);
+ }
+ }
+ });
+ if (fSelection.fContextId != null) {
+ fContextList.selectContext(fSelection.fContextId);
+ }
+ return composite;
+ }
+
+ private void updateButtonState() {
+ getButton(IDialogConstants.OK_ID).setEnabled(fSelection.fContextId != null);
+ }
+
+ protected void handleContextSelected(ProcessInfo contextInfo) {
+ fSelection.fContextId = contextInfo.id;
+ updateButtonState();
+ }
+
+ protected void handlePeerSelected(PeerInfo peerInfo) {
+ fSelection.fPeerId = peerInfo.id;
+ fContextList.setInput(peerInfo.peer);
+ }
+
+}
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/RemoteCMainTab.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/RemoteCMainTab.java
new file mode 100644
index 000000000..7100d680b
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/RemoteCMainTab.java
@@ -0,0 +1,437 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.cdt.ui.launch;
+
+import org.eclipse.cdt.launch.ui.CMainTab;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+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.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.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.tm.internal.tcf.cdt.ui.launch.PeerListControl.PeerInfo;
+import org.eclipse.tm.internal.tcf.debug.launch.TCFLaunchDelegate;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener;
+import org.eclipse.tm.tcf.services.IFileSystem;
+import org.eclipse.tm.tcf.services.IProcesses;
+import org.eclipse.tm.tcf.util.TCFTask;
+import org.eclipse.ui.PlatformUI;
+
+public class RemoteCMainTab extends CMainTab implements IShellProvider {
+
+ private static final String REMOTE_PATH_DEFAULT = EMPTY_STRING;
+ private static final boolean SKIP_DOWNLOAD_TO_REMOTE_DEFAULT = false;
+
+ private PeerListControl fPeerList;
+ private Text fRemoteProgText;
+ private Button fRemoteBrowseButton;
+ private Button fSkipDownloadButton;
+// private Text fPreRunText;
+ private boolean fIsInitializing = false;
+ private PeerInfo fSelectedPeer;
+ private boolean fPeerHasFileSystemService;
+ private boolean fPeerHasProcessesService;
+
+ public RemoteCMainTab() {
+ super(false);
+ }
+
+ @Override
+ public Shell getShell() {
+ return super.getShell();
+ }
+
+ public void createControl(Composite parent) {
+ Composite comp = new Composite(parent, SWT.NONE);
+ GridLayout topLayout = new GridLayout();
+ setControl(comp);
+ comp.setLayout(topLayout);
+
+ /* TCF peer selection control */
+ createPeerListGroup(comp);
+
+ /* The Project and local binary location */
+ createVerticalSpacer(comp, 1);
+ createProjectGroup(comp, 1);
+ createBuildConfigCombo(comp, 1);
+ createExeFileGroup(comp, 1);
+
+ /* The remote binary location and skip download option */
+ createVerticalSpacer(comp, 1);
+ createTargetExePathGroup(comp);
+ createDownloadOption(comp);
+
+ /* If the local binary path changes, modify the remote binary location */
+ fProgText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent evt) {
+ setLocalPathForRemotePath();
+ }
+ });
+
+ PlatformUI
+ .getWorkbench()
+ .getHelpSystem()
+ .setHelp(getControl(),
+ "org.eclipse.tm.tcf.cdt.ui.remoteApplicationLaunchGroup"); //$NON-NLS-1$
+ }
+
+ private void createPeerListGroup(Composite comp) {
+ new Label(comp, SWT.NONE).setText("Targets:");
+ fPeerList = new PeerListControl(comp);
+ fPeerList.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ handlePeerSelectionChanged();
+ useDefaultsFromConnection();
+ updateLaunchConfigurationDialog();
+ }
+ });
+ }
+
+ public boolean isValid(ILaunchConfiguration config) {
+ boolean valid = super.isValid(config);
+ if (valid) {
+ if (fSelectedPeer == null) {
+ setErrorMessage("No target selected.");
+ valid = false;
+ } else if (!fPeerHasProcessesService) {
+ setErrorMessage("Selected target does not support 'Processes' service");
+ valid = false;
+ }
+ if (valid) {
+ String name = fRemoteProgText.getText().trim();
+ if (name.length() == 0) {
+ setErrorMessage("Remote executable path is not specified.");
+ valid = false;
+ }
+ }
+ }
+ return valid;
+ }
+
+ protected void createTargetExePathGroup(Composite parent) {
+ Composite mainComp = new Composite(parent, SWT.NONE);
+ GridLayout mainLayout = new GridLayout();
+ mainLayout.numColumns = 2;
+ mainLayout.marginHeight = 0;
+ mainLayout.marginWidth = 0;
+ mainComp.setLayout(mainLayout);
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ mainComp.setLayoutData(gd);
+
+ Label remoteProgLabel = new Label(mainComp, SWT.NONE);
+ remoteProgLabel.setText("Remote Absolute File Path for C/C++ Application:");
+ gd = new GridData();
+ gd.horizontalSpan = 2;
+ remoteProgLabel.setLayoutData(gd);
+
+ fRemoteProgText = new Text(mainComp, SWT.SINGLE | SWT.BORDER);
+ gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalSpan = 1;
+ fRemoteProgText.setLayoutData(gd);
+ fRemoteProgText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent evt) {
+ updateLaunchConfigurationDialog();
+ }
+ });
+
+ fRemoteBrowseButton = createPushButton(mainComp, "Browse...", null);
+ fRemoteBrowseButton.setEnabled(fPeerHasFileSystemService);
+ fRemoteBrowseButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent evt) {
+ handleRemoteBrowseSelected();
+ updateLaunchConfigurationDialog();
+ }
+ });
+
+ // Commands to run before execution
+ /*
+ Label preRunLabel = new Label(mainComp, SWT.NONE);
+ preRunLabel.setText("Commands to execute before application");
+ gd = new GridData();
+ gd.horizontalSpan = 2;
+ preRunLabel.setLayoutData(gd);
+
+ fPreRunText = new Text(mainComp, SWT.MULTI | SWT.BORDER);
+ gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalSpan = 2;
+ fPreRunText.setLayoutData(gd);
+ fPreRunText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent evt) {
+ updateLaunchConfigurationDialog();
+ }
+ });
+ */
+ }
+
+ protected void createDownloadOption(Composite parent) {
+ Composite mainComp = new Composite(parent, SWT.NONE);
+ GridLayout mainLayout = new GridLayout();
+ mainLayout.marginHeight = 0;
+ mainLayout.marginWidth = 0;
+ mainComp.setLayout(mainLayout);
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ mainComp.setLayoutData(gd);
+
+ fSkipDownloadButton = createCheckButton(mainComp, "Skip download to target path.");
+ fSkipDownloadButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent evt) {
+ updateLaunchConfigurationDialog();
+ }
+ });
+ fSkipDownloadButton.setEnabled(fPeerHasFileSystemService);
+ }
+
+ @Override
+ public void setDefaults(ILaunchConfigurationWorkingCopy config) {
+ super.setDefaults(config);
+ config.setAttribute(TCFLaunchDelegate.ATTR_RUN_LOCAL_AGENT, false);
+ config.setAttribute(TCFLaunchDelegate.ATTR_USE_LOCAL_AGENT, false);
+ }
+
+ public void performApply(ILaunchConfigurationWorkingCopy config) {
+ String peerId = getSelectedPeerId();
+ if (peerId != null) {
+ config.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, peerId);
+ }
+ config.setAttribute(TCFLaunchDelegate.ATTR_RUN_LOCAL_AGENT, false);
+ config.setAttribute(TCFLaunchDelegate.ATTR_USE_LOCAL_AGENT, false);
+ config.setAttribute(TCFLaunchDelegate.ATTR_REMOTE_PROGRAM_FILE, fRemoteProgText.getText());
+ config.setAttribute(TCFLaunchDelegate.ATTR_COPY_TO_REMOTE_FILE, !fSkipDownloadButton.getSelection());
+// config.setAttribute(TCFLaunchDelegate.ATTR_PRERUN_COMMANDS, fPreRunText.getText());
+ super.performApply(config);
+ }
+
+ public void initializeFrom(ILaunchConfiguration config) {
+ fIsInitializing = true;
+ super.initializeFrom(config);
+ updatePeerFromConfig(config);
+ updateTargetProgFromConfig(config);
+ updateSkipDownloadFromConfig(config);
+ fIsInitializing = false;
+ }
+
+ protected void updatePeerFromConfig(ILaunchConfiguration config) {
+ try {
+ String peerId = config.getAttribute(TCFLaunchDelegate.ATTR_PEER_ID, (String) null);
+ if (peerId != null) {
+ PeerInfo info = fPeerList.findPeerInfo(peerId);
+ if (info != null) {
+ fPeerList.setSelection(new StructuredSelection(info));
+ handlePeerSelectionChanged();
+ } else {
+ fPeerList.setInitialSelectedPeerId(peerId);
+ }
+ }
+ }
+ catch (CoreException e) {
+ // Ignore
+ }
+ }
+
+ protected void handleRemoteBrowseSelected() {
+ RemoteFileSelectionDialog dialog = new RemoteFileSelectionDialog(this, SWT.SAVE);
+ dialog.setSelection(fRemoteProgText.getText().trim());
+ dialog.setPeer(fSelectedPeer.peer);
+ if (dialog.open() == Window.OK) {
+ String file = dialog.getSelection();
+ if (file != null) {
+ fRemoteProgText.setText(file);
+ }
+ }
+ }
+
+ protected void updateTargetProgFromConfig(ILaunchConfiguration config) {
+ String targetPath = REMOTE_PATH_DEFAULT;
+ try {
+ targetPath = config.getAttribute(TCFLaunchDelegate.ATTR_REMOTE_PROGRAM_FILE, REMOTE_PATH_DEFAULT);
+ }
+ catch (CoreException e) {
+ // Ignore
+ }
+ fRemoteProgText.setText(targetPath);
+
+// String prelaunchCmd = null;
+// try {
+// prelaunchCmd = config.getAttribute(TCFLaunchDelegate.ATTR_PRERUN_COMMANDS, ""); //$NON-NLS-1$
+// }
+// catch (CoreException e) {
+// // Ignore
+// }
+// fPreRunText.setText(prelaunchCmd);
+ }
+
+ protected void updateSkipDownloadFromConfig(ILaunchConfiguration config) {
+ boolean doDownload = !SKIP_DOWNLOAD_TO_REMOTE_DEFAULT;
+ try {
+ doDownload = config.getAttribute(TCFLaunchDelegate.ATTR_COPY_TO_REMOTE_FILE, doDownload);
+ }
+ catch (CoreException e) {
+ // Ignore for now
+ }
+ fSkipDownloadButton.setSelection(!doDownload);
+ }
+
+ /*
+ * setLocalPathForRemotePath This function sets the remote path text field
+ * with the value of the local executable path.
+ */
+ private void setLocalPathForRemotePath() {
+ String programName = fProgText.getText().trim();
+ boolean bUpdateRemote = false;
+
+ String remoteName = fRemoteProgText.getText().trim();
+ String remoteWsRoot = getRemoteWSRoot();
+ if (remoteName.length() == 0) {
+ bUpdateRemote = true;
+ }
+ else if (remoteWsRoot.length() != 0) {
+ bUpdateRemote = remoteName.equals(remoteWsRoot);
+ }
+
+ if (programName.length() != 0 && bUpdateRemote && getCProject() != null) {
+ IProject project = getCProject().getProject();
+ IPath exePath = new Path(programName);
+ if (!exePath.isAbsolute()) {
+ exePath = project.getFile(programName).getLocation();
+
+ IPath wsRoot = project.getWorkspace().getRoot().getLocation();
+ exePath = makeRelativeToWSRootLocation(exePath, remoteWsRoot,
+ wsRoot);
+ }
+ String path = exePath.toString();
+ fRemoteProgText.setText(path);
+ }
+ }
+
+ private void useDefaultsFromConnection() {
+ // During initialization, we don't want to use the default
+ // values of the connection, but we want to use the ones
+ // that are part of the configuration
+ if (fIsInitializing) return;
+
+ if ((fRemoteProgText != null) && !fRemoteProgText.isDisposed()) {
+ String remoteName = fRemoteProgText.getText().trim();
+ String remoteWsRoot = getRemoteWSRoot();
+ if (remoteName.length() == 0) {
+ fRemoteProgText.setText(remoteWsRoot);
+ }
+ else {
+ // try to use remote path
+ IPath wsRoot = ResourcesPlugin.getWorkspace().getRoot().getLocation();
+ IPath remotePath = makeRelativeToWSRootLocation(new Path(remoteName), remoteWsRoot, wsRoot);
+ fRemoteProgText.setText(remotePath.toString());
+ }
+ }
+ boolean hasFileSystemService = hasFileSystemService();
+ if (fSkipDownloadButton != null && !fSkipDownloadButton.isDisposed()) {
+ fSkipDownloadButton.setEnabled(hasFileSystemService);
+ }
+ if (fRemoteBrowseButton != null && !fRemoteBrowseButton.isDisposed()) {
+ fRemoteBrowseButton.setEnabled(hasFileSystemService);
+ }
+ }
+
+ private boolean hasFileSystemService() {
+ return fPeerHasFileSystemService;
+ }
+
+ private void handlePeerSelectionChanged() {
+ final PeerInfo info;
+ ISelection selection = fPeerList.getSelection();
+ if (selection instanceof IStructuredSelection) {
+ info = (PeerInfo) ((IStructuredSelection) selection).getFirstElement();
+ } else {
+ info = null;
+ }
+ fSelectedPeer = info;
+ fPeerHasFileSystemService = false;
+ fPeerHasProcessesService = false;
+ if (info != null) {
+ Boolean[] available = new TCFTask<Boolean[]>() {
+ public void run() {
+ final IChannel channel = info.peer.openChannel();
+ channel.addChannelListener(new IChannelListener() {
+ boolean opened;
+ public void congestionLevel(int level) {
+ }
+ public void onChannelClosed(final Throwable error) {
+ if (!opened) {
+ // TODO report error?
+ done(new Boolean[] { false, false });
+ }
+ }
+ public void onChannelOpened() {
+ opened = true;
+ Boolean hasFileSystemService = channel.getRemoteService(IFileSystem.class) != null;
+ Boolean hasProcessesService = channel.getRemoteService(IProcesses.class) != null;
+ channel.close();
+ done(new Boolean[] { hasFileSystemService, hasProcessesService });
+ }
+ });
+ }
+ }.getE();
+ fPeerHasFileSystemService = available[0];
+ fPeerHasProcessesService = available[1];
+ }
+ return;
+ }
+
+ private PeerInfo getSelectedPeer() {
+ return fSelectedPeer;
+ }
+
+ private String getSelectedPeerId() {
+ PeerInfo info = getSelectedPeer();
+ if (info != null) {
+ return info.id;
+ }
+ return null;
+ }
+
+ private IPath makeRelativeToWSRootLocation(IPath exePath,
+ String remoteWsRoot, IPath wsRoot) {
+ if (remoteWsRoot.length() != 0) {
+ // use remoteWSRoot instead of Workspace Root
+ if (wsRoot.isPrefixOf(exePath)) {
+ return new Path(remoteWsRoot).append(exePath
+ .removeFirstSegments(wsRoot.segmentCount()).setDevice(
+ null));
+ }
+ }
+ return exePath;
+ }
+
+ private String getRemoteWSRoot() {
+ // TODO remoteWSRoot?
+ return ""; //$NON-NLS-1$
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/RemoteFileSelectionDialog.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/RemoteFileSelectionDialog.java
new file mode 100644
index 000000000..98127e124
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/launch/RemoteFileSelectionDialog.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.cdt.ui.launch;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.tm.internal.tcf.cdt.ui.launch.FileSystemBrowserControl.FileInfo;
+import org.eclipse.tm.tcf.protocol.IPeer;
+
+/**
+ * Dialog to select a remote file.
+ */
+public class RemoteFileSelectionDialog extends Dialog {
+
+ private String fSelection;
+ private FileSystemBrowserControl fFileList;
+ private IPeer fPeer;
+ private boolean fForSave;
+ private Text fFileNameText;
+
+ protected RemoteFileSelectionDialog(IShellProvider parentShell, int style) {
+ super(parentShell);
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ fForSave = (style & SWT.SAVE) != 0;
+ }
+
+ public void setPeer(IPeer peer) {
+ fPeer = peer;
+ if (fFileList != null) {
+ fFileList.setInput(peer);
+ }
+ }
+
+ public void setSelection(String fileSelection) {
+ fSelection = fileSelection;
+ }
+
+ public String getSelection() {
+ return fSelection;
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ newShell.setText("Select File");
+ super.configureShell(newShell);
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ Control control = super.createContents(parent);
+ updateButtonState();
+ return control;
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = (Composite) super.createDialogArea(parent);
+ fFileList = new FileSystemBrowserControl(composite, false);
+ fFileList.getTree().addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ FileInfo contextInfo = fFileList.findFileInfo((TreeItem) e.item);
+ if (contextInfo != null) {
+ handleFileSelected(contextInfo);
+ }
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ widgetSelected(e);
+ if (getButton(IDialogConstants.OK_ID).isEnabled()) {
+ buttonPressed(IDialogConstants.OK_ID);
+ }
+ }
+ });
+
+ if (fForSave) {
+ Composite fileNameComp = new Composite(composite, SWT.NONE);
+ fileNameComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ GridLayout layout = new GridLayout(2, false);
+ layout.marginWidth = 0;
+ fileNameComp.setLayout(layout);
+ new Label(fileNameComp, SWT.NONE).setText("File Name:");
+ fFileNameText = new Text(fileNameComp, SWT.BORDER);
+ fFileNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ fFileNameText.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ handleFileNameChanged();
+ }
+ });
+ }
+
+ if (fSelection != null) {
+ fFileList.setInitialSelection(fSelection);
+ if (fFileNameText != null) {
+ String basename = new Path(fSelection).lastSegment();
+ if (basename != null) {
+ fFileNameText.setText(basename);
+ }
+ }
+ }
+ if (fPeer != null) {
+ fFileList.setInput(fPeer);
+ }
+ return composite;
+ }
+
+ private void updateButtonState() {
+ boolean enabled = fSelection != null;
+ if (enabled && fForSave) {
+ enabled = fFileNameText.getText().trim().length() > 0;
+ }
+ getButton(IDialogConstants.OK_ID).setEnabled(enabled);
+ }
+
+ protected void handleFileNameChanged() {
+ if (fSelection != null) {
+ fSelection = new Path(fSelection).removeLastSegments(1).append(fFileNameText.getText().trim()).toString();
+ updateButtonState();
+ }
+ }
+
+ protected void handleFileSelected(FileInfo fileInfo) {
+ if (fileInfo.isDir) {
+ if (fForSave) {
+ String basename = fFileNameText.getText().trim();
+ if (basename.length() > 0) {
+ fSelection = new Path(fileInfo.fullname).append(basename).toString();
+ } else {
+ fSelection = fileInfo.fullname;
+ }
+ } else {
+ fSelection = null;
+ }
+ } else {
+ fSelection = fileInfo.fullname;
+ if (fFileNameText != null) {
+ String basename = new Path(fSelection).lastSegment();
+ if (basename != null) {
+ fFileNameText.setText(basename);
+ }
+ }
+ }
+ updateButtonState();
+ }
+
+}

Back to the top