debuggercdi/com.nokia.cdt.debug.launch/src/com/nokia/cdt/internal/debug/launch/newwizard/DebugRunProcessDialog.java
changeset 956 d1e221a2875f
child 969 b0dd389735fb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debuggercdi/com.nokia.cdt.debug.launch/src/com/nokia/cdt/internal/debug/launch/newwizard/DebugRunProcessDialog.java	Mon Feb 15 13:49:01 2010 -0600
@@ -0,0 +1,598 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package com.nokia.cdt.internal.debug.launch.newwizard;
+
+import java.io.File;
+import java.text.MessageFormat;
+import java.util.List;
+
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.settings.model.CProjectDescriptionEvent;
+import org.eclipse.cdt.core.settings.model.ICProjectDescriptionListener;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+
+import com.nokia.carbide.cdt.builder.CarbideBuilderPlugin;
+import com.nokia.carbide.cdt.builder.project.ICarbideBuildConfiguration;
+import com.nokia.carbide.cdt.builder.project.ICarbideProjectInfo;
+import com.nokia.carbide.cdt.builder.project.ISISBuilderInfo;
+import com.nokia.cdt.internal.debug.launch.newwizard.LaunchWizardData.EExeSelection;
+import com.nokia.cpp.internal.api.utils.core.PathUtils;
+import com.nokia.cpp.internal.api.utils.ui.BrowseDialogUtils;
+
+/**
+ *	This dialog allows in-depth configuration of the debug/run process options.
+ */
+public class DebugRunProcessDialog extends AbstractLaunchSettingsDialog implements ICProjectDescriptionListener {
+	private ComboViewer projectExecutableViewer;
+	private Text remoteProgramEntry;
+	private Button projectExecutableRadioButton;
+	private Button remoteExecutableRadioButton;
+	private Button attachToProcessRadioButton;
+	
+	private Label packageInfoLabel;
+	private Button installPackageCheckbox;
+	private Combo sisFile;
+	private Text sisEdit;
+	private Button sisBrowse;
+	private Composite installPackageUI;
+	
+	protected DebugRunProcessDialog(Shell shell, LaunchWizardData data) {
+		super(shell, data);
+	}
+
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+	 */
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Composite composite = initDialogArea(parent, 
+				MessageFormat.format("Change {0} Process", data.getModeLabel()),
+				data.isDebug() ? LaunchWizardHelpIds.WIZARD_DIALOG_CHANGE_DEBUG_PROCESS : 
+					LaunchWizardHelpIds.WIZARD_DIALOG_CHANGE_RUN_PROCESS);
+
+
+		createProcessSelector(composite);
+		
+		Label sep = new Label(composite, SWT.NONE);
+		GridDataFactory.fillDefaults().applyTo(sep);
+		
+		createPackageConfiguration(composite);
+
+		initUI();
+		
+		validate();
+
+		return composite;
+	}
+
+
+	private void createProcessSelector(Composite composite) {
+		Label label;
+		
+		label = new Label(composite, SWT.WRAP);
+		label.setText(MessageFormat.format("{0} method:", data.getModeLabel()));
+		label.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
+		
+		GridDataFactory.fillDefaults().grab(true, false).applyTo(composite);
+		
+		Composite radioGroup = new Composite(composite, SWT.NONE);
+		GridDataFactory.fillDefaults().grab(true, false).applyTo(radioGroup);
+		GridLayoutFactory.fillDefaults().extendedMargins(INDENT, 0, 0, 0).numColumns(2).applyTo(radioGroup);
+
+		createProjectExecutableRadioButton(radioGroup);
+		createRemoteExecutableRadioButton(radioGroup);
+		
+		label = new Label(radioGroup, SWT.SEPARATOR | SWT.HORIZONTAL);
+		GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(label);
+		
+		createAttachToProcessRadioButton(radioGroup);
+		
+		String msg;
+		if (data.isDebug())
+			msg = "Configure how to debug the program.  The initial settings reflect the debug capabilities of the selected device and the SIS builder settings.";
+		else
+			msg = "Configure how to run the program.";
+		setMessage(msg);
+		
+		switch (data.getExeSelection()) {
+		case USE_PROJECT_EXECUTABLE:
+			projectExecutableRadioButton.setSelection(true);
+			break;
+		case USE_REMOTE_EXECUTABLE:
+			remoteExecutableRadioButton.setSelection(true);
+			break;
+		case ATTACH_TO_PROCESS:
+			attachToProcessRadioButton.setSelection(true);
+			break;
+		}
+	}
+
+	private void createPackageConfiguration(Composite composite) {
+		Label label;
+		
+		label = new Label(composite, SWT.WRAP);
+		label.setText(MessageFormat.format("Deploy method:", data.getModeLabel()));
+		label.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
+		
+		GridDataFactory.fillDefaults().grab(true, true).applyTo(composite);
+		
+		packageInfoLabel = new Label(composite, SWT.WRAP);
+		GridDataFactory.fillDefaults().grab(true, false).applyTo(packageInfoLabel);
+		composite.addControlListener(new ControlAdapter() {
+			@Override
+			public void controlResized(ControlEvent e) {
+				packageInfoLabel.pack();
+			}
+		});
+		
+		installPackageCheckbox = new Button(composite, SWT.CHECK);
+		GridDataFactory.fillDefaults().applyTo(installPackageCheckbox);
+		
+		installPackageCheckbox.setText("Install package before launch");
+		installPackageUI = new Composite(composite, SWT.NONE);
+		GridDataFactory.fillDefaults().indent(INDENT, 0).applyTo(installPackageUI);
+		
+		createSISContents(installPackageUI);
+		
+		
+		installPackageCheckbox.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				data.setInstallPackage(installPackageCheckbox.getSelection());
+				updatePackageUI();
+			}
+		});
+		
+		
+		if (data.isInstallPackage()) {
+			installPackageCheckbox.setSelection(true);
+			updatePackageUI();
+		}
+		
+		updateSisFile();
+		updatePackageUI();
+	}
+	
+    protected void createSISContents(Composite composite) {
+        GridLayoutFactory.fillDefaults().margins(6, 6).numColumns(2).applyTo(composite);
+            
+		final IProject project = data.getProject();
+		ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager().getProjectInfo(project);
+		if (cpi != null) {
+			final Label sisLabel = new Label(composite, SWT.NONE);
+			sisLabel.setText("SIS File to Install:");
+			GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).span(1, 1).applyTo(sisLabel);
+			sisLabel.setToolTipText("Specify which SIS file to install on the phone prior to launching");
+			sisLabel.setData(UID, "DebugRunProcessDialog.sisLabel");
+
+			sisFile = new Combo(composite, SWT.READ_ONLY);
+			GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(1, 1).grab(true, false).applyTo(sisLabel);
+			sisFile.setToolTipText("Specify which SIS file to install on the phone prior to launching"); 
+			sisFile.add("None"); //$NON-NLS-1$
+			sisFile.setData(UID, "DebugRunProcessDialog.sisFile");
+			
+			sisFile.addSelectionListener(new SelectionAdapter() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					updateSisFile();
+				}
+			});
+			
+			ICarbideBuildConfiguration config = cpi.getDefaultConfiguration();
+			for (ISISBuilderInfo info : config.getSISBuilderInfoList()) {
+				IPath sisPath = info.getSigningType() == ISISBuilderInfo.DONT_SIGN ? info.getUnsignedSISFullPath() : info.getSignedSISFullPath();
+				sisFile.add(sisPath.toOSString());
+			}
+			
+			// select the first sis file if any, otherwise select none
+			if (sisFile.getItemCount() > 1) {
+				sisFile.select(1);
+			} else {
+				sisFile.select(0);
+			}
+
+			// listen for events so we can detect if they click on the link below and add new sis info.
+			CoreModel.getDefault().getProjectDescriptionManager().addCProjectDescriptionListener(this, CProjectDescriptionEvent.APPLIED);
+
+			composite.addDisposeListener(new DisposeListener() {
+				
+				public void widgetDisposed(DisposeEvent e) {
+					CoreModel.getDefault().getProjectDescriptionManager().removeCProjectDescriptionListener(DebugRunProcessDialog.this);
+				}
+			});
+			
+			Link link = new Link(composite, SWT.NONE);
+			link.setText("<a>" + "Modify SIS builder settings for build configuration" + "...</a>");
+			GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1).grab(true, false).applyTo(link);
+			link.addSelectionListener(new SelectionAdapter() {
+				public void widgetSelected(SelectionEvent e) {
+					PreferencesUtil.createPropertyDialogOn(getShell(), project, "com.nokia.carbide.cdt.internal.builder.ui.CarbideBuildConfigurationsPage", null, null).open();
+				}
+			});
+			link.setData(UID, "DebugRunProcessDialog.link");
+		} else {
+			// not a Carbide project, just an executable.  show a browse/edit combo
+			// to let them select a sis file if they want to.
+			final Label sisLabel = new Label(composite, SWT.NONE);
+			sisLabel.setText("SIS File to Install:"); //$NON-NLS-1$
+			GridDataFactory.swtDefaults().span(2, 1).applyTo(sisLabel);
+			sisLabel.setToolTipText("Specify which SIS file to install on the phone prior to launching");
+			sisLabel.setData(UID, "DebugRunProcessDialog.sisLabel");
+
+			sisEdit = new Text(composite, SWT.BORDER);
+			GridDataFactory.fillDefaults().span(1, 1).align(SWT.FILL, SWT.CENTER).grab(true, false).applyTo(sisEdit);
+			sisEdit.setToolTipText("Specify which SIS file to install on the phone prior to launching");
+			sisEdit.addModifyListener(new ModifyListener() {
+				public void modifyText(ModifyEvent e) {
+					updateSisFile();
+					validate();
+				}
+			});
+			sisEdit.setData(UID, "DebugRunProcessDialog.sisEdit");
+
+			sisBrowse = new Button(composite, SWT.NONE);
+			sisBrowse.setText("Browse...");
+			sisBrowse.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+			sisBrowse.addSelectionListener(new SelectionAdapter() {
+				public void widgetSelected(SelectionEvent evt) {
+					FileDialog dialog = new FileDialog(getShell(), SWT.NONE);
+
+					dialog.setText("Select installation file");
+					dialog.setFilterExtensions(new String[] {"*.sis*", "*.*"});
+					dialog.setFilterNames(new String[] {"Installation Files", "All Files"});
+
+					BrowseDialogUtils.initializeFrom(dialog, sisEdit);
+
+					String result = dialog.open();
+					if (result != null && new File(result).exists()) {
+						sisEdit.setText(result);
+						updateSisFile();
+						validate();
+					}
+				}
+			});
+			sisBrowse.setData(UID, "DebugRunProcessDialog.sisBrowse");
+		}
+    }
+    
+    
+	/**
+	 * 
+	 */
+	protected void updateSisFile() {
+		String sisPath;
+    	if (sisFile != null) {
+        	sisPath = sisFile.getSelectionIndex() == 0 ? null : sisFile.getText(); //$NON-NLS-1$
+        	data.setSisPath(sisPath);
+    	} else if (sisEdit != null) {
+    		sisPath = sisEdit.getText();
+    		data.setSisPath(sisPath);
+    	}
+	}
+
+
+	private void updatePackageUI() {
+		installPackageUI.setEnabled(data.isInstallPackage());
+		for (Control kid : installPackageUI.getChildren())
+			kid.setEnabled(data.isInstallPackage());
+	}
+
+
+	public void handleEvent(CProjectDescriptionEvent event) {
+		Shell shell = getShell();
+		if (shell == null || shell.isDisposed()) {
+			return;
+		}
+		
+		IProject project = event.getProject() ;
+		
+		if (project != data.getProject()) {
+			return;
+		}
+		
+		if (sisFile != null) {
+			ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager().getProjectInfo(project);
+			if (cpi != null) {
+				sisFile.removeAll();
+
+				sisFile.add("None");
+				
+				ICarbideBuildConfiguration config = cpi.getDefaultConfiguration();
+				for (ISISBuilderInfo info : config.getSISBuilderInfoList()) {
+					IPath sisPath = info.getSigningType() == ISISBuilderInfo.DONT_SIGN ? info.getUnsignedSISFullPath() : info.getSignedSISFullPath();
+					sisFile.add(sisPath.toOSString());
+				}
+				
+				// select the first sis file if any, otherwise select none
+				if (sisFile.getItemCount() > 1) {
+					sisFile.select(1);
+				} else {
+					sisFile.select(0);
+				}
+			}
+		}
+	}
+	
+	protected void initUI() {
+		List<IPath> exes = data.getExes();
+		projectExecutableViewer.setInput(exes);
+		IPath exeSelectionPath = data.getExeSelectionPath();
+		if (exeSelectionPath.equals(Path.EMPTY) && !exes.isEmpty())
+			exeSelectionPath = exes.get(0);
+		projectExecutableViewer.setSelection(new StructuredSelection(exeSelectionPath));
+		IPath remotePath = createSuggestedRemotePath(exeSelectionPath);
+		remoteProgramEntry.setText(PathUtils.convertPathToWindows(remotePath));
+
+		if (data.getExeSelection() == EExeSelection.USE_PROJECT_EXECUTABLE && exeSelectionPath != null) {
+			projectExecutableRadioButton.forceFocus();
+		}
+		
+		if (data.getExeSelection() == EExeSelection.USE_REMOTE_EXECUTABLE && exeSelectionPath != null) {
+			remoteExecutableRadioButton.forceFocus();
+		}
+		
+		if (data.getExeSelection() == EExeSelection.ATTACH_TO_PROCESS) {
+			attachToProcessRadioButton.forceFocus();
+		}
+
+		handleProjectExecutableRadioSelected();
+		handleRemoteExecutableRadioSelected();
+		handleAttachToProcessRadioSelected();
+	}
+
+
+	private IPath createSuggestedRemotePath(IPath exeSelectionPath) {
+		String filename = exeSelectionPath.lastSegment();
+		return PathUtils.createPath("C:/sys/bin").append(filename);
+	}
+
+	/**
+	 * Allow selecting an executable detected to be built by the program.
+	 * @param radioGroup
+	 */
+	private void createProjectExecutableRadioButton(Composite radioGroup) {
+		projectExecutableRadioButton = new Button(radioGroup, SWT.RADIO);
+		GridDataFactory.fillDefaults().grab(false, false).applyTo(projectExecutableRadioButton);
+		projectExecutableRadioButton.setText("Launch project &executable:");
+		projectExecutableRadioButton.setData(UID, "radio_project_executable");
+		
+		projectExecutableViewer = new ComboViewer(radioGroup, SWT.READ_ONLY);
+		GridDataFactory.fillDefaults().grab(true, false).applyTo(projectExecutableViewer.getControl());
+		projectExecutableViewer.getControl().setData(UID, "combo_project_executable");
+		
+		projectExecutableViewer.setContentProvider(new ArrayContentProvider());
+		projectExecutableViewer.setLabelProvider(new LabelProvider() {
+			@Override
+			public String getText(Object element) {
+				if (element instanceof IPath)
+					return ((IPath) element).lastSegment();
+				return super.getText(element);
+			}
+		});
+		
+		projectExecutableRadioButton.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				handleProjectExecutableRadioSelected();
+			}
+
+		});
+		
+		projectExecutableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+			
+			public void selectionChanged(SelectionChangedEvent event) {
+				Object sel = ((IStructuredSelection) event.getSelection()).getFirstElement();
+				if (sel instanceof IPath) {
+					data.setExeSelectionPath((IPath) sel); 
+					
+					// track the default remote program from the executable, for easy editing
+					if (remoteProgramEntry != null) {
+						IPath exeSelectionPath = createSuggestedRemotePath(data.getExeSelectionPath());
+						remoteProgramEntry.setText(PathUtils.convertPathToWindows(exeSelectionPath)); 
+					}
+					
+					validate();
+				}
+			}
+		});
+	}
+
+	private void handleProjectExecutableRadioSelected() {
+		if (projectExecutableRadioButton.getSelection()) {
+			projectExecutableViewer.getControl().setEnabled(true);
+			data.setExeSelection(EExeSelection.USE_PROJECT_EXECUTABLE);
+			IPath selectedPath = (IPath) ((IStructuredSelection) projectExecutableViewer.getSelection()).getFirstElement();
+			if (selectedPath != null) {
+				String symbianPath = PathUtils.convertPathToWindows(selectedPath);
+				data.setExeSelectionPath(new Path(symbianPath));
+			}
+			validate();
+		} else {
+			projectExecutableViewer.getControl().setEnabled(false);
+			// another button becomes active and sets the new launch process
+		}
+	}
+
+	/**
+	 * Allow user to enter an executable path.
+	 * @param radioGroup
+	 */
+	private void createRemoteExecutableRadioButton(Composite radioGroup) {
+		remoteExecutableRadioButton = new Button(radioGroup, SWT.RADIO);
+		GridDataFactory.fillDefaults().grab(false, false).applyTo(remoteExecutableRadioButton);
+		remoteExecutableRadioButton.setText("Launch &remote program:");
+		
+		remoteExecutableRadioButton.setData(UID, "radio_remote_program");
+		
+		remoteProgramEntry = new Text(radioGroup, SWT.BORDER);
+		GridDataFactory.fillDefaults().grab(true, false).applyTo(remoteProgramEntry);
+		
+		remoteProgramEntry.setData(UID, "text_remote_program");
+		
+		remoteExecutableRadioButton.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				handleRemoteExecutableRadioSelected();
+			}
+
+		});
+		
+		remoteProgramEntry.addModifyListener(new ModifyListener() {
+			public void modifyText(ModifyEvent e) {
+				data.setExeSelectionPath(new Path(remoteProgramEntry.getText().trim()));
+				validate();
+			}
+		});
+	}
+
+	private void handleRemoteExecutableRadioSelected() {
+		if (remoteExecutableRadioButton.getSelection()) {
+			remoteProgramEntry.setEnabled(true);
+			data.setExeSelection(EExeSelection.USE_REMOTE_EXECUTABLE);
+			String symbianPath = PathUtils.convertPathToWindows(remoteProgramEntry.getText());
+			data.setExeSelectionPath(new Path(symbianPath));
+			validate();
+		} else {
+			remoteProgramEntry.setEnabled(false);
+			// another button becomes active and sets the new launch process
+		}
+	}
+
+	/**
+	 * Allow user to attach to a process.
+	 * @param radioGroup
+	 */
+	private void createAttachToProcessRadioButton(Composite radioGroup) {
+		attachToProcessRadioButton = new Button(radioGroup, SWT.RADIO);
+		GridDataFactory.fillDefaults().grab(false, false).applyTo(attachToProcessRadioButton);
+		attachToProcessRadioButton.setText("&Attach to process:");
+		
+		attachToProcessRadioButton.setData(UID, "radio_attach_to_process");
+		
+		Label label = new Label(radioGroup, SWT.WRAP);
+		GridDataFactory.fillDefaults().grab(false, false).align(SWT.LEFT, SWT.CENTER).applyTo(label);
+		
+		label.setText("(selected at launch time)");
+		
+		attachToProcessRadioButton.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				handleAttachToProcessRadioSelected();
+			}
+
+		});
+		
+	}
+	
+	private void handleAttachToProcessRadioSelected() {
+		if (attachToProcessRadioButton.getSelection()) {
+			data.setExeSelection(EExeSelection.ATTACH_TO_PROCESS);
+			data.setExeSelectionPath(null);
+			validate();
+		} else {
+			// another button becomes active and sets the new launch process
+		}
+	}
+
+	@Override
+	protected void validate() {
+		IStatus status = Status.OK_STATUS;
+		
+		// check launch method
+		IPath exePath = data.getExeSelectionPath(); 
+		switch (data.getExeSelection()) {
+		case USE_PROJECT_EXECUTABLE:
+			if (exePath.isEmpty()) {
+				status = error("The project builds no executables.");
+			}
+			break;
+		case USE_REMOTE_EXECUTABLE:
+			if (exePath.isEmpty()) {
+				status = error("Enter a non-empty executable path.");
+			} else {
+				String exePathString = exePath.toString();
+				char drive = exePathString.charAt(0);
+				char colon = exePathString.length() < 2 ? 0x0 : exePathString.charAt(1);
+				char root = exePathString.length() < 3 ? 0x0 : exePathString.charAt(2);
+				char lastChar = exePathString.charAt(exePathString.length() - 1);
+				if (!Character.isLetter(drive) || colon != ':' || (root != '\\' && root != '/') || 
+						lastChar == '\\' || lastChar == '/' || lastChar == ':') { 
+					status = error("The executable path must be absolute.");
+				} else if (exePath.getFileExtension() == null) {
+					status = warning("The executable path should end in a filename.");
+				}
+			}
+			break;
+		case ATTACH_TO_PROCESS:
+			break;
+		}
+		
+		// check SIS selection
+		if (data.isInstallPackage()) {
+	    	if (sisEdit != null) {
+	    		String text = sisEdit.getText().trim();
+	    		if (text.length() > 0) {
+	    			// empty is allowed, but if they specify something, make sure
+	    			// it exists
+	    			File file = new File(text);
+	    			if (!file.exists()) {
+	    				status = error("The SIS file ''{0}'' does not exist.", text);
+	    			}
+	    		}
+	    	}
+		}
+		
+		updateStatus(status);
+	}
+}
+