debuggercdi/com.nokia.cdt.debug.launch/src/com/nokia/cdt/internal/debug/launch/newwizard/DebugRunProcessDialog.java
branchRCL_2_4
changeset 911 81a2e70a37d7
child 913 f1dffcbe3e11
equal deleted inserted replaced
909:24ba32fc0320 911:81a2e70a37d7
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 package com.nokia.cdt.internal.debug.launch.newwizard;
       
    19 
       
    20 import java.io.File;
       
    21 import java.text.MessageFormat;
       
    22 
       
    23 import org.eclipse.cdt.core.model.CoreModel;
       
    24 import org.eclipse.cdt.core.settings.model.CProjectDescriptionEvent;
       
    25 import org.eclipse.cdt.core.settings.model.ICProjectDescriptionListener;
       
    26 import org.eclipse.core.resources.IProject;
       
    27 import org.eclipse.core.runtime.IPath;
       
    28 import org.eclipse.core.runtime.IStatus;
       
    29 import org.eclipse.core.runtime.Path;
       
    30 import org.eclipse.core.runtime.Status;
       
    31 import org.eclipse.jface.layout.GridDataFactory;
       
    32 import org.eclipse.jface.layout.GridLayoutFactory;
       
    33 import org.eclipse.jface.resource.JFaceResources;
       
    34 import org.eclipse.jface.viewers.ArrayContentProvider;
       
    35 import org.eclipse.jface.viewers.ComboViewer;
       
    36 import org.eclipse.jface.viewers.ISelectionChangedListener;
       
    37 import org.eclipse.jface.viewers.IStructuredSelection;
       
    38 import org.eclipse.jface.viewers.LabelProvider;
       
    39 import org.eclipse.jface.viewers.SelectionChangedEvent;
       
    40 import org.eclipse.jface.viewers.StructuredSelection;
       
    41 import org.eclipse.swt.SWT;
       
    42 import org.eclipse.swt.events.ControlAdapter;
       
    43 import org.eclipse.swt.events.ControlEvent;
       
    44 import org.eclipse.swt.events.DisposeEvent;
       
    45 import org.eclipse.swt.events.DisposeListener;
       
    46 import org.eclipse.swt.events.FocusAdapter;
       
    47 import org.eclipse.swt.events.FocusEvent;
       
    48 import org.eclipse.swt.events.ModifyEvent;
       
    49 import org.eclipse.swt.events.ModifyListener;
       
    50 import org.eclipse.swt.events.SelectionAdapter;
       
    51 import org.eclipse.swt.events.SelectionEvent;
       
    52 import org.eclipse.swt.layout.GridData;
       
    53 import org.eclipse.swt.widgets.Button;
       
    54 import org.eclipse.swt.widgets.Combo;
       
    55 import org.eclipse.swt.widgets.Composite;
       
    56 import org.eclipse.swt.widgets.Control;
       
    57 import org.eclipse.swt.widgets.FileDialog;
       
    58 import org.eclipse.swt.widgets.Label;
       
    59 import org.eclipse.swt.widgets.Link;
       
    60 import org.eclipse.swt.widgets.Shell;
       
    61 import org.eclipse.swt.widgets.Text;
       
    62 import org.eclipse.ui.dialogs.PreferencesUtil;
       
    63 
       
    64 import com.nokia.carbide.cdt.builder.CarbideBuilderPlugin;
       
    65 import com.nokia.carbide.cdt.builder.project.ICarbideBuildConfiguration;
       
    66 import com.nokia.carbide.cdt.builder.project.ICarbideProjectInfo;
       
    67 import com.nokia.carbide.cdt.builder.project.ISISBuilderInfo;
       
    68 import com.nokia.cdt.internal.debug.launch.newwizard.LaunchOptionsData.EExeSelection;
       
    69 import com.nokia.cpp.internal.api.utils.core.PathUtils;
       
    70 import com.nokia.cpp.internal.api.utils.ui.BrowseDialogUtils;
       
    71 
       
    72 /**
       
    73  *	This dialog allows in-depth configuration of the debug/run process options.
       
    74  */
       
    75 public class DebugRunProcessDialog extends AbstractLaunchSettingsDialog implements ICProjectDescriptionListener {
       
    76 	private ComboViewer projectExecutableViewer;
       
    77 	private Text remoteProgramEntry;
       
    78 	private Button projectExecutableRadioButton;
       
    79 	private Button remoteExecutableRadioButton;
       
    80 	private Button attachToProcessRadioButton;
       
    81 	
       
    82 	private Label packageInfoLabel;
       
    83 	private Button installPackageCheckbox;
       
    84 	private Combo sisFile;
       
    85 	private Text sisEdit;
       
    86 	private Button sisBrowse;
       
    87 	private Composite installPackageUI;
       
    88 	
       
    89 	protected DebugRunProcessDialog(Shell shell, LaunchOptionsData data) {
       
    90 		super(shell, data);
       
    91 	}
       
    92 
       
    93 	
       
    94 	/* (non-Javadoc)
       
    95 	 * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
       
    96 	 */
       
    97 	@Override
       
    98 	protected Control createDialogArea(Composite parent) {
       
    99 		Composite composite = initDialogArea(parent, 
       
   100 				MessageFormat.format("Change {0} Process", data.getModeLabel()),
       
   101 				data.isDebug() ? LaunchWizardHelpIds.WIZARD_DIALOG_CHANGE_DEBUG_PROCESS : 
       
   102 					LaunchWizardHelpIds.WIZARD_DIALOG_CHANGE_RUN_PROCESS);
       
   103 
       
   104 
       
   105 		createProcessSelector(composite);
       
   106 		
       
   107 		Label sep = new Label(composite, SWT.NONE);
       
   108 		GridDataFactory.fillDefaults().applyTo(sep);
       
   109 		
       
   110 		createPackageConfiguration(composite);
       
   111 
       
   112 		initUI();
       
   113 		
       
   114 		validate();
       
   115 
       
   116 		return composite;
       
   117 	}
       
   118 
       
   119 
       
   120 	private void createProcessSelector(Composite composite) {
       
   121 		Label label;
       
   122 		
       
   123 		label = new Label(composite, SWT.WRAP);
       
   124 		label.setText(MessageFormat.format("{0} method:", data.getModeLabel()));
       
   125 		label.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
       
   126 		
       
   127 		GridDataFactory.fillDefaults().grab(true, false).applyTo(composite);
       
   128 		
       
   129 		Composite radioGroup = new Composite(composite, SWT.NONE);
       
   130 		GridDataFactory.fillDefaults().grab(true, false).applyTo(radioGroup);
       
   131 		GridLayoutFactory.fillDefaults().extendedMargins(INDENT, 0, 0, 0).numColumns(2).applyTo(radioGroup);
       
   132 
       
   133 		createProjectExecutableRadioButton(radioGroup);
       
   134 		createRemoteExecutableRadioButton(radioGroup);
       
   135 		
       
   136 		label = new Label(radioGroup, SWT.SEPARATOR | SWT.HORIZONTAL);
       
   137 		GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(label);
       
   138 		
       
   139 		createAttachToProcessRadioButton(radioGroup);
       
   140 		
       
   141 		String msg;
       
   142 		if (data.isDebug())
       
   143 			msg = "Configure how to debug the program.  The initial settings reflect the debug capabilities of the selected device and the SIS builder settings.";
       
   144 		else
       
   145 			msg = "Configure how to run the program.";
       
   146 		setMessage(msg);
       
   147 		
       
   148 		switch (data.getExeSelection()) {
       
   149 		case USE_PROJECT_EXECUTABLE:
       
   150 			projectExecutableRadioButton.setSelection(true);
       
   151 			break;
       
   152 		case USE_REMOTE_EXECUTABLE:
       
   153 			remoteExecutableRadioButton.setSelection(true);
       
   154 			break;
       
   155 		case ATTACH_TO_PROCESS:
       
   156 			attachToProcessRadioButton.setSelection(true);
       
   157 			break;
       
   158 		}
       
   159 	}
       
   160 	
       
   161 
       
   162 	private void createPackageConfiguration(Composite composite) {
       
   163 		Label label;
       
   164 		
       
   165 		label = new Label(composite, SWT.WRAP);
       
   166 		label.setText(MessageFormat.format("Deploy method:", data.getModeLabel()));
       
   167 		label.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
       
   168 		
       
   169 		GridDataFactory.fillDefaults().grab(true, true).applyTo(composite);
       
   170 		
       
   171 		packageInfoLabel = new Label(composite, SWT.WRAP);
       
   172 		GridDataFactory.fillDefaults().grab(true, false).applyTo(packageInfoLabel);
       
   173 		composite.addControlListener(new ControlAdapter() {
       
   174 			@Override
       
   175 			public void controlResized(ControlEvent e) {
       
   176 				packageInfoLabel.pack();
       
   177 			}
       
   178 		});
       
   179 		
       
   180 		installPackageCheckbox = new Button(composite, SWT.CHECK);
       
   181 		GridDataFactory.fillDefaults().applyTo(installPackageCheckbox);
       
   182 		
       
   183 		installPackageCheckbox.setText("Install package before launch");
       
   184 		installPackageUI = new Composite(composite, SWT.NONE);
       
   185 		GridDataFactory.fillDefaults().indent(INDENT, 0).applyTo(installPackageUI);
       
   186 		
       
   187 		createSISContents(installPackageUI);
       
   188 		
       
   189 		
       
   190 		installPackageCheckbox.addSelectionListener(new SelectionAdapter() {
       
   191 			@Override
       
   192 			public void widgetSelected(SelectionEvent e) {
       
   193 				data.setInstallPackage(installPackageCheckbox.getSelection());
       
   194 				updatePackageUI();
       
   195 			}
       
   196 		});
       
   197 		
       
   198 		
       
   199 		if (data.requiresInstallPackage()) {
       
   200 			installPackageCheckbox.setSelection(true);
       
   201 		}
       
   202 		
       
   203 		updateSisFile();
       
   204 		updatePackageUI();
       
   205 	}
       
   206 	
       
   207     protected void createSISContents(Composite composite) {
       
   208         GridLayoutFactory.fillDefaults().margins(6, 6).numColumns(2).applyTo(composite);
       
   209             
       
   210 		final IProject project = data.getProject();
       
   211 		ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager().getProjectInfo(project);
       
   212 		if (cpi != null) {
       
   213 			final Label sisLabel = new Label(composite, SWT.NONE);
       
   214 			sisLabel.setText("SIS File to Install:");
       
   215 			GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).span(1, 1).applyTo(sisLabel);
       
   216 			sisLabel.setToolTipText("Specify which SIS file to install on the phone prior to launching");
       
   217 			sisLabel.setData(UID, "DebugRunProcessDialog.sisLabel");
       
   218 
       
   219 			sisFile = new Combo(composite, SWT.READ_ONLY);
       
   220 			GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(1, 1).grab(true, false).applyTo(sisLabel);
       
   221 			sisFile.setToolTipText("Specify which SIS file to install on the phone prior to launching"); 
       
   222 			sisFile.add("None"); //$NON-NLS-1$
       
   223 			sisFile.setData(UID, "DebugRunProcessDialog.sisFile");
       
   224 			
       
   225 			sisFile.addSelectionListener(new SelectionAdapter() {
       
   226 				@Override
       
   227 				public void widgetSelected(SelectionEvent e) {
       
   228 					updateSisFile();
       
   229 				}
       
   230 			});
       
   231 			
       
   232 			ICarbideBuildConfiguration config = cpi.getDefaultConfiguration();
       
   233 			for (ISISBuilderInfo info : config.getSISBuilderInfoList()) {
       
   234 				IPath sisPath = info.getSigningType() == ISISBuilderInfo.DONT_SIGN ? info.getUnsignedSISFullPath() : info.getSignedSISFullPath();
       
   235 				sisFile.add(sisPath.toOSString());
       
   236 			}
       
   237 			
       
   238 			// select the first sis file if any, otherwise select none
       
   239 			if (sisFile.getItemCount() > 1) {
       
   240 				sisFile.select(1);
       
   241 			} else {
       
   242 				sisFile.select(0);
       
   243 			}
       
   244 
       
   245 			// listen for events so we can detect if they click on the link below and add new sis info.
       
   246 			CoreModel.getDefault().getProjectDescriptionManager().addCProjectDescriptionListener(this, CProjectDescriptionEvent.APPLIED);
       
   247 
       
   248 			composite.addDisposeListener(new DisposeListener() {
       
   249 				
       
   250 				public void widgetDisposed(DisposeEvent e) {
       
   251 					CoreModel.getDefault().getProjectDescriptionManager().removeCProjectDescriptionListener(DebugRunProcessDialog.this);
       
   252 				}
       
   253 			});
       
   254 			
       
   255 			Link link = new Link(composite, SWT.NONE);
       
   256 			link.setText("<a>" + "Modify SIS builder settings for build configuration" + "...</a>");
       
   257 			GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1).grab(true, false).applyTo(link);
       
   258 			link.addSelectionListener(new SelectionAdapter() {
       
   259 				public void widgetSelected(SelectionEvent e) {
       
   260 					PreferencesUtil.createPropertyDialogOn(getShell(), project, "com.nokia.carbide.cdt.internal.builder.ui.CarbideBuildConfigurationsPage", null, null).open();
       
   261 				}
       
   262 			});
       
   263 			link.setData(UID, "DebugRunProcessDialog.link");
       
   264 		} else {
       
   265 			// not a Carbide project, just an executable.  show a browse/edit combo
       
   266 			// to let them select a sis file if they want to.
       
   267 			final Label sisLabel = new Label(composite, SWT.NONE);
       
   268 			sisLabel.setText("SIS File to Install:"); //$NON-NLS-1$
       
   269 			GridDataFactory.swtDefaults().span(2, 1).applyTo(sisLabel);
       
   270 			sisLabel.setToolTipText("Specify which SIS file to install on the phone prior to launching");
       
   271 			sisLabel.setData(UID, "DebugRunProcessDialog.sisLabel");
       
   272 
       
   273 			sisEdit = new Text(composite, SWT.BORDER);
       
   274 			GridDataFactory.fillDefaults().span(1, 1).align(SWT.FILL, SWT.CENTER).grab(true, false).applyTo(sisEdit);
       
   275 			sisEdit.setToolTipText("Specify which SIS file to install on the phone prior to launching");
       
   276 			sisEdit.addModifyListener(new ModifyListener() {
       
   277 				public void modifyText(ModifyEvent e) {
       
   278 					updateSisFile();
       
   279 					validate();
       
   280 				}
       
   281 			});
       
   282 			sisEdit.setData(UID, "DebugRunProcessDialog.sisEdit");
       
   283 
       
   284 			sisBrowse = new Button(composite, SWT.NONE);
       
   285 			sisBrowse.setText("Browse...");
       
   286 			sisBrowse.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
       
   287 			sisBrowse.addSelectionListener(new SelectionAdapter() {
       
   288 				public void widgetSelected(SelectionEvent evt) {
       
   289 					FileDialog dialog = new FileDialog(getShell(), SWT.NONE);
       
   290 
       
   291 					dialog.setText("Select installation file");
       
   292 					dialog.setFilterExtensions(new String[] {"*.sis*", "*.*"});
       
   293 					dialog.setFilterNames(new String[] {"Installation Files", "All Files"});
       
   294 
       
   295 					BrowseDialogUtils.initializeFrom(dialog, sisEdit);
       
   296 
       
   297 					String result = dialog.open();
       
   298 					if (result != null && new File(result).exists()) {
       
   299 						sisEdit.setText(result);
       
   300 						updateSisFile();
       
   301 						validate();
       
   302 					}
       
   303 				}
       
   304 			});
       
   305 			sisBrowse.setData(UID, "DebugRunProcessDialog.sisBrowse");
       
   306 		}
       
   307     }
       
   308     
       
   309     
       
   310 	/**
       
   311 	 * 
       
   312 	 */
       
   313 	protected void updateSisFile() {
       
   314 		String sisPath;
       
   315     	if (sisFile != null) {
       
   316         	sisPath = sisFile.getSelectionIndex() == 0 ? "" : sisFile.getText(); //$NON-NLS-1$
       
   317         	data.setSisPath(sisPath);
       
   318     	} else if (sisEdit != null) {
       
   319     		sisPath = sisEdit.getText();
       
   320     		data.setSisPath(sisPath);
       
   321     	}
       
   322 	}
       
   323 
       
   324 
       
   325 	private void updatePackageUI() {
       
   326 		installPackageUI.setEnabled(data.isInstallPackage());
       
   327 		for (Control kid : installPackageUI.getChildren())
       
   328 			kid.setEnabled(data.isInstallPackage());
       
   329 	}
       
   330 
       
   331 
       
   332 	public void handleEvent(CProjectDescriptionEvent event) {
       
   333 		if (getShell().isDisposed()) {
       
   334 			return;
       
   335 		}
       
   336 		
       
   337 		IProject project = event.getProject() ;
       
   338 		
       
   339 		if (project != data.getProject()) {
       
   340 			return;
       
   341 		}
       
   342 		
       
   343 		if (sisFile != null) {
       
   344 			ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager().getProjectInfo(project);
       
   345 			if (cpi != null) {
       
   346 				sisFile.removeAll();
       
   347 
       
   348 				sisFile.add("None");
       
   349 				
       
   350 				ICarbideBuildConfiguration config = cpi.getDefaultConfiguration();
       
   351 				for (ISISBuilderInfo info : config.getSISBuilderInfoList()) {
       
   352 					IPath sisPath = info.getSigningType() == ISISBuilderInfo.DONT_SIGN ? info.getUnsignedSISFullPath() : info.getSignedSISFullPath();
       
   353 					sisFile.add(sisPath.toOSString());
       
   354 				}
       
   355 				
       
   356 				// select the first sis file if any, otherwise select none
       
   357 				if (sisFile.getItemCount() > 1) {
       
   358 					sisFile.select(1);
       
   359 				} else {
       
   360 					sisFile.select(0);
       
   361 				}
       
   362 			}
       
   363 		}
       
   364 	}
       
   365 	
       
   366 	
       
   367 	
       
   368 	
       
   369 	
       
   370 	
       
   371 	
       
   372 	protected void initUI() {
       
   373 		projectExecutableViewer.setInput(data.getExes());
       
   374 		
       
   375 		if (data.getExeSelection() == EExeSelection.USE_PROJECT_EXECUTABLE && data.getExeSelectionPath() != null) {
       
   376 			projectExecutableViewer.setSelection(new StructuredSelection(data.getExeSelectionPath()));
       
   377 			projectExecutableRadioButton.forceFocus();
       
   378 		}
       
   379 		
       
   380 		if (data.getExeSelection() == EExeSelection.USE_REMOTE_EXECUTABLE && data.getExeSelectionPath() != null) {
       
   381 			IPath exeSelectionPath = createSuggestedRemotePath(data.getExeSelectionPath());
       
   382 			remoteProgramEntry.setText(PathUtils.convertPathToWindows(exeSelectionPath));
       
   383 			remoteExecutableRadioButton.forceFocus();
       
   384 		}
       
   385 		
       
   386 		if (data.getExeSelection() == EExeSelection.ATTACH_TO_PROCESS) {
       
   387 			attachToProcessRadioButton.forceFocus();
       
   388 		}
       
   389 	}
       
   390 
       
   391 
       
   392 	private IPath createSuggestedRemotePath(IPath exeSelectionPath) {
       
   393 		String filename = exeSelectionPath.lastSegment();
       
   394 		return PathUtils.createPath("C:/sys/bin").append(filename);
       
   395 	}
       
   396 
       
   397 	/**
       
   398 	 * Allow selecting an executable detected to be built by the program.
       
   399 	 * @param radioGroup
       
   400 	 */
       
   401 	private void createProjectExecutableRadioButton(Composite radioGroup) {
       
   402 		projectExecutableRadioButton = new Button(radioGroup, SWT.RADIO);
       
   403 		GridDataFactory.fillDefaults().grab(false, false).applyTo(projectExecutableRadioButton);
       
   404 		projectExecutableRadioButton.setText("Launch project &executable:");
       
   405 		projectExecutableRadioButton.setData(UID, "radio_project_executable");
       
   406 		
       
   407 		projectExecutableViewer = new ComboViewer(radioGroup, SWT.READ_ONLY);
       
   408 		GridDataFactory.fillDefaults().grab(true, false).applyTo(projectExecutableViewer.getControl());
       
   409 		projectExecutableViewer.getControl().setData(UID, "combo_project_executable");
       
   410 		
       
   411 		projectExecutableViewer.setContentProvider(new ArrayContentProvider());
       
   412 		projectExecutableViewer.setLabelProvider(new LabelProvider() {
       
   413 			@Override
       
   414 			public String getText(Object element) {
       
   415 				if (element instanceof IPath)
       
   416 					return ((IPath) element).lastSegment();
       
   417 				return super.getText(element);
       
   418 			}
       
   419 		});
       
   420 		
       
   421 		projectExecutableRadioButton.addSelectionListener(new SelectionAdapter() {
       
   422 			@Override
       
   423 			public void widgetSelected(SelectionEvent e) {
       
   424 				if (projectExecutableRadioButton.getSelection()) {
       
   425 					projectExecutableViewer.getControl().setEnabled(true);
       
   426 					data.setExeSelection(EExeSelection.USE_PROJECT_EXECUTABLE);
       
   427 					
       
   428 					validate();
       
   429 				} else {
       
   430 					projectExecutableViewer.getControl().setEnabled(false);
       
   431 					// another button becomes active and sets the new launch process
       
   432 				}
       
   433 			}
       
   434 		});
       
   435 		
       
   436 		projectExecutableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
       
   437 			
       
   438 			public void selectionChanged(SelectionChangedEvent event) {
       
   439 				Object sel = ((IStructuredSelection) event.getSelection()).getFirstElement();
       
   440 				if (sel instanceof IPath) {
       
   441 					data.setExeSelectionPath((IPath) sel); 
       
   442 					
       
   443 					// track the default remote program from the executable, for easy editing
       
   444 					if (remoteProgramEntry != null) {
       
   445 						IPath exeSelectionPath = createSuggestedRemotePath(data.getExeSelectionPath());
       
   446 						remoteProgramEntry.setText(PathUtils.convertPathToWindows(exeSelectionPath)); 
       
   447 					}
       
   448 					
       
   449 					validate();
       
   450 				}
       
   451 			}
       
   452 		});
       
   453 	}
       
   454 
       
   455 	/**
       
   456 	 * Allow user to enter an executable path.
       
   457 	 * @param radioGroup
       
   458 	 */
       
   459 	private void createRemoteExecutableRadioButton(Composite radioGroup) {
       
   460 		remoteExecutableRadioButton = new Button(radioGroup, SWT.RADIO);
       
   461 		GridDataFactory.fillDefaults().grab(false, false).applyTo(remoteExecutableRadioButton);
       
   462 		remoteExecutableRadioButton.setText("Launch &remote program:");
       
   463 		
       
   464 		remoteExecutableRadioButton.setData(UID, "radio_remote_program");
       
   465 		
       
   466 		remoteProgramEntry = new Text(radioGroup, SWT.BORDER);
       
   467 		GridDataFactory.fillDefaults().grab(true, false).applyTo(remoteProgramEntry);
       
   468 		
       
   469 		remoteProgramEntry.setData(UID, "text_remote_program");
       
   470 		
       
   471 		remoteExecutableRadioButton.addSelectionListener(new SelectionAdapter() {
       
   472 			@Override
       
   473 			public void widgetSelected(SelectionEvent e) {
       
   474 				if (remoteExecutableRadioButton.getSelection()) {
       
   475 					remoteProgramEntry.setEnabled(true);
       
   476 					data.setExeSelection(EExeSelection.USE_REMOTE_EXECUTABLE);
       
   477 					String symbianPath = PathUtils.convertPathToWindows(remoteProgramEntry.getText());
       
   478 					data.setExeSelectionPath(new Path(symbianPath));
       
   479 					validate();
       
   480 				} else {
       
   481 					remoteProgramEntry.setEnabled(false);
       
   482 					// another button becomes active and sets the new launch process
       
   483 				}
       
   484 			}
       
   485 		});
       
   486 		
       
   487 		remoteProgramEntry.addFocusListener(new FocusAdapter() {
       
   488 			@Override
       
   489 			public void focusLost(FocusEvent e) {
       
   490 				data.setExeSelectionPath(new Path(remoteProgramEntry.getText().trim()));
       
   491 				validate();
       
   492 			}
       
   493 		});
       
   494 		
       
   495 	}
       
   496 
       
   497 	/**
       
   498 	 * Allow user to attach to a process.
       
   499 	 * @param radioGroup
       
   500 	 */
       
   501 	private void createAttachToProcessRadioButton(Composite radioGroup) {
       
   502 		attachToProcessRadioButton = new Button(radioGroup, SWT.RADIO);
       
   503 		GridDataFactory.fillDefaults().grab(false, false).applyTo(attachToProcessRadioButton);
       
   504 		attachToProcessRadioButton.setText("&Attach to process:");
       
   505 		
       
   506 		attachToProcessRadioButton.setData(UID, "radio_attach_to_process");
       
   507 		
       
   508 		Label label = new Label(radioGroup, SWT.WRAP);
       
   509 		GridDataFactory.fillDefaults().grab(false, false).align(SWT.LEFT, SWT.CENTER).applyTo(label);
       
   510 		
       
   511 		label.setText("(selected at launch time)");
       
   512 		
       
   513 		attachToProcessRadioButton.addSelectionListener(new SelectionAdapter() {
       
   514 			@Override
       
   515 			public void widgetSelected(SelectionEvent e) {
       
   516 				if (attachToProcessRadioButton.getSelection()) {
       
   517 					data.setExeSelection(EExeSelection.ATTACH_TO_PROCESS);
       
   518 					data.setExeSelectionPath(null);
       
   519 					validate();
       
   520 				} else {
       
   521 					// another button becomes active and sets the new launch process
       
   522 				}
       
   523 			}
       
   524 		});
       
   525 		
       
   526 	}
       
   527 	
       
   528 	@Override
       
   529 	protected void validate() {
       
   530 		IStatus status = Status.OK_STATUS;
       
   531 		
       
   532 		// check launch method
       
   533 		IPath exePath = data.getExeSelectionPath(); 
       
   534 		switch (data.getExeSelection()) {
       
   535 		case USE_PROJECT_EXECUTABLE:
       
   536 			if (exePath.isEmpty()) {
       
   537 				status = error("The project builds no executables.");
       
   538 			}
       
   539 			break;
       
   540 		case USE_REMOTE_EXECUTABLE:
       
   541 			if (exePath.isEmpty()) {
       
   542 				status = error("Enter a non-empty executable path.");
       
   543 			} else {
       
   544 				String exePathString = exePath.toString();
       
   545 				char drive = exePathString.charAt(0);
       
   546 				char colon = exePathString.length() < 2 ? 0x0 : exePathString.charAt(1);
       
   547 				char root = exePathString.length() < 3 ? 0x0 : exePathString.charAt(2);
       
   548 				char lastChar = exePathString.charAt(exePathString.length() - 1);
       
   549 				if (!Character.isLetter(drive) || colon != ':' || (root != '\\' && root != '/') || 
       
   550 						lastChar == '\\' || lastChar == '/' || lastChar == ':') { 
       
   551 					status = error("The executable path must be absolute.");
       
   552 				} else if (exePath.getFileExtension() == null) {
       
   553 					status = warning("The executable path should end in a filename.");
       
   554 				}
       
   555 			}
       
   556 			break;
       
   557 		case ATTACH_TO_PROCESS:
       
   558 			break;
       
   559 		}
       
   560 		
       
   561 		// check SIS selection
       
   562 		if (data.isInstallPackage()) {
       
   563 	    	if (sisEdit != null) {
       
   564 	    		String text = sisEdit.getText().trim();
       
   565 	    		if (text.length() > 0) {
       
   566 	    			// empty is allowed, but if they specify something, make sure
       
   567 	    			// it exists
       
   568 	    			File file = new File(text);
       
   569 	    			if (!file.exists()) {
       
   570 	    				status = error("The SIS file ''{0}'' does not exist.", text);
       
   571 	    			}
       
   572 	    		}
       
   573 	    	}
       
   574 		}
       
   575 		
       
   576 		updateStatus(status);
       
   577 	}
       
   578 }
       
   579