public static class PageID {
    private static int nextHashCode;
    private final int index;

    public PageID() {
        index = ++nextHashCode;
    }

    public final int hashCode() {
        return index;
    }
} public class NavigationEvent {

    private boolean alive;
    private boolean fireBeforeNext;
    private boolean fireAfterNext;
    private boolean fireBeforeShow;
    private WizardPage.PageID sourcePage;
    private WizardPage.PageID destinationPage;

    /**
     * Construct a new NavigationEvent with a reference to the
     * parent {@link Wizard} and the source and destination
     * {@link WizardPage}s.
     * @param wizard the containing {@link Wizard}
     * @param source the {@link PageID} of the source {@link WizardPage}
     * @param destination the {@link PageID} of the destination {@link WizardPage}
     */
    public NavigationEvent(Wizard<?> wizard, WizardPage.PageID source, WizardPage.PageID destination) {
        alive = true;
        setFireBeforeNext(true);
        setFireAfterNext(true);
        setFireBeforeShow(true);
        this.sourcePage = source;
        setDestinationPage(destination);
    }

    /**
     * Cancels the navigation event if the event is cancelable.
     * The event is only cancelabe during {@link WizardPage#beforeNext(NavigationEvent)}.
     */
    public void cancel() {
        alive = false;
    }

    /**
     * Whether or not the event is still alive.
     * {@link #cancel()} kills the event.
     * @return <code>true</code> if the event is alive, <code>false</code> otherwise
     */
    public boolean isAlive() {
        return alive;
    }

    /**
     * Returns the {@link PageID} of the source page.
     * @return the {@link PageID} of the source page
     */
    public WizardPage.PageID getSourcePage() {
        return sourcePage;
    }

    /**
     * Returns the {@link PageID} of the destination page.
     * @return the {@link PageID} of the destination page
     */
    public WizardPage.PageID getDestinationPage() {
        return destinationPage;
    }

    /**
     * Sets a new destination page. Has no effect if
     * the event is not being processed in
     * {@link WizardPage#beforeNext(NavigationEvent)}.
     * @param destinationPage
     */
    public void setDestinationPage(WizardPage.PageID destinationPage) {
        this.destinationPage = destinationPage;
    }

    /**
     * Gets whether or not to call the {@link WizardPage#beforeNext(NavigationEvent)} hook.
     * @return <code>true</code> if the hook should be called, <code>false</code> otherwise
     */
    public boolean getFireBeforeNext() {
        return fireBeforeNext;
    }

    /**
     * Sets whether or not to call the {@link WizardPage#afterNext()} hook.
     * @param fireBeforeNext <code>true</code> if the hook should be called, <code>false</code> otherwise
     */
    public void setFireBeforeNext(boolean fireBeforeNext) {
        this.fireBeforeNext = fireBeforeNext;
    }

    /**
     * Gets whether or not to call the {@link WizardPage#beforeNext(NavigationEvent)} hook.
     * @return <code>true</code> if the hook should be called, <code>false</code> otherwise
     */
    public boolean getFireAfterNext() {
        return fireAfterNext;
    }

    /**
     * Sets whether or not to call the {@link WizardPage#afterNext()} hook.
     * @param fireAfterNext <code>true</code> if the hook should be called, <code>false</code> otherwise
     */
    public void setFireAfterNext(boolean fireAfterNext) {
        this.fireAfterNext = fireAfterNext;
    }

    /**
     * Gets whether or not to call the {@link WizardPage#beforeShow()} hook.
     * @return <code>true</code> if the hook should be called, <code>false</code> otherwise
     */
    public boolean getFireBeforeShow() {
        return fireBeforeShow;
    }

    /**
     * Sets whether or not to call the {@link WizardPage#beforeShow()} hook.
     * @param fireBeforeShow <code>true</code> if the hook should be called, <code>false</code> otherwise
     */
    public void setFireBeforeShow(boolean fireBeforeShow) {
        this.fireBeforeShow = fireBeforeShow;
    }

} public class HandlerFactory<D extends Wizard.Display> {

    private D display;

    private final KeyPressHandler enterKeyNextHandler = new KeyPressHandler() {
        @Override
        public void onKeyPress(KeyPressEvent event) {
            if(event.getCharCode() == KeyCodes.KEY_ENTER)
                display.getButtonBar().getNextButton().click();
        }
    };

    /**
     * Construct a new HandlerFactory, providing the parent display.
     * @param display the parent display
     */
    public HandlerFactory(D display) {
        this.display = display;
    }

    /**
     * Returns a KeyPressHandler that simlulates a click on the {@link Wizard}'s
     * next button when the enter key is pressed.
     * @return GWT KeyPressHandler for moving to the next page on enter key
     */
    public KeyPressHandler getEnterKeyNextHandler() {
        return enterKeyNextHandler;
    }

} public class DuplicatePageException extends RuntimeException {

    private static final long serialVersionUID = -2121855831796245251L;

} public interface HasIndexedWidgets {
    /**
     * Add a Widget to the panel (after the last index).
     * @param wiget the Widget to add to the panel
     */
    public void add(Widget wiget);
    /**
     * Show the Widget at the specified index.
     * @param index the index of the Widget to show
     */
    public void showWidget(int index);
} public interface HasWizardButtonMethods extends HasClickHandlers {

    /**
     * Whether or not the button is enabled.
     * @return <code>true</code> if enabled, <code>false</code> otherwise
     */
    public boolean isEnabled();
    /**
     * Set the enabled state of the button.
     * @param enabled <code>true</code> to enable the button, <code>false</code> to disable it
     */
    public void setEnabled(boolean enabled);
    /**
     * Whether or not the button is visible.
     * @return <code>true</code> if visible, <code>false</code> otherwise
     */
    public boolean isVisible();
    /**
     * Set the visibility of the button.
     * @param visible <code>true</code> to show the button, <code>false</code> to hide it
     */
    public void setVisible(boolean visible);
    /**
     * Simulate a click on the button.
     */
    public void click();

} public interface HasWizardButtons {
    public HasWizardButtonMethods getCancelButton();
    public HasWizardButtonMethods getFinishButton();
    public HasWizardButtonMethods getPreviousButton();
    public HasWizardButtonMethods getNextButton();
} public interface HasWizardTitles {

    /**
     * Adds a page title.
     * @param title the title of the page to add
     */
    public void addPage(String title);

    /**
     * Sets a page title as the currently active title.
     * @param title the title to set as active
     */
    public void setCurrentPage(String title);

} public abstract class LazyComposite extends Composite implements WidgetDisplay {

    private boolean widgetCreated = false;

    /**
     * Creates the Composite's widget with {@link #createWidget()}
     * if it hasn't been created and wraps it with <code>initWidget()</code>.
     * @return the Composite (<code>this</code>).
     */
    @Override
    public final Widget asWidget() {
        if(!widgetCreated) {
            initWidget(createWidget());
            widgetCreated = true;
        }

        return this;
    }

    /**
     * Lazily create the widget and return it to be wrapped
     * by {@link #asWidget()}.
     * @return the Widget to be wrapped by the composite.
     */
    public abstract Widget createWidget();

} public interface WidgetDisplay {
    /**
     * Get this display as a GWT Widget.
     * @return a GWT Widget to attach to the DOM.
     */
    public Widget asWidget();
} public class WizardView extends Composite implements Display {

    private final DockLayoutPanel outerPanel;

    private final HorizontalPanel titlePanel;
    private final HTML titleHtml;
    private final Image workingIndicatorImage;
    private final ScrollPanel pageNamePanelContainer;
    private final WizardPageList pageNamePanel;
    private final WizardDeckPanel pagePanel;
    private final WizardNavigationPanel navigationPanel;

    private final HandlerFactory<Display> handlers;

    private static final WizardViewImages images = GWT.create(WizardViewImages.class);

    public WizardView()
    {
        // Handlers
        handlers = new HandlerFactory<Display>(this);

        // outer panel
        this.outerPanel = new DockLayoutPanel(Unit.PX);
        initWidget(this.outerPanel);

        // title panel and contained html
        this.titlePanel = new HorizontalPanel();
        this.titlePanel.addStyleName("wizardTitle");
        this.titlePanel.addStyleName("hasBorder");

        this.titleHtml = new HTML("&nbsp;");
        this.titleHtml.setWidth("100%");
        this.titlePanel.add(this.titleHtml);
        this.workingIndicatorImage = new Image(images.workingIndicator());
        workingIndicatorImage.setVisible(false);
        this.titlePanel.add(workingIndicatorImage);
        titlePanel.setWidth("100%");

        // list of page names on the left
        this.pageNamePanelContainer = new ScrollPanel();
        this.pageNamePanelContainer.addStyleName("wizardPages");
        this.pageNamePanel = new WizardPageList();
        this.pageNamePanelContainer.add(this.pageNamePanel);

        // the navigation panel at the bottom
        this.navigationPanel = new WizardNavigationPanel();
        this.navigationPanel.addStyleName("wizardNavigation");

        // the main content panel
        this.pagePanel = new WizardDeckPanel();
        this.pagePanel.addStyleName("wizardContent");
        this.pagePanel.setAnimationEnabled(true);

        // add all the panels
        this.outerPanel.addNorth(this.titlePanel, 33);
        this.outerPanel.addWest(this.pageNamePanelContainer, 165);
        this.outerPanel.addSouth(this.navigationPanel, 25);
        this.outerPanel.add(this.pagePanel);
        this.outerPanel.getWidgetContainerElement(this.navigationPanel);
        this.outerPanel.getWidgetContainerElement(this.titlePanel).addClassName("valignMiddle");

        // add borders directly to the TD's
        // each element also gets "hasBorder" so injected styles
        // can override the color, width, etc. of the borders in one selector
        this.titlePanel.getElement().getParentElement().addClassName("bottomBorder");
        this.titlePanel.getElement().getParentElement().addClassName("hasBorder");
        this.pageNamePanelContainer.getElement().getParentElement().addClassName("rightBorder");
        this.pageNamePanelContainer.getElement().getParentElement().addClassName("hasBorder");
        this.navigationPanel.getElement().getParentElement().addClassName("topBorder");
        this.navigationPanel.getElement().getParentElement().addClassName("hasBorder");
    }

    @Override
    public HasWizardButtons getButtonBar() {
        return this.navigationPanel;
    }

    @Override
    public HasWizardTitles getPageList() {
        return this.pageNamePanel;
    }

    @Override
    public HasHTML getCaption() {
        return this.titleHtml;
    }

    @Override
    public HasIndexedWidgets getContent() {
        return this.pagePanel;
    }

    @Override
    public Widget asWidget() {
        return this;
    }

    @Override
    public void startProcessing() {
        workingIndicatorImage.setVisible(true);
    }

    @Override
    public void stopProcessing() {
        workingIndicatorImage.setVisible(false);
    }

    @Override
    public HandlerFactory<Display> getHandlerFactory() {
        return handlers;
    }

} public class WizardDeckPanel extends DeckPanel implements HasIndexedWidgets {
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import net.binarymuse.gwt.client.ui.wizard.WizardPage.PageID;
import net.binarymuse.gwt.client.ui.wizard.event.NavigationEvent;
import net.binarymuse.gwt.client.ui.wizard.event.handler.HandlerFactory;
import net.binarymuse.gwt.client.ui.wizard.exception.DuplicatePageException;
import net.binarymuse.gwt.client.ui.wizard.view.HasIndexedWidgets;
import net.binarymuse.gwt.client.ui.wizard.view.HasWizardButtonMethods;
import net.binarymuse.gwt.client.ui.wizard.view.HasWizardButtons;
import net.binarymuse.gwt.client.ui.wizard.view.HasWizardTitles;
import net.binarymuse.gwt.client.ui.wizard.view.LazyComposite;
import net.binarymuse.gwt.client.ui.wizard.view.WidgetDisplay;
import net.binarymuse.gwt.client.ui.wizard.view.impl.WizardView;
import net.binarymuse.gwt.client.ui.wizard.view.widget.WizardDeckPanel;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasHTML;
import com.google.gwt.user.client.ui.LazyPanel;
import com.google.gwt.user.client.ui.Widget;
package net.binarymuse.gwt.client.ui.wizard;




/**
 * Wizard provides a flexible step-by-step GWT widget.
 * It provides its own view, but you can provide your own
 * by extending the {@link Display} interface and passing
 * it to Wizard's constructor.
 * @author Brandon Tilley
 *
 * @param <C> the {@link WizardContext} subclass type
 */
public class Wizard<C extends WizardContext> extends Composite {

    /**
     * Wizard.Display defines a Wizard's visual display
     * (or "view" in MVP terms). {@link Wizard} comes with its
     * own implementation of Display ({@link WizardView}),
     * but you may provide your own if you wish via
     * {@link Wizard#Wizard(String, WizardContext, Display)}.
     * @author Brandon Tilley
     *
     */
    public interface Display extends WidgetDisplay {
        /**
         * The {@link Wizard}'s title is handled by an object that implements
         * GWT's <code>HasHTML</code>.
         * @return implementation of GWT's <code>HasHTML</code> for the {@link Wizard}'s title
         */
        HasHTML getCaption();
        /**
         * The {@link Wizard} maintains a list of its pages via an
         * implementation of {@link HasWizardTitles}.
         * @return implementation of {@link HasWizardTitles} for the {@link Wizard}'s page titles
         */
        HasWizardTitles getPageList();
        /**
         * The {@link Wizard}'s button bar is an implementation of
         * {@link HasWizardButtons}. If you implement your own button
         * bar, you can remove certain buttons (e.g., "Cancel")
         * by returning <code>null</code> in their getter functions (e.g.
         * {@link HasWizardButtons#getCancelButton()}.
         * @return implementation of {@link HasWizardButtons} for the {@link Wizard}'s button bar
         */
        HasWizardButtons getButtonBar();
        /**
         * The main content area is implemented with a GWT DeckPanel.
         * To keep this decision from being forced upon user-created
         * views, we extend DeckPanel into {@link WizardDeckPanel},
         * which implements {@link HasIndexedWidgets}. If you use a
         * panel that doesn't implement GWT's IndexedPanel, you have to
         * keep track of index-to-Widget relationships yourself,
         * since {@link Wizard} uses <code>getContent().showWidget(int index)</code>.
         * @return implementation of {@link HasIndexedWidgets} for the {@link Wizard}'s main content area
         */
        HasIndexedWidgets getContent();
        /**
         * Returns the Display's {@link HandlerFactory}, which provides
         * common event handlers for user created {@link Wizard}s and {@link WizardPage}s.
         * @return the {@link HandlerFactory} for this display
         */
        HandlerFactory<Display> getHandlerFactory();
        /**
         * Indicate to the view that work is being done. The
         * default view shows an animated "working" icon.
         */
        void startProcessing();
        /**
         * Indicate to the view that work is no longer being
         * done (used after calling {@link #startProcessing()}.
         */
        void stopProcessing();
        /**
         * {@link Wizard} is a composite that. <code>asWidget()</code>
         * returns the Widget that the Wizard will wrap using
         * <code>initWidget</code>.
         * @return the Widget the {@link Wizard} Composite will wrap
         */
        Widget asWidget();
    }

    /**
     * Defines the four types of Buttons a {@link Wizard}
     * can contain. Used in the button methods.
     * @see Wizard#getButton(ButtonType)
     * @see Wizard#setButtonEnabled(ButtonType, boolean)
     * @see Wizard#setButtonVisible(ButtonType, boolean)
     * @see Wizard#clickButton(ButtonType)
     * @author Brandon Tilley
     *
     */
    public enum ButtonType {
        BUTTON_CANCEL,
        BUTTON_FINISH,
        BUTTON_PREVIOUS,
        BUTTON_NEXT
    }

    // helper objects
    protected final WizardPageHelper<C> helper; // protected because there is no getter
    private C context;
    private boolean buttonOverride = false;

    // data objects
    private List<WizardPage<C>> pages;
    private final WizardPageLinkManager pageLinkManager;
    private int pageNum = -1;
    private List<Integer> shownPages;
    private boolean useLazyPageLoading;

    // ui objects
    protected Display display;

    /**
     * Construct a new Wizard, specifying a caption and
     * {@link WizardContext}.
     * @param caption the caption for the Wizard
     * @param context the contet for the Wizard
     */
    public Wizard(String caption, C context) {
        this(caption, context, null);
    }

    /**
     * Construct a new Wizard, specifying a caption,
     * {@link WizardContext}, and custom {@link Display}.
     * @param caption the caption for the Wizard
     * @param context the contet for the Wizard
     * @param view the custom {@link Display} for the Wizard
     */
    public Wizard(String caption, C context, Display view) {
        this.context = context;
        helper = new WizardPageHelper<C>(this);

        pages = new LinkedList<WizardPage<C>>();
        pageLinkManager = new WizardPageLinkManager();
        shownPages = new ArrayList<Integer>();
        useLazyPageLoading = false;

        // initialize view now, as setCaption depends on it.
        display = (view != null) ? view : new WizardView();

        setCaption(caption);
        initUi();
    }

    /**
     * Initializes the UI by calling <code>initWidget</code>
     * on the view and does universal UI setup.
     */
    protected void initUi() {
        // wrap the display in the composite
        initWidget(display.asWidget());
        this.setStylePrimaryName("muse-gwt-Wizard");

        display.getButtonBar().getNextButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                showNextPage();
            }
        });
        display.getButtonBar().getPreviousButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                showPreviousPage();
            }
        });
    }

    /**
     * Gets the Wizard's view as a {@link Display}.
     * @return the Wizard's view
     */
    public Display getView() {
        return display;
    }

    /**
     * Returns the Wizard page being displayed.
     * @return the page being displayed, or <code>null</code> if none
     * @see #getCurrentPageID()
     */
    public WizardPage<C> getCurrentPage() {
        return (pageNum != -1) ? pages.get(pageNum) : null;
    }

    /**
     * Convenience method to get the {@link PageID} of the
     * current {@link WizardPage}.
     * @return the {@link PageID} of the current {@link WizardPage}, or <code>null</code> if none
     * @see #getCurrentPage()
     */
    public WizardPage.PageID getCurrentPageID() {