com.google.appinventor.client.wizards.Wizard.java Source code

Java tutorial

Introduction

Here is the source code for com.google.appinventor.client.wizards.Wizard.java

Source

// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.client.wizards;

import static com.google.appinventor.client.Ode.MESSAGES;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * A wizard controls a dialog box that cycles through a series of pages.
 * <p>
 * The user may decide to cancel the wizard before viewing or completing
 * all of the pages. In that case, the wizard is closed and no further
 * action is taken.
 * <p>
 * After all pages have been cycled through, the user may invoke
 * a finish command. Immediately before the command is invoked,
 * the wizard dialog will be closed automatically.
 *
 */
public abstract class Wizard extends DialogBox {
    // UI for button panel to switch between wizard pages
    private final HorizontalPanel buttonPanel;
    private final Button backButton;
    private final Button cancelButton;
    private final Button nextButton;
    private final Button okButton;

    // Wizard pages
    private final AbsolutePanel pagePanel;
    private final DeckPanel pageDeck;
    private int currentPageIndex;

    // Command to execute upon finishing the wizard (not executed on cancel)
    private Command finishCommand;

    // Command to execute upon canceling the wizard (can be null)
    private Command cancelCommand;

    // Indicates whether the browser area size should be considered when calculating the wizard size
    private final boolean adaptiveSizing;

    // Indicates modality of the wizard
    private final boolean modal;

    /**
     * Creates a new wizard.
     * <p>
     * Implementations are expected to build the wizard dialog in their
     * constructor. In particular, it is expected that
     * {@link #addPage(Panel)} and {@link #initFinishCommand(Command)}
     * will be called before the constructor terminates.
     *
     * @param title title displayed in wizard dialog box
     * @param modal indicates modality of the wizard
     * @param adaptiveSizing instead of using the minimal size for the
     *                       wizard also considers the size of the browser area
     */
    protected Wizard(String title, boolean modal, boolean adaptiveSizing) {
        // Initialize UI
        // TODO(lizlooney) - investigate using built-in modality support. The
        // reasons for not using it initially are no longer valid.
        super(false, false);

        this.modal = modal;
        this.adaptiveSizing = adaptiveSizing;

        setStylePrimaryName("ode-DialogBox");
        setText(title);

        ClickListener buttonListener = new ClickListener() {
            @Override
            public void onClick(Widget sender) {
                if (sender == cancelButton) {
                    handleCancelClick();
                } else if (sender == nextButton) {
                    showNextPage();
                } else if (sender == backButton) {
                    showPreviousPage();
                } else if (sender == okButton) {
                    handleOkClick();
                }
            }
        };
        cancelButton = new Button(MESSAGES.cancelButton());
        cancelButton.addClickListener(buttonListener);
        backButton = new Button(MESSAGES.backButton());
        backButton.addClickListener(buttonListener);
        nextButton = new Button(MESSAGES.nextButton());
        nextButton.addClickListener(buttonListener);
        okButton = new Button(MESSAGES.okButton());
        okButton.addClickListener(buttonListener);

        buttonPanel = new HorizontalPanel();
        buttonPanel.add(cancelButton);
        buttonPanel.add(backButton);
        buttonPanel.add(nextButton);
        buttonPanel.add(okButton);
        buttonPanel.setSize("100%", "24px");

        pageDeck = new DeckPanel();
        pageDeck.setSize("100%", "100%");

        pagePanel = new AbsolutePanel();
        pagePanel.add(pageDeck);
        pagePanel.setWidth("100%");

        VerticalPanel contentPanel = new VerticalPanel();
        contentPanel.add(pagePanel);
        contentPanel.add(buttonPanel);
        contentPanel.setSize("100%", "100%");

        add(contentPanel);
    }

    @Override
    public boolean onEventPreview(Event event) {
        // Always allow event if capturing is enabled
        if (DOM.getCaptureElement() != null) {
            return true;
        }

        // If this is a modal wizard then only allow it if the target element is a child of this wizard
        if (modal) {
            Element target = DOM.eventGetTarget(event);
            return (target != null && DOM.isOrHasChild(getElement(), target));
        } else {
            return super.onEventPreview(event);
        }
    }

    /**
     * {@inheritDoc}
     *
     * Subclasses may override this to perform additional actions
     * after the wizard is shown, such as explicitly setting the
     * initially focused widget. Remember to call {@code super.show()}
     * as the first action in such overriding methods.
     */
    @Override
    public void show() {
        ensureInited();

        // Wizard size (having it resize between page changes is quite annoying)
        int width = 480;
        int height = 320;
        if (adaptiveSizing) {
            width = Math.max(width, Window.getClientWidth() / 3);
            height = Math.max(height, Window.getClientHeight() / 2);
        }
        setPixelSize(width, height);

        super.show();

        if (pageDeck.getWidgetCount() == 1) {
            buttonPanel.remove(backButton);
            buttonPanel.remove(nextButton);
        }

        // Show first wizard page
        currentPageIndex = 0;
        showCurrentPage();
    }

    /**
     * Adds a new page to the end of the wizard.
     */
    protected void addPage(Panel page) {
        page = new ScrollPanel(page);
        pageDeck.add(page);
    }

    public void setPagePanelHeight(int height) {
        pagePanel.setHeight(height + "px");
    }

    /**
     * Sets the command to be executed upon finish (not on cancel).
     * May only be invoked once.
     */
    protected void initFinishCommand(Command finishCommand) {
        if (this.finishCommand != null) {
            throw new IllegalStateException();
        }
        this.finishCommand = finishCommand;
    }

    /**
     * Sets the command to be executed upon cancel.
     * May be invoked no more than once.
     */
    protected void initCancelCommand(Command cancelCommand) {
        this.cancelCommand = cancelCommand;
    }

    /**
     * Ensures that this class is fully initialized.
     */
    private void ensureInited() {
        if (pageDeck.getWidgetCount() == 0 || finishCommand == null) {
            throw new IllegalStateException();
        }
    }

    /**
     * Invoked immediately after showing a new page
     *
     * @param pageNumber  number of page to be shown
     */
    protected void onPageInit(int pageNumber) {
    }

    /**
     * Invoked immediately before moving away from the current page.
     *
     * @param pageNumber  number of current page
     */
    protected void onPageFinish(int pageNumber) {
    }

    /**
     * Invoked immediately before closing the wizard.
     */
    protected void onHide() {
    }

    /**
     * Shows the previous page.
     */
    protected void showPreviousPage() {
        onPageFinish(currentPageIndex);
        currentPageIndex--;
        showCurrentPage();
        onPageInit(currentPageIndex);
    }

    /**
     * Shows the next page.
     */
    protected void showNextPage() {
        onPageFinish(currentPageIndex);
        currentPageIndex++;
        showCurrentPage();
        onPageInit(currentPageIndex);
    }

    protected final void handleCancelClick() {
        hideWizard();
        if (cancelCommand != null) {
            cancelCommand.execute();
        }
    }

    protected final void handleOkClick() {
        if (okButton.isEnabled()) {
            hideWizard();
            finishCommand.execute();
        }
    }

    protected final Button getConfirmButton() {
        return okButton;
    }

    protected void disableOkButton() {
        okButton.setEnabled(false);
    }

    protected void enableOkButton() {
        okButton.setEnabled(true);
    }

    /*
     * Hides the wizard.
     * Note that we are not overriding hide() because it is called by center() which can some
     * ugliness!
     */
    private void hideWizard() {
        onPageFinish(currentPageIndex);
        onHide();
        hide();
    }

    /*
     * Shows the wizard page for the currentPageIndex in the dialog box.
     */
    private void showCurrentPage() {
        // Enable back button if the current page is not the first page
        backButton.setEnabled(currentPageIndex > 0);

        // Enable next button if the current page is not the last page otherwise enable finish button
        boolean isLastPage = currentPageIndex == pageDeck.getWidgetCount() - 1;
        nextButton.setEnabled(!isLastPage);
        okButton.setEnabled(isLastPage);

        // Show page
        pageDeck.showWidget(currentPageIndex);

        // Because pages are embedded in scroll panels it is important to set the size of the page to
        // the current height of the content panel
        pageDeck.getWidget(currentPageIndex).setHeight(pagePanel.getOffsetHeight() + "px");
    }
}