org.kelvinst.psfimport.ui.importWizards.PsfImportWizardFilesSelectionPage.java Source code

Java tutorial

Introduction

Here is the source code for org.kelvinst.psfimport.ui.importWizards.PsfImportWizardFilesSelectionPage.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2012 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.kelvinst.psfimport.ui.importWizards;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ITreeViewerListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeExpansionEvent;
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.custom.BusyIndicator;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
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.Image;
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.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.model.WorkbenchViewerComparator;
import org.kelvinst.psfimport.ui.FileContentProvider;
import org.kelvinst.psfimport.ui.FileElement;
import org.kelvinst.psfimport.ui.FileStructureProvider;
import org.kelvinst.psfimport.ui.FolderContentProvider;
import org.kelvinst.psfimport.ui.IFileElementFilter;

/**
 * Page 1 of the base resource import-from-file-system Wizard
 */
public class PsfImportWizardFilesSelectionPage extends WizardPage {
    // widgets
    protected Combo sourceNameField;

    protected Button sourceBrowseButton;

    // A boolean to indicate if the user has typed anything
    private boolean entryChanged = false;

    private FileStructureProvider fileStructureProvider = new FileStructureProvider();

    // dialog store id constants
    private final static String STORE_SOURCE_NAMES_ID = "WizardFileSystemResourceImportPage1.STORE_SOURCE_NAMES_ID";//$NON-NLS-1$

    protected static final int COMBO_HISTORY_LENGTH = 5;

    private IResource currentResourceSelection;

    /**
     * The <code>selectionGroup</code> field should have been created with a
     * private modifier. Subclasses should not access this field directly.
     */
    private FileElement root;

    private String actualPath;

    private FileElement currentTreeSelection;

    private Collection<FileElement> expandedTreeElements;

    private Map<FileElement, List<FileElement>> checkedStateStore = new HashMap<FileElement, List<FileElement>>(9);

    private HashSet<FileElement> whiteCheckedTreeItems = new HashSet<FileElement>();

    private FolderContentProvider foldersContentProvider;

    private FileContentProvider filesContentProvider;

    private ILabelProvider folderLabelProvider;

    private ILabelProvider filesLabelProvider;

    // widgets
    private CheckboxTreeViewer treeViewer;

    private CheckboxTableViewer listViewer;

    // height hint for viewers
    private static int PREFERRED_HEIGHT = 150;

    /**
     * An empty array that can be returned from a call to
     * {@link #getListeners()} when {@link #listenerList} is <code>null</code>.
     */
    private static final Object[] EMPTY_ARRAY = new Object[0];

    /**
     * A collection of objects listening to changes to this manager. This
     * collection is <code>null</code> if there are no listeners.
     */
    private transient ListenerList listenerList = null;

    /**
     * Adds a listener to this manager that will be notified when this manager's
     * state changes.
     * 
     * @param listener
     *            The listener to be added; must not be <code>null</code>.
     */
    protected synchronized final void addListenerObject(final Object listener) {
        if (listenerList == null) {
            listenerList = new ListenerList(ListenerList.IDENTITY);
        }

        listenerList.add(listener);
    }

    /**
     * Returns the listeners attached to this event manager.
     * 
     * @return The listeners currently attached; may be empty, but never
     *         <code>null</code>
     */
    protected final Object[] getListeners() {
        final ListenerList list = listenerList;
        if (list == null) {
            return EMPTY_ARRAY;
        }

        return list.getListeners();
    }

    /**
     * Add the passed listener to self's collection of clients that listen for
     * changes to element checked states
     * 
     * @param listener
     *            ICheckStateListener
     */
    public void addCheckStateListener(ICheckStateListener listener) {
        addListenerObject(listener);
    }

    /**
     * Return a boolean indicating whether all children of the passed tree
     * element are currently white-checked
     * 
     * @return boolean
     * @param treeElement
     *            java.lang.Object
     */
    protected boolean areAllChildrenWhiteChecked(Object treeElement) {
        Object[] children = foldersContentProvider.getChildren(treeElement);
        for (int i = 0; i < children.length; ++i) {
            if (!whiteCheckedTreeItems.contains(children[i])) {
                return false;
            }
        }

        return true;
    }

    /**
     * Return a boolean indicating whether all list elements associated with the
     * passed tree element are currently checked
     * 
     * @return boolean
     * @param treeElement
     *            java.lang.Object
     */
    protected boolean areAllElementsChecked(FileElement treeElement) {
        List<FileElement> checkedElements = checkedStateStore.get(treeElement);
        if (checkedElements == null) {
            return false;
        }

        return getListItemsSize(treeElement) == checkedElements.size();
    }

    /**
     * Iterate through the passed elements which are being realized for the
     * first time and check each one in the tree viewer as appropriate
     */
    protected void checkNewTreeElements(FileElement[] elements) {
        for (int i = 0; i < elements.length; ++i) {
            FileElement currentElement = elements[i];
            boolean checked = checkedStateStore.containsKey(currentElement);
            treeViewer.setChecked(currentElement, checked);
            treeViewer.setGrayed(currentElement, checked && !whiteCheckedTreeItems.contains(currentElement));
        }
    }

    /**
     * An item was checked in one of self's two views. Determine which view this
     * occurred in and delegate appropriately
     * 
     * @param event
     *            CheckStateChangedEvent
     */
    public void checkListStateChanged(final CheckStateChangedEvent event) {

        // Potentially long operation - show a busy cursor
        BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), new Runnable() {
            public void run() {
                if (event.getCheckable().equals(treeViewer)) {
                    treeItemChecked((FileElement) event.getElement(), event.getChecked());
                } else {
                    listItemChecked((FileElement) event.getElement(), event.getChecked(), true);
                }

                notifyCheckStateChangeListeners(event);
            }
        });
    }

    /**
     * Lay out and initialize self's visual components.
     * 
     * @param parent
     *            org.eclipse.swt.widgets.Composite
     * @param style
     *            the style flags for the new Composite
     */
    protected void createContents(Composite parent, int style) {
        // group pane
        Composite composite = new Composite(parent, style);
        composite.setFont(parent.getFont());
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        layout.makeColumnsEqualWidth = true;
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        composite.setLayout(layout);
        composite.setLayoutData(new GridData(GridData.FILL_BOTH));

        createTreeViewer(composite);
        createListViewer(composite);

        initialize();
    }

    /**
     * Create this group's list viewer.
     */
    protected void createListViewer(Composite parent) {
        listViewer = CheckboxTableViewer.newCheckList(parent, SWT.BORDER);
        GridData data = new GridData(GridData.FILL_BOTH);
        data.heightHint = PREFERRED_HEIGHT;
        listViewer.getTable().setLayoutData(data);
        listViewer.getTable().setFont(parent.getFont());
        listViewer.setContentProvider(filesContentProvider);
        listViewer.setLabelProvider(filesLabelProvider);
        listViewer.addCheckStateListener(new ICheckStateListener() {

            @Override
            public void checkStateChanged(CheckStateChangedEvent event) {
                checkListStateChanged(event);
            }
        });
    }

    /**
     * Create this group's tree viewer.
     */
    protected void createTreeViewer(Composite parent) {
        Tree tree = new Tree(parent, SWT.CHECK | SWT.BORDER);
        GridData data = new GridData(GridData.FILL_BOTH);
        data.heightHint = PREFERRED_HEIGHT;
        tree.setLayoutData(data);
        tree.setFont(parent.getFont());

        treeViewer = new CheckboxTreeViewer(tree);
        treeViewer.setContentProvider(foldersContentProvider);
        treeViewer.setLabelProvider(folderLabelProvider);
        treeViewer.addTreeListener(new ITreeViewerListener() {

            @Override
            public void treeExpanded(TreeExpansionEvent event) {
                expandTreeElement((FileElement) event.getElement());
            }

            @Override
            public void treeCollapsed(TreeExpansionEvent event) {
                // We don't need to do anything with this
            }
        });
        treeViewer.addCheckStateListener(new ICheckStateListener() {

            @Override
            public void checkStateChanged(CheckStateChangedEvent event) {
                checkListStateChanged(event);
            }
        });
        treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {

            @Override
            public void selectionChanged(SelectionChangedEvent event) {
                IStructuredSelection selection = (IStructuredSelection) event.getSelection();
                FileElement selectedElement = (FileElement) selection.getFirstElement();
                if (selectedElement == null) {
                    currentTreeSelection = null;
                    listViewer.setInput(currentTreeSelection);
                    return;
                }

                // ie.- if not an item deselection
                if (selectedElement != currentTreeSelection) {
                    populateListViewer(selectedElement);
                }

                currentTreeSelection = selectedElement;
            }
        });
    }

    /**
     * Returns a boolean indicating whether the passed tree element should be at
     * LEAST gray-checked. Note that this method does not consider whether it
     * should be white-checked, so a specified tree item which should be
     * white-checked will result in a <code>true</code> answer from this method.
     * To determine whether a tree item should be white-checked use method
     * #determineShouldBeWhiteChecked(Object).
     * 
     * @param treeElement
     *            java.lang.Object
     * @return boolean
     * @see #determineShouldBeWhiteChecked(Object)
     */
    protected boolean determineShouldBeAtLeastGrayChecked(Object treeElement) {
        // if any list items associated with treeElement are checked then it
        // retains its gray-checked status regardless of its children
        List<FileElement> checked = checkedStateStore.get(treeElement);
        if (checked != null && (!checked.isEmpty())) {
            return true;
        }

        // if any children of treeElement are still gray-checked then
        // treeElement
        // must remain gray-checked as well. Only ask expanded nodes
        if (expandedTreeElements.contains(treeElement)) {
            FileElement[] children = foldersContentProvider.getChildren(treeElement);
            for (int i = 0; i < children.length; ++i) {
                if (checkedStateStore.containsKey(children[i])) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Returns a boolean indicating whether the passed tree item should be
     * white-checked.
     * 
     * @return boolean
     * @param treeElement
     *            java.lang.Object
     */
    protected boolean determineShouldBeWhiteChecked(FileElement treeElement) {
        return areAllChildrenWhiteChecked(treeElement) && areAllElementsChecked(treeElement);
    }

    /**
     * Expand an element in a tree viewer
     */
    private void expandTreeElement(final FileElement item) {
        BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), new Runnable() {
            public void run() {

                // First see if the children need to be given their checked
                // state at all. If they've
                // already been realized then this won't be necessary
                if (expandedTreeElements.contains(item)) {
                    checkNewTreeElements(foldersContentProvider.getChildren(item));
                } else {

                    expandedTreeElements.add(item);
                    if (whiteCheckedTreeItems.contains(item)) {
                        // If this is the first expansion and this is a
                        // white checked node then check the children
                        FileElement[] children = foldersContentProvider.getChildren(item);
                        for (int i = 0; i < children.length; ++i) {
                            if (!whiteCheckedTreeItems.contains(children[i])) {
                                FileElement child = children[i];
                                setWhiteChecked(child, true);
                                treeViewer.setChecked(child, true);
                                checkedStateStore.put(child, new ArrayList<FileElement>());
                            }
                        }

                        // Now be sure to select the list of items too
                        setListForWhiteSelection(item);
                    }
                }

            }
        });
    }

    /**
     * Add all of the selected children of nextEntry to result recursively. This
     * does not set any values in the checked state.
     * 
     * @param treeElement
     *            The tree elements being queried
     * @param addAll
     *            a boolean to indicate if the checked state store needs to be
     *            queried
     * @param filter
     *            IElementFilter - the filter being used on the data
     * @param monitor
     *            IProgressMonitor or null that the cancel is polled for
     */
    private void findAllSelectedListElements(FileElement treeElement, String parentLabel, boolean addAll,
            IFileElementFilter filter, IProgressMonitor monitor) throws InterruptedException {

        String fullLabel = null;
        if (monitor != null && monitor.isCanceled()) {
            return;
        }
        if (monitor != null) {
            fullLabel = getFullLabel(treeElement, parentLabel);
            monitor.subTask(fullLabel);
        }

        if (addAll) {
            filter.filterElements(filesContentProvider.getChildren(treeElement), monitor);
        } else { // Add what we have stored
            if (checkedStateStore.containsKey(treeElement)) {
                filter.filterElements(checkedStateStore.get(treeElement), monitor);
            }
        }

        FileElement[] treeChildren = foldersContentProvider.getChildren(treeElement);
        for (int i = 0; i < treeChildren.length; i++) {
            FileElement child = treeChildren[i];
            if (addAll) {
                findAllSelectedListElements(child, fullLabel, true, filter, monitor);
            } else { // Only continue for those with checked state
                if (checkedStateStore.containsKey(child)) {
                    findAllSelectedListElements(child, fullLabel, whiteCheckedTreeItems.contains(child), filter,
                            monitor);
                }
            }

        }
    }

    /**
     * Find all of the white checked children of the treeElement and add them to
     * the collection. If the element itself is white select add it. If not then
     * add any selected list elements and recurse down to the children.
     * 
     * @param treeElement
     *            java.lang.Object
     * @param result
     *            java.util.Collection
     */
    private void findAllWhiteCheckedItems(FileElement treeElement, Collection<FileElement> result) {

        if (whiteCheckedTreeItems.contains(treeElement)) {
            result.add(treeElement);
        } else {
            Collection<FileElement> listChildren = checkedStateStore.get(treeElement);
            // if it is not in the store then it and it's children are not
            // interesting
            if (listChildren == null) {
                return;
            }
            result.addAll(listChildren);
            FileElement[] children = foldersContentProvider.getChildren(treeElement);
            for (int i = 0; i < children.length; ++i) {
                findAllWhiteCheckedItems(children[i], result);
            }
        }
    }

    /**
     * Returns a list of all of the items that are white checked. Any folders
     * that are white checked are added and then any files from white checked
     * folders are added.
     * 
     * @return the list of all of the items that are white checked
     */
    public List<FileElement> getAllWhiteCheckedItems() {

        List<FileElement> result = new ArrayList<FileElement>();

        // Iterate through the children of the root as the root is not in
        // the store
        FileElement[] children = foldersContentProvider.getChildren(root);
        for (int i = 0; i < children.length; ++i) {
            findAllWhiteCheckedItems(children[i], result);
        }

        return result;
    }

    /**
     * Get the full label of the treeElement (its name and its parent's name).
     * 
     * @param treeElement
     *            - the element being exported
     * @param parentLabel
     *            - the label of the parent, can be null
     * @return String
     */
    protected String getFullLabel(FileElement treeElement, String parentLabel) {
        String label = parentLabel;
        if (parentLabel == null) {
            label = ""; //$NON-NLS-1$
        }
        IPath parentName = new Path(label);

        String elementText = treeElement.getName();
        if (elementText == null) {
            return parentName.toString();
        }
        return parentName.append(elementText).toString();
    }

    /**
     * Return a count of the number of list items associated with a given tree
     * item.
     * 
     * @return int
     * @param treeElement
     *            java.lang.Object
     */
    protected int getListItemsSize(Object treeElement) {
        Object[] elements = filesContentProvider.getElements(treeElement);
        return elements.length;
    }

    /**
     * Logically gray-check all ancestors of treeItem by ensuring that they
     * appear in the checked table
     */
    protected void grayCheckHierarchy(FileElement treeElement) {

        // expand the element first to make sure we have populated for it
        expandTreeElement(treeElement);

        // if this tree element is already gray then its ancestors all are
        // as well
        if (checkedStateStore.containsKey(treeElement)) {
            return; // no need to proceed upwards from here
        }

        checkedStateStore.put(treeElement, new ArrayList<FileElement>());
        FileElement parent = foldersContentProvider.getParent(treeElement);
        if (parent != null) {
            grayCheckHierarchy(parent);
        }
    }

    /**
     * Set the checked state of self and all ancestors appropriately. Do not
     * white check anyone - this is only done down a hierarchy.
     */
    private void grayUpdateHierarchy(Object treeElement) {

        boolean shouldBeAtLeastGray = determineShouldBeAtLeastGrayChecked(treeElement);

        treeViewer.setGrayChecked(treeElement, shouldBeAtLeastGray);

        if (whiteCheckedTreeItems.contains(treeElement)) {
            whiteCheckedTreeItems.remove(treeElement);
        }

        // proceed up the tree element hierarchy
        Object parent = foldersContentProvider.getParent(treeElement);
        if (parent != null) {
            grayUpdateHierarchy(parent);
        }
    }

    /**
     * Initialize this group's viewers after they have been laid out.
     */
    protected void initialize() {
        treeViewer.setInput(root);
        this.expandedTreeElements = new ArrayList<FileElement>();
        this.expandedTreeElements.add(root);
    }

    /**
     * Callback that's invoked when the checked status of an item in the list is
     * changed by the user. Do not try and update the hierarchy if we are
     * building the initial list.
     */
    protected void listItemChecked(FileElement listElement, boolean state, boolean updatingFromSelection) {
        List<FileElement> checkedListItems = checkedStateStore.get(currentTreeSelection);
        // If it has not been expanded do so as the selection of list items
        // will affect gray state
        if (!expandedTreeElements.contains(currentTreeSelection)) {
            expandTreeElement(currentTreeSelection);
        }

        if (state) {
            if (checkedListItems == null) {
                // since the associated tree item has gone from 0 -> 1
                // checked
                // list items, tree checking may need to be updated
                grayCheckHierarchy(currentTreeSelection);
                checkedListItems = checkedStateStore.get(currentTreeSelection);
            }
            checkedListItems.add(listElement);
        } else {
            checkedListItems.remove(listElement);
            if (checkedListItems.isEmpty()) {
                // since the associated tree item has gone from 1 -> 0
                // checked
                // list items, tree checking may need to be updated
                ungrayCheckHierarchy(currentTreeSelection);
            }
        }

        // Update the list with the selections if there are any
        if (checkedListItems.size() > 0) {
            checkedStateStore.put(currentTreeSelection, checkedListItems);
        }
        if (updatingFromSelection) {
            grayUpdateHierarchy(currentTreeSelection);
        }
    }

    /**
     * Notify all checked state listeners that the passed element has had its
     * checked state changed to the passed state
     */
    protected void notifyCheckStateChangeListeners(final CheckStateChangedEvent event) {
        Object[] array = getListeners();
        for (int i = 0; i < array.length; i++) {
            final ICheckStateListener l = (ICheckStateListener) array[i];
            SafeRunner.run(new SafeRunnable() {
                public void run() {
                    l.checkStateChanged(event);
                }
            });
        }
    }

    /**
     * Set the contents of the list viewer based upon the specified selected
     * tree element. This also includes checking the appropriate list items.
     * 
     * @param treeElement
     *            java.lang.Object
     */
    protected void populateListViewer(final FileElement treeElement) {
        listViewer.setInput(treeElement);

        // If the element is white checked but not expanded we have not set
        // up all of the children yet
        if (!(expandedTreeElements.contains(treeElement)) && whiteCheckedTreeItems.contains(treeElement)) {

            // Potentially long operation - show a busy cursor
            BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), new Runnable() {
                public void run() {
                    setListForWhiteSelection(treeElement);
                    listViewer.setAllChecked(true);
                }
            });

        } else {
            List<FileElement> listItemsToCheck = checkedStateStore.get(treeElement);

            if (listItemsToCheck != null) {
                Iterator<FileElement> listItemsEnum = listItemsToCheck.iterator();
                while (listItemsEnum.hasNext()) {
                    listViewer.setChecked(listItemsEnum.next(), true);
                }
            }
        }
    }

    /**
     * Select or deselect all of the elements in the tree depending on the value
     * of the selection boolean. Be sure to update the displayed files as well.
     * 
     * @param selection
     */
    public void setAllSelections(final boolean selection) {

        // If there is no root there is nothing to select
        if (root == null) {
            return;
        }

        // Potentially long operation - show a busy cursor
        BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), new Runnable() {
            public void run() {
                setTreeChecked(root, selection);
                listViewer.setAllChecked(selection);
            }
        });
    }

    /**
     * The treeElement has been white selected. Get the list for the element and
     * set it in the checked state store.
     * 
     * @param treeElement
     *            the element being updated
     */
    private void setListForWhiteSelection(FileElement treeElement) {

        FileElement[] listItems = filesContentProvider.getChildren(treeElement);
        List<FileElement> listItemsChecked = new ArrayList<FileElement>();
        for (int i = 0; i < listItems.length; ++i) {
            listItemsChecked.add(listItems[i]);
        }

        checkedStateStore.put(treeElement, listItemsChecked);
    }

    /**
     * Set the list viewer's providers to those passed
     * 
     * @param contentProvider
     *            ITreeContentProvider
     * @param labelProvider
     *            ILabelProvider
     */
    public void setListProviders(IStructuredContentProvider contentProvider, ILabelProvider labelProvider) {
        listViewer.setContentProvider(contentProvider);
        listViewer.setLabelProvider(labelProvider);
    }

    /**
     * Set the comparator that is to be applied to self's list viewer
     * 
     * @param comparator
     *            the sorter for the list
     */
    public void setListComparator(ViewerComparator comparator) {
        listViewer.setComparator(comparator);
    }

    /**
     * Set the root of the widget to be new Root. Regenerate all of the tables
     * and lists from this value.
     * 
     * @param newRoot
     */
    public void setRoot(FileElement newRoot) {
        this.root = newRoot;
        initialize();
    }

    /**
     * Set the checked state of the passed tree element appropriately, and do so
     * recursively to all of its child tree elements as well
     */
    protected void setTreeChecked(FileElement treeElement, boolean state) {

        if (treeElement.equals(currentTreeSelection)) {
            listViewer.setAllChecked(state);
        }

        if (state) {
            setListForWhiteSelection(treeElement);
        } else {
            checkedStateStore.remove(treeElement);
        }

        setWhiteChecked(treeElement, state);
        treeViewer.setChecked(treeElement, state);
        treeViewer.setGrayed(treeElement, false);

        // now logically check/uncheck all children as well if it has been
        // expanded
        if (expandedTreeElements.contains(treeElement)) {
            FileElement[] children = foldersContentProvider.getChildren(treeElement);
            for (int i = 0; i < children.length; ++i) {
                setTreeChecked(children[i], state);
            }
        }
    }

    /**
     * Set the tree viewer's providers to those passed
     * 
     * @param contentProvider
     *            ITreeContentProvider
     * @param labelProvider
     *            ILabelProvider
     */
    public void setTreeProviders(ITreeContentProvider contentProvider, ILabelProvider labelProvider) {
        treeViewer.setContentProvider(contentProvider);
        treeViewer.setLabelProvider(labelProvider);
    }

    /**
     * Set the comparator that is to be applied to self's tree viewer
     * 
     * @param comparator
     *            the comparator for the tree
     */
    public void setTreeComparator(ViewerComparator comparator) {
        treeViewer.setComparator(comparator);
    }

    /**
     * Adjust the collection of references to white-checked tree elements
     * appropriately.
     * 
     * @param treeElement
     *            java.lang.Object
     * @param isWhiteChecked
     *            boolean
     */
    protected void setWhiteChecked(FileElement treeElement, boolean isWhiteChecked) {
        if (isWhiteChecked) {
            if (!whiteCheckedTreeItems.contains(treeElement)) {
                whiteCheckedTreeItems.add(treeElement);
            }
        } else {
            whiteCheckedTreeItems.remove(treeElement);
        }
    }

    /**
     * Callback that's invoked when the checked status of an item in the tree is
     * changed by the user.
     */
    protected void treeItemChecked(FileElement treeElement, boolean state) {

        // recursively adjust all child tree elements appropriately
        setTreeChecked(treeElement, state);

        FileElement parent = foldersContentProvider.getParent(treeElement);

        // workspace root is not shown in the tree, so ignore it
        if (parent == null || parent instanceof IWorkspaceRoot) {
            return;
        }

        // now update upwards in the tree hierarchy
        if (state) {
            grayCheckHierarchy(parent);
        } else {
            ungrayCheckHierarchy(parent);
        }

        // Update the hierarchy but do not white select the parent
        grayUpdateHierarchy(parent);
    }

    /**
     * Logically un-gray-check all ancestors of treeItem iff appropriate.
     */
    protected void ungrayCheckHierarchy(Object treeElement) {
        if (!determineShouldBeAtLeastGrayChecked(treeElement)) {
            checkedStateStore.remove(treeElement);
        }

        Object parent = foldersContentProvider.getParent(treeElement);
        if (parent != null) {
            ungrayCheckHierarchy(parent);
        }
    }

    /**
     * Set the checked state of self and all ancestors appropriately
     */
    protected void updateHierarchy(FileElement treeElement) {

        boolean whiteChecked = determineShouldBeWhiteChecked(treeElement);
        boolean shouldBeAtLeastGray = determineShouldBeAtLeastGrayChecked(treeElement);

        treeViewer.setChecked(treeElement, shouldBeAtLeastGray);
        setWhiteChecked(treeElement, whiteChecked);
        if (whiteChecked) {
            treeViewer.setGrayed(treeElement, false);
        } else {
            treeViewer.setGrayed(treeElement, shouldBeAtLeastGray);
        }

        // proceed up the tree element hierarchy but gray select all of them
        Object parent = foldersContentProvider.getParent(treeElement);
        if (parent != null) {
            grayUpdateHierarchy(parent);
        }
    }

    /**
     * Set the focus on to the list widget.
     */
    public void setTreeviewFocus() {

        treeViewer.getTree().setFocus();
        if (treeViewer.getSelection().isEmpty()) {
            Object[] elements = foldersContentProvider.getElements(root);
            if (elements.length > 0) {
                StructuredSelection selection = new StructuredSelection(elements[0]);
                treeViewer.setSelection(selection);
            }
        }

    }

    /**
     * Creates an instance of this class
     * 
     * @param selection
     *            IStructuredSelection
     */
    public PsfImportWizardFilesSelectionPage(IStructuredSelection selection) {
        super("fileSystemImportPage1");

        // Initialize to null
        currentResourceSelection = null;
        if ((selection != null) && (selection.size() == 1)) {
            Object firstElement = selection.getFirstElement();
            if (firstElement instanceof IAdaptable) {
                Object resource = ((IAdaptable) firstElement).getAdapter(IResource.class);
                if (resource != null) {
                    currentResourceSelection = (IResource) resource;
                }
            }
        }

        if (currentResourceSelection != null) {
            if (currentResourceSelection.getType() == IResource.FILE) {
                currentResourceSelection = currentResourceSelection.getParent();
            }

            if (!currentResourceSelection.isAccessible()) {
                currentResourceSelection = null;
            }
        }

        setTitle("Import project sets");
        setDescription("Select the files to import.");
    }

    /**
     * Adds an entry to a history, while taking care of duplicate history items
     * and excessively long histories. The assumption is made that all histories
     * should be of length
     * <code>WizardDataTransferPage.COMBO_HISTORY_LENGTH</code>.
     * 
     * @param history
     *            the current history
     * @param newEntry
     *            the entry to add to the history
     */
    protected String[] addToHistory(String[] history, String newEntry) {
        ArrayList<String> l = new ArrayList<String>(Arrays.asList(history));
        addToHistory(l, newEntry);
        String[] r = new String[l.size()];
        l.toArray(r);
        return r;
    }

    /**
     * Adds an entry to a history, while taking care of duplicate history items
     * and excessively long histories. The assumption is made that all histories
     * should be of length
     * <code>WizardDataTransferPage.COMBO_HISTORY_LENGTH</code>.
     * 
     * @param history
     *            the current history
     * @param newEntry
     *            the entry to add to the history
     */
    protected void addToHistory(List<String> history, String newEntry) {
        history.remove(newEntry);
        history.add(0, newEntry);

        // since only one new item was added, we can be over the limit
        // by at most one item
        if (history.size() > COMBO_HISTORY_LENGTH) {
            history.remove(COMBO_HISTORY_LENGTH);
        }
    }

    /**
     * Creates a new label with a bold font.
     * 
     * @param parent
     *            the parent control
     * @param text
     *            the label text
     * @return the new label control
     */
    protected Label createBoldLabel(Composite parent, String text) {
        Label label = new Label(parent, SWT.NONE);
        label.setFont(JFaceResources.getBannerFont());
        label.setText(text);
        GridData data = new GridData();
        data.verticalAlignment = GridData.FILL;
        data.horizontalAlignment = GridData.FILL;
        label.setLayoutData(data);
        return label;
    }

    /**
     * Creates a new label with a bold font.
     * 
     * @param parent
     *            the parent control
     * @param text
     *            the label text
     * @return the new label control
     */
    protected Label createPlainLabel(Composite parent, String text) {
        Label label = new Label(parent, SWT.NONE);
        label.setText(text);
        label.setFont(parent.getFont());
        GridData data = new GridData();
        data.verticalAlignment = GridData.FILL;
        data.horizontalAlignment = GridData.FILL;
        label.setLayoutData(data);
        return label;
    }

    /**
     * Creates a horizontal spacer line that fills the width of its container.
     * 
     * @param parent
     *            the parent control
     */
    protected void createSpacer(Composite parent) {
        Label spacer = new Label(parent, SWT.NONE);
        GridData data = new GridData();
        data.horizontalAlignment = GridData.FILL;
        data.verticalAlignment = GridData.BEGINNING;
        spacer.setLayoutData(data);
    }

    /**
     * Get a path from the supplied text widget.
     * 
     * @return org.eclipse.core.runtime.IPath
     */
    protected IPath getPathFromText(Text textField) {
        String text = textField.getText();
        // Do not make an empty path absolute so as not to confuse with the root
        if (text.length() == 0) {
            return new Path(text);
        }

        return (new Path(text)).makeAbsolute();
    }

    /**
     * Queries the user to supply a container resource.
     * 
     * @return the path to an existing or new container, or <code>null</code> if
     *         the user cancelled the dialog
     */
    protected IPath queryForContainer(IContainer initialSelection, String msg) {
        return queryForContainer(initialSelection, msg, null);
    }

    /**
     * Queries the user to supply a container resource.
     * 
     * @return the path to an existing or new container, or <code>null</code> if
     *         the user cancelled the dialog
     */
    protected IPath queryForContainer(IContainer initialSelection, String msg, String title) {
        ContainerSelectionDialog dialog = new ContainerSelectionDialog(getControl().getShell(), initialSelection,
                allowNewContainerName(), msg);
        if (title != null) {
            dialog.setTitle(title);
        }
        dialog.showClosedProjects(false);
        dialog.open();
        Object[] result = dialog.getResult();
        if (result != null && result.length == 1) {
            return (IPath) result[0];
        }
        return null;
    }

    /**
     * Displays a Yes/No question to the user with the specified message and
     * returns the user's response.
     * 
     * @param message
     *            the question to ask
     * @return <code>true</code> for Yes, and <code>false</code> for No
     */
    protected boolean queryYesNoQuestion(String message) {
        MessageDialog dialog = new MessageDialog(getContainer().getShell(), "Question", (Image) null, message,
                MessageDialog.NONE, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 0) {
            protected int getShellStyle() {
                return super.getShellStyle() | SWT.SHEET;
            }
        };
        // ensure yes is the default

        return dialog.open() == 0;
    }

    /**
     * Determine if the page is complete and update the page appropriately.
     */
    protected void updatePageCompletion() {
        boolean pageComplete = determinePageCompletion();
        setPageComplete(pageComplete);
        if (pageComplete) {
            setErrorMessage(null);
        }
    }

    /**
     * Returns whether this page's destination specification controls currently
     * all contain valid values.
     * <p>
     * The <code>WizardDataTransferPage</code> implementation of this method
     * returns <code>true</code>. Subclasses may reimplement this hook method.
     * </p>
     * 
     * @return <code>true</code> indicating validity of all controls in the
     *         destination specification group
     */
    protected boolean validateDestinationGroup() {
        return true;
    }

    /**
     * Returns whether this page's options group's controls currently all
     * contain valid values.
     * <p>
     * The <code>WizardDataTransferPage</code> implementation of this method
     * returns <code>true</code>. Subclasses may reimplement this hook method.
     * </p>
     * 
     * @return <code>true</code> indicating validity of all controls in the
     *         options group
     */
    protected boolean validateOptionsGroup() {
        return true;
    }

    /**
     * Display an error dialog with the specified message.
     * 
     * @param message
     *            the error message
     */
    protected void displayErrorDialog(String message) {
        MessageDialog.open(MessageDialog.ERROR, getContainer().getShell(), "Import Problems", message, SWT.SHEET);
    }

    /**
     * Display an error dislog with the information from the supplied exception.
     * 
     * @param exception
     *            Throwable
     */
    protected void displayErrorDialog(Throwable exception) {
        String message = exception.getMessage();
        // Some system exceptions have no message
        if (message == null) {
            message = NLS.bind("Error occurred during operation: {0}", exception);
        }
        displayErrorDialog(message);
    }

    /**
     * The <code>WizardResourceImportPage</code> implementation of this
     * <code>WizardDataTransferPage</code> method returns <code>true</code>.
     * Subclasses may override this method.
     */
    protected boolean allowNewContainerName() {
        return true;
    }

    /**
     * Create the import source selection widget
     */
    protected void createFileSelectionGroup(Composite parent) {
        root = new FileElement("Dummy", null, true);
        this.foldersContentProvider = new FolderContentProvider(fileStructureProvider);
        this.filesContentProvider = new FileContentProvider(fileStructureProvider);
        this.folderLabelProvider = new WorkbenchLabelProvider();
        this.filesLabelProvider = new WorkbenchLabelProvider();

        createContents(parent, SWT.NONE);

        ICheckStateListener listener = new ICheckStateListener() {
            public void checkStateChanged(CheckStateChangedEvent event) {
                updateWidgetEnablements();
            }
        };

        WorkbenchViewerComparator comparator = new WorkbenchViewerComparator();
        setTreeComparator(comparator);
        setListComparator(comparator);
        addCheckStateListener(listener);

    }

    /**
     * Returns this page's list of currently-specified resources to be imported.
     * This is the primary resource selection facility accessor for subclasses.
     * 
     * @return a list of resources currently selected for export (element type:
     *         <code>IResource</code>)
     */
    protected List<FileElement> getSelectedResources() {
        final ArrayList<FileElement> returnValue = new ArrayList<FileElement>();

        IFileElementFilter passThroughFilter = new IFileElementFilter() {

            public void filterElements(Collection<FileElement> elements, IProgressMonitor monitor) {
                returnValue.addAll(elements);
            }

            public void filterElements(FileElement[] elements, IProgressMonitor monitor) {
                for (int i = 0; i < elements.length; i++) {
                    returnValue.add((FileElement) elements[i]);
                }
            }
        };

        try {
            // Iterate through the children of the root as the root is not in
            // the store
            FileElement[] children = foldersContentProvider.getChildren(root);
            for (int i = 0; i < children.length; ++i) {
                findAllSelectedListElements(children[i], null, whiteCheckedTreeItems.contains(children[i]),
                        passThroughFilter, null);
            }
        } catch (InterruptedException exception) {
            return new ArrayList<FileElement>();
        }

        return returnValue;
    }

    /**
     * Returns this page's list of currently-specified resources to be imported
     * filtered by the IElementFilter.
     * 
     */
    protected void getSelectedResources(IFileElementFilter filter, IProgressMonitor monitor)
            throws InterruptedException {
        // Iterate through the children of the root as the root is not in
        // the store
        FileElement[] children = foldersContentProvider.getChildren(root);
        for (int i = 0; i < children.length; ++i) {
            findAllSelectedListElements(children[i], null, whiteCheckedTreeItems.contains(children[i]), filter,
                    monitor);
        }
    }

    /*
     * @see WizardDataTransferPage.determinePageCompletion.
     */
    protected boolean determinePageCompletion() {
        boolean complete = validateSourceGroup() && validateDestinationGroup() && validateOptionsGroup();

        // Avoid draw flicker by not clearing the error
        // message unless all is valid.
        if (complete) {
            setErrorMessage(null);
        }

        return complete;
    }

    /*
     * (non-Javadoc) Method declared on IDialogPage.
     */
    public void createControl(Composite parent) {
        initializeDialogUnits(parent);

        Composite composite = new Composite(parent, SWT.NULL);
        composite.setLayout(new GridLayout());
        composite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_FILL));
        composite.setSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
        composite.setFont(parent.getFont());

        createSourceGroup(composite);

        restoreWidgetValues();
        updateWidgetEnablements();
        setPageComplete(determinePageCompletion());
        setErrorMessage(null); // should not initially have error message

        setControl(composite);
        validateSourceGroup();
    }

    /**
     * Create the group for creating the root directory
     */
    protected void createRootDirectoryGroup(Composite parent) {
        Composite sourceContainerGroup = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.numColumns = 3;
        sourceContainerGroup.setLayout(layout);
        sourceContainerGroup.setFont(parent.getFont());
        sourceContainerGroup.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));

        Label groupLabel = new Label(sourceContainerGroup, SWT.NONE);
        groupLabel.setText("From director&y:");
        groupLabel.setFont(parent.getFont());

        // source name entry field
        sourceNameField = new Combo(sourceContainerGroup, SWT.BORDER);
        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
        data.widthHint = 250;
        sourceNameField.setLayoutData(data);
        sourceNameField.setFont(parent.getFont());

        sourceNameField.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                updateFromSourceField();
            }
        });

        sourceNameField.addKeyListener(new KeyListener() {
            /*
             * @see KeyListener.keyPressed
             */
            public void keyPressed(KeyEvent e) {
                if (e.character == SWT.CR) {
                    entryChanged = false;
                    updateFromSourceField();
                }
            }

            /*
             * @see KeyListener.keyReleased
             */
            public void keyReleased(KeyEvent e) {
            }
        });

        sourceNameField.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                entryChanged = true;
            }
        });

        sourceNameField.addFocusListener(new FocusListener() {
            /*
             * @see FocusListener.focusGained(FocusEvent)
             */
            public void focusGained(FocusEvent e) {
                // Do nothing when getting focus
            }

            /*
             * @see FocusListener.focusLost(FocusEvent)
             */
            public void focusLost(FocusEvent e) {
                // Clear the flag to prevent constant update
                if (entryChanged) {
                    entryChanged = false;
                    updateFromSourceField();
                }

            }
        });

        // source browse button
        sourceBrowseButton = new Button(sourceContainerGroup, SWT.PUSH);
        sourceBrowseButton.setText("B&rowse...");
        sourceBrowseButton.addListener(SWT.Selection, new Listener() {

            @Override
            public void handleEvent(Event event) {
                if (event.widget == sourceBrowseButton) {
                    handleSourceBrowseButtonPressed();
                }

                updateWidgetEnablements();
            }
        });
        sourceBrowseButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
        sourceBrowseButton.setFont(parent.getFont());
        setButtonLayoutData(sourceBrowseButton);
    }

    /**
     * Update the receiver from the source name field.
     */

    private void updateFromSourceField() {
        setSourceName(sourceNameField.getText());

        // Update enablements when this is selected
        updateWidgetEnablements();
        fileStructureProvider.clearVisitedDirs();
        setTreeviewFocus();
    }

    /**
     * Creates and returns a <code>FileSystemElement</code> if the specified
     * file system object merits one. The criteria for this are: Also create the
     * children.
     */
    protected FileElement createRootElement(File fileSystemObject, FileStructureProvider provider) {
        boolean isContainer = fileSystemObject.isDirectory();
        String elementLabel = provider.getLabel(fileSystemObject);

        // Use an empty label so that display of the element's full name
        // doesn't include a confusing label
        FileElement dummyParent = new FileElement("", null, true);//$NON-NLS-1$
        dummyParent.setPopulated();
        FileElement result = new FileElement(elementLabel, dummyParent, isContainer);
        result.setFile(fileSystemObject);

        // Get the files for the element so as to build the first level
        result.getFiles(provider);

        return dummyParent;
    }

    /**
     * Create the import source specification widgets
     */
    protected void createSourceGroup(Composite parent) {
        createRootDirectoryGroup(parent);
        createFileSelectionGroup(parent);
    }

    /**
     * Answer a boolean indicating whether the specified source currently exists
     * and is valid
     */
    protected boolean ensureSourceIsValid() {
        if (new File(getSourceDirectoryName()).isDirectory()) {
            return true;
        }

        setErrorMessage("Source directory is not valid or has not been specified.");
        return false;
    }

    /**
     * Answer the root FileSystemElement that represents the contents of the
     * currently-specified source. If this FileSystemElement is not currently
     * defined then create and return it.
     */
    protected FileElement getFileSystemTree() {

        File sourceDirectory = getSourceDirectory();
        if (sourceDirectory == null) {
            return null;
        }

        return selectFiles(sourceDirectory, fileStructureProvider);
    }

    /**
     * Returns a File object representing the currently-named source directory
     * iff it exists as a valid directory, or <code>null</code> otherwise.
     */
    protected File getSourceDirectory() {
        return getSourceDirectory(this.sourceNameField.getText());
    }

    /**
     * Returns a File object representing the currently-named source directory
     * iff it exists as a valid directory, or <code>null</code> otherwise.
     * 
     * @param path
     *            a String not yet formatted for java.io.File compatability
     */
    private File getSourceDirectory(String path) {
        File sourceDirectory = new File(getSourceDirectoryName(path));
        if (!sourceDirectory.exists() || !sourceDirectory.isDirectory()) {
            return null;
        }

        return sourceDirectory;
    }

    /**
     * Answer the directory name specified as being the import source. Note that
     * if it ends with a separator then the separator is first removed so that
     * java treats it as a proper directory
     */
    private String getSourceDirectoryName() {
        return getSourceDirectoryName(this.sourceNameField.getText());
    }

    /**
     * Answer the directory name specified as being the import source. Note that
     * if it ends with a separator then the separator is first removed so that
     * java treats it as a proper directory
     */
    private String getSourceDirectoryName(String sourceName) {
        IPath result = new Path(sourceName.trim());

        if (result.getDevice() != null && result.segmentCount() == 0) {
            result = result.addTrailingSeparator();
        } else {
            result = result.removeTrailingSeparator();
        }

        return result.toOSString();
    }

    /**
     * Open an appropriate source browser so that the user can specify a source
     * to import from
     */
    protected void handleSourceBrowseButtonPressed() {

        String currentSource = this.sourceNameField.getText();
        DirectoryDialog dialog = new DirectoryDialog(sourceNameField.getShell(), SWT.SAVE | SWT.SHEET);
        dialog.setText("Import from directory");
        dialog.setMessage("Select a directory to import from.");
        dialog.setFilterPath(getSourceDirectoryName(currentSource));

        String selectedDirectory = dialog.open();
        if (selectedDirectory != null) {
            // Just quit if the directory is not valid
            if ((getSourceDirectory(selectedDirectory) == null) || selectedDirectory.equals(currentSource)) {
                return;
            }
            // If it is valid then proceed to populate
            setErrorMessage(null);
            setSourceName(selectedDirectory);
            setTreeviewFocus();
        }
    }

    /**
     * Returns whether the extension provided is an extension that has been
     * specified for export by the user.
     * 
     * @param extension
     *            the resource name
     * @return <code>true</code> if the resource name is suitable for export
     *         based upon its extension
     */
    protected boolean isExportableExtension(String extension) {
        return "psf".equals(extension);
    }

    /**
     * Repopulate the view based on the currently entered directory.
     */
    protected void resetSelection() {
        FileElement currentRoot = getFileSystemTree();
        setRoot(currentRoot);
    }

    /**
     * Use the dialog store to restore widget values to the values that they
     * held last time this wizard was used to completion
     */
    protected void restoreWidgetValues() {
        IDialogSettings settings = getDialogSettings();
        if (settings != null) {
            String[] sourceNames = settings.getArray(STORE_SOURCE_NAMES_ID);
            if (sourceNames == null) {
                return; // ie.- no values stored, so stop
            }

            // set filenames history
            for (int i = 0; i < sourceNames.length; i++) {
                sourceNameField.add(sourceNames[i]);
            }

            updateWidgetEnablements();
        }
    }

    /**
     * Since Finish was pressed, write widget values to the dialog store so that
     * they will persist into the next invocation of this wizard page
     */
    protected void saveWidgetValues() {
        IDialogSettings settings = getDialogSettings();
        if (settings != null) {
            // update source names history
            String[] sourceNames = settings.getArray(STORE_SOURCE_NAMES_ID);
            if (sourceNames == null) {
                sourceNames = new String[0];
            }

            sourceNames = addToHistory(sourceNames, getSourceDirectoryName());
            settings.put(STORE_SOURCE_NAMES_ID, sourceNames);

        }
    }

    /**
     * Invokes a file selection operation using the specified file system and
     * structure provider. If the user specifies files to be imported then this
     * selection is cached for later retrieval and is returned.
     */
    protected FileElement selectFiles(final File rootFileSystemObject,
            final FileStructureProvider structureProvider) {

        final FileElement[] results = new FileElement[1];

        BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
            public void run() {
                // Create the root element from the supplied file system object
                results[0] = createRootElement(rootFileSystemObject, structureProvider);
            }
        });

        return results[0];
    }

    /**
     * Sets the source name of the import to be the supplied path. Adds the name
     * of the path to the list of items in the source combo and selects it.
     * 
     * @param path
     *            the path to be added
     */
    protected void setSourceName(String path) {

        if ((path.length() > 0) && (!path.equals(actualPath))) {

            String[] currentItems = this.sourceNameField.getItems();
            int selectionIndex = -1;
            for (int i = 0; i < currentItems.length; i++) {
                if (currentItems[i].equals(path)) {
                    selectionIndex = i;
                }
            }
            if (selectionIndex < 0) {
                int oldLength = currentItems.length;
                String[] newItems = new String[oldLength + 1];
                System.arraycopy(currentItems, 0, newItems, 0, oldLength);
                newItems[oldLength] = path;
                this.sourceNameField.setItems(newItems);
                selectionIndex = oldLength;
            }
            this.sourceNameField.select(selectionIndex);
            this.actualPath = path;

            resetSelection();
        }
    }

    /*
     * (non-Javadoc) Method declared on IDialogPage. Set the selection up when
     * it becomes visible.
     */
    public void setVisible(boolean visible) {
        super.setVisible(visible);
        if (visible) {
            setTreeviewFocus();
            this.sourceNameField.setFocus();
        }
    }

    /**
     * Check if widgets are enabled or disabled by a change in the dialog.
     * Provided here to give access to inner classes.
     */
    protected void updateWidgetEnablements() {
        updatePageCompletion();
    }

    /**
     * Answer a boolean indicating whether self's source specification widgets
     * currently all contain valid values.
     */
    protected boolean validateSourceGroup() {
        File sourceDirectory = getSourceDirectory();
        if (sourceDirectory == null) {
            setMessage("Source must not be empty.");
            return false;
        }

        List<FileElement> resourcesToExport = getAllWhiteCheckedItems();
        if (resourcesToExport.size() == 0) {
            setMessage(null);
            setErrorMessage("There are no project sets currently selected for import.");
            return false;
        }

        setErrorMessage(null);
        return true;
    }
}