com.legstar.eclipse.plugin.common.wizards.AbstractWizardPage.java Source code

Java tutorial

Introduction

Here is the source code for com.legstar.eclipse.plugin.common.wizards.AbstractWizardPage.java

Source

/*******************************************************************************
 * Copyright (c) 2010 LegSem.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     LegSem - initial API and implementation
 ******************************************************************************/
package com.legstar.eclipse.plugin.common.wizards;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.preference.DirectoryFieldEditor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
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.Canvas;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.ImageHyperlink;
import org.eclipse.ui.plugin.AbstractUIPlugin;

import com.legstar.eclipse.plugin.common.Activator;
import com.legstar.eclipse.plugin.common.Messages;
import com.legstar.eclipse.plugin.common.preferences.PreferenceConstants;
import com.legstar.eclipse.plugin.common.preferences.PreferenceUrlHistory;

/**
 * A generic wizard page that gives all LegStar wizards the same look
 * and feel.
 */
public abstract class AbstractWizardPage extends WizardPage {

    /** The initial selection in the workspace. */
    private IStructuredSelection mInitialSelection = null;

    /** The main grid layout column number. */
    public static final int LAYOUT_COLUMNS = 3;

    /** Manages the history of URLs entered across sessions. */
    private PreferenceUrlHistory mUrlHistory;

    /**
     * Construct a wizard page.
     * 
     * @param initialSelection the workbench current selection
     * @param pageName the name of this page
     * @param title the title that should appear on this page
     * @param description the text that should describe the purpose of this page
     */
    public AbstractWizardPage(final IStructuredSelection initialSelection, final String pageName,
            final String title, final String description) {
        super(pageName);
        setTitle(title);
        setDescription(description);
        mInitialSelection = initialSelection;
        mUrlHistory = new PreferenceUrlHistory(Activator.getDefault().getPreferenceStore(),
                PreferenceConstants.URL_HISTORY_STORE_KEY_PFX);

        ImageDescriptor image = AbstractUIPlugin.imageDescriptorFromPlugin(Activator.PLUGIN_ID, Activator.LOGO_IMG);
        setImageDescriptor(image);
    }

    /** {@inheritDoc} */
    public void createControl(final Composite parent) {
        Composite container = new Composite(parent, SWT.NULL);
        final GridLayout gridLayout = new GridLayout();
        gridLayout.numColumns = LAYOUT_COLUMNS;
        gridLayout.verticalSpacing = 9;
        container.setLayout(gridLayout);
        setControl(container);

        createExtendedControls(container);

        initContents();
        dialogChanged();
    }

    /**
     * Set the initial values for controls on this page.
     */
    public abstract void initContents();

    /**
     * Add the controls that are specific to this wizard page.
     * 
     * @param container the parent container
     */
    public abstract void createExtendedControls(final Composite container);

    /**
     * Process new input from user. Validate all control contents.
     */
    public abstract void dialogChanged();

    /**
     * Adds a label that spans only one column.
     * 
     * @param container parent composite
     * @param text the label text
     * @return the new label
     */
    public static Label createLabel(final Composite container, final String text) {
        return createLabel(container, text, 1);
    }

    /**
     * Adds a label that spans only one column.
     * 
     * @param container parent composite
     * @param text the label text
     * @param span how many columns of the grid this should span
     * @return the new label
     */
    public static Label createLabel(final Composite container, final String text, final int span) {
        final Label label = new Label(container, SWT.NONE);
        final GridData gridData = new GridData();
        gridData.horizontalSpan = span;
        label.setLayoutData(gridData);
        label.setText(text);
        return label;
    }

    /**
     * Create a text field that fills a grid column.
     * 
     * @param container the parent container
     * @return the new text field
     */
    public static Text createText(final Composite container) {
        return createText(container, 1);
    }

    /**
     * Create a text field that fills a grid column.
     * 
     * @param container the parent container
     * @param span how many columns of the grid this should span
     * @return the new text field
     */
    public static Text createText(final Composite container, final int span) {
        final Text text = new Text(container, SWT.BORDER | SWT.SINGLE);
        final GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
        gridData.horizontalSpan = span;
        text.setLayoutData(gridData);
        return text;
    }

    /**
     * Add a new button on a composite.
     * 
     * @param parent the parent composite
     * @param text text to appear on button
     * @return the newly created button
     */
    public static Button createButton(final Composite parent, final String text) {
        Button button = new Button(parent, SWT.PUSH);
        button.setText(text);
        return button;
    }

    /**
     * Create a group container spanning all columns.
     * 
     * @param container the parent container
     * @param text the group text
     * @return the new group
     */
    public static Group createGroup(final Composite container, final String text) {
        return createGroup(container, text, LAYOUT_COLUMNS);
    }

    /**
     * Create a Combo widget.
     * 
     * @param container parent composite
     * @return the new combo widget
     */
    public static Combo createCombo(final Composite container) {
        Combo combo = new Combo(container, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL);
        combo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        return combo;
    }

    /**
     * Create a container spanning all columns of parent container grid.
     * 
     * @param container the parent container
     * @param columns the number of columns this containers layout should have
     * @return the new container
     */
    public static Canvas createCanvas(final Composite container, final int columns) {
        final Canvas canvas = new Canvas(container, SWT.NONE);
        final GridData groupGridData = new GridData(GridData.FILL_HORIZONTAL);
        groupGridData.horizontalSpan = LAYOUT_COLUMNS;
        canvas.setLayoutData(groupGridData);
        canvas.setLayout(new GridLayout(columns, false));
        return canvas;
    }

    /**
     * Create a group container spanning all columns but with a potentially
     * different number of columns for its internal layout.
     * 
     * @param container the parent container
     * @param text the group text
     * @param columns the number of columns this groups layout should have
     * @return the new group
     */
    public static Group createGroup(final Composite container, final String text, final int columns) {
        final Group group = new Group(container, SWT.SHADOW_ETCHED_IN);
        final GridData groupGridData = new GridData(GridData.FILL_HORIZONTAL);
        groupGridData.horizontalSpan = LAYOUT_COLUMNS;
        group.setLayoutData(groupGridData);
        group.setLayout(new GridLayout(columns, false));
        group.setText(text);
        return group;
    }

    /**
     * This type of widget has a textbox and a browse button to lookup a folder
     * on the file system. The content is tied to a preference store element so
     * content can be saved and restored.
     * 
     * @param container the parent composite
     * @param preferenceName the preference store item
     * @param labelText the label's text appearing before the textbox
     * @return the composite
     */
    public Text createDirectoryFieldEditor(final Composite container, final String preferenceName,
            final String labelText) {
        DirectoryFieldEditor editor = new DirectoryFieldEditor(preferenceName, labelText, container);
        return editor.getTextControl(container);
    }

    /**
     * This type of widget is a simple textbox preceded by a label.
     * The content can be initialized from a preference store.
     * 
     * @param container the parent composite
     * @param store a preference store
     * @param preferenceName the preference store item
     * @param labelText the label's text appearing before the textbox
     * @return the composite
     */
    public static Text createTextField(final Composite container, final IPreferenceStore store,
            final String preferenceName, final String labelText) {
        createLabel(container, labelText);
        Text text = createText(container);
        if (preferenceName != null) {
            text.setText(store.getString(preferenceName));
        }
        return text;
    }

    /**
     * Create a browse button. It pops up a dialog to select a folder and
     * sets an associated text field with the result.
     * 
     * @param container parent container
     * @param dialogTitle title that browse dialog should display
     * @param result Text field to update on return from dialog
     * @return a new button
     */
    public Button createBrowseForContainerButton(final Composite container, final String dialogTitle,
            final Text result) {
        final Button button = new Button(container, SWT.PUSH);
        button.setText(Messages.browse_button_label);
        button.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(final SelectionEvent e) {
                Path destPath = handleBrowseForContainer(dialogTitle);
                if (destPath != null) {
                    result.setText(destPath.toOSString());
                }
            }
        });
        return button;
    }

    /**
     * Create a browse button. It pops up a dialog to select a folder and
     * sets an associated text field with the result.
     * 
     * @param container parent container
     * @param dialogTitle title that browse dialog should display
     * @param result Text field to update on return from dialog
     * @return a new button
     */
    public Button createBrowseForFolderButton(final Composite container, final String dialogTitle,
            final Text result) {
        final Button button = new Button(container, SWT.PUSH);
        button.setText(Messages.browse_button_label);
        button.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(final SelectionEvent e) {
                String folderName = handleBrowseForDirectory(dialogTitle);
                result.setText(folderName);
            }
        });
        return button;
    }

    /**
     * Opens a file selection dialog and merges all selected files
     * contents into a single string.
     * 
     * @param dialogTitle title that browse dialog should display
     * @param encoding the file encoding
     * @return a cumulative content of all files selected
     */
    public String selectSingleFileContent(final String dialogTitle, final String encoding) {
        String fileName = handleBrowseForFiles(dialogTitle);
        StringBuilder sb = new StringBuilder();
        if (fileName != null) {
            try {
                sb.append(getContent(fileName, encoding));
            } catch (IOException e1) {
                sb.append(NLS.bind(Messages.file_open_error_msg, fileName, e1.getMessage()));
            }
        }
        return sb.toString();
    }

    /**
     * Uses the standard file selection dialog to choose a set of files
     * from the file system.
     * 
     * @param dialogTitle what the title should say
     * @return an array of selected file names or null
     */
    public String handleBrowseForFiles(final String dialogTitle) {
        FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
        dialog.setText(dialogTitle);
        return dialog.open();
    }

    /**
     * Uses the standard directory selection dialog to choose folders
     * from the file system.
     * 
     * @param dialogTitle what the title should say
     * @return an array of selected file names or null
     */
    public String handleBrowseForDirectory(final String dialogTitle) {
        DirectoryDialog dialog = new DirectoryDialog(getShell(), SWT.OPEN);
        dialog.setText(dialogTitle);
        return dialog.open();
    }

    /**
     * Reads the content of a file in a string.
     * 
     * @param fileName name of the file
     * @param encoding the file encoding
     * @return a string with the file content
     * @throws IOException if fails to read file
     */
    public static String getContent(final String fileName, final String encoding) throws IOException {
        BufferedReader in = new BufferedReader(
                new InputStreamReader(new FileInputStream(new File(fileName)), encoding));
        StringBuilder resStr = new StringBuilder();
        String str = in.readLine();
        while (str != null) {
            resStr.append(str + '\n');
            str = in.readLine();
        }
        in.close();
        return resStr.toString();
    }

    /**
     * Create a Hyperlink Eclipse 3.0 style.
     * 
     * @param container the parent container
     * @param text the text of the hyperlink
     * @param image an image to show on the left of the ling
     * @param listener what to do when link is clicked
     * @return the new hyperlink
     */
    public ImageHyperlink createHyperlink(final Composite container, final String text, final Image image,
            final IHyperlinkListener listener) {
        return createHyperlink(container, text, image, LAYOUT_COLUMNS, listener);
    }

    /**
     * Create a Hyperlink Eclipse 3.0 style.
     * 
     * @param container the parent container
     * @param text the text of the hyperlink
     * @param image an image to show on the left of the ling
     * @param span how many columns of the grid this should span
     * @param listener what to do when link is clicked
     * @return the new hyperlink
     */
    public ImageHyperlink createHyperlink(final Composite container, final String text, final Image image,
            final int span, final IHyperlinkListener listener) {
        ImageHyperlink link = new ImageHyperlink(container, SWT.NULL);
        link.setText(text);
        link.setImage(image);
        link.setUnderlined(true);
        link.addHyperlinkListener(listener);
        final GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
        gridData.horizontalSpan = span;
        link.setLayoutData(gridData);
        return link;
    }

    /**
     * Creates a Combo box and additional widgets. This group of widgets allow
     * users to enter a URL in various ways.
     * <ul>
     * <li>Typing in the URL in a text box</li>
     * <li>Selecting a previous URL from the combo box</li>
     * <li>Browsing for a local file</li>
     * </ul>
     * 
     * @param container the parent container
     * @param urlType the type of URL this group is supposed to fetch. This is
     *            used for labels.
     * @param modifyListener listener to be notified when the content of the
     *            combo box changes
     * @param selectionListener listener to be notified when a URL is selected
     *            either because the Go button is pressed or a URL was returned
     *            from
     *            the file system.
     * @return the Combo box holding URLs
     */
    public Combo createUrlComboGroup(final Composite container, final String urlType,
            final ModifyListener modifyListener, final IURLSelectionListener selectionListener) {

        createLabel(container, urlType + " URL");

        final Combo urlCombo = createCombo(container);

        ImageHyperlink link = createHyperlink(container,
                NLS.bind(Messages.url_select_from_file_system_text, urlType),
                PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER), 2,
                new HyperlinkAdapter() {
                    public void linkActivated(final HyperlinkEvent e) {
                        String fileName = handleBrowseForFiles(NLS.bind(Messages.url_select_a_file_label, urlType));
                        if (fileName != null && fileName.length() > 0) {
                            urlCombo.setText(fileName);
                            selectionListener.urlSelected(urlCombo.getText());
                            getUrlHistory().add(urlCombo.getText());
                        }
                    }
                });

        urlCombo.moveBelow(link);
        final GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
        gridData.horizontalSpan = 2;
        urlCombo.setLayoutData(gridData);
        urlCombo.addModifyListener(modifyListener);

        Button getButton = createButton(container, Messages.go_button_label);
        getButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(final SelectionEvent e) {
                selectionListener.urlSelected(urlCombo.getText());
                getUrlHistory().add(urlCombo.getText());
            }
        });

        return urlCombo;
    }

    /**
     * Uses the standard container selection dialog to choose the new value for
     * a container field.
     * 
     * @param dialogTitle what the title should say
     * @return a Path to the selected location or null
     */
    private Path handleBrowseForContainer(final String dialogTitle) {
        ContainerSelectionDialog dialog = new ContainerSelectionDialog(getShell(), null, false, dialogTitle);
        dialog.showClosedProjects(false);
        if (dialog.open() == ContainerSelectionDialog.OK) {
            Object[] result = dialog.getResult();
            if (result.length == 1) {
                return (Path) result[0];
            }
        }
        return null;
    }

    /**
     * Invalidate the dialog content if error message is not null and make sure
     * error message is displayed.
     * <p/>
     * The Finish button is enabled only on the valid last page.
     * 
     * @param errorMessage the text
     */
    public void updateStatus(final String errorMessage) {
        if (getNextPage() == null) {
            ((AbstractWizard) getWizard()).setCanFinish((errorMessage == null) ? true : false);
        }
        setErrorMessage(errorMessage);
        setPageComplete(errorMessage == null);
    }

    /**
     * What we do here is that we search a project classpath for any occurrence
     * of a container library.
     * 
     * @param jproject the target java project
     * @param libraryName the name of the container library
     * @return true if the container library is already on the classpath
     */
    public boolean lookupContainerLibrary(final IJavaProject jproject, final String libraryName) {
        try {
            IClasspathEntry[] cpe = jproject.getRawClasspath();
            for (int i = 0; i < cpe.length; i++) {
                if (cpe[i].getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
                    if (cpe[i].getPath().equals(new Path(libraryName))) {
                        return true;
                    }
                }
            }
            return false;
        } catch (JavaModelException e) {
            return false;
        }
    }

    /**
     * The target Java project needs a container library on its classpath.
     * This assumes a classpath initializer did define the library
     * container and all what is left to do is to update the project with yet
     * another classpath entry.
     * 
     * @param jproject the target java project
     * @param libraryName the name of the container library
     * @throws JavaModelException if seting up classpath fails
     */
    public void setupContainerLibrary(final IJavaProject jproject, final String libraryName)
            throws JavaModelException {
        IClasspathEntry varEntry = JavaCore.newContainerEntry(new Path(libraryName), false);

        java.util.List<IClasspathEntry> sourceEntries = new ArrayList<IClasspathEntry>();
        for (IClasspathEntry entry : jproject.getRawClasspath()) {
            sourceEntries.add(entry);
        }
        sourceEntries.add(varEntry);
        IClasspathEntry[] entries = (IClasspathEntry[]) sourceEntries
                .toArray(new IClasspathEntry[sourceEntries.size()]);
        jproject.setRawClasspath(entries, null);
    }

    /**
     * @return the initial selection when this page is entered
     */
    public IStructuredSelection getInitialSelection() {
        return mInitialSelection;
    }

    /**
     * @param initialSelection the initial selection when this page is entered
     *            to set
     */
    public void setInitialSelection(final IStructuredSelection initialSelection) {
        mInitialSelection = initialSelection;
    }

    /**
     * We can't set SWT Text values with null values so make sure we
     * pass empty strings instead.
     * 
     * @param text the text field to set
     * @param value the potentially null value
     */
    public static void setTextFromString(final Text text, final String value) {
        if (value == null) {
            text.setText("");
        } else {
            text.setText(value);
        }
    }

    /**
     * Moves values from Text fields to strings nullifying empty strings.
     * 
     * @param text the text field
     * @return the text value or null if value is empty
     */
    public static String getValueFromText(final Text text) {
        if (text.getText().length() == 0) {
            return null;
        }
        return text.getText();
    }

    /**
     * Pops an error message.
     * 
     * @param shell parent shell
     * @param dialogTitle the error dialog title
     * @param pluginID the parent plugin ID
     * @param shortMessage text
     * @param reason a more detailed explanation
     */
    public static void errorDialog(final Shell shell, final String dialogTitle, final String pluginID,
            final String shortMessage, final String reason) {
        AbstractWizard.errorDialog(shell, dialogTitle, pluginID, shortMessage, reason);
    }

    /**
     * Log exception.
     * 
     * @param innerException exception
     * @param pluginID plugin ID
     */
    public static void logCoreException(final Throwable innerException, final String pluginID) {
        AbstractWizard.logCoreException(innerException, pluginID);
    }

    /**
     * Create a formatted core exception.
     * 
     * @param e an exception
     * @throws CoreException the core exception
     */
    public static void throwCoreException(final Exception e) throws CoreException {
        AbstractWizard.throwCoreException(e);
    }

    /**
     * Create a formatted core exception.
     * 
     * @param message the error message
     * @throws CoreException the core exception
     */
    public static void throwCoreException(final String message) throws CoreException {
        AbstractWizard.throwCoreException(message);
    }

    /**
     * @return the URL history manager
     */
    public PreferenceUrlHistory getUrlHistory() {
        return mUrlHistory;
    }

    /**
     * @param urlHistory the URL history manager to set
     */
    public void setUrlHistory(final PreferenceUrlHistory urlHistory) {
        mUrlHistory = urlHistory;
    }
}