All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openbp.swing.components.wizard.WizardImpl Maven / Gradle / Ivy

/*
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package org.openbp.swing.components.wizard;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.openbp.common.rc.ResourceCollection;

/**
 * Wizard component.
 *
 * @author Heiko Erhardt
 */
public class WizardImpl extends JPanel
	implements Wizard, ChangeListener
{
	/** Wizard resource file */
	private ResourceCollection wizardResourceCollection;

	/** Optional resource prefix for wizard page resources */
	private String pageResourcePrefix;

	/** Default wizard image */
	private ImageIcon defaultWizardImage;

	/** Default background image */
	private ImageIcon defaultBackgroundImage;

	/** Data collection model holding the data of the pages */
	private WizardDataModel dataModel;

	/** Page sequence manager */
	private SequenceManager manager;

	/** Wizard result page name */
	private String resultPageName;

	/** Wizard listeners */
	private List listeners;

	/** Deck of wizard pages */
	private JPanel deckPanel;

	/** Table of pages (maps page names to {@link WizardPage} objects) */
	private Map pages;

	/** Layout manager */
	private WizardLayout layout;

	/** Name of the recently added page */
	private String lastAdded;

	/** Navigation bar */
	private WizardNavigator nav;

	/**
	 * Constructor.
	 */
	public WizardImpl()
	{
		this(null, null, null);
	}

	/**
	 * Constructor.
	 *
	 * @param wizardResourceCollection The resource that contains texts and images for the wizard's navigator
	 */
	public WizardImpl(ResourceCollection wizardResourceCollection)
	{
		this(wizardResourceCollection, null, null);
	}

	/**
	 * Constructor.
	 *
	 * @param wizardResourceCollection The resource that contains texts and images for the wizard's navigator
	 * @param defaultWizardImage Default wizard image
	 */
	public WizardImpl(ResourceCollection wizardResourceCollection, ImageIcon defaultWizardImage)
	{
		this(wizardResourceCollection, defaultWizardImage, null);
	}

	/**
	 * Constructor.
	 *
	 * @param wizardResourceCollection The resource that contains texts and images for the wizard's navigator
	 * @param defaultWizardImage Default wizard image
	 * @param defaultBackgroundImage Default background image
	 */
	public WizardImpl(ResourceCollection wizardResourceCollection, ImageIcon defaultWizardImage, ImageIcon defaultBackgroundImage)
	{
		this.wizardResourceCollection = wizardResourceCollection;
		this.defaultWizardImage = defaultWizardImage;
		this.defaultBackgroundImage = defaultBackgroundImage;

		pages = new HashMap();

		setManager(new SequenceManagerImpl());
		setDataModel(new WizardDataModelImpl());

		setLayout(new BorderLayout());

		layout = new WizardLayout();
		deckPanel = new JPanel();
		deckPanel.setLayout(layout);
		add("Center", deckPanel);

		nav = new WizardNavigator(this, wizardResourceCollection);
		add("South", nav);

		// Map ESC key to cancel
		ActionListener cancelListener = new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				cancel();
			}
		};

		registerKeyboardAction(cancelListener, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
		nav.registerKeyboardAction(cancelListener, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

		// Don't show help button by default
		setShowHelp(false);
	}

	//////////////////////////////////////////////////
	// @@ Page access
	//////////////////////////////////////////////////

	/**
	 * Adds a page to the wizard and links it into the sequence manager's list.
	 * The pages will be displayed in the sequence
	 * they have been added to the wizard using this method.
	 *
	 * @param name Name of the page. Use this name for any sequence
	 * manager operations (see {@link #getManager}).
	 * @param page page to add.
	 * The page should be a subclass of {@link WizardPage}
	 */
	public void addAndLinkPage(String name, Component page)
	{
		if (pages.get(name) == null)
		{
			if (lastAdded == null)
			{
				manager.setFirst(name);
				manager.setCurrent(name);
			}
			else
			{
				manager.setPrevious(name, lastAdded);
				manager.setNext(lastAdded, name);
			}

			addPage(name, page);

			lastAdded = name;
		}
	}

	/**
	 * Adds a page to the wizard, but does not link it into the sequence manager's list.
	 * You have to use the methods of the sequence manager (see {@link #getManager}) to
	 * define the order the pages will appear.
	 *
	 * @param name Name of the page. Use this name for any sequence
	 * manager operations (see {@link #getManager}).
	 * @param page page to add.
	 * The page should be a subclass of {@link WizardPage}
	 */
	public void addPage(String name, Component page)
	{
		if (page instanceof WizardPage)
		{
			// Try to get the page title and description from the resource if not present yet
			WizardPage wp = (WizardPage) page;

			if (wp.getTitle() == null)
			{
				wp.setTitle(getPageResourceString(name, "title"));
			}

			if (wp.getDescription() == null)
			{
				wp.setDescription(getPageResourceString(name, "description"));
			}
		}

		page.setVisible(true);
		if (pages.get(name) == null)
		{
			pages.put(name, page);
			deckPanel.add(name, page);
		}
	}

	/**
	 * Removes a page from the wizard and the sequence manager.
	 *
	 * @param name Name of the page
	 */
	public void removePage(String name)
	{
		Component page = (Component) pages.remove(name);
		if (page != null)
		{
			deckPanel.remove(page);
		}

		manager.remove(name);
	}

	/**
	 * Gets a page by its name.
	 *
	 * @param name Name of the page or null for the current page
	 * @return The page component (usually an instance of {@link WizardPage})
	 */
	public Component getPage(String name)
	{
		return (Component) pages.get(name);
	}

	/**
	 * Gets the list of page names.
	 *
	 * @return An iterator of wizard page names (strings)
	 */
	public Iterator getPageNames()
	{
		return pages.keySet().iterator();
	}

	/**
	 * Gets the list of pages.
	 *
	 * @return An iterator of wizard pages (Component objects)
	 */
	public Iterator getPages()
	{
		return pages.values().iterator();
	}

	/**
	 * Gets the wizard result page name.
	 * The result page will be displayed after the user has pressed the 'Finish' button.
	 * It will not be considered by the sequence manager. Note that the result page
	 * component must have been added using the {@link #addPage} method.
	 *
	 * @return The name of the result page or null if no result page is set
	 */
	public String getResultPageName()
	{
		return resultPageName;
	}

	/**
	 * Sets the wizard result page name.
	 * The result page will be displayed after the user has pressed the 'Finish' button.
	 * It will not be considered by the sequence manager. Note that the result page
	 * component must have been added using the {@link #addPage} method.
	 *
	 * @param resultPageName The name of the result page or null for no result page
	 */
	public void setResultPageName(String resultPageName)
	{
		this.resultPageName = resultPageName;
	}

	/**
	 * Adds a result page to the wizard.
	 * The result page will be displayed after the user has pressed the 'Finish' button.
	 * It will not be considered by the sequence manager.
* This method is a convenience method for {@link #addPage} + {@link #setResultPageName} * * @param resultPageName The name of the result page or null for no result page * @param page Page component to add (usually a {@link WizardPage}) */ public void setResultPage(String resultPageName, Component page) { addPage(resultPageName, page); setResultPageName(resultPageName); } /** * Clears the wizard pages. * Clears all pages and the sequence manager information */ public void clearPages() { pages.clear(); manager.clear(); deckPanel.removeAll(); lastAdded = null; } ////////////////////////////////////////////////// // @@ Navigation ////////////////////////////////////////////////// /** * Displays the first page in the sequence. */ public void displayFirst() { if (!fireWizardEvent(WizardEvent.FIRST)) return; displayPage(manager.getFirst()); } /** * Displays the previous page. * Also called if the user presses the 'Back' button. */ public void displayBack() { if (!fireWizardEvent(WizardEvent.BACK)) return; displayPage(manager.getPrevious()); } /** * Displays the next page. * Also called if the user presses the 'Next' button. */ public void displayNext() { if (!fireWizardEvent(WizardEvent.NEXT)) return; displayPage(manager.getNext()); } /** * Finishes the wizard. * Also called if the user presses the 'Finish' button. */ public void finish() { if (!fireWizardEvent(WizardEvent.FINISH)) return; String currentPageName = manager.getCurrent(); if (resultPageName != null && !resultPageName.equals(currentPageName) && getPage(resultPageName) != null) { // We need to display the result page // Make sure we can get back from there manager.setPrevious(resultPageName, currentPageName); displayPage(resultPageName); } else { hideWizard(); } } /** * Cancels the wizard. * Also called if the user presses the 'Cancel' button. */ public void cancel() { if (!fireWizardEvent(WizardEvent.CANCEL)) return; hideWizard(); } /** * Closes the wizard. * Also called if the user presses the 'Close' button. */ public void close() { if (!fireWizardEvent(WizardEvent.CLOSE)) return; hideWizard(); } /** * Determines if we can return to the previous page. * Default: true. */ public boolean canMoveBackward() { WizardValidator validator = getCurrentValidator(); if (validator != null) { if (!validator.canMoveBackward()) return false; } return hasBackward(); } /** * Determines if there is a previous page. */ public boolean hasBackward() { return manager.getPrevious() != null; } /** * Determines if we can advance to the next page. * Default: false. */ public boolean canMoveForward() { WizardValidator validator = getCurrentValidator(); if (validator != null) { if (!validator.canMoveForward()) return false; } return hasForward(); } /** * Determines if there is a next page. */ public boolean hasForward() { return manager.getNext() != null; } /** * Determines if we can finish the wizard dialog at this point. * Default: false. */ public boolean canFinish() { WizardValidator validator = getCurrentValidator(); if (validator != null) { return validator.canFinish(); } if (hasForward()) return false; return true; } /** * Determines if we can cancel the wizard dialog at this point. * Default: true. */ public boolean canCancel() { WizardValidator validator = getCurrentValidator(); if (validator != null) { if (!validator.canCancel()) return false; } return true; } /** * Shows a particular page and updates the navigator. * * @param name Name of the page to show or null for the current one */ public void displayPage(String name) { if (name == null) name = manager.getCurrent(); Component page = getPage(name); if (page == null) return; manager.setCurrent(name); layout.show(deckPanel, page); fireWizardEvent(WizardEvent.SHOW); nav.updateNavigator(); // Set the focus to the page Component focusComponent = page; if (page instanceof WizardPage) { Component c = ((WizardPage) page).getFocusComponent(); if (c != null) focusComponent = c; } focusComponent.requestFocus(); } /** * Updates the navigation bar. * This method should be called if a page that does not make use of the wizard data model * (see {@link #setDataModel(WizardDataModel)}) has changed its status and wants to update the state of the navigation * bar buttons accordingly. */ public void updateNavigator() { nav.updateNavigator(); } /** * Hides the window the wizard is contained in. */ public void hideWizard() { Container root = getTopLevelAncestor(); root.setVisible(false); } ////////////////////////////////////////////////// // @@ Wizard events ////////////////////////////////////////////////// /** * Adds a wizard event listener. * The listener will be notified each time a property value changes. * * @param listener Listener */ public void addWizardListener(WizardListener listener) { if (listeners == null) listeners = new Vector(); listeners.add(listener); } /** * Removes a wizard event listener. * * @param listener Listener */ public void removeWizardListener(WizardListener listener) { listeners.remove(listener); if (listeners.isEmpty()) listeners = null; } /** * Fires a wizard event using the given event code. * * @param eventType Event code to fire * @return * true Processing can be continued.
* false The cancel flag of the event has been set by an event listener. */ public boolean fireWizardEvent(int eventType) { return fireWizardEvent(new WizardEvent(this, eventType)); } /** * Fires a wizard event. * * @param event Event to fire * @return * true Processing can be continued.
* false The cancel flag of the event has been set by an event listener. */ protected boolean fireWizardEvent(WizardEvent event) { // Send the event also to the current wizard page if it implements the listener interface Component c = getPage(manager.getCurrent()); if (c instanceof WizardListener) { ((WizardListener) c).handleWizardEvent(event); if (event.cancel) return false; } // Call all registered listeners if (listeners != null) { for (int i = 0; i < listeners.size(); i++) { WizardListener listener = (WizardListener) listeners.get(i); listener.handleWizardEvent(event); if (event.cancel) return false; } } return true; } ////////////////////////////////////////////////// // @@ Model change listener ////////////////////////////////////////////////// /** * Called if the state of the model changed. * The navigator is updated to reflect any changes in the model * that might lead to enable/disable the 'Next' or 'Finish' buttons. * * @param event Event */ public void stateChanged(ChangeEvent event) { nav.updateNavigator(); } ////////////////////////////////////////////////// // @@ Property access ////////////////////////////////////////////////// /** * Gets the data collection model holding the data of the pages. */ public WizardDataModel getDataModel() { return dataModel; } /** * Sets the data collection model holding the data of the pages. */ public void setDataModel(WizardDataModel dataModel) { if (this.dataModel != dataModel) { if (this.dataModel != null) dataModel.removeChangeListener(this); this.dataModel = dataModel; dataModel.addChangeListener(this); } } /** * Gets the page sequence manager. */ public SequenceManager getManager() { return manager; } /** * Sets the page sequence manager. */ public void setManager(SequenceManager manager) { this.manager = manager; } /** * Gets the wizard resource. */ public ResourceCollection getResource() { return wizardResourceCollection; } /** * Sets the wizard resource. */ public void setWizardResource(ResourceCollection wizardResourceCollection) { this.wizardResourceCollection = wizardResourceCollection; } /** * Gets the optional resource prefix for wizard page resources. */ public String getPageResourcePrefix() { return pageResourcePrefix; } /** * Sets the optional resource prefix for wizard page resources. */ public void setPageResourcePrefix(String pageResourcePrefix) { this.pageResourcePrefix = pageResourcePrefix; } /** * Sets the show help. */ public void setShowHelp(boolean showHelp) { nav.setShowHelp(showHelp); } /** * Gets the default wizard image. */ public ImageIcon getDefaultWizardImage() { return defaultWizardImage; } /** * Sets the default wizard image. */ public void setDefaultWizardImage(ImageIcon defaultWizardImage) { this.defaultWizardImage = defaultWizardImage; } /** * Gets the default background image. */ public ImageIcon getDefaultBackgroundImage() { return defaultBackgroundImage; } /** * Sets the default background image. */ public void setDefaultBackgroundImage(ImageIcon defaultBackgroundImage) { this.defaultBackgroundImage = defaultBackgroundImage; } ////////////////////////////////////////////////// // @@ Helpers ////////////////////////////////////////////////// /** * Gets a text resource for the specified page from the wizard resource. * The method will search the wizard resource for a string named "wizard.\i@lp pageResourcePrefix\i.\ipageName\i.\isuffix\i" * if a page resource prefix has been set. * If no such string can be found, the method will try "wizard.\ipageName\i.\isuffix\i" and "wizard.\isuffix\i". * * @param pageName Name of the wizard page * @param suffix Suffix to use for the the resource item name generation * @return The value of the resource item or null if no such resource item exists */ public String getPageResourceString(String pageName, String suffix) { String text = null; if (pageName != null) { if (pageResourcePrefix != null) { text = wizardResourceCollection.getOptionalString("wizard." + pageResourcePrefix + "." + pageName + "." + suffix); } if (text == null) { text = wizardResourceCollection.getOptionalString("wizard." + pageName + "." + suffix); } } if (text == null) { text = wizardResourceCollection.getOptionalString("wizard." + suffix); } return text; } /** * Gets the validator of the current wizard page. * * @return The validator object or null if there is no validator */ private WizardValidator getCurrentValidator() { Component c = getPage(manager.getCurrent()); if (c instanceof WizardValidator) { return ((WizardValidator) c); } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy