diff options
author | eutarass | 2008-09-25 21:36:25 +0000 |
---|---|---|
committer | eutarass | 2008-09-25 21:36:25 +0000 |
commit | c6d9344ab3988164cf6008d45fc80f83036a5f51 (patch) | |
tree | dfa526ecb45363f3f7cd3df4dcab43ce41ee5a34 | |
parent | a3e68f01b6d211fc5832e695037a562a7a65af2d (diff) | |
download | org.eclipse.tcf-c6d9344ab3988164cf6008d45fc80f83036a5f51.tar.gz org.eclipse.tcf-c6d9344ab3988164cf6008d45fc80f83036a5f51.tar.xz org.eclipse.tcf-c6d9344ab3988164cf6008d45fc80f83036a5f51.zip |
New extension point: org.eclipse.tm.tcf.debug.ui.launch.context - for integration with development tools.
New plug-in: org.eclipse.tm.tcf.cdt.ui - contains TCF/CDT integration code.
TCF Launch Configuration is improved: now supports: default values from current CDT project, search of executable files in CDT projects, download of executable file to remote target.
26 files changed, 2072 insertions, 792 deletions
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/.classpath b/plugins/org.eclipse.tm.tcf.cdt.ui/.classpath new file mode 100644 index 000000000..64c5e31b7 --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/.project b/plugins/org.eclipse.tm.tcf.cdt.ui/.project new file mode 100644 index 000000000..5cbeef203 --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.tm.tcf.cdt.ui</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.tm.tcf.cdt.ui/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..e115508c0 --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,18 @@ +#Mon Sep 22 12:28:22 PDT 2008 +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch,.svn/ +org.eclipse.jdt.core.circularClasspath=error +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.5 +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/.settings/org.eclipse.jdt.ui.prefs b/plugins/org.eclipse.tm.tcf.cdt.ui/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 000000000..547f1a097 --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,4 @@ +#Tue Sep 23 17:25:53 PDT 2008
+eclipse.preferences.version=1
+formatter_profile=_Java STD
+formatter_settings_version=11
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 new file mode 100644 index 000000000..6837b4167 --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/META-INF/MANIFEST.MF @@ -0,0 +1,19 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.tcf.cdt.ui;singleton:=true +Bundle-Version: 0.2.0 +Bundle-Activator: org.eclipse.tm.internal.tcf.cdt.ui.Activator +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.debug.core, + org.eclipse.cdt.core, + org.eclipse.core.resources, + org.eclipse.cdt.debug.core, + org.eclipse.debug.ui, + org.eclipse.cdt.ui, + org.eclipse.tm.tcf.debug, + org.eclipse.tm.tcf.debug.ui +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-Vendor: %providerName diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/about.html b/plugins/org.eclipse.tm.tcf.cdt.ui/about.html new file mode 100644 index 000000000..6c5b3615b --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/about.html @@ -0,0 +1,28 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>January 10, 2008</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. +For purposes of the EPL, "Program" will mean the Content.</p> + +<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p> + +</body> +</html>
\ No newline at end of file diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/build.properties b/plugins/org.eclipse.tm.tcf.cdt.ui/build.properties new file mode 100644 index 000000000..43883590f --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/build.properties @@ -0,0 +1,9 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + about.html,\ + plugin.properties +src.includes = about.html +
\ No newline at end of file diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.properties b/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.properties new file mode 100644 index 000000000..c4fbf4d03 --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.properties @@ -0,0 +1,12 @@ +############################################################################### +# Copyright (c) 2007, 2008 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 implementation +############################################################################### +pluginName=TCF/CDT Integration UI (Incubation) +providerName=Eclipse.org diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.xml b/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.xml new file mode 100644 index 000000000..3871f04ea --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/plugin.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="3.2"?> +<plugin> + + <extension point="org.eclipse.tm.tcf.debug.ui.launch_context"> + <class name="org.eclipse.tm.internal.tcf.cdt.ui.TCFLaunchContext" /> + </extension> + +</plugin> diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/Activator.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/Activator.java new file mode 100644 index 000000000..9a5060fcd --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/Activator.java @@ -0,0 +1,76 @@ +package org.eclipse.tm.internal.tcf.cdt.ui; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + public static final String PLUGIN_ID = "org.eclipse.tm.tcf.cdt.ui"; + private static Activator plugin; + + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + public static Activator getDefault() { + return plugin; + } + + public static void log(IStatus status) { + getDefault().getLog().log(status); + } + + public static void log(Throwable e) { + log(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.ERROR, e.getMessage(), e)); + } + + public static IWorkbenchWindow getActiveWorkbenchWindow() { + return getDefault().getWorkbench().getActiveWorkbenchWindow(); + } + + public static IWorkbenchPage getActivePage() { + IWorkbenchWindow w = getActiveWorkbenchWindow(); + if (w != null) { + return w.getActivePage(); + } + return null; + } + + public static Shell getActiveWorkbenchShell() { + IWorkbenchWindow window = getActiveWorkbenchWindow(); + if (window != null) { + return window.getShell(); + } + return null; + } + + public static void errorDialog(String message, IStatus status) { + log(status); + Shell shell = getActiveWorkbenchShell(); + if (shell == null) return; + ErrorDialog.openError(shell, "Error", message, status); + } + + public static void errorDialog(String message, Throwable t) { + log(t); + Shell shell = getActiveWorkbenchShell(); + if (shell == null) return; + IStatus status = new Status(IStatus.ERROR, PLUGIN_ID, 1, t.getMessage(), null); + ErrorDialog.openError(shell, "Error", message, status); + } +} diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFLaunchContext.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFLaunchContext.java new file mode 100644 index 000000000..83c5fb75a --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFLaunchContext.java @@ -0,0 +1,326 @@ +/******************************************************************************* + * Copyright (c) 2008 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 org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.IBinaryParser; +import org.eclipse.cdt.core.ICExtensionReference; +import org.eclipse.cdt.core.IBinaryParser.IBinaryObject; +import org.eclipse.cdt.core.model.CModelException; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.IBinary; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.ui.CElementLabelProvider; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.debug.ui.ILaunchConfigurationDialog; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.custom.BusyIndicator; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tm.internal.tcf.debug.launch.TCFLaunchDelegate; +import org.eclipse.tm.internal.tcf.debug.ui.launch.ITCFLaunchContext; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.dialogs.TwoPaneElementSelector; + +public class TCFLaunchContext implements ITCFLaunchContext { + + public boolean isActive() { + return getContext(null) != null; + } + + public boolean isSupportedProject(IProject project) { + return CoreModel.getDefault().getCModel().getCProject(project.getName()) != null; + } + + public void setDefaults(ILaunchConfigurationDialog dlg, ILaunchConfigurationWorkingCopy config) { + ICElement cElement = getContext(config); + if (cElement != null) { + initializeCProject(cElement, config); + initializeProgramName(cElement, dlg, config); + } + } + + /** + * Returns the current C element context from which to initialize default + * settings, or <code>null</code> if none. Note, if possible we will + * return the IBinary based on configuration entry as this may be more useful then + * just the project. + * + * @return C element context. + */ + private ICElement getContext(ILaunchConfiguration config) { + String projectName = null; + String programName = null; + if (config != null) { + try { + projectName = config.getAttribute(TCFLaunchDelegate.ATTR_PROJECT_NAME, (String)null); + programName = config.getAttribute(TCFLaunchDelegate.ATTR_LOCAL_PROGRAM_FILE, (String)null); + } + catch (CoreException e) { + Activator.log(e); + } + } + Object obj = null; + IWorkbenchPage page = Activator.getActivePage(); + if (projectName != null && !projectName.equals("")) { //$NON-NLS-1$ + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); + ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(project); + if (cProject != null && cProject.exists()) obj = cProject; + } + else { + if (page != null) { + ISelection selection = page.getSelection(); + if (selection instanceof IStructuredSelection) { + IStructuredSelection ss = (IStructuredSelection)selection; + if (!ss.isEmpty()) obj = ss.getFirstElement(); + } + } + } + if (obj instanceof IResource) { + ICElement ce = CoreModel.getDefault().create((IResource)obj); + if (ce == null) { + IProject pro = ((IResource)obj).getProject(); + ce = CoreModel.getDefault().create(pro); + } + obj = ce; + } + if (obj instanceof ICElement) { + if (programName == null || programName.equals("")) { //$NON-NLS-1$ + return (ICElement)obj; + } + ICElement ce = (ICElement)obj; + IProject project; + project = (IProject)ce.getCProject().getResource(); + IPath programFile = project.getFile(programName).getLocation(); + ce = CCorePlugin.getDefault().getCoreModel().create(programFile); + if (ce != null && ce.exists()) return ce; + return (ICElement)obj; + } + IEditorPart part = page.getActiveEditor(); + if (part != null) { + IEditorInput input = part.getEditorInput(); + return (ICElement)input.getAdapter(ICElement.class); + } + return null; + } + + /** + * Set the C project attribute based on the ICElement. + */ + private void initializeCProject(ICElement cElement, ILaunchConfigurationWorkingCopy config) { + ICProject cProject = cElement.getCProject(); + String name = null; + if (cProject != null && cProject.exists()) { + name = cProject.getElementName(); + config.setMappedResources(new IResource[] {cProject.getProject()}); + } + config.setAttribute(TCFLaunchDelegate.ATTR_PROJECT_NAME, name); + } + + /** + * Set the program name attributes on the working copy based on the ICElement + */ + private void initializeProgramName(ICElement cElement, ILaunchConfigurationDialog dlg, ILaunchConfigurationWorkingCopy config) { + + boolean renamed = false; + + if (!(cElement instanceof IBinary)) { + cElement = cElement.getCProject(); + } + + if (cElement instanceof ICProject) { + + IProject project = cElement.getCProject().getProject(); + String name = project.getName(); + ICProjectDescription projDes = CCorePlugin.getDefault().getProjectDescription(project); + if (projDes != null) { + String buildConfigName = projDes.getActiveConfiguration().getName(); + name = name + " " + buildConfigName; //$NON-NLS-1$ + } + name = dlg.generateName(name); + config.rename(name); + renamed = true; + } + + IBinary binary = null; + if (cElement instanceof ICProject) { + IBinary[] bins = getBinaryFiles((ICProject)cElement); + if (bins != null && bins.length == 1) { + binary = bins[0]; + } + } + else if (cElement instanceof IBinary) { + binary = (IBinary)cElement; + } + + if (binary != null) { + String path; + path = binary.getResource().getProjectRelativePath().toOSString(); + config.setAttribute(TCFLaunchDelegate.ATTR_LOCAL_PROGRAM_FILE, path); + if (!renamed) + { + String name = binary.getElementName(); + int index = name.lastIndexOf('.'); + if (index > 0) { + name = name.substring(0, index); + } + name = dlg.generateName(name); + config.rename(name); + renamed = true; + } + } + + if (!renamed) { + String name = dlg.generateName(cElement.getCProject().getElementName()); + config.rename(name); + } + } + + public String getBuildConfigID(IProject project) { + ICProjectDescription projDes = CCorePlugin.getDefault().getProjectDescription(project); + if (projDes == null) return null; + return projDes.getActiveConfiguration().getId(); + } + + /** + * Iterate through and suck up all of the executable files that we can find. + */ + private IBinary[] getBinaryFiles(final ICProject cproject) { + if (cproject == null || !cproject.exists()) return null; + final Display display = Display.getCurrent(); + final Object[] ret = new Object[1]; + BusyIndicator.showWhile(display, new Runnable() { + + public void run() { + try { + ret[0] = cproject.getBinaryContainer().getBinaries(); + } + catch (CModelException e) { + Activator.errorDialog("Launch UI internal error", e); + } + } + }); + return (IBinary[])ret[0]; + } + + /** + * Return true if given file path names a binary file. + * @param project + * @param exePath + * @return true if binary file. + * @throws CoreException + */ + public boolean isBinary(IProject project, IPath exePath) throws CoreException { + ICExtensionReference[] parserRef = CCorePlugin.getDefault().getBinaryParserExtensions(project); + for (int i = 0; i < parserRef.length; i++) { + try { + IBinaryParser parser = (IBinaryParser)parserRef[i].createExtension(); + if ((IBinaryObject)parser.getBinary(exePath) != null) return true; + } + catch (Exception e) { + } + } + IBinaryParser parser = CCorePlugin.getDefault().getDefaultBinaryParser(); + try { + return (IBinaryObject)parser.getBinary(exePath) != null; + } + catch (Exception e) { + } + return false; + } + + public String chooseBinary(Shell shell, IProject project) { + ILabelProvider programLabelProvider = new CElementLabelProvider() { + + @Override + public String getText(Object element) { + if (element instanceof IBinary) { + IBinary bin = (IBinary)element; + StringBuffer name = new StringBuffer(); + name.append(bin.getPath().lastSegment()); + return name.toString(); + } + return super.getText(element); + } + + @Override + public Image getImage(Object element) { + if (! (element instanceof ICElement)) { + return super.getImage(element); + } + ICElement celement = (ICElement)element; + + if (celement.getElementType() == ICElement.C_BINARY) { + IBinary belement = (IBinary)celement; + if (belement.isExecutable()) { + return DebugUITools.getImage(IDebugUIConstants.IMG_ACT_RUN); + } + } + + return super.getImage(element); + } + }; + + ILabelProvider qualifierLabelProvider = new CElementLabelProvider() { + + @Override + public String getText(Object element) { + if (element instanceof IBinary) { + IBinary bin = (IBinary)element; + StringBuffer name = new StringBuffer(); + name.append(bin.getCPU() + (bin.isLittleEndian() ? "le" : "be")); //$NON-NLS-1$ //$NON-NLS-2$ + name.append(" - "); //$NON-NLS-1$ + name.append(bin.getPath().toString()); + return name.toString(); + } + return super.getText(element); + } + }; + + TwoPaneElementSelector dialog = new TwoPaneElementSelector(shell, programLabelProvider, qualifierLabelProvider); + dialog.setElements(getBinaryFiles(getCProject(project.getName()))); + dialog.setMessage("Choose program to run"); + dialog.setTitle("Program Selection"); + dialog.setUpperListLabel("Binaries:"); + dialog.setLowerListLabel("Qualifier:"); + dialog.setMultipleSelection(false); + // dialog.set + if (dialog.open() != Window.OK) return null; + IBinary binary = (IBinary)dialog.getFirstResult(); + return binary.getResource().getProjectRelativePath().toString(); + } + + /** + * Return the ICProject corresponding to the project name in the project name text field, or + * null if the text does not match a project name. + */ + private ICProject getCProject(String name) { + String projectName = name.trim(); + if (projectName.length() < 1) return null; + return CoreModel.getDefault().getCModel().getCProject(projectName); + } +} diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/icons/target_tab.gif b/plugins/org.eclipse.tm.tcf.debug.ui/icons/target_tab.gif Binary files differnew file mode 100644 index 000000000..e9df7b871 --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.debug.ui/icons/target_tab.gif diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml b/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml index b593b7cfe..6b3a641af 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml +++ b/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml @@ -2,6 +2,8 @@ <?eclipse version="3.2"?> <plugin> + <extension-point id="launch_context" name="TCF Launch Context" schema="schema/launch_context.exsd"/> + <extension point="org.eclipse.tm.tcf.startup"/> <extension diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/schema/launch_context.exsd b/plugins/org.eclipse.tm.tcf.debug.ui/schema/launch_context.exsd new file mode 100644 index 000000000..473255026 --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.debug.ui/schema/launch_context.exsd @@ -0,0 +1,72 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- Schema file written by PDE --> +<schema targetNamespace="org.eclipse.tm.tcf"> +<annotation> + <appInfo> + <meta.schema plugin="org.eclipse.tm.tcf.debug.ui" id="launch_context" name="TCF Launch Context"/> + </appInfo> + <documentation> + This extension point is used to register plugins + that want to extends TCF Launch Configuration functionality. + </documentation> + +</annotation> + + <element name="extension"> + <complexType> + <sequence> + <element ref="class" minOccurs="0" maxOccurs="unbounded"/> + </sequence> + <attribute name="point" type="string" use="required"> + <annotation> + <documentation> + a fully qualified identifier of the target extension point + </documentation> + </annotation> + </attribute> + <attribute name="id" type="string"> + <annotation> + <documentation> + an optional identifier of the extension instance + </documentation> + </annotation> + </attribute> + <attribute name="name" type="string"> + <annotation> + <documentation> + an optional name of the extension instance + </documentation> + </annotation> + </attribute> + </complexType> + </element> + + <element name="class"> + <complexType> + <attribute name="name" type="string"> + <annotation> + <documentation> + Class should implement ILaunchContext interface + </documentation> + </annotation> + </attribute> + </complexType> + </element> + + <annotation> + <appInfo> + <meta.section type="apiInfo"/> + </appInfo> + <documentation> + </documentation> + </annotation> + + <annotation> + <appInfo> + <meta.section type="implementation"/> + </appInfo> + <documentation> + </documentation> + </annotation> + +</schema> diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java index 55817ebd0..275f9c113 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java @@ -126,4 +126,18 @@ public class Activator extends AbstractUIPlugin { plugin.getBundle().getSymbolicName(), IStatus.OK, msg, err)); } } + + /** + * Send error message into Eclipse log. + * @param err - exception + */ + public static void log(Throwable err) { + if (plugin == null || plugin.getLog() == null) { + err.printStackTrace(); + } + else { + plugin.getLog().log(new Status(IStatus.ERROR, + plugin.getBundle().getSymbolicName(), IStatus.OK, "Unhandled exception in TCF UI", err)); + } + } } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/ImageCache.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/ImageCache.java index 30629136c..285932265 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/ImageCache.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/ImageCache.java @@ -25,6 +25,7 @@ public class ImageCache { public static final String IMG_TCF = "icons/tcf.gif", + IMG_TARGET_TAB = "icons/target_tab.gif", IMG_ARGUMENTS_TAB = "icons/arguments_tab.gif", IMG_ATTRIBUTE = "icons/attribute.gif", diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/ITCFLaunchContext.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/ITCFLaunchContext.java new file mode 100644 index 000000000..90be235bc --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/ITCFLaunchContext.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2008 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.debug.ui.launch; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.ILaunchConfigurationDialog; +import org.eclipse.swt.widgets.Shell; + +/** + * TCF clients can implement ITCFLaunchContext to provide information about + * workspace projects to TCF Launch Configuration. + * + * The information includes default values for launch configuration attributes, + * list of executable binary files, etc. + * + * Since each project type can have its own methods to retrieve relevant information, + * there should be implementation of this interface for each project type that support TCF. + * + * Implementation should be able to examine current IDE state (like active editor input source, + * project explorer selection, etc.) and figure out an "active project". + */ +public interface ITCFLaunchContext { + + /** + * Check if this context is currently active. + * @return true if active. + */ + boolean isActive(); + + /** + * Check if this context recognizes type of a project. + * @param project + * @return true if the project is supported by this context. + */ + boolean isSupportedProject(IProject project); + + /** + * Set launch configuration attributes to default values best suited for current context. + * @param dlg - currently open launch configuration dialog + * @param config - currently open launch configuration + */ + void setDefaults(ILaunchConfigurationDialog dlg, ILaunchConfigurationWorkingCopy config); + + /** + * Get project build configuration ID. + * @param project + * @return build configuration ID. + */ + String getBuildConfigID(IProject project); + + /** + * Show a dialog box that allows user to select executable binary file from a list + * of available file in this context. + * @param project_name + * @param shell + * @return binary file path + */ + String chooseBinary(Shell shell, IProject project); + + /** + * Check if a path represents an executable binary file. + * @param project + * @param path + * @return + * @throws CoreException + */ + boolean isBinary(IProject project, IPath path) throws CoreException; +} diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFArgumentsTab.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFArgumentsTab.java index 23c43051b..c13c7b310 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFArgumentsTab.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFArgumentsTab.java @@ -26,7 +26,7 @@ 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.Group; +import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.tm.internal.tcf.debug.launch.TCFLaunchDelegate; import org.eclipse.tm.internal.tcf.debug.ui.ImageCache; @@ -36,8 +36,6 @@ public class TCFArgumentsTab extends AbstractLaunchConfigurationTab { private Text text_arguments; private Button button_variables; - private Text text_working_dir; - private Button button_default_dir; public void createControl(Composite parent) { Font font = parent.getFont(); @@ -51,30 +49,34 @@ public class TCFArgumentsTab extends AbstractLaunchConfigurationTab { setControl(comp); createArgumentsGroup(comp); - createWorkingDirGroup(comp); } - private void createArgumentsGroup(Composite comp) { - Font font = comp.getFont(); + private void createArgumentsGroup(Composite parent) { + Composite comp = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.marginHeight = 0; + layout.marginWidth = 0; + comp.setLayout(layout); + GridData gd = new GridData(GridData.FILL_BOTH); + comp.setLayoutData(gd); - Group group = new Group(comp, SWT.NONE); - group.setFont(font); - group.setLayout(new GridLayout()); - group.setLayoutData(new GridData(GridData.FILL_BOTH)); - group.setText("Program Arguments"); + Label label = new Label(comp, SWT.NONE); + label.setText("Program Arguments:"); + gd = new GridData(); + gd.horizontalSpan = 2; + label.setLayoutData(gd); - text_arguments = new Text(group, SWT.MULTI | SWT.WRAP | SWT.BORDER | SWT.V_SCROLL); - GridData gd = new GridData(GridData.FILL_BOTH); + text_arguments = new Text(comp, SWT.MULTI | SWT.WRAP | SWT.BORDER | SWT.V_SCROLL); + gd = new GridData(GridData.FILL_BOTH); gd.heightHint = 40; gd.widthHint = 100; text_arguments.setLayoutData(gd); - text_arguments.setFont(font); text_arguments.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent evt) { updateLaunchConfigurationDialog(); } }); - button_variables= createPushButton(group, "Variables", null); + button_variables= createPushButton(comp, "Variables", null); gd = new GridData(GridData.HORIZONTAL_ALIGN_END); button_variables.setLayoutData(gd); button_variables.addSelectionListener(new SelectionAdapter() { @@ -84,27 +86,6 @@ public class TCFArgumentsTab extends AbstractLaunchConfigurationTab { }); } - private void createWorkingDirGroup(Composite comp) { - Font font = comp.getFont(); - - Group group = new Group(comp, SWT.NONE); - GridLayout workingDirLayout = new GridLayout(); - workingDirLayout.makeColumnsEqualWidth = false; - group.setLayout(workingDirLayout); - group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - group.setFont(font); - group.setText("Working directory"); - - text_working_dir = new Text(group, SWT.SINGLE | SWT.BORDER); - text_working_dir.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - text_working_dir.setFont(font); - - button_default_dir = new Button(group, SWT.CHECK); - button_default_dir.setText("Use default"); - button_default_dir.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false)); - button_default_dir.setFont(font); - } - /** * A variable entry button has been pressed for the given text * field. Prompt the user for a variable and enter the result @@ -137,7 +118,6 @@ public class TCFArgumentsTab extends AbstractLaunchConfigurationTab { public void initializeFrom(ILaunchConfiguration configuration) { try { text_arguments.setText(configuration.getAttribute(TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS, "")); //$NON-NLS-1$ - text_working_dir.setText(configuration.getAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, "")); //$NON-NLS-1$ } catch (CoreException e) { setErrorMessage("Cannot read launch configuration: " + e); @@ -148,9 +128,6 @@ public class TCFArgumentsTab extends AbstractLaunchConfigurationTab { configuration.setAttribute( TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS, getAttributeValueFrom(text_arguments)); - configuration.setAttribute( - TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, - getAttributeValueFrom(text_working_dir)); } protected String getAttributeValueFrom(Text text) { diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFMainTab.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFMainTab.java index 798b0bbde..d9402707d 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFMainTab.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFMainTab.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2008 Wind River Systems, Inc. and others. + * Copyright (c) 2008 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 @@ -10,821 +10,482 @@ *******************************************************************************/ package org.eclipse.tm.internal.tcf.debug.ui.launch; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; +import java.io.File; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.CLabel; 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.graphics.Font; import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.ProgressBar; -import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; -import org.eclipse.swt.widgets.TreeItem; import org.eclipse.tm.internal.tcf.debug.launch.TCFLaunchDelegate; -import org.eclipse.tm.internal.tcf.debug.launch.TCFUserDefPeer; -import org.eclipse.tm.internal.tcf.debug.tests.TCFTestSuite; +import org.eclipse.tm.internal.tcf.debug.ui.Activator; import org.eclipse.tm.internal.tcf.debug.ui.ImageCache; -import org.eclipse.tm.tcf.protocol.IChannel; -import org.eclipse.tm.tcf.protocol.IPeer; -import org.eclipse.tm.tcf.protocol.Protocol; -import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener; -import org.eclipse.tm.tcf.services.ILocator; +import org.eclipse.ui.dialogs.ElementListSelectionDialog; +import org.osgi.framework.Bundle; - -/** - * Launch configuration dialog tab to specify the Target Communication Framework - * configuration. - */ public class TCFMainTab extends AbstractLaunchConfigurationTab { - - private Text peer_id_text; - private Text program_text; - private Tree peer_tree; - private Runnable update_peer_buttons; - private final PeerInfo peer_info = new PeerInfo(); - private Display display; - - private final Map<LocatorListener,ILocator> listeners = new HashMap<LocatorListener,ILocator>(); - - private static class PeerInfo { - PeerInfo parent; - int index; - String id; - Map<String,String> attrs; - PeerInfo[] children; - boolean children_pending; - Throwable children_error; - IPeer peer; - } - - 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; - 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; - loadChildren(arr[i]); - 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)) { - buf[j++] = arr[i]; - } - } - parent.children = buf; - updateItems(parent); - } - }); - } + private Text project_text; + private Text local_program_text; + private Text remote_program_text; + private Text working_dir_text; + private Button default_dir_button; + private Button terminal_button; - 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) { - loadChildren(arr[i]); - } - break; - } - } - } - }); - } - } - public void createControl(Composite parent) { - display = parent.getDisplay(); - assert display != null; - - Font font = parent.getFont(); Composite comp = new Composite(parent, SWT.NONE); - GridLayout layout = new GridLayout(1, true); - comp.setLayout(layout); - comp.setFont(font); - - GridData gd = new GridData(GridData.FILL_BOTH); - comp.setLayoutData(gd); setControl(comp); - createTargetGroup(comp); - createProgramGroup(comp); + GridLayout topLayout = new GridLayout(); + comp.setLayout(topLayout); + + createVerticalSpacer(comp, 1); + createProjectGroup(comp); + createApplicationGroup(comp); + createWorkingDirGroup(comp); + createVerticalSpacer(comp, 1); + createTerminalOption(comp, 1); } - private void createTargetGroup(Composite parent) { - Font font = parent.getFont(); - + private void createProjectGroup(Composite parent) { Group group = new Group(parent, SWT.NONE); - GridLayout top_layout = new GridLayout(); - top_layout.verticalSpacing = 0; - top_layout.numColumns = 2; - group.setLayout(top_layout); - group.setLayoutData(new GridData(GridData.FILL_BOTH)); - group.setFont(font); - group.setText("Target"); - - createVerticalSpacer(group, top_layout.numColumns); - - Label host_label = new Label(group, SWT.NONE); - host_label.setText("Target ID:"); - host_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); - host_label.setFont(font); - - peer_id_text = new Text(group, SWT.SINGLE | SWT.BORDER); - peer_id_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - peer_id_text.setFont(font); - peer_id_text.setEditable(false); - peer_id_text.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + group.setLayout(layout); + group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + group.setText("Project"); + + Label label = new Label(group, SWT.NONE); + label.setText("Project Name:"); + GridData gd = new GridData(); + gd.horizontalSpan = 2; + label.setLayoutData(gd); + + project_text = new Text(group, SWT.SINGLE | SWT.BORDER); + gd = new GridData(GridData.FILL_HORIZONTAL); + project_text.setLayoutData(gd); + project_text.addModifyListener(new ModifyListener() { + + public void modifyText(ModifyEvent evt) { updateLaunchConfigurationDialog(); } }); - createVerticalSpacer(group, top_layout.numColumns); + Button project_button = createPushButton(group, "Browse...", null); + project_button.addSelectionListener(new SelectionAdapter() { - Label peer_label = new Label(group, SWT.NONE); - peer_label.setText("&Available targets:"); - peer_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); - peer_label.setFont(font); - - loadChildren(peer_info); - createPeerListArea(group); - } - - private void createPeerListArea(Composite parent) { - Font font = parent.getFont(); - Composite composite = new Composite(parent, SWT.NONE); - GridLayout layout = new GridLayout(2, false); - composite.setFont(font); - composite.setLayout(layout); - composite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1)); - - peer_tree = new Tree(composite, SWT.VIRTUAL | SWT.BORDER | SWT.SINGLE); - GridData gd = new GridData(GridData.FILL_BOTH); - gd.minimumHeight = 150; - gd.minimumWidth = 470; - 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) { - PeerInfo parent = findPeerInfo(item.getParentItem()); - if (parent == null) { - item.setText("Invalid"); - } - else { - if (parent.children == null || parent.children_error != null) { - loadChildren(parent); - } - updateItems(parent); - } - } - else { - fillItem(item, info); - } - } - }); - peer_tree.addSelectionListener(new SelectionAdapter() { @Override - public void widgetDefaultSelected(SelectionEvent e) { - TreeItem[] selections = peer_tree.getSelection(); - if (selections.length == 0) return; - assert selections.length == 1; - final PeerInfo info = findPeerInfo(selections[0]); - if (info == null) return; - new PeerPropsDialog(getShell(), getImage(), info.attrs, - info.peer instanceof TCFUserDefPeer).open(); - if (!(info.peer instanceof TCFUserDefPeer)) return; - Protocol.invokeLater(new Runnable() { - public void run() { - ((TCFUserDefPeer)info.peer).updateAttributes(info.attrs); - TCFUserDefPeer.savePeers(); - } - }); - } - @Override - public void widgetSelected(SelectionEvent e) { - update_peer_buttons.run(); - TreeItem[] selections = peer_tree.getSelection(); - if (selections.length > 0) { - assert selections.length == 1; - PeerInfo info = findPeerInfo(selections[0]); - if (info != null) peer_id_text.setText(getPath(info)); - } + public void widgetSelected(SelectionEvent evt) { + handleProjectButtonSelected(); + updateLaunchConfigurationDialog(); } }); - - createPeerButtons(composite); } - private void createPeerButtons(Composite parent) { - Font font = parent.getFont(); - Composite composite = new Composite(parent, SWT.NONE); + private void createApplicationGroup(Composite parent) { + Group group = new Group(parent, SWT.NONE); GridLayout layout = new GridLayout(); - composite.setFont(font); - composite.setLayout(layout); - composite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL)); + group.setLayout(layout); + group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + group.setText("Application"); - final Button button_new = new Button(composite, SWT.PUSH); - button_new.setText("N&ew..."); - button_new.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); - button_new.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - final Map<String,String> attrs = new HashMap<String,String>(); - if (new PeerPropsDialog(getShell(), getImage(), attrs, true).open() != Window.OK) return; - Protocol.invokeLater(new Runnable() { - public void run() { - new TCFUserDefPeer(attrs); - TCFUserDefPeer.savePeers(); - } - }); - } - }); - - final Button button_edit = new Button(composite, SWT.PUSH); - button_edit.setText("E&dit..."); - button_edit.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); - button_edit.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - TreeItem[] selection = peer_tree.getSelection(); - if (selection.length == 0) return; - final PeerInfo info = findPeerInfo(selection[0]); - if (info == null) return; - if (new PeerPropsDialog(getShell(), getImage(), info.attrs, - info.peer instanceof TCFUserDefPeer).open() != Window.OK) return; - if (!(info.peer instanceof TCFUserDefPeer)) return; - Protocol.invokeLater(new Runnable() { - public void run() { - ((TCFUserDefPeer)info.peer).updateAttributes(info.attrs); - TCFUserDefPeer.savePeers(); - } - }); - } - }); + createLocalExeFileGroup(group); + createRemoteExeFileGroup(group); + } - final Button button_remove = new Button(composite, SWT.PUSH); - button_remove.setText("&Remove"); - button_remove.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); - button_remove.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - TreeItem[] selection = peer_tree.getSelection(); - if (selection.length == 0) return; - final PeerInfo info = findPeerInfo(selection[0]); - if (info == null) return; - if (!(info.peer instanceof TCFUserDefPeer)) return; - Protocol.invokeLater(new Runnable() { - public void run() { - ((TCFUserDefPeer)info.peer).dispose(); - TCFUserDefPeer.savePeers(); - } - }); + private void createLocalExeFileGroup(Composite parent) { + Composite comp = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + layout.marginHeight = 0; + layout.marginWidth = 0; + comp.setLayout(layout); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + comp.setLayoutData(gd); + + Label program_label = new Label(comp, SWT.NONE); + program_label.setText("Local File Path:"); + gd = new GridData(); + gd.horizontalSpan = 3; + program_label.setLayoutData(gd); + + local_program_text = new Text(comp, SWT.SINGLE | SWT.BORDER); + local_program_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + local_program_text.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent evt) { + updateLaunchConfigurationDialog(); } }); - - createVerticalSpacer(composite, 20); - final Button button_test = new Button(composite, SWT.PUSH); - button_test.setText("Run &Tests"); - button_test.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); - button_test.addSelectionListener(new SelectionAdapter() { + Button search_button = createPushButton(comp, "Search...", null); + search_button.addSelectionListener(new SelectionAdapter() { @Override - public void widgetSelected(SelectionEvent e) { - TreeItem[] selection = peer_tree.getSelection(); - if (selection.length > 0) { - assert selection.length == 1; - runDiagnostics(selection[0], false); - } + public void widgetSelected(SelectionEvent evt) { + handleSearchButtonSelected(); + updateLaunchConfigurationDialog(); } }); - final Button button_loop = new Button(composite, SWT.PUSH); - button_loop.setText("Tests &Loop"); - button_loop.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); - button_loop.addSelectionListener(new SelectionAdapter() { + Button browse_button = createPushButton(comp, "Browse...", null); + browse_button.addSelectionListener(new SelectionAdapter() { @Override - public void widgetSelected(SelectionEvent e) { - TreeItem[] selection = peer_tree.getSelection(); - if (selection.length > 0) { - assert selection.length == 1; - runDiagnostics(selection[0], true); - } + public void widgetSelected(SelectionEvent evt) { + handleBinaryBrowseButtonSelected(); + updateLaunchConfigurationDialog(); } }); - - update_peer_buttons = new Runnable() { - - public void run() { - PeerInfo info = null; - TreeItem[] selection = peer_tree.getSelection(); - if (selection.length > 0) info = findPeerInfo(selection[0]); - button_edit.setEnabled(info != null); - button_remove.setEnabled(info != null && info.peer instanceof TCFUserDefPeer); - button_test.setEnabled(info != null); - button_loop.setEnabled(info != null); - } - }; - update_peer_buttons.run(); } - private void createProgramGroup(Composite parent) { - display = parent.getDisplay(); - - Font font = parent.getFont(); + private void createRemoteExeFileGroup(Composite parent) { + Composite comp = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.marginHeight = 0; + layout.marginWidth = 0; + comp.setLayout(layout); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + comp.setLayoutData(gd); - Group group = new Group(parent, SWT.NONE); - GridLayout top_layout = new GridLayout(); - group.setLayout(top_layout); - group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - group.setFont(font); - group.setText("Program"); + Label program_label = new Label(comp, SWT.NONE); + program_label.setText("Remote File Path:"); + gd = new GridData(); + gd.horizontalSpan = 3; + program_label.setLayoutData(gd); - program_text = new Text(group, SWT.SINGLE | SWT.BORDER); - program_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - program_text.setFont(font); - program_text.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { + remote_program_text = new Text(comp, SWT.SINGLE | SWT.BORDER); + remote_program_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + remote_program_text.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent evt) { updateLaunchConfigurationDialog(); } }); } + + private void createWorkingDirGroup(Composite comp) { + Group group = new Group(comp, SWT.NONE); + GridLayout layout = new GridLayout(); + group.setLayout(layout); + group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + group.setText("Working directory"); + + working_dir_text = new Text(group, SWT.SINGLE | SWT.BORDER); + working_dir_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + default_dir_button = new Button(group, SWT.CHECK); + default_dir_button.setText("Use default"); + default_dir_button.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false)); + } - @Override - public void dispose() { - Protocol.invokeAndWait(new Runnable() { - public void run() { - for (Iterator<LocatorListener> i = listeners.keySet().iterator(); i.hasNext();) { - LocatorListener listener = i.next(); - listeners.get(listener).removeListener(listener); + private ITCFLaunchContext getLaunchContext(IProject project) { + try { + IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(Activator.PLUGIN_ID, "launch_context"); + IExtension[] extensions = point.getExtensions(); + for (int i = 0; i < extensions.length; i++) { + try { + Bundle bundle = Platform.getBundle(extensions[i].getNamespaceIdentifier()); + bundle.start(); + IConfigurationElement[] e = extensions[i].getConfigurationElements(); + for (int j = 0; j < e.length; j++) { + String nm = e[j].getName(); + if (nm.equals("class")) { //$NON-NLS-1$ + Class<?> c = bundle.loadClass(e[j].getAttribute("name")); //$NON-NLS-1$ + ITCFLaunchContext launch_context = (ITCFLaunchContext)c.newInstance(); + if (project != null) { + if (launch_context.isSupportedProject(project)) return launch_context; + } + else { + if (launch_context.isActive()) return launch_context; + } + } + } + } + catch (Throwable x) { + Activator.log("Cannot access launch context extension points", x); } - listeners.clear(); - display = null; } - }); - super.dispose(); + } + catch (Exception x) { + Activator.log("Cannot access launch context extension points", x); + } + return null; } - public String getName() { - return "Main"; + private void createTerminalOption(Composite parent, int colSpan) { + Composite terminal_comp = new Composite(parent, SWT.NONE); + GridLayout terminal_layout = new GridLayout(); + terminal_layout.numColumns = 1; + terminal_layout.marginHeight = 0; + terminal_layout.marginWidth = 0; + terminal_comp.setLayout(terminal_layout); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = colSpan; + terminal_comp.setLayoutData(gd); + + terminal_button = createCheckButton(terminal_comp, "Use Terminal"); + terminal_button.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent evt) { + updateLaunchConfigurationDialog(); + } + }); + terminal_button.setEnabled(true); } - - @Override - public Image getImage() { - return ImageCache.getImage(ImageCache.IMG_TCF); + + public void initializeFrom(ILaunchConfiguration config) { + updateProjectFromConfig(config); + updateLocalProgramFromConfig(config); + updateRemoteProgramFromConfig(config); + updateTerminalFromConfig(config); + updateWorkingDirFromConfig(config); } - public void initializeFrom(ILaunchConfiguration configuration) { + private void updateTerminalFromConfig(ILaunchConfiguration config) { + boolean use_terminal = true; try { - String id = configuration.getAttribute( - TCFLaunchDelegate.ATTR_PEER_ID, (String)null); - if (id != null) { - peer_id_text.setText(id); - TreeItem item = findItem(findPeerInfo(id)); - if (item != null) { - peer_tree.setSelection(item); - update_peer_buttons.run(); - } - } - program_text.setText(configuration.getAttribute( - TCFLaunchDelegate.ATTR_PROGRAM_FILE, "")); //$NON-NLS-1$ + use_terminal = config.getAttribute(TCFLaunchDelegate.ATTR_USE_TERMINAL, true); } catch (CoreException e) { - setErrorMessage(e.getMessage()); + Activator.log(e); } + terminal_button.setSelection(use_terminal); } - public boolean isValid(ILaunchConfiguration launchConfig) { - String id = peer_id_text.getText().trim(); - if (id.length() == 0) { - setErrorMessage("Specify a target ID"); - return false; + private void updateProjectFromConfig(ILaunchConfiguration config) { + String project_name = ""; + try { + project_name = config.getAttribute(TCFLaunchDelegate.ATTR_PROJECT_NAME, ""); } - setErrorMessage(null); - return super.isValid(launchConfig); + catch (CoreException ce) { + Activator.log(ce); + } + project_text.setText(project_name); } - public void performApply(ILaunchConfigurationWorkingCopy configuration) { - String id = peer_id_text.getText().trim(); - if (id.length() == 0) id = null; - configuration.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, id); - String nm = program_text.getText().trim(); - if (nm.length() == 0) nm = null; - configuration.setAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, nm); + private void updateLocalProgramFromConfig(ILaunchConfiguration config) { + String program_name = ""; + try { + program_name = config.getAttribute(TCFLaunchDelegate.ATTR_LOCAL_PROGRAM_FILE, ""); + } + catch (CoreException ce) { + Activator.log(ce); + } + local_program_text.setText(program_name); } - public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { - configuration.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, "TCFLocal"); - configuration.setAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, (String)null); + private void updateRemoteProgramFromConfig(ILaunchConfiguration config) { + String program_name = ""; + try { + program_name = config.getAttribute(TCFLaunchDelegate.ATTR_REMOTE_PROGRAM_FILE, ""); + } + catch (CoreException ce) { + Activator.log(ce); + } + remote_program_text.setText(program_name); } - - private LocatorListener createLocatorListener(PeerInfo peer, ILocator locator) { - assert Protocol.isDispatchThread(); - Map<String,IPeer> map = locator.getPeers(); - PeerInfo[] buf = new PeerInfo[map.size()]; - int n = 0; - for (IPeer p : map.values()) { - PeerInfo info = new PeerInfo(); - info.parent = peer; - info.index = n; - info.id = p.getID(); - info.attrs = new HashMap<String,String>(p.getAttributes()); - info.peer = p; - buf[n++] = info; + + private void updateWorkingDirFromConfig(ILaunchConfiguration config) { + String name = ""; + try { + name = config.getAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, ""); //$NON-NLS-1$ + } + catch (CoreException ce) { + Activator.log(ce); } - LocatorListener listener = new LocatorListener(peer); - listeners.put(listener, locator); - locator.addListener(listener); - setChildren(peer, null, buf); - return listener; + working_dir_text.setText(name); } - - private boolean canHaveChildren(PeerInfo parent) { - return parent == peer_info || parent.attrs.get(IPeer.ATTR_PROXY) != null; + + private IProject getProject() { + String name = project_text.getText().trim(); + if (name.length() == 0) return null; + return ResourcesPlugin.getWorkspace().getRoot().getProject(name); } - - private void loadChildren(final PeerInfo parent) { - assert Thread.currentThread() == display.getThread(); - if (parent.children_pending) return; - if (!canHaveChildren(parent)) { - if (parent.children == null) updateItems(parent); + + public void performApply(ILaunchConfigurationWorkingCopy config) { + config.setAttribute(TCFLaunchDelegate.ATTR_PROJECT_NAME, project_text.getText()); + config.setAttribute(TCFLaunchDelegate.ATTR_LOCAL_PROGRAM_FILE, local_program_text.getText()); + config.setAttribute(TCFLaunchDelegate.ATTR_REMOTE_PROGRAM_FILE, remote_program_text.getText()); + config.setAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, working_dir_text.getText()); + config.setAttribute(TCFLaunchDelegate.ATTR_USE_TERMINAL, terminal_button.getSelection()); + } + + /** + * Show a dialog that lists all executable files in currently selected project. + */ + private void handleSearchButtonSelected() { + IProject project = getProject(); + if (project == null) { + MessageDialog.openInformation(getShell(), + "Project required", + "Enter project before searching for program"); return; } - parent.children_pending = true; - Protocol.invokeAndWait(new Runnable() { - public void run() { - if (parent == peer_info) { - createLocatorListener(peer_info, Protocol.getLocator()); - } - else { - final IChannel channel = parent.peer.openChannel(); - final LocatorListener[] listener = new LocatorListener[1]; - channel.addChannelListener(new IChannelListener() { - public void congestionLevel(int level) { - } - public void onChannelClosed(Throwable error) { - setChildren(parent, error, new PeerInfo[0]); - if (listener[0] != null) listeners.remove(listener[0]); - } - public void onChannelOpened() { - ILocator locator = channel.getRemoteService(ILocator.class); - if (locator == null) { - channel.close(); - } - else { - listener[0] = createLocatorListener(parent, locator); - } - } - }); - } - } - }); + ITCFLaunchContext launch_context = getLaunchContext(project); + if (launch_context == null) return; + String path = launch_context.chooseBinary(getShell(), project); + if (path != null) local_program_text.setText(path); } - - private void setChildren(final PeerInfo parent, final Throwable error, final PeerInfo[] children) { - assert Protocol.isDispatchThread(); - display.asyncExec(new Runnable() { - public void run() { - parent.children_pending = false; - parent.children = children; - parent.children_error = error; - updateItems(parent); - } - }); + + /** + * Show a dialog that lets the user select a project. This in turn provides context for the main + * type, allowing the user to key a main type name, or constraining the search for main types to + * the specified project. + */ + private void handleBinaryBrowseButtonSelected() { + FileDialog file_dialog = new FileDialog(getShell(), SWT.NONE); + file_dialog.setFileName(local_program_text.getText()); + String path = file_dialog.open(); + if (path != null) local_program_text.setText(path); } - - private void updateItems(PeerInfo parent) { - assert Thread.currentThread() == display.getThread(); - if (!canHaveChildren(parent)) { - parent.children = new PeerInfo[0]; - parent.children_error = null; - } - PeerInfo[] arr = parent.children; - TreeItem[] items = null; - if (arr == 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; - item.setItemCount(1); - items = item.getItems(); - } - if (parent.children_pending) { - items[0].setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND)); - items[0].setText("Loading..."); - } - else if (parent.children_error != null) { - String msg = parent.children_error.getMessage().replace('\n', ' '); - items[0].setForeground(display.getSystemColor(SWT.COLOR_RED)); - items[0].setText(msg); - } - else { - items[0].setForeground(display.getSystemColor(SWT.COLOR_RED)); - items[0].setText("Invalid children list"); - } - int n = peer_tree.getColumnCount(); - for (int i = 1; i < n; i++) items[0].setText(i, ""); - items[0].setItemCount(0); + + /** + * Show a dialog that lets the user select a project. This in turn provides context for the main + * type, allowing the user to key a main type name, or constraining the search for main types to + * the specified project. + */ + private void handleProjectButtonSelected() { + try { + IProject project = chooseProject(); + if (project == null) return; + project_text.setText(project.getName()); } - else { - if (parent == peer_info) { - peer_tree.setItemCount(arr.length); - items = peer_tree.getItems(); - } - else { - TreeItem item = findItem(parent); - if (item == null) return; - item.setItemCount(arr.length); - items = item.getItems(); - } - assert items.length == arr.length; - for (int i = 0; i < items.length; i++) fillItem(items[i], arr[i]); - String id = peer_id_text.getText(); - TreeItem item = findItem(findPeerInfo(id)); - if (item != null) { - peer_tree.setSelection(item); - update_peer_buttons.run(); - } + catch (Exception e) { + Activator.log("Cannot get project description", e); } } - private 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 PeerInfo findPeerInfo(String path) { - int i = path.lastIndexOf('/'); - String id = null; - PeerInfo[] arr = null; - if (i < 0) { - arr = peer_info.children; - id = path; - } - else { - PeerInfo p = findPeerInfo(path.substring(0, i)); - if (p == null) return null; - arr = p.children; - id = path.substring(i + 1); + /** + * Show project list dialog and return the first selected project, or null. + */ + private IProject chooseProject() { + try { + IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); + ILabelProvider label_provider = new LabelProvider() { + + @Override + public String getText(Object element) { + if (element == null) return ""; + return ((IProject)element).getName(); + } + }; + ElementListSelectionDialog dialog = new ElementListSelectionDialog(getShell(), label_provider); + dialog.setTitle("Project Selection"); + dialog.setMessage("Choose project to constrain search for program"); + dialog.setElements(projects); + + IProject cProject = getProject(); + if (cProject != null) dialog.setInitialSelections(new Object[]{cProject}); + if (dialog.open() == Window.OK) return (IProject)dialog.getFirstResult(); } - if (arr == null) return null; - for (int n = 0; n < arr.length; n++) { - if (arr[n].id.equals(id)) return arr[n]; + catch (Exception e) { + Activator.log("Cannot show project list dialog", e); } return null; } - - private TreeItem findItem(PeerInfo info) { - if (info == null) return null; - assert info.parent != null; - if (info.parent == peer_info) { - return peer_tree.getItem(info.index); - } - TreeItem i = findItem(info.parent); - if (i == null) return null; - peer_tree.showItem(i); - return i.getItem(info.index); - } - - private void runDiagnostics(TreeItem item, boolean loop) { - final Shell shell = new Shell(getShell(), SWT.TITLE | SWT.PRIMARY_MODAL); - GridLayout layout = new GridLayout(); - layout.verticalSpacing = 0; - layout.numColumns = 2; - shell.setLayout(layout); - shell.setText("Running Diagnostics..."); - CLabel label = new CLabel(shell, SWT.NONE); - label.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false)); - label.setText("Running Diagnostics..."); - final TCFTestSuite[] test = new TCFTestSuite[1]; - Button button_cancel = new Button(shell, SWT.PUSH); - button_cancel.setText("&Cancel"); - button_cancel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false)); - button_cancel.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - Protocol.invokeLater(new Runnable() { - public void run() { - if (test[0] != null) test[0].cancel(); - } - }); + + @Override + public boolean isValid(ILaunchConfiguration config) { + setErrorMessage(null); + setMessage(null); + + String project_name = project_text.getText().trim(); + if (project_name.length() != 0) { + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(project_name); + if (!project.exists()) { + setErrorMessage("Project does not exist"); + return false; } - }); - createVerticalSpacer(shell, 0); - ProgressBar bar = new ProgressBar(shell, SWT.HORIZONTAL); - bar.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 2, 1)); - shell.setDefaultButton(button_cancel); - shell.pack(); - shell.setSize(483, shell.getSize().y); - Rectangle rc0 = getShell().getBounds(); - Rectangle rc1 = shell.getBounds(); - shell.setLocation(rc0.x + (rc0.width - rc1.width) / 2, rc0.y + (rc0.height - rc1.height) / 2); - shell.setVisible(true); - runDiagnostics(item, loop, test, shell, label, bar); - } - - private void runDiagnostics(final TreeItem item, final boolean loop, final TCFTestSuite[] test, - final Shell shell, final CLabel label, final ProgressBar bar) { - final TCFTestSuite.TestListener done = new TCFTestSuite.TestListener() { - private String last_text = ""; - private int last_count = 0; - private int last_total = 0; - public void progress(final String label_text, final int count_done, final int count_total) { - assert test[0] != null; - if ((label_text == null || last_text.equals(label_text)) && - last_total == count_total && - (count_done - last_count) / (float)count_total < 0.02f) return; - if (label_text != null) last_text = label_text; - last_total = count_total; - last_count = count_done; - display.asyncExec(new Runnable() { - public void run() { - label.setText(last_text); - bar.setMinimum(0); - bar.setMaximum(last_total); - bar.setSelection(last_count); - } - }); + if (!project.isOpen()) { + setErrorMessage("Project must be opened"); + return false; } - public void done(final Collection<Throwable> errors) { - assert test[0] != null; - final boolean b = test[0].isCanceled(); - test[0] = null; - display.asyncExec(new Runnable() { - public void run() { - if (errors.size() > 0) { - shell.dispose(); - new TestErrorsDialog(getControl().getShell(), - ImageCache.getImage(ImageCache.IMG_TCF), errors).open(); - } - else if (loop && !b && display != null) { - runDiagnostics(item, true, test, shell, label, bar); - } - else { - shell.dispose(); - } - } - }); + } + String local_name = local_program_text.getText().trim(); + if (local_name.equals(".") || local_name.equals("..")) { //$NON-NLS-1$ //$NON-NLS-2$ + setErrorMessage("Invalid local program name"); + return false; + } + String remote_name = remote_program_text.getText().trim(); + if (remote_name.equals(".") || remote_name.equals("..")) { //$NON-NLS-1$ //$NON-NLS-2$ + setErrorMessage("Invalid remote program name"); + return false; + } + if (local_name.length() > 0) { + IProject project = getProject(); + IPath program_path = new Path(local_name); + if (!program_path.isAbsolute()) { + if (project == null || !project.getFile(local_name).exists()) { + setErrorMessage("Program does not exist"); + return false; + } + program_path = project.getFile(local_name).getLocation(); } - }; - final PeerInfo info = findPeerInfo(item); - Protocol.invokeLater(new Runnable() { - public void run() { + else { + File file = program_path.toFile(); + if (!file.exists()) { + setErrorMessage("Program file does not exist"); + return false; + } + if (file.isDirectory()) { + setErrorMessage("Program path is directory name"); + return false; + } + } + if (project != null) { try { - test[0] = new TCFTestSuite(info.peer, done); + ITCFLaunchContext launch_context = getLaunchContext(project); + if (launch_context != null && !launch_context.isBinary(project, program_path)) { + setErrorMessage("Program is not a recongnized executable"); + return false; + } } - catch (Throwable x) { - ArrayList<Throwable> errors = new ArrayList<Throwable>(); - errors.add(x); - done.done(errors); + catch (CoreException e) { + Activator.log(e); + setErrorMessage(e.getLocalizedMessage()); + return false; } } - }); + } + return true; } - - private void fillItem(TreeItem item, PeerInfo 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); - 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); + + public void setDefaults(ILaunchConfigurationWorkingCopy config) { + config.setAttribute(TCFLaunchDelegate.ATTR_PROJECT_NAME, ""); + config.setAttribute(TCFLaunchDelegate.ATTR_USE_TERMINAL, true); + ITCFLaunchContext launch_context = getLaunchContext(null); + if (launch_context != null) launch_context.setDefaults(getLaunchConfigurationDialog(), config); } - - private String getPath(PeerInfo info) { - if (info.parent == peer_info) return info.id; - return getPath(info.parent) + "/" + info.id; + + public String getName() { + return "Main"; } - - private String getImageName(PeerInfo info) { - return ImageCache.IMG_TCF; + + @Override + public Image getImage() { + return ImageCache.getImage(ImageCache.IMG_TCF); } } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTabGroup.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTabGroup.java index 39c53c999..c8676502b 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTabGroup.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTabGroup.java @@ -25,6 +25,7 @@ public class TCFTabGroup extends AbstractLaunchConfigurationTabGroup { public void createTabs(ILaunchConfigurationDialog dialog, String mode) { setTabs(new ILaunchConfigurationTab[] { new TCFMainTab(), + new TCFTargetTab(), new TCFArgumentsTab(), new EnvironmentTab(), new SourceLookupTab(), diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTargetTab.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTargetTab.java new file mode 100644 index 000000000..6d0bace5d --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTargetTab.java @@ -0,0 +1,801 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 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.debug.ui.launch; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CLabel; +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.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.ProgressBar; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.tm.internal.tcf.debug.launch.TCFLaunchDelegate; +import org.eclipse.tm.internal.tcf.debug.launch.TCFUserDefPeer; +import org.eclipse.tm.internal.tcf.debug.tests.TCFTestSuite; +import org.eclipse.tm.internal.tcf.debug.ui.ImageCache; +import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IPeer; +import org.eclipse.tm.tcf.protocol.Protocol; +import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener; +import org.eclipse.tm.tcf.services.ILocator; + + +/** + * Launch configuration dialog tab to specify the Target Communication Framework + * configuration. + */ +public class TCFTargetTab extends AbstractLaunchConfigurationTab { + + private Text peer_id_text; + private Tree peer_tree; + private Runnable update_peer_buttons; + private final PeerInfo peer_info = new PeerInfo(); + private Display display; + + private final Map<LocatorListener,ILocator> listeners = new HashMap<LocatorListener,ILocator>(); + + private static class PeerInfo { + PeerInfo parent; + int index; + String id; + Map<String,String> attrs; + PeerInfo[] children; + boolean children_pending; + Throwable children_error; + IPeer peer; + } + + 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; + 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; + loadChildren(arr[i]); + 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)) { + 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) { + loadChildren(arr[i]); + } + break; + } + } + } + }); + } + } + + public void createControl(Composite parent) { + display = parent.getDisplay(); + assert display != null; + + Font font = parent.getFont(); + Composite comp = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(1, true); + comp.setLayout(layout); + comp.setFont(font); + + GridData gd = new GridData(GridData.FILL_BOTH); + comp.setLayoutData(gd); + setControl(comp); + + createTargetGroup(comp); + } + + private void createTargetGroup(Composite parent) { + Font font = parent.getFont(); + + Group group = new Group(parent, SWT.NONE); + GridLayout top_layout = new GridLayout(); + top_layout.verticalSpacing = 0; + top_layout.numColumns = 2; + group.setLayout(top_layout); + group.setLayoutData(new GridData(GridData.FILL_BOTH)); + group.setFont(font); + group.setText("Target"); + + createVerticalSpacer(group, top_layout.numColumns); + + Label host_label = new Label(group, SWT.NONE); + host_label.setText("Target ID:"); + host_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); + host_label.setFont(font); + + peer_id_text = new Text(group, SWT.SINGLE | SWT.BORDER); + peer_id_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + peer_id_text.setFont(font); + peer_id_text.setEditable(false); + peer_id_text.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent e) { + updateLaunchConfigurationDialog(); + } + }); + + createVerticalSpacer(group, top_layout.numColumns); + + Label peer_label = new Label(group, SWT.NONE); + peer_label.setText("&Available targets:"); + peer_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); + peer_label.setFont(font); + + loadChildren(peer_info); + createPeerListArea(group); + } + + private void createPeerListArea(Composite parent) { + Font font = parent.getFont(); + Composite composite = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + composite.setFont(font); + composite.setLayout(layout); + composite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1)); + + peer_tree = new Tree(composite, SWT.VIRTUAL | SWT.BORDER | SWT.SINGLE); + GridData gd = new GridData(GridData.FILL_BOTH); + gd.minimumHeight = 150; + gd.minimumWidth = 470; + 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) { + PeerInfo parent = findPeerInfo(item.getParentItem()); + if (parent == null) { + item.setText("Invalid"); + } + else { + if (parent.children == null || parent.children_error != null) { + loadChildren(parent); + } + updateItems(parent); + } + } + else { + fillItem(item, info); + } + } + }); + peer_tree.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetDefaultSelected(SelectionEvent e) { + TreeItem[] selections = peer_tree.getSelection(); + if (selections.length == 0) return; + assert selections.length == 1; + final PeerInfo info = findPeerInfo(selections[0]); + if (info == null) return; + new PeerPropsDialog(getShell(), getImage(), info.attrs, + info.peer instanceof TCFUserDefPeer).open(); + if (!(info.peer instanceof TCFUserDefPeer)) return; + Protocol.invokeLater(new Runnable() { + public void run() { + ((TCFUserDefPeer)info.peer).updateAttributes(info.attrs); + TCFUserDefPeer.savePeers(); + } + }); + } + @Override + public void widgetSelected(SelectionEvent e) { + update_peer_buttons.run(); + TreeItem[] selections = peer_tree.getSelection(); + if (selections.length > 0) { + assert selections.length == 1; + PeerInfo info = findPeerInfo(selections[0]); + if (info != null) peer_id_text.setText(getPath(info)); + } + } + }); + + createPeerButtons(composite); + } + + private void createPeerButtons(Composite parent) { + Font font = parent.getFont(); + Composite composite = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + composite.setFont(font); + composite.setLayout(layout); + composite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL)); + + final Button button_new = new Button(composite, SWT.PUSH); + button_new.setText("N&ew..."); + button_new.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); + button_new.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + final Map<String,String> attrs = new HashMap<String,String>(); + if (new PeerPropsDialog(getShell(), getImage(), attrs, true).open() != Window.OK) return; + Protocol.invokeLater(new Runnable() { + public void run() { + new TCFUserDefPeer(attrs); + TCFUserDefPeer.savePeers(); + } + }); + } + }); + + final Button button_edit = new Button(composite, SWT.PUSH); + button_edit.setText("E&dit..."); + button_edit.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); + button_edit.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TreeItem[] selection = peer_tree.getSelection(); + if (selection.length == 0) return; + final PeerInfo info = findPeerInfo(selection[0]); + if (info == null) return; + if (new PeerPropsDialog(getShell(), getImage(), info.attrs, + info.peer instanceof TCFUserDefPeer).open() != Window.OK) return; + if (!(info.peer instanceof TCFUserDefPeer)) return; + Protocol.invokeLater(new Runnable() { + public void run() { + ((TCFUserDefPeer)info.peer).updateAttributes(info.attrs); + TCFUserDefPeer.savePeers(); + } + }); + } + }); + + final Button button_remove = new Button(composite, SWT.PUSH); + button_remove.setText("&Remove"); + button_remove.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); + button_remove.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TreeItem[] selection = peer_tree.getSelection(); + if (selection.length == 0) return; + final PeerInfo info = findPeerInfo(selection[0]); + if (info == null) return; + if (!(info.peer instanceof TCFUserDefPeer)) return; + Protocol.invokeLater(new Runnable() { + public void run() { + ((TCFUserDefPeer)info.peer).dispose(); + TCFUserDefPeer.savePeers(); + } + }); + } + }); + + createVerticalSpacer(composite, 20); + + final Button button_test = new Button(composite, SWT.PUSH); + button_test.setText("Run &Tests"); + button_test.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); + button_test.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TreeItem[] selection = peer_tree.getSelection(); + if (selection.length > 0) { + assert selection.length == 1; + runDiagnostics(selection[0], false); + } + } + }); + + final Button button_loop = new Button(composite, SWT.PUSH); + button_loop.setText("Tests &Loop"); + button_loop.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); + button_loop.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TreeItem[] selection = peer_tree.getSelection(); + if (selection.length > 0) { + assert selection.length == 1; + runDiagnostics(selection[0], true); + } + } + }); + + update_peer_buttons = new Runnable() { + + public void run() { + PeerInfo info = null; + TreeItem[] selection = peer_tree.getSelection(); + if (selection.length > 0) info = findPeerInfo(selection[0]); + button_edit.setEnabled(info != null); + button_remove.setEnabled(info != null && info.peer instanceof TCFUserDefPeer); + button_test.setEnabled(info != null); + button_loop.setEnabled(info != null); + } + }; + update_peer_buttons.run(); + } + + @Override + public void dispose() { + Protocol.invokeAndWait(new Runnable() { + public void run() { + for (Iterator<LocatorListener> i = listeners.keySet().iterator(); i.hasNext();) { + LocatorListener listener = i.next(); + listeners.get(listener).removeListener(listener); + } + listeners.clear(); + display = null; + } + }); + super.dispose(); + } + + public String getName() { + return "Target"; + } + + @Override + public Image getImage() { + return ImageCache.getImage(ImageCache.IMG_TARGET_TAB); + } + + public void initializeFrom(ILaunchConfiguration configuration) { + try { + String id = configuration.getAttribute( + TCFLaunchDelegate.ATTR_PEER_ID, (String)null); + if (id != null) { + peer_id_text.setText(id); + TreeItem item = findItem(findPeerInfo(id)); + if (item != null) { + peer_tree.setSelection(item); + update_peer_buttons.run(); + } + } + } + catch (CoreException e) { + setErrorMessage(e.getMessage()); + } + } + + public boolean isValid(ILaunchConfiguration launchConfig) { + String id = peer_id_text.getText().trim(); + if (id.length() == 0) { + setErrorMessage("Specify a target ID"); + return false; + } + setErrorMessage(null); + return super.isValid(launchConfig); + } + + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + String id = peer_id_text.getText().trim(); + if (id.length() == 0) id = null; + configuration.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, id); + } + + public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { + configuration.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, "TCFLocal"); + } + + private LocatorListener createLocatorListener(PeerInfo peer, ILocator locator) { + assert Protocol.isDispatchThread(); + Map<String,IPeer> map = locator.getPeers(); + PeerInfo[] buf = new PeerInfo[map.size()]; + int n = 0; + for (IPeer p : map.values()) { + PeerInfo info = new PeerInfo(); + info.parent = peer; + info.index = n; + info.id = p.getID(); + info.attrs = new HashMap<String,String>(p.getAttributes()); + info.peer = p; + buf[n++] = info; + } + LocatorListener listener = new LocatorListener(peer); + listeners.put(listener, locator); + locator.addListener(listener); + setChildren(peer, null, buf); + return listener; + } + + 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; + if (!canHaveChildren(parent)) { + if (parent.children == null) updateItems(parent); + return; + } + parent.children_pending = true; + Protocol.invokeAndWait(new Runnable() { + public void run() { + if (parent == peer_info) { + createLocatorListener(peer_info, Protocol.getLocator()); + } + else { + final IChannel channel = parent.peer.openChannel(); + final LocatorListener[] listener = new LocatorListener[1]; + channel.addChannelListener(new IChannelListener() { + public void congestionLevel(int level) { + } + public void onChannelClosed(Throwable error) { + setChildren(parent, error, new PeerInfo[0]); + if (listener[0] != null) listeners.remove(listener[0]); + } + public void onChannelOpened() { + ILocator locator = channel.getRemoteService(ILocator.class); + if (locator == null) { + channel.close(); + } + else { + listener[0] = createLocatorListener(parent, locator); + } + } + }); + } + } + }); + } + + private void setChildren(final PeerInfo parent, final Throwable error, final PeerInfo[] children) { + assert Protocol.isDispatchThread(); + display.asyncExec(new Runnable() { + public void run() { + parent.children_pending = false; + parent.children = children; + parent.children_error = error; + updateItems(parent); + } + }); + } + + private void updateItems(PeerInfo parent) { + if (display == null) return; + assert Thread.currentThread() == display.getThread(); + if (!canHaveChildren(parent)) { + parent.children = new PeerInfo[0]; + parent.children_error = null; + } + PeerInfo[] arr = parent.children; + TreeItem[] items = null; + if (arr == 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; + item.setItemCount(1); + items = item.getItems(); + } + if (parent.children_pending) { + items[0].setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND)); + items[0].setText("Loading..."); + } + else if (parent.children_error != null) { + String msg = parent.children_error.getMessage().replace('\n', ' '); + items[0].setForeground(display.getSystemColor(SWT.COLOR_RED)); + items[0].setText(msg); + } + else { + items[0].setForeground(display.getSystemColor(SWT.COLOR_RED)); + items[0].setText("Invalid children list"); + } + int n = peer_tree.getColumnCount(); + for (int i = 1; i < n; i++) items[0].setText(i, ""); + items[0].setItemCount(0); + } + else { + if (parent == peer_info) { + peer_tree.setItemCount(arr.length); + items = peer_tree.getItems(); + } + else { + TreeItem item = findItem(parent); + if (item == null) return; + item.setItemCount(arr.length); + items = item.getItems(); + } + assert items.length == arr.length; + for (int i = 0; i < items.length; i++) fillItem(items[i], arr[i]); + String id = peer_id_text.getText(); + TreeItem item = findItem(findPeerInfo(id)); + if (item != null) { + peer_tree.setSelection(item); + update_peer_buttons.run(); + } + } + } + + private 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 PeerInfo findPeerInfo(String path) { + int i = path.lastIndexOf('/'); + String id = null; + PeerInfo[] arr = null; + if (i < 0) { + arr = peer_info.children; + id = path; + } + else { + PeerInfo p = findPeerInfo(path.substring(0, i)); + if (p == null) return null; + arr = p.children; + id = path.substring(i + 1); + } + if (arr == null) return null; + for (int n = 0; n < arr.length; n++) { + if (arr[n].id.equals(id)) return arr[n]; + } + return null; + } + + private TreeItem findItem(PeerInfo info) { + if (info == null) return null; + assert info.parent != null; + if (info.parent == peer_info) { + return peer_tree.getItem(info.index); + } + TreeItem i = findItem(info.parent); + if (i == null) return null; + peer_tree.showItem(i); + return i.getItem(info.index); + } + + private void runDiagnostics(TreeItem item, boolean loop) { + final Shell shell = new Shell(getShell(), SWT.TITLE | SWT.PRIMARY_MODAL); + GridLayout layout = new GridLayout(); + layout.verticalSpacing = 0; + layout.numColumns = 2; + shell.setLayout(layout); + shell.setText("Running Diagnostics..."); + CLabel label = new CLabel(shell, SWT.NONE); + label.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false)); + label.setText("Running Diagnostics..."); + final TCFTestSuite[] test = new TCFTestSuite[1]; + Button button_cancel = new Button(shell, SWT.PUSH); + button_cancel.setText("&Cancel"); + button_cancel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false)); + button_cancel.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + Protocol.invokeLater(new Runnable() { + public void run() { + if (test[0] != null) test[0].cancel(); + } + }); + } + }); + createVerticalSpacer(shell, 0); + ProgressBar bar = new ProgressBar(shell, SWT.HORIZONTAL); + bar.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 2, 1)); + shell.setDefaultButton(button_cancel); + shell.pack(); + shell.setSize(483, shell.getSize().y); + Rectangle rc0 = getShell().getBounds(); + Rectangle rc1 = shell.getBounds(); + shell.setLocation(rc0.x + (rc0.width - rc1.width) / 2, rc0.y + (rc0.height - rc1.height) / 2); + shell.setVisible(true); + runDiagnostics(item, loop, test, shell, label, bar); + } + + private void runDiagnostics(final TreeItem item, final boolean loop, final TCFTestSuite[] test, + final Shell shell, final CLabel label, final ProgressBar bar) { + final TCFTestSuite.TestListener done = new TCFTestSuite.TestListener() { + private String last_text = ""; + private int last_count = 0; + private int last_total = 0; + public void progress(final String label_text, final int count_done, final int count_total) { + assert test[0] != null; + if ((label_text == null || last_text.equals(label_text)) && + last_total == count_total && + (count_done - last_count) / (float)count_total < 0.02f) return; + if (label_text != null) last_text = label_text; + last_total = count_total; + last_count = count_done; + display.asyncExec(new Runnable() { + public void run() { + label.setText(last_text); + bar.setMinimum(0); + bar.setMaximum(last_total); + bar.setSelection(last_count); + } + }); + } + public void done(final Collection<Throwable> errors) { + assert test[0] != null; + final boolean b = test[0].isCanceled(); + test[0] = null; + display.asyncExec(new Runnable() { + public void run() { + if (errors.size() > 0) { + shell.dispose(); + new TestErrorsDialog(getControl().getShell(), + ImageCache.getImage(ImageCache.IMG_TCF), errors).open(); + } + else if (loop && !b && display != null) { + runDiagnostics(item, true, test, shell, label, bar); + } + else { + shell.dispose(); + } + } + }); + } + }; + final PeerInfo info = findPeerInfo(item); + Protocol.invokeLater(new Runnable() { + public void run() { + try { + test[0] = new TCFTestSuite(info.peer, done); + } + catch (Throwable x) { + ArrayList<Throwable> errors = new ArrayList<Throwable>(); + errors.add(x); + done.done(errors); + } + } + }); + } + + private void fillItem(TreeItem item, PeerInfo 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); + 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 getPath(PeerInfo info) { + if (info.parent == peer_info) return info.id; + return getPath(info.parent) + "/" + info.id; + } + + private String getImageName(PeerInfo info) { + return ImageCache.IMG_TARGET_TAB; + } +} diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java index d49c91b12..6c7a232e6 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java @@ -295,24 +295,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider, launch_node.dispose(); launch_node = null; } - final Throwable error = launch.getError(); - if (error != null) launch.setError(null); - display.asyncExec(new Runnable() { - public void run() { - IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); - if (window == null) return; - IDebugView view = (IDebugView)window.getActivePage().findView(IDebugUIConstants.ID_DEBUG_VIEW); - if (view != null) ((StructuredViewer)view.getViewer()).refresh(launch); - if (error != null) { - String msg = error.getLocalizedMessage(); - if (msg == null || msg.length() == 0) msg = error.getClass().getName(); - MessageBox mb = new MessageBox(window.getShell(), SWT.ICON_ERROR | SWT.OK); - mb.setText("TCF Connection Error"); - mb.setMessage("Communication channel is closed.\n" + msg); - mb.open(); - } - } - }); + refreshLaunchView(); assert id2node.size() == 0; } @@ -381,6 +364,9 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider, launch_node.addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); fireModelChanged(); } + else { + refreshLaunchView(); + } } void dispose() { @@ -634,6 +620,37 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider, }); } + private void refreshLaunchView() { + final Throwable error = launch.getError(); + if (error != null) launch.setError(null); + display.asyncExec(new Runnable() { + public void run() { + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) return; + IDebugView view = (IDebugView)window.getActivePage().findView(IDebugUIConstants.ID_DEBUG_VIEW); + if (view != null) ((StructuredViewer)view.getViewer()).refresh(launch); + if (error != null) { + StringBuffer buf = new StringBuffer(); + Throwable err = error; + while (err != null) { + String msg = err.getLocalizedMessage(); + if (msg == null || msg.length() == 0) msg = err.getClass().getName(); + buf.append(msg); + err = err.getCause(); + if (err != null) { + buf.append('\n'); + buf.append("Caused by:\n"); + } + } + MessageBox mb = new MessageBox(window.getShell(), SWT.ICON_ERROR | SWT.OK); + mb.setText("TCF Launch Error"); + mb.setMessage(buf.toString()); + mb.open(); + } + } + }); + } + /** * Open an editor for given editor input. * @param input - IEditorInput representing a source file to be shown in the editor diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/launch/TCFLaunchDelegate.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/launch/TCFLaunchDelegate.java index b25cb9303..84edbff0d 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/launch/TCFLaunchDelegate.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/launch/TCFLaunchDelegate.java @@ -27,9 +27,13 @@ public class TCFLaunchDelegate extends LaunchConfigurationDelegate { public static final String ATTR_PEER_ID = ITCFConstants.ID_TCF_DEBUG_MODEL + ".PeerID", - ATTR_PROGRAM_FILE = ITCFConstants.ID_TCF_DEBUG_MODEL + ".ProgramFile", + ATTR_PROJECT_NAME = ITCFConstants.ID_TCF_DEBUG_MODEL + ".ProjectName", + ATTR_LOCAL_PROGRAM_FILE = ITCFConstants.ID_TCF_DEBUG_MODEL + ".LocalProgramFile", + ATTR_REMOTE_PROGRAM_FILE = ITCFConstants.ID_TCF_DEBUG_MODEL + ".ProgramFile", + ATTR_COPY_TO_REMOTE_FILE = ITCFConstants.ID_TCF_DEBUG_MODEL + ".CopyToRemote", ATTR_PROGRAM_ARGUMENTS = ITCFConstants.ID_TCF_DEBUG_MODEL + ".ProgramArguments", - ATTR_WORKING_DIRECTORY = ITCFConstants.ID_TCF_DEBUG_MODEL + ".WorkingDirectory"; + ATTR_WORKING_DIRECTORY = ITCFConstants.ID_TCF_DEBUG_MODEL + ".WorkingDirectory", + ATTR_USE_TERMINAL = ITCFConstants.ID_TCF_DEBUG_MODEL + ".UseTerminal"; public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException { return new TCFLaunch(configuration, mode); @@ -41,7 +45,7 @@ public class TCFLaunchDelegate extends LaunchConfigurationDelegate { Protocol.invokeLater(new Runnable() { public void run() { try { - String id = configuration.getAttribute(TCFLaunchDelegate.ATTR_PEER_ID, ""); + String id = configuration.getAttribute(ATTR_PEER_ID, ""); IPeer peer = Protocol.getLocator().getPeers().get(id); if (peer == null) throw new IOException("Cannot locate peer " + id); ((TCFLaunch)launch).launchTCF(mode, peer); diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/launch/TCFSourcePathComputerDelegate.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/launch/TCFSourcePathComputerDelegate.java index 357a0de94..76fac6768 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/launch/TCFSourcePathComputerDelegate.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/launch/TCFSourcePathComputerDelegate.java @@ -36,7 +36,7 @@ public class TCFSourcePathComputerDelegate implements ISourcePathComputerDelegat ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException { ISourceContainer sourceContainer = null; - String path = configuration.getAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, (String)null); + String path = configuration.getAttribute(TCFLaunchDelegate.ATTR_LOCAL_PROGRAM_FILE, (String)null); if (path != null) { IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(path)); if (resource != null) { diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java index b7c30a78d..76bb99c13 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java @@ -10,14 +10,22 @@ *******************************************************************************/ package org.eclipse.tm.internal.tcf.debug.model; +import java.io.FileInputStream; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; @@ -31,7 +39,10 @@ import org.eclipse.tm.tcf.protocol.IPeer; import org.eclipse.tm.tcf.protocol.IService; 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.IProcesses; +import org.eclipse.tm.tcf.services.IFileSystem.FileSystemException; +import org.eclipse.tm.tcf.services.IFileSystem.IFileHandle; import org.eclipse.tm.tcf.services.IProcesses.ProcessContext; @@ -155,8 +166,10 @@ public class TCFLaunch extends Launch { Protocol.invokeLater(done); return; } - final String file = cfg.getAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, ""); - if (file.length() == 0) { + final String project = cfg.getAttribute(TCFLaunchDelegate.ATTR_PROJECT_NAME, ""); + final String local_file = cfg.getAttribute(TCFLaunchDelegate.ATTR_LOCAL_PROGRAM_FILE, ""); + final String remote_file = cfg.getAttribute(TCFLaunchDelegate.ATTR_REMOTE_PROGRAM_FILE, ""); + if (local_file.length() == 0 && remote_file.length() == 0) { Protocol.invokeLater(done); return; } @@ -166,36 +179,138 @@ public class TCFLaunch extends Launch { final boolean append = cfg.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true); final boolean attach = mode.equals(ILaunchManager.DEBUG_MODE); final IProcesses ps = channel.getRemoteService(IProcesses.class); - if (ps == null) throw new Exception("Target does not provide Processes service"); - IProcesses.DoneGetEnvironment done_env = new IProcesses.DoneGetEnvironment() { - public void doneGetEnvironment(IToken token, Exception error, Map<String,String> def) { - if (error != null) { - channel.terminate(error); - return; - } - Map<String,String> vars = new HashMap<String,String>(); - if (append) vars.putAll(def); - if (env != null) vars.putAll(env); - ps.start(dir, file, toArgsArray(file, args), vars, attach, new IProcesses.DoneStart() { - public void doneStart(IToken token, Exception error, ProcessContext process) { + Runnable r = new Runnable() { + public void run() { + if (ps == null) channel.terminate(new Exception("Target does not provide Processes service")); + IProcesses.DoneGetEnvironment done_env = new IProcesses.DoneGetEnvironment() { + public void doneGetEnvironment(IToken token, Exception error, Map<String,String> def) { if (error != null) { channel.terminate(error); return; } - TCFLaunch.this.process = process; - Protocol.invokeLater(done); + Map<String,String> vars = new HashMap<String,String>(); + if (append) vars.putAll(def); + if (env != null) vars.putAll(env); + String file = remote_file; + if (file == null) file = getProgramPath(project, local_file); + if (file == null) { + channel.terminate(new Exception("Program does not exist")); + return; + } + ps.start(dir, file, toArgsArray(file, args), vars, attach, new IProcesses.DoneStart() { + public void doneStart(IToken token, Exception error, ProcessContext process) { + if (error != null) { + channel.terminate(error); + return; + } + TCFLaunch.this.process = process; + Protocol.invokeLater(done); + } + }); } - }); + }; + if (append) ps.getEnvironment(done_env); + else done_env.doneGetEnvironment(null, null, null); } }; - if (append) ps.getEnvironment(done_env); - else done_env.doneGetEnvironment(null, null, null); + if (local_file.length() == 0 || remote_file.length() == 0) r.run(); + else copyToRemoteTarget(getProgramPath(project, local_file), remote_file, r); } catch (Exception x) { channel.terminate(x); } } + private void copyToRemoteTarget(String local_file, String remote_file, final Runnable done) { + if (local_file == null) { + channel.terminate(new Exception("Program does not exist")); + return; + } + final IFileSystem fs = channel.getRemoteService(IFileSystem.class); + if (fs == null) { + channel.terminate(new Exception( + "Cannot download program file: target does not provide File System service")); + return; + } + try { + final InputStream inp = new FileInputStream(local_file); + int flags = IFileSystem.TCF_O_WRITE | IFileSystem.TCF_O_CREAT | IFileSystem.TCF_O_TRUNC; + fs.open(remote_file, flags, null, new IFileSystem.DoneOpen() { + + IFileHandle handle; + long offset = 0; + final Set<IToken> cmds = new HashSet<IToken>(); + final byte[] buf = new byte[0x1000]; + + public void doneOpen(IToken token, FileSystemException error, IFileHandle handle) { + this.handle = handle; + if (error != null) { + TCFLaunch.this.error = new Exception("Cannot download program file", error); + fireChanged(); + done.run(); + } + else { + write_next(); + } + } + + private void write_next() { + try { + while (cmds.size() < 8) { + int rd = inp.read(buf); + if (rd < 0) { + close(); + break; + } + cmds.add(fs.write(handle, offset, buf, 0, rd, new IFileSystem.DoneWrite() { + + public void doneWrite(IToken token, FileSystemException error) { + cmds.remove(token); + if (error != null) channel.terminate(error); + else write_next(); + } + })); + offset += rd; + } + } + catch (Throwable x) { + channel.terminate(x); + } + } + + private void close() { + if (cmds.size() > 0) return; + try { + inp.close(); + fs.close(handle, new IFileSystem.DoneClose() { + + public void doneClose(IToken token, FileSystemException error) { + if (error != null) channel.terminate(error); + else done.run(); + } + }); + } + catch (Throwable x) { + channel.terminate(x); + } + } + }); + } + catch (Throwable x) { + channel.terminate(x); + } + } + + private String getProgramPath(String project_name, String local_file) { + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(project_name); + IPath program_path = new Path(local_file); + if (!program_path.isAbsolute()) { + if (project == null || !project.getFile(local_file).exists()) return null; + program_path = project.getFile(local_file).getLocation(); + } + return program_path.toOSString(); + } + protected void runShutdownSequence(final Runnable done) { done.run(); } diff --git a/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/launch/LaunchDialogTabGroup.java b/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/launch/LaunchDialogTabGroup.java index aad3b3e63..999e4ada5 100644 --- a/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/launch/LaunchDialogTabGroup.java +++ b/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/launch/LaunchDialogTabGroup.java @@ -17,7 +17,7 @@ import org.eclipse.debug.ui.ILaunchConfigurationDialog; import org.eclipse.debug.ui.ILaunchConfigurationTab; import org.eclipse.debug.ui.sourcelookup.SourceLookupTab; import org.eclipse.tm.internal.tcf.debug.ui.launch.TCFArgumentsTab; -import org.eclipse.tm.internal.tcf.debug.ui.launch.TCFMainTab; +import org.eclipse.tm.internal.tcf.debug.ui.launch.TCFTargetTab; /** @@ -27,7 +27,7 @@ public class LaunchDialogTabGroup extends AbstractLaunchConfigurationTabGroup { public void createTabs(ILaunchConfigurationDialog dialog, String mode) { setTabs(new ILaunchConfigurationTab[] { - new TCFMainTab(), + new TCFTargetTab(), new TCFArgumentsTab(), new EnvironmentTab(), new SourceLookupTab(), |