Bug 400399 - Project import wizard does not remember selected folder or
archive

Use a Combo to remember previous import locations.
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/WizardProjectsImportPage.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/WizardProjectsImportPage.java
index 709c26d..1ecc109 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/WizardProjectsImportPage.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/WizardProjectsImportPage.java
@@ -51,9 +51,7 @@
 import org.eclipse.core.runtime.SubProgressMonitor;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.dialogs.ErrorDialog;
-import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.dialogs.IDialogSettings;
-import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.layout.PixelConverter;
 import org.eclipse.jface.operation.IRunnableWithProgress;
 import org.eclipse.jface.viewers.CheckStateChangedEvent;
@@ -65,7 +63,6 @@
 import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.jface.viewers.ViewerComparator;
-import org.eclipse.jface.wizard.WizardPage;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.FocusAdapter;
@@ -74,21 +71,23 @@
 import org.eclipse.swt.events.TraverseEvent;
 import org.eclipse.swt.events.TraverseListener;
 import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.DirectoryDialog;
+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.Text;
 import org.eclipse.ui.IWorkingSet;
 import org.eclipse.ui.IWorkingSetManager;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.actions.WorkspaceModifyOperation;
-import org.eclipse.ui.dialogs.IOverwriteQuery;
+import org.eclipse.ui.dialogs.WizardDataTransferPage;
 import org.eclipse.ui.dialogs.WorkingSetGroup;
-import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
 import org.eclipse.ui.internal.ide.StatusUtil;
 import org.eclipse.ui.statushandlers.StatusManager;
@@ -99,8 +98,7 @@
  * The WizardProjectsImportPage is the page that allows the user to import
  * projects from a particular location.
  */
-public class WizardProjectsImportPage extends WizardPage implements
-		IOverwriteQuery {
+public class WizardProjectsImportPage extends WizardDataTransferPage {
 
 	/**
 	 * The name of the folder containing metadata information for the workspace.
@@ -287,13 +285,16 @@
 	}
 
 	// dialog store id constants
+    private final static String STORE_DIRECTORIES = "WizardProjectsImportPage.STORE_DIRECTORIES";//$NON-NLS-1$
+    private final static String STORE_ARCHIVES = "WizardProjectsImportPage.STORE_ARCHIVES";//$NON-NLS-1$
+
 	private final static String STORE_NESTED_PROJECTS = "WizardProjectsImportPage.STORE_NESTED_PROJECTS"; //$NON-NLS-1$
 	
 	private final static String STORE_COPY_PROJECT_ID = "WizardProjectsImportPage.STORE_COPY_PROJECT_ID"; //$NON-NLS-1$
 
 	private final static String STORE_ARCHIVE_SELECTED = "WizardProjectsImportPage.STORE_ARCHIVE_SELECTED"; //$NON-NLS-1$
 
-	private Text directoryPathField;
+	private Combo directoryPathField;
 
 	private CheckboxTreeViewer projectsList;
 
@@ -323,7 +324,7 @@
 
 	private Button projectFromArchiveRadio;
 
-	private Text archivePathField;
+	private Combo archivePathField;
 
 	private Button browseDirectoriesButton;
 
@@ -403,7 +404,7 @@
 
 		createProjectsRoot(workArea);
 		createProjectsList(workArea);
-		createOptionsArea(workArea);
+		createOptionsGroup(workArea);
 		createWorkingSetGroup(workArea);
 		restoreWidgetValues();
 		Dialog.applyDialogFont(workArea);
@@ -419,16 +420,7 @@
 		workingSetGroup = new WorkingSetGroup(workArea, currentSelection, workingSetIds);
 	}
 
-	/**
-	 * Create the area with the extra options.
-	 * 
-	 * @param workArea
-	 */
-	private void createOptionsArea(Composite workArea) {
-		Composite optionsGroup = new Composite(workArea, SWT.NONE);
-		optionsGroup.setLayout(new GridLayout());
-		optionsGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
-
+	protected void createOptionsGroupButtons(Group optionsGroup) {
 		nestedProjectsCheckbox = new Button(optionsGroup, SWT.CHECK);
 		nestedProjectsCheckbox
 				.setText(DataTransferMessages.WizardProjectsImportPage_SearchForNestedProjects);
@@ -667,8 +659,8 @@
 		projectFromDirectoryRadio
 				.setText(DataTransferMessages.WizardProjectsImportPage_RootSelectTitle);
 
-		// project location entry field
-		this.directoryPathField = new Text(projectGroup, SWT.BORDER);
+		// project location entry combo
+		this.directoryPathField = new Combo(projectGroup, SWT.BORDER);
 
 		GridData directoryPathData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
 		directoryPathData.widthHint = new PixelConverter(directoryPathField).convertWidthInCharsToPixels(25);
@@ -685,8 +677,8 @@
 		projectFromArchiveRadio
 				.setText(DataTransferMessages.WizardProjectsImportPage_ArchiveSelectTitle);
 
-		// project location entry field
-		archivePathField = new Text(projectGroup, SWT.BORDER);
+		// project location entry combo
+		archivePathField = new Combo(projectGroup, SWT.BORDER);
 
 		GridData archivePathData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
 		archivePathData.widthHint = new PixelConverter(archivePathField).convertWidthInCharsToPixels(25);
@@ -759,6 +751,12 @@
 
 		});
 
+		directoryPathField.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent e) {
+				updateProjectsList(directoryPathField.getText().trim());
+			}
+		});
+
 		archivePathField.addTraverseListener(new TraverseListener() {
 
 			/*
@@ -790,6 +788,12 @@
 			}
 		});
 
+		archivePathField.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent e) {
+				updateProjectsList(archivePathField.getText().trim());
+			}
+		});
+
 		projectFromDirectoryRadio.addSelectionListener(new SelectionAdapter() {
 			/*
 			 * (non-Javadoc)
@@ -1070,24 +1074,6 @@
 	}
 
 	/**
-	 * Display an error dialog with the specified message.
-	 * 
-	 * @param message
-	 * 		the error message
-	 */
-	protected void displayErrorDialog(String message) {
-		MessageDialog.open(MessageDialog.ERROR, getContainer().getShell(),
-				getErrorDialogTitle(), message, SWT.SHEET);
-	}
-
-	/**
-	 * Get the title for an error dialog. Subclasses should override.
-	 */
-	protected String getErrorDialogTitle() {
-		return IDEWorkbenchMessages.WizardExportPage_internalErrorTitle;
-	}
-
-	/**
 	 * Collect the list of .project files that are under directory into files.
 	 * 
 	 * @param files
@@ -1447,58 +1433,6 @@
 	}
 
 	/**
-	 * The <code>WizardDataTransfer</code> implementation of this
-	 * <code>IOverwriteQuery</code> method asks the user whether the existing
-	 * resource at the given path should be overwritten.
-	 * 
-	 * @param pathString
-	 * @return the user's reply: one of <code>"YES"</code>, <code>"NO"</code>,
-	 * 	<code>"ALL"</code>, or <code>"CANCEL"</code>
-	 */
-	public String queryOverwrite(String pathString) {
-
-		Path path = new Path(pathString);
-
-		String messageString;
-		// Break the message up if there is a file name and a directory
-		// and there are at least 2 segments.
-		if (path.getFileExtension() == null || path.segmentCount() < 2) {
-			messageString = NLS.bind(
-					IDEWorkbenchMessages.WizardDataTransfer_existsQuestion,
-					pathString);
-		} else {
-			messageString = NLS
-					.bind(
-							IDEWorkbenchMessages.WizardDataTransfer_overwriteNameAndPathQuestion,
-							path.lastSegment(), path.removeLastSegments(1)
-									.toOSString());
-		}
-
-		final MessageDialog dialog = new MessageDialog(getContainer()
-				.getShell(), IDEWorkbenchMessages.Question, null,
-				messageString, MessageDialog.QUESTION, new String[] {
-						IDialogConstants.YES_LABEL,
-						IDialogConstants.YES_TO_ALL_LABEL,
-						IDialogConstants.NO_LABEL,
-						IDialogConstants.NO_TO_ALL_LABEL,
-						IDialogConstants.CANCEL_LABEL }, 0) {
-			protected int getShellStyle() {
-				return super.getShellStyle() | SWT.SHEET;
-			}
-		};
-		String[] response = new String[] { YES, ALL, NO, NO_ALL, CANCEL };
-		// run in syncExec because callback is from an operation,
-		// which is probably not running in the UI thread.
-		getControl().getDisplay().syncExec(new Runnable() {
-			public void run() {
-				dialog.open();
-			}
-		});
-		return dialog.getReturnCode() < 0 ? CANCEL : response[dialog
-				.getReturnCode()];
-	}
-
-	/**
 	 * Method used for test suite.
 	 * 
 	 * @return Button the Import from Directory RadioButton
@@ -1600,7 +1534,10 @@
 		// take care of the checkbox
 		IDialogSettings settings = getDialogSettings();
 		if (settings != null) {
-			// checkbox
+            restoreFromHistory(settings, STORE_DIRECTORIES, directoryPathField);
+            restoreFromHistory(settings, STORE_ARCHIVES, archivePathField);
+
+            // checkbox
 			nestedProjects = settings.getBoolean(STORE_NESTED_PROJECTS);
 			nestedProjectsCheckbox.setSelection(nestedProjects);
 			lastNestedProjects = nestedProjects;
@@ -1640,16 +1577,27 @@
 
 			if (dir) {
 				directoryPathField.setText(initialPath);
-				directoryPathField.setSelection(initialPath.length());
+				directoryPathField.setSelection(new Point(initialPath.length(), initialPath.length()));
 				directoryRadioSelected();
 			} else {
 				archivePathField.setText(initialPath);
-				archivePathField.setSelection(initialPath.length());
+				archivePathField.setSelection(new Point(initialPath.length(), initialPath.length()));
 				archiveRadioSelected();
 			}
 		}
 	}
 
+	private void restoreFromHistory(IDialogSettings settings, String key, Combo combo) {
+		String[] sourceNames = settings.getArray(key);
+		if (sourceNames == null) {
+			return; // ie.- no values stored, so stop
+		}
+
+		for (int i = 0; i < sourceNames.length; i++) {
+			combo.add(sourceNames[i]);
+		}
+	}
+
 	/**
 	 * Since Finish was pressed, write widget values to the dialog store so that
 	 * they will persist into the next invocation of this wizard page.
@@ -1659,7 +1607,10 @@
 	public void saveWidgetValues() {
 		IDialogSettings settings = getDialogSettings();
 		if (settings != null) {
-			settings.put(STORE_NESTED_PROJECTS, nestedProjectsCheckbox.getSelection());
+            saveInHistory(settings, STORE_DIRECTORIES, directoryPathField.getText());
+            saveInHistory(settings, STORE_ARCHIVES, archivePathField.getText());
+
+            settings.put(STORE_NESTED_PROJECTS, nestedProjectsCheckbox.getSelection());
 			
 			settings.put(STORE_COPY_PROJECT_ID, copyCheckbox.getSelection());
 
@@ -1668,6 +1619,15 @@
 		}
 	}
 
+	private void saveInHistory(IDialogSettings settings, String key, String value) {
+		String[] sourceNames = settings.getArray(key);
+		if (sourceNames == null) {
+			sourceNames = new String[0];
+		}
+		sourceNames = addToHistory(sourceNames, value);
+		settings.put(key, sourceNames);
+	}
+
 	/**
 	 * Method used for test suite.
 	 * 
@@ -1685,5 +1645,12 @@
 	public Button getNestedProjectsCheckbox() {
 		return nestedProjectsCheckbox;
 	}
+
+	public void handleEvent(Event event) {
+	}
+
+	protected boolean allowNewContainerName() {
+		return true;
+	}
 	
 }