debuggercdi/com.nokia.cdt.debug.launch/src/com/nokia/cdt/internal/debug/launch/newwizard/DebugRunProcessDialog.java
changeset 1285 84caa86f9460
parent 1284 7ef1318ac801
child 2163 f0a9f2d04d4a
--- a/debuggercdi/com.nokia.cdt.debug.launch/src/com/nokia/cdt/internal/debug/launch/newwizard/DebugRunProcessDialog.java	Fri Apr 23 15:24:20 2010 -0500
+++ b/debuggercdi/com.nokia.cdt.debug.launch/src/com/nokia/cdt/internal/debug/launch/newwizard/DebugRunProcessDialog.java	Mon Apr 26 15:40:54 2010 -0500
@@ -9,17 +9,17 @@
 * Initial Contributors:
 * Nokia Corporation - initial contribution.
 *
-* Contributors:
-*
+* Contributors:     
+*   
 * Description: 
-*
+* 
 */
 
 package com.nokia.cdt.internal.debug.launch.newwizard;
 
 import java.io.File;
 import java.text.MessageFormat;
-import java.util.Iterator;
+import java.util.ArrayList;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -47,6 +47,8 @@
 import org.eclipse.swt.events.ControlEvent;
 import org.eclipse.swt.events.DisposeEvent;
 import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
 import org.eclipse.swt.events.ModifyEvent;
 import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.events.SelectionAdapter;
@@ -90,7 +92,8 @@
 	private Button sisBrowse;
 	private Composite installPackageUI;
 	
-	private Set<IPath> remotePathEntries = new LinkedHashSet<IPath>();
+	private List<IPath> remotePathEntries = new ArrayList<IPath>();
+	private List<IPath> projectGeneratedRemotePaths;
 	
 	protected DebugRunProcessDialog(Shell shell, LaunchWizardData data) {
 		super(shell, data);
@@ -137,27 +140,28 @@
 	 * 
 	 */
 	protected void saveRemoteProgramEntries() {
+		// in case user was typing, ensure that entry is present
+		if(remoteProgramViewer != null) {
+			IPath currentPath = PathUtils.createPath(remoteProgramViewer.getCombo().getText().trim());
+			remotePathEntries.remove(currentPath);
+			remotePathEntries.add(0, currentPath);	// MRU
+		}
+
+		// make a set, removing user dupes, and also removing the entries we added
 		Set<IPath> uniqueRemotePathEntries = new LinkedHashSet<IPath>(remotePathEntries);
+		if (projectGeneratedRemotePaths != null)
+			uniqueRemotePathEntries.removeAll(projectGeneratedRemotePaths);
 		
-		// in case user was typing, ensure that entry is present
-		if(remoteProgramViewer != null)
-			uniqueRemotePathEntries.add(PathUtils.createPath(remoteProgramViewer.getCombo().getText().trim()));
-		
-		for (Iterator<IPath> iter = uniqueRemotePathEntries.iterator(); iter.hasNext(); ) { 
-			IPath path = iter.next();
-			if (path.isEmpty() || data.getExes().contains(path))
-				iter.remove();
+		// truncate size, removing from end
+		List<IPath> mruPathEntries = new ArrayList<IPath>(uniqueRemotePathEntries);
+		while (mruPathEntries.size() > 10) {
+			mruPathEntries.remove(mruPathEntries.size() - 1);
 		}
 		
-		// truncate size
-		while (uniqueRemotePathEntries.size() > 10)
-			uniqueRemotePathEntries.remove(uniqueRemotePathEntries.iterator().next());
-		
-		String pathSoup = TextUtils.catenateStrings(uniqueRemotePathEntries.toArray(), "|"); //$NON-NLS-1$
+		String pathSoup = TextUtils.catenateStrings(mruPathEntries.toArray(), "|"); //$NON-NLS-1$
 		LaunchPlugin.getDefault().getPreferenceStore().setValue(USER_REMOTE_PATHS, pathSoup);
 	}
 
-
 	/**
 	 * 
 	 */
@@ -234,6 +238,8 @@
 		GridDataFactory.fillDefaults().applyTo(installPackageCheckbox);
 		
 		installPackageCheckbox.setText(Messages.getString("DebugRunProcessDialog.InstallBeforeLaunchLabel")); //$NON-NLS-1$
+		installPackageCheckbox.setToolTipText(Messages.getString("DebugRunProcessDialog.SISCheckboxTooltip")); //$NON-NLS-1$
+		
 		installPackageUI = new Composite(composite, SWT.NONE);
 		GridDataFactory.fillDefaults().indent(INDENT, 0).applyTo(installPackageUI);
 		
@@ -418,16 +424,35 @@
 	protected void initUI() {
 		List<IPath> exes = data.getLaunchableExes();
 		projectExecutableViewer.setInput(exes);
+		
+		// this path may either be a project-relative or remote path
 		IPath exeSelectionPath = data.getExeSelectionPath();
 		if (exeSelectionPath.equals(Path.EMPTY) && !exes.isEmpty())
 			exeSelectionPath = exes.get(0);
+		
 		if (!Path.EMPTY.equals(exeSelectionPath)) {
+			// keep previous path if possible...
+			IPath remotePath = exeSelectionPath;
+			if (data.getExes().contains(remotePath)) {
+				// unless that was actually a host-side path, which should be converted
+				remotePath = createSuggestedRemotePath(exeSelectionPath);
+			} else {
+				// selection is already a remote path; map back to project if possible
+				IPath projPath = getHostFileForRemoteLocation(exeSelectionPath);
+				if (projPath != null) {
+					exeSelectionPath = projPath;
+				}
+				else {
+					// remote path does not correspond to anything; select some project exe so
+					// the combo isn't empty
+					exeSelectionPath = exes.get(0);
+				}
+			}
 			projectExecutableViewer.setSelection(new StructuredSelection(exeSelectionPath));
-			IPath remotePath = exeSelectionPath;
+			
 			if (remoteProgramViewer != null) {
 				if (!remotePathEntries.contains(remotePath)) {
-					remotePath = createSuggestedRemotePath(exeSelectionPath);
-					remotePathEntries.add(remotePath);
+					remotePathEntries.add(0, remotePath);	// MRU
 					remoteProgramViewer.add(remotePath);
 				}
 				remoteProgramViewer.setSelection(new StructuredSelection(remotePath));
@@ -435,11 +460,11 @@
 		}
 		
 		if (data.getExeSelection() == EExeSelection.USE_PROJECT_EXECUTABLE && exeSelectionPath != null) {
-			projectExecutableRadioButton.forceFocus();
+			projectExecutableViewer.getControl().forceFocus();
 		}
 		
 		if (data.getExeSelection() == EExeSelection.USE_REMOTE_EXECUTABLE && exeSelectionPath != null) {
-			remoteExecutableRadioButton.forceFocus();
+			remoteProgramViewer.getControl().forceFocus();
 		}
 		
 		if (data.getExeSelection() == EExeSelection.ATTACH_TO_PROCESS) {
@@ -457,6 +482,27 @@
 		return PathUtils.createPath("C:/sys/bin").append(filename); //$NON-NLS-1$
 	}
 
+
+	/**
+	 * Get the host-side file for a given remote location.  Opposite of
+	 * {@link #createSuggestedRemotePath(IPath)}.
+	 * @param path
+	 * @return host path or <code>null</code>
+	 */
+	private IPath getHostFileForRemoteLocation(IPath path) {
+		for (IPath exe : data.getExes()) {
+			// no... we don't have any knowledge (yet) of the actual install path,
+			// so comparing the exact path will fail if the user edited it.
+			// IPath remoteSuggested = createSuggestedRemotePath(exe);
+			
+			// be pretty loose in the matching for now 
+			if (exe.lastSegment().equalsIgnoreCase(path.lastSegment())) {
+				return exe;
+			}
+		}
+		return null;
+	}
+
 	/**
 	 * Allow selecting an executable detected to be built by the program.
 	 * @param radioGroup
@@ -466,10 +512,13 @@
 		GridDataFactory.fillDefaults().grab(false, false).applyTo(projectExecutableRadioButton);
 		projectExecutableRadioButton.setText(Messages.getString("DebugRunProcessDialog.LaunchProjectExeLabel")); //$NON-NLS-1$
 		projectExecutableRadioButton.setData(UID, "radio_project_executable"); //$NON-NLS-1$
+		projectExecutableRadioButton.setToolTipText(Messages.getString("DebugRunProcessDialog.LaunchProjectExecutableRadioTooltip")); //$NON-NLS-1$
+
 		
 		projectExecutableViewer = new ComboViewer(radioGroup, SWT.READ_ONLY);
 		GridDataFactory.fillDefaults().grab(true, false).applyTo(projectExecutableViewer.getControl());
 		projectExecutableViewer.getControl().setData(UID, "combo_project_executable"); //$NON-NLS-1$
+		projectExecutableViewer.getControl().setToolTipText(Messages.getString("DebugRunProcessDialog.LaunchProjectExecutableSelectorTooltip")); //$NON-NLS-1$
 		
 		projectExecutableViewer.setContentProvider(new ArrayContentProvider());
 		projectExecutableViewer.setLabelProvider(new LabelProvider() {
@@ -494,10 +543,12 @@
 			public void selectionChanged(SelectionChangedEvent event) {
 				Object sel = ((IStructuredSelection) event.getSelection()).getFirstElement();
 				if (sel instanceof IPath) {
-					data.setExeSelectionPath((IPath) sel); 
+					if (projectExecutableRadioButton.getSelection()) {
+						data.setExeSelectionPath((IPath) sel);
+					}
 					
 					// track the default remote program from the executable, for easy editing
-					if (remoteProgramViewer != null) {
+					if (remoteProgramViewer != null && !remoteExecutableRadioButton.getSelection()) {
 						IPath exeSelectionPath = createSuggestedRemotePath(data.getExeSelectionPath());
 						// path should already be in model
 						remoteProgramViewer.setSelection(new StructuredSelection(exeSelectionPath)); 
@@ -534,11 +585,18 @@
 		remoteExecutableRadioButton.setText(Messages.getString("DebugRunProcessDialog.LaunchRemoteProgLabel")); //$NON-NLS-1$
 		
 		remoteExecutableRadioButton.setData(UID, "radio_remote_program"); //$NON-NLS-1$
+		remoteExecutableRadioButton.setToolTipText(Messages.getString("DebugRunProcessDialog.LaunchRemoteProgramRadioTooltip")); //$NON-NLS-1$
 		
 		remoteProgramViewer = new ComboViewer(radioGroup, SWT.BORDER);
 		GridDataFactory.fillDefaults().grab(true, false).applyTo(remoteProgramViewer.getControl());
 		
-		remotePathEntries.addAll(data.getExes());
+		projectGeneratedRemotePaths = new ArrayList<IPath>();
+		for (IPath launchable : data.getLaunchableExes()) {
+			projectGeneratedRemotePaths.add(createSuggestedRemotePath(launchable));
+		}
+		
+		// add the entries before the user MRU entries
+		remotePathEntries.addAll(0, projectGeneratedRemotePaths);
 		
 		remoteProgramViewer.setContentProvider(new ArrayContentProvider());
 		remoteProgramViewer.setLabelProvider(new LabelProvider() {
@@ -550,10 +608,10 @@
 			}
 		});
 		remoteProgramViewer.setInput(remotePathEntries);
-		remoteProgramViewer.getCombo().setVisibleItemCount(remotePathEntries.size());
-		
+		remoteProgramViewer.getCombo().setVisibleItemCount(Math.min(10, remotePathEntries.size()));
 		
 		remoteProgramViewer.setData(UID, "combo_remote_program"); //$NON-NLS-1$
+		remoteProgramViewer.getControl().setToolTipText(Messages.getString("DebugRunProcessDialog.LaunchRemoteProgramSelectorTooltip")); //$NON-NLS-1$
 		
 		remoteExecutableRadioButton.addSelectionListener(new SelectionAdapter() {
 			@Override
@@ -565,10 +623,35 @@
 		
 		remoteProgramViewer.getCombo().addModifyListener(new ModifyListener() {
 			public void modifyText(ModifyEvent e) {
-				data.setExeSelectionPath(PathUtils.createPath(remoteProgramViewer.getCombo().getText().trim()));
+				IPath path = PathUtils.createPath(remoteProgramViewer.getCombo().getText().trim());
+				if (remoteExecutableRadioButton.getSelection()) {
+					data.setExeSelectionPath(path);
+				}
+				
+				if (!projectExecutableRadioButton.getSelection()) {
+					IPath projPath = getHostFileForRemoteLocation(path);
+					if (projPath != null) {
+						projectExecutableViewer.setSelection(new StructuredSelection(projPath));
+					}
+				}
+				
 				validate();
 			}
 		});
+		
+		remoteProgramViewer.getCombo().addFocusListener(new FocusAdapter() {
+			/* (non-Javadoc)
+			 * @see org.eclipse.swt.events.FocusAdapter#focusLost(org.eclipse.swt.events.FocusEvent)
+			 */
+			@Override
+			public void focusLost(FocusEvent e) {
+				IPath path = PathUtils.createPath(remoteProgramViewer.getCombo().getText().trim());
+				
+				// MRU behavior
+				remotePathEntries.remove(path);
+				remotePathEntries.add(0, path);
+			}
+		});
 	}
 
 	private void handleRemoteExecutableRadioSelected() {
@@ -594,7 +677,8 @@
 		attachToProcessRadioButton.setText(Messages.getString("DebugRunProcessDialog.AttachLabel")); //$NON-NLS-1$
 		
 		attachToProcessRadioButton.setData(UID, "radio_attach_to_process"); //$NON-NLS-1$
-		
+		attachToProcessRadioButton.setToolTipText(Messages.getString("DebugRunProcessDialog.AttachProcessRadioTooltip")); //$NON-NLS-1$
+
 		Label label = new Label(radioGroup, SWT.WRAP);
 		GridDataFactory.fillDefaults().grab(false, false).align(SWT.LEFT, SWT.CENTER).applyTo(label);